From a928459b9d6f6ee6da2f0d036e4fc64f54ddb5ed Mon Sep 17 00:00:00 2001 From: "Ricardo M." Date: Tue, 17 Dec 2024 15:20:16 +0100 Subject: [PATCH] feat(Canvas): add useVizNodeModel Temp: All test passing except for Kamelets and Pipes --- .../hoverToolbarActions.cy.ts | 4 - .../sidepanelConfig/propertiesFilter.cy.ts | 2 + .../Form/properties/PropertiesField.tsx | 2 +- .../Form/properties/PropertyRow.tsx | 3 - .../Canvas/Form/CanvasFormBody.tsx | 126 ++++++++---------- .../Visualization/Custom/Node/CustomNode.tsx | 7 +- .../Custom/hooks/disable-step.hook.tsx | 18 +-- packages/ui/src/hooks/index.ts | 1 + packages/ui/src/hooks/viznode-model.ts | 18 +++ packages/ui/src/stubs/kamelet-route.ts | 3 +- .../get-custom-schema-from-kamelet.test.ts | 112 +++------------- packages/ui/src/utils/pipe-custom-schema.ts | 9 +- .../update-kamelet-from-custom-schema.ts | 42 +++--- 13 files changed, 134 insertions(+), 213 deletions(-) create mode 100644 packages/ui/src/hooks/viznode-model.ts diff --git a/packages/ui-tests/cypress/e2e/designer/basicNodeActions/hoverToolbarActions.cy.ts b/packages/ui-tests/cypress/e2e/designer/basicNodeActions/hoverToolbarActions.cy.ts index 61f8adbfd..857edd637 100644 --- a/packages/ui-tests/cypress/e2e/designer/basicNodeActions/hoverToolbarActions.cy.ts +++ b/packages/ui-tests/cypress/e2e/designer/basicNodeActions/hoverToolbarActions.cy.ts @@ -33,15 +33,11 @@ describe('Test toolbar on hover actions', () => { cy.openStepConfigurationTab('setHeader'); cy.get('[data-testid="step-toolbar-button-disable"]').click(); - cy.openStepConfigurationTab('setHeader'); cy.selectFormTab('All'); cy.checkConfigCheckboxObject('disabled', true); - cy.openStepConfigurationTab('setHeader'); cy.get('[data-testid="step-toolbar-button-disable"]').click(); - cy.openStepConfigurationTab('setHeader'); - cy.selectFormTab('All'); cy.checkConfigCheckboxObject('disabled', false); }); diff --git a/packages/ui-tests/cypress/e2e/designer/sidepanelConfig/propertiesFilter.cy.ts b/packages/ui-tests/cypress/e2e/designer/sidepanelConfig/propertiesFilter.cy.ts index 32ba8c828..3d7eaaf9c 100644 --- a/packages/ui-tests/cypress/e2e/designer/sidepanelConfig/propertiesFilter.cy.ts +++ b/packages/ui-tests/cypress/e2e/designer/sidepanelConfig/propertiesFilter.cy.ts @@ -86,6 +86,8 @@ describe('Tests for side panel step filtering', () => { cy.get(`input[name="variableSend"]`).should('exist'); cy.get(`input[name="variableReceive"]`).should('exist'); + cy.checkConfigInputObject('variableSend', 'testVariableSend'); + cy.checkConfigInputObject('variableReceive', 'testVariableReceive'); cy.get(`textarea[name="description"]`).should('not.exist'); cy.get(`input[name="id"]`).should('not.exist'); diff --git a/packages/ui/src/components/Form/properties/PropertiesField.tsx b/packages/ui/src/components/Form/properties/PropertiesField.tsx index 37e856fc1..c00d41ee4 100644 --- a/packages/ui/src/components/Form/properties/PropertiesField.tsx +++ b/packages/ui/src/components/Form/properties/PropertiesField.tsx @@ -18,7 +18,7 @@ import { PropertyRow } from './PropertyRow'; * @constructor */ export const PropertiesField = connectField((props: IPropertiesField) => { - const propertiesModel = props.value ? { ...props.value } : {}; + const propertiesModel = props.value; const [isFieldExpanded, setFieldExpanded] = useState(Object.keys(propertiesModel).length > 0); const [expandedNodes, setExpandedNodes] = useState([]); const [placeholderState, setPlaceholderState] = useState(null); diff --git a/packages/ui/src/components/Form/properties/PropertyRow.tsx b/packages/ui/src/components/Form/properties/PropertyRow.tsx index ae4791bd2..38d67c83a 100644 --- a/packages/ui/src/components/Form/properties/PropertyRow.tsx +++ b/packages/ui/src/components/Form/properties/PropertyRow.tsx @@ -85,9 +85,6 @@ export function PropertyRow({ setUserInputName(nodeName); setUserInputValue(nodeValue); setIsEditing(false); - if (isPlaceholder) { - onChangeModel(); - } } function getKey() { diff --git a/packages/ui/src/components/Visualization/Canvas/Form/CanvasFormBody.tsx b/packages/ui/src/components/Visualization/Canvas/Form/CanvasFormBody.tsx index d8f7b9b94..cb3c6d042 100644 --- a/packages/ui/src/components/Visualization/Canvas/Form/CanvasFormBody.tsx +++ b/packages/ui/src/components/Visualization/Canvas/Form/CanvasFormBody.tsx @@ -1,35 +1,37 @@ -import { FunctionComponent, useCallback, useContext, useEffect, useMemo, useRef } from 'react'; -import { EntitiesContext } from '../../../../providers/entities.provider'; +import { FunctionComponent, useContext, useEffect, useRef } from 'react'; +import { useVizNodeModel } from '../../../../hooks'; +import { CanvasFormTabsContext } from '../../../../providers/canvas-form-tabs.provider'; import { SchemaBridgeProvider } from '../../../../providers/schema-bridge.provider'; -import { getUserUpdatedPropertiesSchema, getRequiredPropertiesSchema, isDefined, setValue } from '../../../../utils'; +import { getRequiredPropertiesSchema, getUserUpdatedPropertiesSchema, isDefined, setValue } from '../../../../utils'; import { CustomAutoForm, CustomAutoFormRef } from '../../../Form/CustomAutoForm'; import { DataFormatEditor } from '../../../Form/dataFormat/DataFormatEditor'; import { LoadBalancerEditor } from '../../../Form/loadBalancer/LoadBalancerEditor'; import { StepExpressionEditor } from '../../../Form/stepExpression/StepExpressionEditor'; import { UnknownNode } from '../../Custom/UnknownNode'; import { CanvasNode } from '../canvas.models'; -import { CanvasFormTabsContext } from '../../../../providers/canvas-form-tabs.provider'; interface CanvasFormTabsProps { selectedNode: CanvasNode; } export const CanvasFormBody: FunctionComponent = (props) => { - const entitiesContext = useContext(EntitiesContext); + const vizNode = props.selectedNode.data?.vizNode; + if (!vizNode) { + throw new Error('CanvasFormBody must be used only on Node elements with an available IVisualizationNode'); + } + const { selectedTab } = useContext(CanvasFormTabsContext) ?? { selectedTab: 'Required' }; const divRef = useRef(null); const formRef = useRef(null); - const omitFields = useRef(props.selectedNode.data?.vizNode?.getOmitFormFields() || []); + const omitFields = useRef(vizNode.getOmitFormFields() || []); - const visualComponentSchema = useMemo(() => { - const answer = props.selectedNode.data?.vizNode?.getComponentSchema(); - // Overriding parameters with an empty object When the parameters property is mistakenly set to null - if (answer?.definition?.parameters === null) { - answer!.definition.parameters = {}; - } - return answer; - }, [props.selectedNode.data?.vizNode, selectedTab]); - const model = visualComponentSchema?.definition; + const { model, updateModel } = useVizNodeModel>(vizNode); + // Overriding parameters with an empty object When the parameters property is mistakenly set to null + if (model.parameters === null) { + model.parameters = {}; + } + + const visualComponentSchema = vizNode.getComponentSchema(); let processedSchema = visualComponentSchema?.schema; if (selectedTab === 'Required') { processedSchema = getRequiredPropertiesSchema(visualComponentSchema?.schema ?? {}); @@ -40,68 +42,48 @@ export const CanvasFormBody: FunctionComponent = (props) => }; } - useEffect(() => { - formRef.current?.form.reset(); - }, [props.selectedNode.data?.vizNode, selectedTab]); + const comment = visualComponentSchema?.schema?.['$comment'] ?? ''; + const isExpressionAwareStep = comment.includes('expression'); + const isDataFormatAwareStep = comment.includes('dataformat'); + const isLoadBalanceAwareStep = comment.includes('loadbalance'); + const isUnknownComponent = + !isDefined(visualComponentSchema) || + !isDefined(visualComponentSchema.schema) || + Object.keys(visualComponentSchema.schema).length === 0; - const stepFeatures = useMemo(() => { - const comment = visualComponentSchema?.schema?.['$comment'] ?? ''; - const isExpressionAwareStep = comment.includes('expression'); - const isDataFormatAwareStep = comment.includes('dataformat'); - const isLoadBalanceAwareStep = comment.includes('loadbalance'); - const isUnknownComponent = - !isDefined(visualComponentSchema) || - !isDefined(visualComponentSchema.schema) || - Object.keys(visualComponentSchema.schema).length === 0; - return { isExpressionAwareStep, isDataFormatAwareStep, isLoadBalanceAwareStep, isUnknownComponent }; - }, [visualComponentSchema]); + const handleOnChangeIndividualProp = (path: string, value: unknown) => { + let updatedValue = value; + if (typeof value === 'string' && value.trim() === '') { + updatedValue = undefined; + } - const handleOnChangeIndividualProp = useCallback( - (path: string, value: unknown) => { - if (!props.selectedNode.data?.vizNode) { - return; - } + setValue(model, path, updatedValue); + updateModel(model); + }; - let updatedValue = value; - if (typeof value === 'string' && value.trim() === '') { - updatedValue = undefined; - } + useEffect(() => { + formRef.current?.form.reset(); + }, [vizNode, selectedTab]); - const newModel = props.selectedNode.data.vizNode.getComponentSchema()?.definition || {}; - setValue(newModel, path, updatedValue); - props.selectedNode.data.vizNode.updateModel(newModel); - entitiesContext?.updateSourceCodeFromEntities(); - }, - [entitiesContext, props.selectedNode.data?.vizNode], - ); + if (isUnknownComponent) { + return ; + } return ( - <> - {stepFeatures.isUnknownComponent ? ( - - ) : ( - - {stepFeatures.isExpressionAwareStep && ( - - )} - {stepFeatures.isDataFormatAwareStep && ( - - )} - {stepFeatures.isLoadBalanceAwareStep && ( - - )} - -
- - )} - + + {isExpressionAwareStep && } + {isDataFormatAwareStep && } + {isLoadBalanceAwareStep && } + +
+ ); }; diff --git a/packages/ui/src/components/Visualization/Custom/Node/CustomNode.tsx b/packages/ui/src/components/Visualization/Custom/Node/CustomNode.tsx index dc8092876..f9fc0b3a4 100644 --- a/packages/ui/src/components/Visualization/Custom/Node/CustomNode.tsx +++ b/packages/ui/src/components/Visualization/Custom/Node/CustomNode.tsx @@ -27,6 +27,7 @@ import { NodeContextMenuFn } from '../ContextMenu/NodeContextMenu'; import { AddStepIcon } from '../Edge/AddStepIcon'; import { TargetAnchor } from '../target-anchor'; import './CustomNode.scss'; +import { useVizNodeModel } from '../../../../hooks'; type DefaultNodeProps = Parameters[0]; interface CustomNodeProps extends DefaultNodeProps, WithSelectionProps { @@ -43,10 +44,8 @@ const CustomNode: FunctionComponent = observer(({ element, onCo const vizNode: IVisualizationNode | undefined = element.getData()?.vizNode; const settingsAdapter = useContext(SettingsContext); const label = vizNode?.getNodeLabel(settingsAdapter.getSettings().nodeLabel); - const isDisabled = !!vizNode?.getComponentSchema()?.definition?.disabled; const tooltipContent = vizNode?.getTooltipContent(); const validationText = vizNode?.getNodeValidationText(); - const doesHaveWarnings = !isDisabled && !!validationText; const [isSelected, onSelect] = useSelection(); const [isGHover, gHoverRef] = useHover(CanvasDefaults.HOVER_DELAY_IN, CanvasDefaults.HOVER_DELAY_OUT); const [isToolbarHover, toolbarHoverRef] = useHover( @@ -76,6 +75,10 @@ const CustomNode: FunctionComponent = observer(({ element, onCo return null; } + const { model } = useVizNodeModel<{ disabled?: boolean }>(vizNode); + const isDisabled = !!model.disabled; + const doesHaveWarnings = !isDisabled && !!validationText; + return ( { - const entitiesContext = useContext(EntitiesContext); - const isDisabled = !!vizNode.getComponentSchema()?.definition?.disabled; + const { model, updateModel } = useVizNodeModel<{ disabled?: boolean }>(vizNode); + const isDisabled = !!model.disabled; const onToggleDisableNode = useCallback(() => { - const newModel = vizNode.getComponentSchema()?.definition || {}; - setValue(newModel, 'disabled', !isDisabled); - vizNode.updateModel(newModel); - - entitiesContext?.updateEntitiesFromCamelResource(); - }, [entitiesContext, isDisabled, vizNode]); + const newModel = { ...model, disabled: !isDisabled }; + updateModel(newModel); + }, [isDisabled, model, updateModel]); const value = useMemo( () => ({ diff --git a/packages/ui/src/hooks/index.ts b/packages/ui/src/hooks/index.ts index b1886c631..d95e58dd8 100644 --- a/packages/ui/src/hooks/index.ts +++ b/packages/ui/src/hooks/index.ts @@ -2,3 +2,4 @@ export * from './applied-schema.hook'; export * from './entities'; export * from './local-storage.hook'; export * from './schema-bridge.hook'; +export * from './viznode-model'; diff --git a/packages/ui/src/hooks/viznode-model.ts b/packages/ui/src/hooks/viznode-model.ts new file mode 100644 index 000000000..a51ae3272 --- /dev/null +++ b/packages/ui/src/hooks/viznode-model.ts @@ -0,0 +1,18 @@ +import { useContext } from 'react'; +import { IVisualizationNode } from '../models'; +import { EntitiesContext, SourceCodeContext } from '../providers'; + +export const useVizNodeModel = ( + vizNode: IVisualizationNode, +): { model: T; updateModel: (model: unknown) => void; sourceCode: string } => { + const entitiesContext = useContext(EntitiesContext); + const sourceCode = useContext(SourceCodeContext); + const model = vizNode.getComponentSchema()?.definition ?? {}; + + const updateModel = (newModel: unknown) => { + vizNode.updateModel(newModel); + entitiesContext?.updateSourceCodeFromEntities(); + }; + + return { model, updateModel, sourceCode }; +}; diff --git a/packages/ui/src/stubs/kamelet-route.ts b/packages/ui/src/stubs/kamelet-route.ts index 8ebdd7d34..c8fbbb3d2 100644 --- a/packages/ui/src/stubs/kamelet-route.ts +++ b/packages/ui/src/stubs/kamelet-route.ts @@ -1,4 +1,5 @@ import { parse } from 'yaml'; +import { IKameletDefinition } from '../models/kamelets-catalog'; /** * This is a stub Kamelet in YAML format. @@ -53,4 +54,4 @@ spec: * This is a stub Kamelet in JSON format. * It is used to test the Canvas component. */ -export const kameletJson = parse(kameletYaml); +export const kameletJson: IKameletDefinition = parse(kameletYaml); diff --git a/packages/ui/src/utils/get-custom-schema-from-kamelet.test.ts b/packages/ui/src/utils/get-custom-schema-from-kamelet.test.ts index 9732f1bae..c29f44f56 100644 --- a/packages/ui/src/utils/get-custom-schema-from-kamelet.test.ts +++ b/packages/ui/src/utils/get-custom-schema-from-kamelet.test.ts @@ -2,76 +2,13 @@ import { cloneDeep } from 'lodash'; import { SourceSchemaType } from '../models/camel/source-schema-type'; import { IKameletDefinition, IKameletSpecProperty } from '../models/kamelets-catalog'; import { getCustomSchemaFromKamelet } from './get-custom-schema-from-kamelet'; +import { kameletJson } from '../stubs'; describe('getCustomSchemaFromKamelet', () => { let inputKameletStruct: IKameletDefinition; beforeEach(() => { - inputKameletStruct = { - apiVersion: 'camel.apache.org/v1', - kind: SourceSchemaType.Kamelet, - metadata: { - annotations: { - 'camel.apache.org/catalog.version': 'main-SNAPSHOT', - 'camel.apache.org/kamelet.group': 'Users', - 'camel.apache.org/kamelet.icon': - 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgNjAgNjAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYwIDYwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxwYXRoIGQ9Ik00OC4wMTQsNDIuODg5bC05LjU1My00Ljc3NkMzNy41NiwzNy42NjIsMzcsMzYuNzU2LDM3LDM1Ljc0OHYtMy4zODFjMC4yMjktMC4yOCwwLjQ3LTAuNTk5LDAuNzE5LTAuOTUxCgljMS4yMzktMS43NSwyLjIzMi0zLjY5OCwyLjk1NC01Ljc5OUM0Mi4wODQsMjQuOTcsNDMsMjMuNTc1LDQzLDIydi00YzAtMC45NjMtMC4zNi0xLjg5Ni0xLTIuNjI1di01LjMxOQoJYzAuMDU2LTAuNTUsMC4yNzYtMy44MjQtMi4wOTItNi41MjVDMzcuODU0LDEuMTg4LDM0LjUyMSwwLDMwLDBzLTcuODU0LDEuMTg4LTkuOTA4LDMuNTNDMTcuNzI0LDYuMjMxLDE3Ljk0NCw5LjUwNiwxOCwxMC4wNTYKCXY1LjMxOWMtMC42NCwwLjcyOS0xLDEuNjYyLTEsMi42MjV2NGMwLDEuMjE3LDAuNTUzLDIuMzUyLDEuNDk3LDMuMTA5YzAuOTE2LDMuNjI3LDIuODMzLDYuMzYsMy41MDMsNy4yMzd2My4zMDkKCWMwLDAuOTY4LTAuNTI4LDEuODU2LTEuMzc3LDIuMzJsLTguOTIxLDQuODY2QzguODAxLDQ0LjQyNCw3LDQ3LjQ1OCw3LDUwLjc2MlY1NGMwLDQuNzQ2LDE1LjA0NSw2LDIzLDZzMjMtMS4yNTQsMjMtNnYtMy4wNDMKCUM1Myw0Ny41MTksNTEuMDg5LDQ0LjQyNyw0OC4wMTQsNDIuODg5eiIvPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K', - 'camel.apache.org/kamelet.namespace': 'test', - 'camel.apache.org/kamelet.support.level': 'Stable', - 'camel.apache.org/provider': 'Apache Software Foundation', - foo: 'bar', - }, - labels: { - 'camel.apache.org/kamelet.type': 'Action', - type: 'Action', - }, - name: 'test', - }, - spec: { - definition: { - description: 'test description!', - properties: { - period: { - default: 5000, - description: 'The time interval between two events', - title: 'Period', - type: 'integer', - }, - }, - title: 'kamelet-35256', - type: 'object', - }, - dependencies: ['camel:timer', 'camel:http', 'camel:kamelet'], - template: { - from: { - steps: [ - { - to: { - uri: 'https', - parameters: { - httpUri: 'random-data-api.com/api/v2/users', - }, - }, - }, - { - to: 'kamelet:sink', - }, - ], - id: 'from-3836', - parameters: { - period: '{{period}}', - timerName: 'user', - }, - uri: 'timer', - }, - }, - types: { - out: { - mediaType: 'application/json', - }, - }, - }, - }; + inputKameletStruct = cloneDeep(kameletJson); }); it('should get a custom kamelet definition from a empty kamelet', () => { @@ -97,22 +34,18 @@ describe('getCustomSchemaFromKamelet', () => { it('should get a custom kamelet definition from a kamelet official spec', () => { const expectedCustomSchema = { - name: 'test', - title: 'kamelet-35256', - description: 'test description!', - type: 'Action', + name: 'user-source', + title: 'User Source', + description: 'Produces periodic events about random users!', + type: 'source', icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgNjAgNjAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYwIDYwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxwYXRoIGQ9Ik00OC4wMTQsNDIuODg5bC05LjU1My00Ljc3NkMzNy41NiwzNy42NjIsMzcsMzYuNzU2LDM3LDM1Ljc0OHYtMy4zODFjMC4yMjktMC4yOCwwLjQ3LTAuNTk5LDAuNzE5LTAuOTUxCgljMS4yMzktMS43NSwyLjIzMi0zLjY5OCwyLjk1NC01Ljc5OUM0Mi4wODQsMjQuOTcsNDMsMjMuNTc1LDQzLDIydi00YzAtMC45NjMtMC4zNi0xLjg5Ni0xLTIuNjI1di01LjMxOQoJYzAuMDU2LTAuNTUsMC4yNzYtMy44MjQtMi4wOTItNi41MjVDMzcuODU0LDEuMTg4LDM0LjUyMSwwLDMwLDBzLTcuODU0LDEuMTg4LTkuOTA4LDMuNTNDMTcuNzI0LDYuMjMxLDE3Ljk0NCw5LjUwNiwxOCwxMC4wNTYKCXY1LjMxOWMtMC42NCwwLjcyOS0xLDEuNjYyLTEsMi42MjV2NGMwLDEuMjE3LDAuNTUzLDIuMzUyLDEuNDk3LDMuMTA5YzAuOTE2LDMuNjI3LDIuODMzLDYuMzYsMy41MDMsNy4yMzd2My4zMDkKCWMwLDAuOTY4LTAuNTI4LDEuODU2LTEuMzc3LDIuMzJsLTguOTIxLDQuODY2QzguODAxLDQ0LjQyNCw3LDQ3LjQ1OCw3LDUwLjc2MlY1NGMwLDQuNzQ2LDE1LjA0NSw2LDIzLDZzMjMtMS4yNTQsMjMtNnYtMy4wNDMKCUM1Myw0Ny41MTksNTEuMDg5LDQ0LjQyNyw0OC4wMTQsNDIuODg5eiIvPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K', supportLevel: 'Stable', catalogVersion: 'main-SNAPSHOT', provider: 'Apache Software Foundation', group: 'Users', - namespace: 'test', - labels: { - type: 'Action', - }, - annotations: { - foo: 'bar', - }, + namespace: undefined, + labels: {}, + annotations: {}, kameletProperties: [ { name: 'period', @@ -124,35 +57,32 @@ describe('getCustomSchemaFromKamelet', () => { ], }; - const customSchema = getCustomSchemaFromKamelet(inputKameletStruct as unknown as IKameletDefinition); + const customSchema = getCustomSchemaFromKamelet(inputKameletStruct); expect(customSchema).toEqual(expectedCustomSchema); }); it('should get a custom kamelet definition from a kamelet with string properties', () => { - const kameletWithStringProperties = cloneDeep(inputKameletStruct); - kameletWithStringProperties.spec.definition.properties = test as unknown as Record; + inputKameletStruct.spec.definition.properties = { + period: 'test', + } as unknown as Record; const expectedCustomSchema = { - name: 'test', - title: 'kamelet-35256', - description: 'test description!', - type: 'Action', + name: 'user-source', + title: 'User Source', + description: 'Produces periodic events about random users!', + type: 'source', icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgNjAgNjAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDYwIDYwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxwYXRoIGQ9Ik00OC4wMTQsNDIuODg5bC05LjU1My00Ljc3NkMzNy41NiwzNy42NjIsMzcsMzYuNzU2LDM3LDM1Ljc0OHYtMy4zODFjMC4yMjktMC4yOCwwLjQ3LTAuNTk5LDAuNzE5LTAuOTUxCgljMS4yMzktMS43NSwyLjIzMi0zLjY5OCwyLjk1NC01Ljc5OUM0Mi4wODQsMjQuOTcsNDMsMjMuNTc1LDQzLDIydi00YzAtMC45NjMtMC4zNi0xLjg5Ni0xLTIuNjI1di01LjMxOQoJYzAuMDU2LTAuNTUsMC4yNzYtMy44MjQtMi4wOTItNi41MjVDMzcuODU0LDEuMTg4LDM0LjUyMSwwLDMwLDBzLTcuODU0LDEuMTg4LTkuOTA4LDMuNTNDMTcuNzI0LDYuMjMxLDE3Ljk0NCw5LjUwNiwxOCwxMC4wNTYKCXY1LjMxOWMtMC42NCwwLjcyOS0xLDEuNjYyLTEsMi42MjV2NGMwLDEuMjE3LDAuNTUzLDIuMzUyLDEuNDk3LDMuMTA5YzAuOTE2LDMuNjI3LDIuODMzLDYuMzYsMy41MDMsNy4yMzd2My4zMDkKCWMwLDAuOTY4LTAuNTI4LDEuODU2LTEuMzc3LDIuMzJsLTguOTIxLDQuODY2QzguODAxLDQ0LjQyNCw3LDQ3LjQ1OCw3LDUwLjc2MlY1NGMwLDQuNzQ2LDE1LjA0NSw2LDIzLDZzMjMtMS4yNTQsMjMtNnYtMy4wNDMKCUM1Myw0Ny41MTksNTEuMDg5LDQ0LjQyNyw0OC4wMTQsNDIuODg5eiIvPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K', supportLevel: 'Stable', catalogVersion: 'main-SNAPSHOT', provider: 'Apache Software Foundation', group: 'Users', - namespace: 'test', - labels: { - type: 'Action', - }, - annotations: { - foo: 'bar', - }, + namespace: undefined, + labels: {}, + annotations: {}, kameletProperties: [], }; - const customSchema = getCustomSchemaFromKamelet(kameletWithStringProperties as unknown as IKameletDefinition); + const customSchema = getCustomSchemaFromKamelet(inputKameletStruct); expect(customSchema).toEqual(expectedCustomSchema); }); diff --git a/packages/ui/src/utils/pipe-custom-schema.ts b/packages/ui/src/utils/pipe-custom-schema.ts index d9c60e2c1..ea109ed29 100644 --- a/packages/ui/src/utils/pipe-custom-schema.ts +++ b/packages/ui/src/utils/pipe-custom-schema.ts @@ -1,5 +1,6 @@ import { Pipe } from '@kaoto/camel-catalog/types'; import { getValue } from './get-value'; +import { isDefined } from './is-defined'; import { setValue } from './set-value'; export const getCustomSchemaFromPipe = (pipe: Pipe) => { @@ -17,6 +18,10 @@ export const getCustomSchemaFromPipe = (pipe: Pipe) => { }; export const updatePipeFromCustomSchema = (pipe: Pipe, value: Record): void => { + if (!isDefined(value)) { + return; + } + // Ensure 'labels' and 'annotations' are defined in 'value' if (value && getValue(value, 'labels') === undefined) { value.labels = {}; @@ -24,9 +29,9 @@ export const updatePipeFromCustomSchema = (pipe: Pipe, value: Record = getValue(pipe, 'metadata.annotations', {}); const previousLabels: Record = getValue(pipe, 'metadata.labels', {}); diff --git a/packages/ui/src/utils/update-kamelet-from-custom-schema.ts b/packages/ui/src/utils/update-kamelet-from-custom-schema.ts index 20c5ca589..e78eb0955 100644 --- a/packages/ui/src/utils/update-kamelet-from-custom-schema.ts +++ b/packages/ui/src/utils/update-kamelet-from-custom-schema.ts @@ -1,35 +1,26 @@ import { + IKameletCustomProperty, IKameletDefinition, - IKameletMetadataAnnotations, - IKameletMetadataLabels, + IKameletSpecProperty, KameletKnownAnnotations, KameletKnownLabels, - IKameletSpecProperty, - IKameletCustomProperty, } from '../models/kamelets-catalog'; import { getValue } from './get-value'; +import { isDefined } from './is-defined'; import { setValue } from './set-value'; export const updateKameletFromCustomSchema = (kamelet: IKameletDefinition, value: Record): void => { - const previousName = getValue(kamelet, 'metadata.name'); - const previousTitle = getValue(kamelet, 'spec.definition.title'); - const previousDescription = getValue(kamelet, 'spec.definition.description'); + if (!isDefined(value)) { + return; + } const newName: string = getValue(value, 'name'); const newTitle: string = getValue(value, 'title'); const newDescription: string = getValue(value, 'description'); - setValue(kamelet, 'metadata.name', newName ?? previousName); - setValue(kamelet, 'spec.definition.title', newTitle ?? previousTitle); - setValue(kamelet, 'spec.definition.description', newDescription ?? previousDescription); - - const previousAnnotations = getValue(kamelet, 'metadata.annotations', {} as IKameletMetadataAnnotations); - const previousIcon = previousAnnotations[KameletKnownAnnotations.Icon]; - const previousSupportLevel = previousAnnotations[KameletKnownAnnotations.SupportLevel]; - const previousCatalogVersion = previousAnnotations[KameletKnownAnnotations.CatalogVersion]; - const previousProvider = previousAnnotations[KameletKnownAnnotations.Provider]; - const previousGroup = previousAnnotations[KameletKnownAnnotations.Group]; - const previousNamespace = previousAnnotations[KameletKnownAnnotations.Namespace]; + setValue(kamelet, 'metadata.name', newName); + setValue(kamelet, 'spec.definition.title', newTitle); + setValue(kamelet, 'spec.definition.description', newDescription); const newIcon = getValue(value, 'icon'); const newSupportLevel = getValue(value, 'supportLevel'); @@ -39,18 +30,17 @@ export const updateKameletFromCustomSchema = (kamelet: IKameletDefinition, value const newNamespace = getValue(value, 'namespace'); const customAnnotations = { - [KameletKnownAnnotations.Icon]: newIcon ?? previousIcon, - [KameletKnownAnnotations.SupportLevel]: newSupportLevel ?? previousSupportLevel, - [KameletKnownAnnotations.CatalogVersion]: newCatalogVersion ?? previousCatalogVersion, - [KameletKnownAnnotations.Provider]: newProvider ?? previousProvider, - [KameletKnownAnnotations.Group]: newGroup ?? previousGroup, - [KameletKnownAnnotations.Namespace]: newNamespace ?? previousNamespace, + [KameletKnownAnnotations.Icon]: newIcon, + [KameletKnownAnnotations.SupportLevel]: newSupportLevel, + [KameletKnownAnnotations.CatalogVersion]: newCatalogVersion, + [KameletKnownAnnotations.Provider]: newProvider, + [KameletKnownAnnotations.Group]: newGroup, + [KameletKnownAnnotations.Namespace]: newNamespace, }; - const previousType = getValue(kamelet, 'metadata.labels', {} as IKameletMetadataLabels)[KameletKnownLabels.Type]; const incomingLabels = getValue(value, 'labels', {}); const newLabels = Object.assign({}, incomingLabels, { - [KameletKnownLabels.Type]: getValue(value, 'type', previousType), + [KameletKnownLabels.Type]: getValue(value, 'type'), }); const newAnnotations = Object.assign({}, getValue(value, 'annotations', {}), customAnnotations);