Skip to content

Commit

Permalink
feat(Canvas): add useVizNodeModel
Browse files Browse the repository at this point in the history
Temp: All test passing except for Kamelets and Pipes
  • Loading branch information
lordrip committed Dec 17, 2024
1 parent cebaac9 commit a928459
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<boolean>(Object.keys(propertiesModel).length > 0);
const [expandedNodes, setExpandedNodes] = useState<string[]>([]);
const [placeholderState, setPlaceholderState] = useState<PlaceholderState | null>(null);
Expand Down
3 changes: 0 additions & 3 deletions packages/ui/src/components/Form/properties/PropertyRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ export function PropertyRow({
setUserInputName(nodeName);
setUserInputValue(nodeValue);
setIsEditing(false);
if (isPlaceholder) {
onChangeModel();
}
}

function getKey() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<CanvasFormTabsProps> = (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<HTMLDivElement>(null);
const formRef = useRef<CustomAutoFormRef>(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<Record<string, unknown>>(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 ?? {});
Expand All @@ -40,68 +42,48 @@ export const CanvasFormBody: FunctionComponent<CanvasFormTabsProps> = (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 <UnknownNode model={model} />;
}

return (
<>
{stepFeatures.isUnknownComponent ? (
<UnknownNode model={model} />
) : (
<SchemaBridgeProvider schema={processedSchema} parentRef={divRef}>
{stepFeatures.isExpressionAwareStep && (
<StepExpressionEditor selectedNode={props.selectedNode} formMode={selectedTab} />
)}
{stepFeatures.isDataFormatAwareStep && (
<DataFormatEditor selectedNode={props.selectedNode} formMode={selectedTab} />
)}
{stepFeatures.isLoadBalanceAwareStep && (
<LoadBalancerEditor selectedNode={props.selectedNode} formMode={selectedTab} />
)}
<CustomAutoForm
key={props.selectedNode.id}
ref={formRef}
model={model}
onChange={handleOnChangeIndividualProp}
sortFields={false}
omitFields={omitFields.current}
data-testid="autoform"
/>
<div data-testid="root-form-placeholder" ref={divRef} />
</SchemaBridgeProvider>
)}
</>
<SchemaBridgeProvider schema={processedSchema} parentRef={divRef}>
{isExpressionAwareStep && <StepExpressionEditor selectedNode={props.selectedNode} formMode={selectedTab} />}
{isDataFormatAwareStep && <DataFormatEditor selectedNode={props.selectedNode} formMode={selectedTab} />}
{isLoadBalanceAwareStep && <LoadBalancerEditor selectedNode={props.selectedNode} formMode={selectedTab} />}
<CustomAutoForm
key={props.selectedNode.id}
ref={formRef}
model={model}
onChange={handleOnChangeIndividualProp}
sortFields={false}
omitFields={omitFields.current}
data-testid="autoform"
/>
<div data-testid="root-form-placeholder" ref={divRef} />
</SchemaBridgeProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof DefaultNode>[0];
interface CustomNodeProps extends DefaultNodeProps, WithSelectionProps {
Expand All @@ -43,10 +44,8 @@ const CustomNode: FunctionComponent<CustomNodeProps> = 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<SVGGElement>(CanvasDefaults.HOVER_DELAY_IN, CanvasDefaults.HOVER_DELAY_OUT);
const [isToolbarHover, toolbarHoverRef] = useHover<SVGForeignObjectElement>(
Expand Down Expand Up @@ -76,6 +75,10 @@ const CustomNode: FunctionComponent<CustomNodeProps> = observer(({ element, onCo
return null;
}

const { model } = useVizNodeModel<{ disabled?: boolean }>(vizNode);
const isDisabled = !!model.disabled;
const doesHaveWarnings = !isDisabled && !!validationText;

return (
<Layer id={DEFAULT_LAYER}>
<g
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { useCallback, useContext, useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { useVizNodeModel } from '../../../../hooks';
import { IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { setValue } from '../../../../utils/set-value';

export const useDisableStep = (vizNode: IVisualizationNode) => {
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(
() => ({
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
18 changes: 18 additions & 0 deletions packages/ui/src/hooks/viznode-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useContext } from 'react';
import { IVisualizationNode } from '../models';
import { EntitiesContext, SourceCodeContext } from '../providers';

export const useVizNodeModel = <T = unknown>(
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 };
};
3 changes: 2 additions & 1 deletion packages/ui/src/stubs/kamelet-route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { parse } from 'yaml';
import { IKameletDefinition } from '../models/kamelets-catalog';

/**
* This is a stub Kamelet in YAML format.
Expand Down Expand Up @@ -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);
Loading

0 comments on commit a928459

Please sign in to comment.