From 6372d1e72fb2f53432bb014e7eab1149cb046c71 Mon Sep 17 00:00:00 2001 From: Shivam Gupta Date: Tue, 25 Jun 2024 19:15:15 +0530 Subject: [PATCH] fix(1022): Avoid serializing empty strings for Expressions, Loadbalancers and dataformat fields --- .../Form/bean/BeanReferenceField.tsx | 4 +- .../Form/dataFormat/DataFormatEditor.tsx | 3 +- .../expression/ExpressionAwareNestField.tsx | 3 +- .../Form/expression/ExpressionField.tsx | 3 +- .../Form/loadBalancer/LoadBalancerEditor.tsx | 3 +- .../stepExpression/StepExpressionEditor.tsx | 3 +- .../ui/src/utils/get-serialized-model.test.ts | 61 +++++++++++++++++++ packages/ui/src/utils/get-serialized-model.ts | 9 +++ packages/ui/src/utils/index.ts | 1 + 9 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 packages/ui/src/utils/get-serialized-model.test.ts create mode 100644 packages/ui/src/utils/get-serialized-model.ts diff --git a/packages/ui/src/components/Form/bean/BeanReferenceField.tsx b/packages/ui/src/components/Form/bean/BeanReferenceField.tsx index 74665811c..18c1c2a03 100644 --- a/packages/ui/src/components/Form/bean/BeanReferenceField.tsx +++ b/packages/ui/src/components/Form/bean/BeanReferenceField.tsx @@ -18,6 +18,7 @@ import { wrapField } from '@kaoto-next/uniforms-patternfly'; import { BeanFactory } from '@kaoto/camel-catalog/types'; import { NewBeanModal } from './NewBeanModal'; import { BeansEntityHandler } from '../../../models/visualization/metadata/beans-entity-handler'; +import { getSerializedModel } from '../../../utils'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type BeanReferenceFieldProps = HTMLFieldProps; @@ -109,7 +110,6 @@ const BeanReferenceFieldComponent = (props: BeanReferenceFieldProps) => { const onSelect = useCallback( (_event: React.MouseEvent | undefined, value: string | number | undefined) => { // eslint-disable-next-line no-console - if (value) { if (value === createNewWithNameValue) { setIsNewBeanModalOpen(true); @@ -218,7 +218,7 @@ const BeanReferenceFieldComponent = (props: BeanReferenceFieldProps) => { const handleCreateBean = useCallback( (model: BeanFactory) => { - beansHandler.addNewBean(model); + beansHandler.addNewBean(getSerializedModel(model as unknown as Record)); const beanRef = beansHandler.getReferenceFromName(model.name); onSelect(undefined, beanRef); diff --git a/packages/ui/src/components/Form/dataFormat/DataFormatEditor.tsx b/packages/ui/src/components/Form/dataFormat/DataFormatEditor.tsx index bef0bd813..afa26a3d1 100644 --- a/packages/ui/src/components/Form/dataFormat/DataFormatEditor.tsx +++ b/packages/ui/src/components/Form/dataFormat/DataFormatEditor.tsx @@ -12,6 +12,7 @@ import { CanvasNode } from '../../Visualization/Canvas/canvas.models'; import './DataFormatEditor.scss'; import { DataFormatService } from './dataformat.service'; import { TypeaheadEditor } from '../customField/TypeaheadEditor'; +import { getSerializedModel } from '../../../utils'; interface DataFormatEditorProps { selectedNode: CanvasNode; @@ -69,7 +70,7 @@ export const DataFormatEditor: FunctionComponent = (props dataFormatCatalogMap, model, selectedDataFormatOption ? selectedDataFormatOption!.name : '', - newDataFormatModel, + getSerializedModel(newDataFormatModel), ); props.selectedNode.data?.vizNode?.updateModel(model); entitiesContext?.updateSourceCodeFromEntities(); diff --git a/packages/ui/src/components/Form/expression/ExpressionAwareNestField.tsx b/packages/ui/src/components/Form/expression/ExpressionAwareNestField.tsx index ff96ff758..beb52aaa2 100644 --- a/packages/ui/src/components/Form/expression/ExpressionAwareNestField.tsx +++ b/packages/ui/src/components/Form/expression/ExpressionAwareNestField.tsx @@ -24,6 +24,7 @@ import { ExpressionModalLauncher } from './ExpressionModalLauncher'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { ICamelLanguageDefinition } from '../../../models'; import { ExpressionService } from './expression.service'; +import { getSerializedModel } from '../../../utils'; export type NestFieldProps = HTMLFieldProps; @@ -64,7 +65,7 @@ export const ExpressionAwareNestField = connectField( (languageName: string, model: any) => { const language = ExpressionService.getDefinitionFromModelName(languageCatalogMap, languageName); setPreparedLanguage(language); - setPreparedModel(model); + setPreparedModel(getSerializedModel(model)); }, [languageCatalogMap], ); diff --git a/packages/ui/src/components/Form/expression/ExpressionField.tsx b/packages/ui/src/components/Form/expression/ExpressionField.tsx index 3649533c3..86e78b57a 100644 --- a/packages/ui/src/components/Form/expression/ExpressionField.tsx +++ b/packages/ui/src/components/Form/expression/ExpressionField.tsx @@ -4,6 +4,7 @@ import { HTMLFieldProps, connectField } from 'uniforms'; import { ICamelLanguageDefinition } from '../../../models'; import { ExpressionModalLauncher } from './ExpressionModalLauncher'; import { ExpressionService } from './expression.service'; +import { getSerializedModel } from '../../../utils'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ExpressionFieldProps = HTMLFieldProps; @@ -32,7 +33,7 @@ const ExpressionFieldComponent = (props: ExpressionFieldProps) => { (languageName: string, model: Record) => { const language = ExpressionService.getDefinitionFromModelName(languageCatalogMap, languageName); setPreparedLanguage(language); - setPreparedModel(model); + setPreparedModel(getSerializedModel(model)); }, [languageCatalogMap], ); diff --git a/packages/ui/src/components/Form/loadBalancer/LoadBalancerEditor.tsx b/packages/ui/src/components/Form/loadBalancer/LoadBalancerEditor.tsx index a32a57d99..4ac586903 100644 --- a/packages/ui/src/components/Form/loadBalancer/LoadBalancerEditor.tsx +++ b/packages/ui/src/components/Form/loadBalancer/LoadBalancerEditor.tsx @@ -12,6 +12,7 @@ import { CanvasNode } from '../../Visualization/Canvas/canvas.models'; import { LoadBalancerService } from './loadbalancer.service'; import './LoadBalancerEditor.scss'; import { TypeaheadEditor } from '../customField/TypeaheadEditor'; +import { getSerializedModel } from '../../../utils'; interface LoadBalancerEditorProps { selectedNode: CanvasNode; @@ -69,7 +70,7 @@ export const LoadBalancerEditor: FunctionComponent = (p loadBalancerCatalogMap, model, selectedLoadBalancerOption ? selectedLoadBalancerOption!.name : '', - newLoadBalancerModel, + getSerializedModel(newLoadBalancerModel), ); props.selectedNode.data?.vizNode?.updateModel(model); entitiesContext?.updateSourceCodeFromEntities(); diff --git a/packages/ui/src/components/Form/stepExpression/StepExpressionEditor.tsx b/packages/ui/src/components/Form/stepExpression/StepExpressionEditor.tsx index 55662b48f..0586933d4 100644 --- a/packages/ui/src/components/Form/stepExpression/StepExpressionEditor.tsx +++ b/packages/ui/src/components/Form/stepExpression/StepExpressionEditor.tsx @@ -5,6 +5,7 @@ import { EntitiesContext } from '../../../providers'; import { CanvasNode } from '../../Visualization/Canvas/canvas.models'; import { ExpressionService } from '..//expression/expression.service'; import { ExpressionModalLauncher } from '../expression/ExpressionModalLauncher'; +import { getSerializedModel } from '../../../utils'; interface StepExpressionEditorProps { selectedNode: CanvasNode; @@ -42,7 +43,7 @@ export const StepExpressionEditor: FunctionComponent (selectedLanguage: string, newExpressionModel: Record) => { const language = ExpressionService.getDefinitionFromModelName(languageCatalogMap, selectedLanguage); setPreparedLanguage(language); - setPreparedModel(newExpressionModel); + setPreparedModel(getSerializedModel(newExpressionModel)); }, [languageCatalogMap], ); diff --git a/packages/ui/src/utils/get-serialized-model.test.ts b/packages/ui/src/utils/get-serialized-model.test.ts new file mode 100644 index 000000000..90bb4f99f --- /dev/null +++ b/packages/ui/src/utils/get-serialized-model.test.ts @@ -0,0 +1,61 @@ +import { getSerializedModel } from './get-serialized-model'; + +describe('getSerializedModel', () => { + let inputValue: Record; + + it('should get an object with empty string value unserialized', () => { + inputValue = { + name: 'test', + type: 'test', + builderClass: '', + constructors: { + testConstructor: 'test', + }, + destroyMethod: ' test ', + factoryBean: '', + properties: { + testProperty: {}, + }, + }; + + const expectedOutputValue = { + name: 'test', + type: 'test', + constructors: { + testConstructor: 'test', + }, + destroyMethod: ' test ', + properties: { + testProperty: {}, + }, + }; + const serializedModel = getSerializedModel(inputValue); + expect(serializedModel).toEqual(expectedOutputValue); + }); + + it('should get a object with empty string value with whitespaces unserialized', () => { + inputValue = { + id: 'test', + allowJmsType: true, + library: '', + collectionType: ' ', + timezone: 'test ', + }; + + const expectedOutputValue = { + id: 'test', + allowJmsType: true, + timezone: 'test ', + }; + const serializedModel = getSerializedModel(inputValue); + expect(serializedModel).toEqual(expectedOutputValue); + }); + + it('should get a empty object serialized', () => { + inputValue = {}; + + const expectedOutputValue = {}; + const serializedModel = getSerializedModel(inputValue); + expect(serializedModel).toEqual(expectedOutputValue); + }); +}); diff --git a/packages/ui/src/utils/get-serialized-model.ts b/packages/ui/src/utils/get-serialized-model.ts new file mode 100644 index 000000000..058e15aa2 --- /dev/null +++ b/packages/ui/src/utils/get-serialized-model.ts @@ -0,0 +1,9 @@ +export const getSerializedModel = (model: Record): Record => { + Object.keys(model).forEach((key) => { + if (typeof model[key] === 'string' && (model[key] as string).trim() === '') { + delete model[key]; + } + }); + + return model; +}; diff --git a/packages/ui/src/utils/index.ts b/packages/ui/src/utils/index.ts index 6dd8effd8..3937fc85e 100644 --- a/packages/ui/src/utils/index.ts +++ b/packages/ui/src/utils/index.ts @@ -13,4 +13,5 @@ export * from './get-custom-schema-from-kamelet'; export * from './update-kamelet-from-custom-schema'; export * from './pipe-custom-schema'; export * from './get-field-groups'; +export * from './get-serialized-model'; export * from './weight-schema-properties';