Skip to content

Commit

Permalink
feat(Canvas): Rename steps context menu items
Browse files Browse the repository at this point in the history
  • Loading branch information
lordrip committed May 3, 2024
1 parent 8fbb7b4 commit 6184a73
Show file tree
Hide file tree
Showing 15 changed files with 540 additions and 246 deletions.
2 changes: 1 addition & 1 deletion packages/ui-tests/cypress/support/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
export {};

declare global {
type ActionType = 'append' | 'prepend' | 'replace' | 'insert' | 'insert-special' | 'remove';
type ActionType = 'append' | 'prepend' | 'replace' | 'insert' | 'insert-special' | 'delete';

namespace Cypress {
interface Chainable {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-tests/cypress/support/next-commands/design.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Cypress.Commands.add('checkConfigInputObject', (inputName: string, value: string
});

Cypress.Commands.add('removeNodeByName', (nodeName: string, nodeIndex?: number) => {
cy.performNodeAction(nodeName, 'remove', nodeIndex);
cy.performNodeAction(nodeName, 'delete', nodeIndex);
cy.get(nodeName).should('not.exist');
// wait for the canvas rerender
cy.wait(1000);
Expand Down
52 changes: 41 additions & 11 deletions packages/ui/src/components/Visualization/Custom/CustomGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { CodeBranchIcon } from '@patternfly/react-icons';
import {
ContextMenuSeparator,
DefaultGroup,
ElementModel,
GraphElement,
Layer,
isNode,
observer,
withContextMenu,
withSelection,
} from '@patternfly/react-topology';
import { FunctionComponent } from 'react';
import { FunctionComponent, ReactElement } from 'react';
import { AddStepMode } from '../../../models/visualization/base-visual-entity';
import { CanvasNode } from '../Canvas/canvas.models';
import { ItemInsertChildNode } from './ItemInsertChildNode';
import { ItemRemoveGroup } from './ItemRemoveGroup';
import { ItemDeleteGroup } from './ItemDeleteGroup';
import { ItemInsertStep } from './ItemInsertStep';

type IDefaultGroup = Parameters<typeof DefaultGroup>[0];
interface ICustomGroup extends IDefaultGroup {
Expand Down Expand Up @@ -45,11 +48,38 @@ const CustomGroup: FunctionComponent<ICustomGroup> = observer(({ element, ...res
);
});

export const CustomGroupWithSelection = withContextMenu(() => [
<ItemInsertChildNode
key="context-menu-item-insert-special"
data-testid="context-menu-item-insert-special"
mode={AddStepMode.InsertSpecialChildStep}
/>,
<ItemRemoveGroup key="context-menu-container-remove" data-testid="context-menu-container-remove" />,
])(withSelection()(CustomGroup));
export const CustomGroupWithSelection = withSelection()(
withContextMenu((element: GraphElement<ElementModel, CanvasNode['data']>) => {
const items: ReactElement[] = [];
const vizNode = element.getData()?.vizNode;
if (!vizNode) return items;

const nodeInteractions = vizNode.getNodeInteraction();

if (nodeInteractions.canHaveSpecialChildren) {
items.push(
<ItemInsertStep
key="context-menu-item-insert-special"
data-testid="context-menu-item-insert-special"
mode={AddStepMode.InsertSpecialChildStep}
vizNode={vizNode}
>
<CodeBranchIcon /> Add branch
</ItemInsertStep>,
);
items.push(<ContextMenuSeparator key="context-menu-separator-insert" />);
}

if (nodeInteractions.canRemoveFlow) {
items.push(
<ItemDeleteGroup
key="context-menu-container-remove"
data-testid="context-menu-container-remove"
vizNode={vizNode}
/>,
);
}

return items;
})(CustomGroup),
);
130 changes: 101 additions & 29 deletions packages/ui/src/components/Visualization/Custom/CustomNode.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { Tooltip } from '@patternfly/react-core';
import { ArrowDownIcon, ArrowUpIcon, CodeBranchIcon, PlusIcon } from '@patternfly/react-icons';
import {
ContextMenuSeparator,
DefaultNode,
ElementModel,
GraphElement,
Node,
NodeStatus,
WithSelectionProps,
observer,
withContextMenu,
withSelection,
WithSelectionProps,
} from '@patternfly/react-topology';
import { Tooltip } from '@patternfly/react-core';
import { FunctionComponent } from 'react';
import { FunctionComponent, ReactElement } from 'react';
import { AddStepMode } from '../../../models/visualization/base-visual-entity';
import { CanvasDefaults } from '../Canvas/canvas.defaults';
import { CanvasNode } from '../Canvas/canvas.models';
import './CustomNode.scss';
import { ItemAddNode } from './ItemAddNode';
import { ItemInsertChildNode } from './ItemInsertChildNode';
import { ItemRemoveNode } from './ItemRemoveNode';
import { ItemReplaceNode } from './ItemReplaceNode';
import { ItemRemoveGroup } from './ItemRemoveGroup';
import { ItemAddStep } from './ItemAddStep';
import { ItemDeleteGroup } from './ItemDeleteGroup';
import { ItemDeleteStep } from './ItemDeleteStep';
import { ItemInsertStep } from './ItemInsertStep';
import { ItemReplaceStep } from './ItemReplaceStep';

interface CustomNodeProps extends WithSelectionProps {
element: Node<CanvasNode, CanvasNode['data']>;
Expand Down Expand Up @@ -60,24 +64,92 @@ const CustomNode: FunctionComponent<CustomNodeProps> = observer(({ element, ...r
);
});

export const CustomNodeWithSelection: typeof DefaultNode = withContextMenu(() => [
<ItemAddNode
key="context-menu-item-prepend"
data-testid="context-menu-item-prepend"
mode={AddStepMode.PrependStep}
/>,
<ItemAddNode key="context-menu-item-append" data-testid="context-menu-item-append" mode={AddStepMode.AppendStep} />,
<ItemInsertChildNode
key="context-menu-item-insert"
data-testid="context-menu-item-insert"
mode={AddStepMode.InsertChildStep}
/>,
<ItemInsertChildNode
key="context-menu-item-insert-special"
data-testid="context-menu-item-insert-special"
mode={AddStepMode.InsertSpecialChildStep}
/>,
<ItemReplaceNode key="context-menu-item-replace" data-testid="context-menu-item-replace" />,
<ItemRemoveNode key="context-menu-item-remove" data-testid="context-menu-item-remove" />,
<ItemRemoveGroup key="context-menu-container-remove" data-testid="context-menu-container-remove" />,
])(withSelection()(CustomNode) as typeof DefaultNode) as typeof DefaultNode;
export const CustomNodeWithSelection: typeof DefaultNode = withSelection()(
withContextMenu((element: GraphElement<ElementModel, CanvasNode['data']>) => {
const items: ReactElement[] = [];
const vizNode = element.getData()?.vizNode;
if (!vizNode) return items;

const nodeInteractions = vizNode.getNodeInteraction();

if (nodeInteractions.canHavePreviousStep) {
items.push(
<ItemAddStep
key="context-menu-item-prepend"
data-testid="context-menu-item-prepend"
mode={AddStepMode.PrependStep}
vizNode={vizNode}
>
<ArrowUpIcon /> Prepend
</ItemAddStep>,
);
}
if (nodeInteractions.canHaveNextStep) {
items.push(
<ItemAddStep
key="context-menu-item-append"
data-testid="context-menu-item-append"
mode={AddStepMode.AppendStep}
vizNode={vizNode}
>
<ArrowDownIcon /> Append
</ItemAddStep>,
);
}
if (nodeInteractions.canHavePreviousStep || nodeInteractions.canHaveNextStep) {
items.push(<ContextMenuSeparator key="context-menu-separator-add" />);
}

if (nodeInteractions.canHaveChildren) {
items.push(
<ItemInsertStep
key="context-menu-item-insert"
data-testid="context-menu-item-insert"
mode={AddStepMode.InsertChildStep}
vizNode={vizNode}
>
<PlusIcon /> Add step
</ItemInsertStep>,
);
}
if (nodeInteractions.canHaveSpecialChildren) {
items.push(
<ItemInsertStep
key="context-menu-item-insert-special"
data-testid="context-menu-item-insert-special"
mode={AddStepMode.InsertSpecialChildStep}
vizNode={vizNode}
>
<CodeBranchIcon /> Add branch
</ItemInsertStep>,
);
}
if (nodeInteractions.canHaveChildren || nodeInteractions.canHaveSpecialChildren) {
items.push(<ContextMenuSeparator key="context-menu-separator-insert" />);
}

if (nodeInteractions.canReplaceStep) {
items.push(
<ItemReplaceStep key="context-menu-item-replace" data-testid="context-menu-item-replace" vizNode={vizNode} />,
);
items.push(<ContextMenuSeparator key="context-menu-separator" />);
}

if (nodeInteractions.canRemoveStep) {
items.push(
<ItemDeleteStep key="context-menu-item-delete" data-testid="context-menu-item-delete" vizNode={vizNode} />,
);
}
if (nodeInteractions.canRemoveFlow) {
items.push(
<ItemDeleteGroup
key="context-menu-container-remove"
data-testid="context-menu-container-remove"
vizNode={vizNode}
/>,
);
}

return items;
})(CustomNode as typeof DefaultNode),
) as typeof DefaultNode;
58 changes: 0 additions & 58 deletions packages/ui/src/components/Visualization/Custom/ItemAddNode.tsx

This file was deleted.

39 changes: 39 additions & 0 deletions packages/ui/src/components/Visualization/Custom/ItemAddStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ContextMenuItem } from '@patternfly/react-topology';
import { FunctionComponent, PropsWithChildren, useCallback, useContext } from 'react';
import { IDataTestID } from '../../../models';
import { AddStepMode, IVisualizationNode } from '../../../models/visualization/base-visual-entity';
import { CatalogModalContext } from '../../../providers/catalog-modal.provider';
import { EntitiesContext } from '../../../providers/entities.provider';

interface ItemAddStepProps extends PropsWithChildren<IDataTestID> {
mode: AddStepMode.PrependStep | AddStepMode.AppendStep;
vizNode: IVisualizationNode;
}

export const ItemAddStep: FunctionComponent<ItemAddStepProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);
const catalogModalContext = useContext(CatalogModalContext);

const onAddNode = useCallback(async () => {
if (!props.vizNode || !entitiesContext) return;

/** Get compatible nodes and the location where can be introduced */
const compatibleNodes = entitiesContext.camelResource.getCompatibleComponents(props.mode, props.vizNode.data);

/** Open Catalog modal, filtering the compatible nodes */
const definedComponent = await catalogModalContext?.getNewComponent(compatibleNodes);
if (!definedComponent) return;

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

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

return (
<ContextMenuItem onClick={onAddNode} data-testid={props['data-testid']}>
{props.children}
</ContextMenuItem>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { TrashIcon } from '@patternfly/react-icons';
import { ContextMenuItem } from '@patternfly/react-topology';
import { FunctionComponent, PropsWithChildren, useCallback, useContext } from 'react';
import { IDataTestID } from '../../../models';
import { IVisualizationNode } from '../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../providers/entities.provider';

interface ItemDeleteGroupProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
}

export const ItemDeleteGroup: FunctionComponent<ItemDeleteGroupProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);
const flowId = props.vizNode?.getBaseEntity()?.getId();

const onRemoveGroup = useCallback(() => {
entitiesContext?.camelResource.removeEntity(flowId);
entitiesContext?.updateEntitiesFromCamelResource();
}, [entitiesContext, flowId]);

return (
<ContextMenuItem onClick={onRemoveGroup} data-testid={props['data-testid']}>
<TrashIcon /> Delete
</ContextMenuItem>
);
};
25 changes: 25 additions & 0 deletions packages/ui/src/components/Visualization/Custom/ItemDeleteStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { TrashIcon } from '@patternfly/react-icons';
import { ContextMenuItem } from '@patternfly/react-topology';
import { FunctionComponent, PropsWithChildren, useCallback, useContext } from 'react';
import { IDataTestID } from '../../../models';
import { IVisualizationNode } from '../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../providers/entities.provider';

interface ItemDeleteStepProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
}

export const ItemDeleteStep: FunctionComponent<ItemDeleteStepProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);

const onRemoveNode = useCallback(() => {
props.vizNode?.removeChild();
entitiesContext?.updateEntitiesFromCamelResource();
}, [entitiesContext, props.vizNode]);

return (
<ContextMenuItem onClick={onRemoveNode} data-testid={props['data-testid']}>
<TrashIcon /> Delete
</ContextMenuItem>
);
};
Loading

0 comments on commit 6184a73

Please sign in to comment.