Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

Commit

Permalink
fix(DataMapper): Delete DataMapper metadata entry when the step is de…
Browse files Browse the repository at this point in the history
…leted

Fixes: #80
  • Loading branch information
igarashitm committed Oct 7, 2024
1 parent b1c353e commit 65e738d
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 6 deletions.
8 changes: 7 additions & 1 deletion packages/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
} from './providers';
import { isDefined } from './utils';
import { CatalogSchemaLoader } from './utils/catalog-schema-loader';
import { RegisterNodeInteractions } from './components/registers/RegisterNodeInteractions';
import { NodeInteractionProvider } from './components/registers/interactions/node-interaction.provider';

function App() {
const ReloadProvider = useReload();
Expand All @@ -40,7 +42,11 @@ function App() {
<VisibleFlowsProvider>
<RenderingProvider>
<RegisterComponents>
<Outlet />
<NodeInteractionProvider>
<RegisterNodeInteractions>
<Outlet />
</RegisterNodeInteractions>
</NodeInteractionProvider>
</RegisterComponents>
</RenderingProvider>
</VisibleFlowsProvider>
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/src/components/DataMapper/on-delete-datamapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DataMapperMetadataService } from '../../services/datamapper-metadata.service';
import { IMetadataApi } from '../../providers';
import { IVisualizationNode } from '../../models';

export const onDeleteDataMapper = (api: IMetadataApi, vizNode: IVisualizationNode) => {
const metadataId = DataMapperMetadataService.getDataMapperMetadataId(vizNode);
DataMapperMetadataService.deleteMetadata(api, metadataId);
// TODO DataMapperMetadataService.deleteXsltFile(api, metadataId);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { IDataTestID } from '../../../../models';
import { IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
import { ActionConfirmationModalContext } from '../../../../providers/action-confirmation-modal.provider';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { NodeInteractionContext } from '../../../registers/interactions/node-interaction.provider';
import { IInteractionType } from '../../../registers/interactions/node-interaction.model';

interface ItemDeleteGroupProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
Expand All @@ -15,6 +17,21 @@ export const ItemDeleteGroup: FunctionComponent<ItemDeleteGroupProps> = (props)
const deleteModalContext = useContext(ActionConfirmationModalContext);
const flowId = props.vizNode?.getId();

const { getRegisteredInteractions } = useContext(NodeInteractionContext);

const onDeleteRecursively = useCallback(
(parentVizNode: IVisualizationNode) => {
parentVizNode.getChildren()?.forEach((child) => {
onDeleteRecursively(child);
});
const interactions = getRegisteredInteractions(IInteractionType.ON_DELETE, parentVizNode);
interactions.forEach((interaction) => {
interaction.callback(parentVizNode);
});
},
[getRegisteredInteractions],
);

const onRemoveGroup = useCallback(async () => {
/** Open delete confirm modal, get the confirmation */
const isDeleteConfirmed = await deleteModalContext?.actionConfirmation({
Expand All @@ -24,9 +41,11 @@ export const ItemDeleteGroup: FunctionComponent<ItemDeleteGroupProps> = (props)

if (!isDeleteConfirmed) return;

onDeleteRecursively(props.vizNode);

entitiesContext?.camelResource.removeEntity(flowId);
entitiesContext?.updateEntitiesFromCamelResource();
}, [deleteModalContext, entitiesContext, flowId]);
}, [deleteModalContext, entitiesContext, flowId, onDeleteRecursively, props.vizNode]);

return (
<ContextMenuItem onClick={onRemoveGroup} data-testid={props['data-testid']}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { IDataTestID } from '../../../../models';
import { IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { ActionConfirmationModalContext } from '../../../../providers/action-confirmation-modal.provider';
import { NodeInteractionContext } from '../../../registers/interactions/node-interaction.provider';
import { IInteractionType } from '../../../registers/interactions/node-interaction.model';

interface ItemDeleteStepProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
Expand All @@ -14,6 +16,20 @@ interface ItemDeleteStepProps extends PropsWithChildren<IDataTestID> {
export const ItemDeleteStep: FunctionComponent<ItemDeleteStepProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);
const deleteModalContext = useContext(ActionConfirmationModalContext);
const { getRegisteredInteractions } = useContext(NodeInteractionContext);

const onDeleteRecursively = useCallback(
(parentVizNode: IVisualizationNode) => {
parentVizNode.getChildren()?.forEach((child) => {
onDeleteRecursively(child);
});
const interactions = getRegisteredInteractions(IInteractionType.ON_DELETE, parentVizNode);
interactions.forEach((interaction) => {
interaction.callback(parentVizNode);
});
},
[getRegisteredInteractions],
);

const onRemoveNode = useCallback(async () => {
if (props.loadActionConfirmationModal) {
Expand All @@ -26,9 +42,11 @@ export const ItemDeleteStep: FunctionComponent<ItemDeleteStepProps> = (props) =>
if (!isDeleteConfirmed) return;
}

onDeleteRecursively(props.vizNode);

props.vizNode?.removeChild();
entitiesContext?.updateEntitiesFromCamelResource();
}, [deleteModalContext, entitiesContext, props.loadActionConfirmationModal, props.vizNode]);
}, [deleteModalContext, entitiesContext, onDeleteRecursively, props.loadActionConfirmationModal, props.vizNode]);

return (
<ContextMenuItem onClick={onRemoveNode} data-testid={props['data-testid']}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AddStepMode, IVisualizationNode } from '../../../../models/visualizatio
import { CatalogModalContext } from '../../../../providers/catalog-modal.provider';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { ActionConfirmationModalContext } from '../../../../providers/action-confirmation-modal.provider';
import { NodeInteractionContext } from '../../../registers/interactions/node-interaction.provider';
import { IInteractionType } from '../../../registers/interactions/node-interaction.model';

interface ItemReplaceStepProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
Expand All @@ -16,6 +18,20 @@ export const ItemReplaceStep: FunctionComponent<ItemReplaceStepProps> = (props)
const entitiesContext = useContext(EntitiesContext);
const catalogModalContext = useContext(CatalogModalContext);
const replaceModalContext = useContext(ActionConfirmationModalContext);
const { getRegisteredInteractions } = useContext(NodeInteractionContext);

const onDeleteRecursively = useCallback(
(parentVizNode: IVisualizationNode) => {
parentVizNode.getChildren()?.forEach((child) => {
onDeleteRecursively(child);
});
const interactions = getRegisteredInteractions(IInteractionType.ON_DELETE, parentVizNode);
interactions.forEach((interaction) => {
interaction.callback(parentVizNode);
});
},
[getRegisteredInteractions],
);

const onReplaceNode = useCallback(async () => {
if (!props.vizNode || !entitiesContext) return;
Expand All @@ -40,12 +56,21 @@ export const ItemReplaceStep: FunctionComponent<ItemReplaceStepProps> = (props)
const definedComponent = await catalogModalContext?.getNewComponent(catalogFilter);
if (!definedComponent) return;

onDeleteRecursively(props.vizNode);

/** Add new node to the entities */
props.vizNode.addBaseEntityStep(definedComponent, AddStepMode.ReplaceStep);

/** Update entity */
entitiesContext.updateEntitiesFromCamelResource();
}, [replaceModalContext, catalogModalContext, entitiesContext, props.vizNode]);
}, [
props.vizNode,
props.loadActionConfirmationModal,
entitiesContext,
catalogModalContext,
onDeleteRecursively,
replaceModalContext,
]);

return (
<ContextMenuItem onClick={onReplaceNode} data-testid={props['data-testid']}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { datamapperActivationFn } from './datamapper.activationfn';

export const RegisterComponents: FunctionComponent<PropsWithChildren> = ({ children }) => {
const { registerComponent } = useContext(RenderingAnchorContext);

const componentsToRegister = useRef<IRegisteredComponent[]>([
{
anchor: Anchors.CanvasFormHeader,
Expand Down
26 changes: 26 additions & 0 deletions packages/ui/src/components/registers/RegisterNodeInteractions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { FunctionComponent, PropsWithChildren, useContext, useRef } from 'react';
import { datamapperActivationFn } from './datamapper.activationfn';
import { MetadataContext } from '../../providers';
import { onDeleteDataMapper } from '../DataMapper/on-delete-datamapper';
import { NodeInteractionContext } from './interactions/node-interaction.provider';
import { IInteractionType, IRegisteredInteraction } from './interactions/node-interaction.model';

export const RegisterNodeInteractions: FunctionComponent<PropsWithChildren> = ({ children }) => {
const metadataApi = useContext(MetadataContext)!;
const { registerInteraction } = useContext(NodeInteractionContext);
const interactionsToRegister = useRef<IRegisteredInteraction[]>([
{
interaction: IInteractionType.ON_DELETE,
activationFn: datamapperActivationFn,
callback: (vizNode) => {
metadataApi && onDeleteDataMapper(metadataApi, vizNode);
},
},
]);

interactionsToRegister.current.forEach((interaction) => {
registerInteraction(interaction);
});

return <>{children}</>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { IVisualizationNode } from '../../../models';

export enum IInteractionType {
ON_DELETE = 'onDelete',
}

export interface IRegisteredInteraction {
interaction: IInteractionType;
activationFn: (vizNode: IVisualizationNode) => boolean;
callback: (vizNode: IVisualizationNode) => void;
}

export interface INodeInteractionContext {
/**
* Register a component to be rendered in the given anchor
*
* @example
* ```tsx
* const nodeInteractionContext = useContext(NodeInteractionContext);
*
* renderingAnchorContext.registerInteraction({
* activationFn: () => true,
* onDelete: () => { doSomething() }
* });
* ```
* @param interaction Registered node interaction
* @returns void
*/
registerInteraction: (interaction: IRegisteredInteraction) => void;

/**
* Get registered interactions
*
* @example
* ```tsx
* const nodeInteractionContext = useContext(NodeInteractionContext);
*
* const interactions = nodeInteractionContext.getRegisteredInteractions(vizNode);
* interactions.forEach((i) => {
* i.onDelete(vizNode);
* });
* ```
* @param interaction The interaction type enum value
* @param vizNode The visualization node to pass to the interaction
* @returns `IRegisteredInteraction` An array of registered interactions
*/
getRegisteredInteractions: (interaction: IInteractionType, vizNode: IVisualizationNode) => IRegisteredInteraction[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createContext, FunctionComponent, PropsWithChildren, useCallback, useMemo, useRef } from 'react';
import { IVisualizationNode } from '../../../models';
import { IInteractionType, INodeInteractionContext, IRegisteredInteraction } from './node-interaction.model';

export const NodeInteractionContext = createContext<INodeInteractionContext>({
registerInteraction: () => {},
getRegisteredInteractions: () => [],
});

export const NodeInteractionProvider: FunctionComponent<PropsWithChildren> = ({ children }) => {
const registeredInteractions = useRef<IRegisteredInteraction[]>([]);

const registerInteraction = useCallback((interaction: IRegisteredInteraction) => {
registeredInteractions.current.push(interaction);
}, []);

const getRegisteredInteractions = useCallback((interaction: IInteractionType, vizNode: IVisualizationNode) => {
return registeredInteractions.current.filter(
(registeredInteraction) =>
registeredInteraction.interaction === interaction && registeredInteraction.activationFn(vizNode),
);
}, []);

const value = useMemo(
() => ({ registerInteraction, getRegisteredInteractions }),
[getRegisteredInteractions, registerInteraction],
);

return <NodeInteractionContext.Provider value={value}>{children}</NodeInteractionContext.Provider>;
};
8 changes: 7 additions & 1 deletion packages/ui/src/multiplying-architecture/KaotoBridge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
VisibleFlowsProvider,
} from '../providers';
import { EventNotifier } from '../utils';
import { NodeInteractionProvider } from '../components/registers/interactions/node-interaction.provider';
import { RegisterNodeInteractions } from '../components/registers/RegisterNodeInteractions';

interface KaotoBridgeProps {
/**
Expand Down Expand Up @@ -213,7 +215,11 @@ export const KaotoBridge = forwardRef<EditorApi, PropsWithChildren<KaotoBridgePr
<VisibleFlowsProvider>
<RenderingProvider>
<MetadataProvider api={metadataApi}>
<RegisterComponents>{children}</RegisterComponents>
<RegisterComponents>
<NodeInteractionProvider>
<RegisterNodeInteractions>{children}</RegisterNodeInteractions>
</NodeInteractionProvider>
</RegisterComponents>
</MetadataProvider>
</RenderingProvider>
</VisibleFlowsProvider>
Expand Down
6 changes: 5 additions & 1 deletion packages/ui/src/services/datamapper-metadata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class DataMapperMetadataService {
// eslint-disable-next-line
const xsltStep = model.steps.find((step: any) => step.to?.uri?.startsWith('xslt'));
const splitted = xsltStep?.to?.uri?.split(':');
let xsltFileName = `${model.id}.xsl`;
let xsltFileName = `${metadataId}.xsl`;
if (splitted.length < 2) {
xsltStep.to.uri = `xslt:${xsltFileName}`;
vizNode.updateModel(model);
Expand Down Expand Up @@ -204,4 +204,8 @@ export class DataMapperMetadataService {
title: 'Attaching document schema file',
});
}

static deleteMetadata(api: IMetadataApi, metadataId: string) {
api.setMetadata(metadataId, undefined);
}
}

0 comments on commit 65e738d

Please sign in to comment.