Skip to content

Commit

Permalink
Merge remote-tracking branch 'datamapper/main' into merge-datamapper
Browse files Browse the repository at this point in the history
  • Loading branch information
igarashitm committed Dec 9, 2024
2 parents 5a07676 + 00cad09 commit 3105b83
Show file tree
Hide file tree
Showing 342 changed files with 42,467 additions and 1,482 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ jobs:
- name: 💅 Run stylelint
run: yarn workspace @kaoto/kaoto run lint:style

# Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
- name: Build packages
run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build

# Run tests
- name: 🧪 Run tests
run: yarn workspaces foreach --verbose --all --topological-dev run test
Expand All @@ -45,10 +49,6 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}

# Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
- name: Build packages
run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build

# Build lib
- name: Build @kaoto/kaoto package in lib mode
run: yarn workspace @kaoto/kaoto run build:lib
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DataMapperDebugger } from '@kaoto/kaoto/testing';
import { Meta, StoryFn } from '@storybook/react';
import { fn } from '@storybook/test';

export default {
title: 'DataMapper/Debugger',
component: DataMapperDebugger,
} as Meta<typeof DataMapperDebugger>;

const Template: StoryFn<typeof DataMapperDebugger> = (args) => {
return <DataMapperDebugger {...args} />;
};

export const Debugger = Template.bind({});
Debugger.args = {
onUpdateDocument: fn(),
onUpdateMappings: fn(),
};
14 changes: 14 additions & 0 deletions packages/ui/jest-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ Object.defineProperty(window, 'fetch', {
value: jest.fn(),
});

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});

jest
.spyOn(global, 'crypto', 'get')
.mockImplementation(() => ({ getRandomValues: () => [12345678], subtle }) as unknown as Crypto);
Expand Down
9 changes: 8 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
],
"scripts": {
"start": "vite",
"build": "tsc && vite build --config vite.config.js",
"build": "tsc && NODE_OPTIONS=--max-old-space-size=3072 vite build --config vite.config.js",
"build:lib": "yarn rimraf ./lib && yarn copy-catalog && yarn build:esm && yarn build:cjs && yarn write-version",
"build:esm": "tsc --project tsconfig.esm.json && copyfiles -u 1 './src/**/*.scss' './src/assets/**' ./lib/esm",
"build:cjs": "tsc --project tsconfig.cjs.json && copyfiles -u 1 './src/**/*.scss' './src/assets/**' ./lib/cjs",
Expand All @@ -51,12 +51,17 @@
"lint:style:fix": "yarn lint:style --fix"
},
"dependencies": {
"@dnd-kit/core": "^6.1.0",
"@kaoto-next/uniforms-patternfly": "^0.7.14",
"@kaoto/xml-schema-ts": "workspace:*",
"@kie-tools-core/editor": "0.32.0",
"@kie-tools-core/notifications": "0.32.0",
"@types/uuid": "^10.0.0",
"@types/xml-name-validator": "^4.0.3",
"@visx/shape": "^3.12.0",
"ajv": "^8.12.0",
"ajv-formats": "^3.0.0",
"chevrotain": "10.5.0",
"clsx": "^2.1.0",
"html-to-image": "^1.11.11",
"lodash": "^4.17.21",
Expand All @@ -67,6 +72,8 @@
"uniforms-bridge-json-schema": "4.0.0-alpha.6",
"usehooks-ts": "^3.0.0",
"uuid": "^10.0.0",
"xml-formatter": "^3.6.2",
"xml-name-validator": "^5.0.0",
"yaml": "^2.3.2",
"zustand": "^4.3.9"
},
Expand Down
24 changes: 21 additions & 3 deletions packages/ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { VisualizationProvider } from '@patternfly/react-topology';
import { useMemo } from 'react';
import { Outlet } from 'react-router-dom';
import { RenderingProvider } from './components/RenderingAnchor/rendering.provider';
import { ControllerService } from './components/Visualization/Canvas/controller.service';
import { RegisterComponents } from './components/registers/RegisterComponents';
import { RegisterNodeInteractionAddons } from './components/registers/RegisterNodeInteractionAddons';
import { NodeInteractionAddonProvider } from './components/registers/interactions/node-interaction-addon.provider';
import { useReload } from './hooks/reload.hook';
import { Shell } from './layout/Shell';
import { LocalStorageSettingsAdapter } from './models/settings/localstorage-settings-adapter';
Expand All @@ -17,6 +24,7 @@ import { CatalogSchemaLoader } from './utils/catalog-schema-loader';

function App() {
const ReloadProvider = useReload();
const controller = useMemo(() => ControllerService.createController(), []);
const settingsAdapter = new LocalStorageSettingsAdapter();
let catalogUrl = CatalogSchemaLoader.DEFAULT_CATALOG_PATH;
const settingsCatalogUrl = settingsAdapter.getSettings().catalogUrl;
Expand All @@ -35,9 +43,19 @@ function App() {
<SchemasLoaderProvider>
<CatalogLoaderProvider>
<CatalogTilesProvider>
<VisibleFlowsProvider>
<Outlet />
</VisibleFlowsProvider>
<VisualizationProvider controller={controller}>
<VisibleFlowsProvider>
<RenderingProvider>
<RegisterComponents>
<NodeInteractionAddonProvider>
<RegisterNodeInteractionAddons>
<Outlet />
</RegisterNodeInteractionAddons>
</NodeInteractionAddonProvider>
</RegisterComponents>
</RenderingProvider>
</VisibleFlowsProvider>
</VisualizationProvider>
</CatalogTilesProvider>
</CatalogLoaderProvider>
</SchemasLoaderProvider>
Expand Down
Binary file added packages/ui/src/assets/components/datamapper.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 97 additions & 0 deletions packages/ui/src/assets/kaoto-patterns/kaoto-patterns.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"kaoto-datamapper" : {
"model" : {
"kind" : "model",
"name" : "kaoto-datamapper",
"title" : "Kaoto DataMapper",
"description" : "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
"deprecated" : false,
"label" : "transformation",
"javaType" : "org.apache.camel.model.StepDefinition",
"supportLevel" : "Stable",
"abstract" : false,
"input" : true,
"output" : true
},
"properties" : {
"description" : {
"index" : 0,
"kind" : "attribute",
"displayName" : "Description",
"group" : "common",
"required" : false,
"type" : "string",
"javaType" : "java.lang.String",
"deprecated" : false,
"autowired" : false,
"secret" : false,
"description" : "Sets the description of this node"
},
"disabled" : {
"index" : 1,
"kind" : "attribute",
"displayName" : "Disabled",
"group" : "advanced",
"label" : "advanced",
"required" : false,
"type" : "boolean",
"javaType" : "java.lang.Boolean",
"deprecated" : false,
"autowired" : false,
"secret" : false,
"defaultValue" : false,
"description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime."
},
"outputs" : {
"index" : 2,
"kind" : "element",
"displayName" : "Outputs",
"group" : "common",
"required" : true,
"type" : "array",
"javaType" : "java.util.List",
"oneOf" : [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "onFallback", "otherwise", "pausable", "pipeline", "policy", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "serviceCall", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "transacted", "transform", "unmarshal", "validate", "when", "whenSkipSendToEndpoint", "wireTap" ],
"deprecated" : false,
"autowired" : false,
"secret" : false
}
},
"exchangeProperties" : {
"CamelStepId" : {
"index" : 0,
"kind" : "exchangeProperty",
"displayName" : "Step Id",
"label" : "producer",
"required" : false,
"javaType" : "String",
"deprecated" : false,
"autowired" : false,
"secret" : false,
"description" : "The id of the Step EIP"
}
},
"propertiesSchema" : {
"title" : "Kaoto DataMapper",
"description" : "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
"type" : "object",
"additionalProperties" : false,
"properties" : {
"description" : {
"type" : "string",
"title" : "Description",
"description" : "Sets the description of this node",
"group" : "common"
},
"disabled" : {
"type" : "boolean",
"title" : "Disabled",
"description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
"group" : "advanced"
}
},
"$comment" : "steps",
"$schema" : "http://json-schema.org/draft-07/schema#",
"required" : [ ]
}
}
}
17 changes: 16 additions & 1 deletion packages/ui/src/camel-utils/camel-random-id.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCamelRandomId } from './camel-random-id';
import { getCamelRandomId, getHexaDecimalRandomId } from './camel-random-id';

describe('camel-random-id', () => {
it('should return a random number', () => {
Expand Down Expand Up @@ -35,4 +35,19 @@ describe('camel-random-id', () => {

expect(getCamelRandomId('route')).toEqual(expect.any(String));
});

describe('getHexaDecimalRandomId()', () => {
it('should return a random number with Hexadecimal format', async () => {
// crypto.getRandomValues() in Jest returns a fixed number 12345678. Replacing with Date.now()
jest
.spyOn(global, 'crypto', 'get')
.mockImplementation(() => ({ getRandomValues: () => [Date.now()] }) as unknown as Crypto);
const one = getHexaDecimalRandomId('test');
expect(one).toMatch(/test-[0-9a-f]{1,8}/);
await new Promise((f) => setTimeout(f, 1));
const two = getHexaDecimalRandomId('test');
expect(two).toMatch(/test-[0-9a-f]{1,8}/);
expect(one).not.toEqual(two);
});
});
});
12 changes: 10 additions & 2 deletions packages/ui/src/camel-utils/camel-random-id.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
const getCryptoObj = () => {
return window.crypto || (window as Window & { msCrypto?: Crypto }).msCrypto;
};

export const getCamelRandomId = (kind: string, length = 4): string => {
const cryptoObj = window.crypto || (window as Window & { msCrypto?: Crypto }).msCrypto;
const randomNumber = Math.floor(cryptoObj?.getRandomValues(new Uint32Array(1))[0] ?? Date.now());
const randomNumber = Math.floor(getCryptoObj()?.getRandomValues(new Uint32Array(1))[0] ?? Date.now());

return `${kind}-${randomNumber.toString(10).slice(0, length)}`;
};

export const getHexaDecimalRandomId = (prefix: string) => {
const randomNumber = getCryptoObj()?.getRandomValues(new Uint32Array(1))[0] ?? Date.now();
return `${prefix}-${randomNumber.toString(16)}`;
};
113 changes: 113 additions & 0 deletions packages/ui/src/components/DataMapper/DataMapper.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { render, screen } from '@testing-library/react';
import { IVisualizationNode } from '../../models';
import { DocumentDefinitionType } from '../../models/datamapper/document';
import { IDataMapperMetadata } from '../../models/datamapper/metadata';
import { IMetadataApi, MetadataProvider } from '../../providers';
import { shipOrderToShipOrderXslt, shipOrderXsd } from '../../stubs/data-mapper';
import { DataMapper } from './DataMapper';

describe('DataMapperPage', () => {
const vizNode = {
getId: () => 'route-1234',
getComponentSchema: () => {
return {
definition: { id: 'kaoto-datamapper-1234' },
};
},
} as unknown as IVisualizationNode;
const defaultMetadata: IDataMapperMetadata = {
sourceBody: {
type: DocumentDefinitionType.Primitive,
filePath: [],
},
sourceParameters: {},
targetBody: {
type: DocumentDefinitionType.Primitive,
filePath: [],
},
xsltPath: `kaoto-datamapper-1234.xsl`,
};

let metadata: IDataMapperMetadata;
let fileContents: Record<string, string>;
const api = {
getMetadata: (_key: string) => {
return Promise.resolve(metadata);
},
setMetadata: (_key: string, meta: IDataMapperMetadata) => {
Object.assign(metadata, meta);
return Promise.resolve();
},
getResourceContent: (path: string) => {
return Promise.resolve(fileContents[path]);
},
saveResourceContent: (path: string, content: string) => {
fileContents[path] = content;
return Promise.resolve();
},
} as IMetadataApi;

beforeEach(() => {
metadata = defaultMetadata;
fileContents = {};
});

it('should render initial XSLT mappings', async () => {
fileContents[metadata.xsltPath] = shipOrderToShipOrderXslt;
render(
<MetadataProvider api={api}>
<DataMapper vizNode={vizNode} />
</MetadataProvider>,
);
await screen.findByTestId('card-source-parameters-header');
// TODO assert mappings are restored even without loading schema... But how? Lines are not drawn...
});

it('should render initial XSLT mappings with initial documents', async () => {
fileContents['ShipOrder.xsd'] = shipOrderXsd;
metadata.sourceBody = {
filePath: ['ShipOrder.xsd'],
type: DocumentDefinitionType.XML_SCHEMA,
};
metadata.targetBody = {
filePath: ['ShipOrder.xsd'],
type: DocumentDefinitionType.XML_SCHEMA,
};
metadata.sourceParameters['testparam1'] = {
filePath: [],
type: DocumentDefinitionType.Primitive,
};
render(
<MetadataProvider api={api}>
<DataMapper vizNode={vizNode} />
</MetadataProvider>,
);
await screen.findByTestId('card-source-parameters-header');
expect(screen.getByTestId('node-source-doc-param-testparam1')).toBeInTheDocument();
expect(screen.getByTestId('node-source-doc-sourceBody-Body')).toBeInTheDocument();
expect(screen.getByTestId('node-target-doc-targetBody-Body')).toBeInTheDocument();
expect(screen.getByTestId(/node-source-field-OrderId-\n*/)).toBeInTheDocument();
expect(screen.getByTestId(/node-target-field-OrderId-\n*/)).toBeInTheDocument();
// TODO assert mappings are restored even without loading schema... But how? Lines are not drawn...
});

it('should not render toolbar menu in embedded mode', async () => {
render(
<MetadataProvider api={api}>
<DataMapper vizNode={vizNode} />
</MetadataProvider>,
);
try {
await screen.findByTestId('main-menu-button');
fail();
} catch (e) {
expect(e).toBeTruthy();
}
});

it('should show an error message if vizNode is not provided', async () => {
render(<DataMapper />);
const error = await screen.findByText('No associated DataMapper step was provided.');
expect(error).toBeInTheDocument();
});
});
Loading

0 comments on commit 3105b83

Please sign in to comment.