Skip to content

Commit

Permalink
feat(Canvas): Disable steps
Browse files Browse the repository at this point in the history
Some EIPs provide a `disabled` property to ignore them during the
runtime.

This commit adds a quick access to that property, so users can easily
enable/disable nodes in the canvas. In addition to that, the step is
grayed out when disabled.

fix: #758
fix: #699
  • Loading branch information
lordrip committed May 7, 2024
1 parent b6395a3 commit 76cf246
Show file tree
Hide file tree
Showing 25 changed files with 181 additions and 15 deletions.
36 changes: 26 additions & 10 deletions packages/ui/src/components/Visualization/Custom/CustomNode.scss
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
/* stylelint-disable-next-line selector-class-pattern */
.custom-node__image {
display: flex;
flex-flow: column;
align-items: center;
height: 100%;
justify-content: center;

img {
max-height: 80%;
.custom-node {
&__image {
display: flex;
flex-flow: column;
align-items: center;
height: 100%;
justify-content: center;

img {
max-height: 80%;
max-width: 95%;
}
}

&[data-disabled='true'] &__image {
filter: grayscale(100%);
}

&--disabled {
--pf-topology__node_decorator--Color: var(--pf-v5-global--BackgroundColor--dark-200);
}
}

/* stylelint-disable-next-line selector-class-pattern */
.custom-node__label--disabled {
font-style: italic;
text-decoration: line-through;
}
37 changes: 32 additions & 5 deletions packages/ui/src/components/Visualization/Custom/CustomNode.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Tooltip } from '@patternfly/react-core';
import { ArrowDownIcon, ArrowUpIcon, CodeBranchIcon, PlusIcon } from '@patternfly/react-icons';
import { ArrowDownIcon, ArrowUpIcon, BanIcon, CodeBranchIcon, PlusIcon } from '@patternfly/react-icons';
import {
ContextMenuSeparator,
Decorator,
DefaultNode,
ElementModel,
GraphElement,
Expand All @@ -12,6 +13,7 @@ import {
withContextMenu,
withSelection,
} from '@patternfly/react-topology';
import clsx from 'clsx';
import { FunctionComponent, ReactElement } from 'react';
import { AddStepMode } from '../../../models/visualization/base-visual-entity';
import { CanvasDefaults } from '../Canvas/canvas.defaults';
Expand All @@ -20,6 +22,7 @@ import './CustomNode.scss';
import { ItemAddStep } from './ItemAddStep';
import { ItemDeleteGroup } from './ItemDeleteGroup';
import { ItemDeleteStep } from './ItemDeleteStep';
import { ItemDisableStep } from './ItemDisableStep';
import { ItemInsertStep } from './ItemInsertStep';
import { ItemReplaceStep } from './ItemReplaceStep';

Expand All @@ -31,22 +34,29 @@ const noopFn = () => {};
const CustomNode: FunctionComponent<CustomNodeProps> = observer(({ element, ...rest }) => {
const vizNode = element.getData()?.vizNode;
const label = vizNode?.getNodeLabel();
const isDisabled = !!vizNode?.getComponentSchema()?.definition?.disabled;
const tooltipContent = vizNode?.getTooltipContent();
const statusDecoratorTooltip = vizNode?.getNodeValidationText();
const nodeStatus = !statusDecoratorTooltip ? NodeStatus.default : NodeStatus.warning;
const nodeStatus = !statusDecoratorTooltip || isDisabled ? NodeStatus.default : NodeStatus.warning;

return (
<DefaultNode
{...rest}
element={element}
label={label}
labelClassName={clsx('custom-node__label', { 'custom-node__label--disabled': isDisabled })}
truncateLength={15}
showStatusDecorator
showStatusDecorator={!isDisabled}
statusDecoratorTooltip={statusDecoratorTooltip}
nodeStatus={nodeStatus}
onStatusDecoratorClick={noopFn}
>
<g data-testid={`custom-node__${vizNode?.id}`} data-nodelabel={label}>
<g
className="custom-node"
data-testid={`custom-node__${vizNode?.id}`}
data-nodelabel={label}
data-disabled={isDisabled}
>
<foreignObject
x="0"
y="0"
Expand All @@ -59,6 +69,16 @@ const CustomNode: FunctionComponent<CustomNodeProps> = observer(({ element, ...r
</div>
</Tooltip>
</foreignObject>

{isDisabled && (
<Decorator
radius={12}
x={CanvasDefaults.DEFAULT_NODE_DIAMETER}
y={0}
icon={<BanIcon className="custom-node--disabled" />}
showBackground
/>
)}
</g>
</DefaultNode>
);
Expand Down Expand Up @@ -128,11 +148,18 @@ export const CustomNodeWithSelection: typeof DefaultNode = withSelection()(
items.push(<ContextMenuSeparator key="context-menu-separator-insert" />);
}

if (nodeInteractions.canBeDisabled) {
items.push(
<ItemDisableStep key="context-menu-item-disable" data-testid="context-menu-item-disable" vizNode={vizNode} />,
);
}
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.canBeDisabled || nodeInteractions.canReplaceStep) {
items.push(<ContextMenuSeparator key="context-menu-separator-replace" />);
}

if (nodeInteractions.canRemoveStep) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { BanIcon, CheckIcon } 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';
import { setValue } from '../../../utils/set-value';

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

export const ItemDisableStep: FunctionComponent<ItemDisableStepProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);

const isDisabled = !!props.vizNode.getComponentSchema()?.definition?.disabled;

const onToggleDisableNode = useCallback(() => {
const newModel = props.vizNode.getComponentSchema()?.definition || {};
setValue(newModel, 'disabled', !isDisabled);
props.vizNode.updateModel(newModel);

entitiesContext?.updateEntitiesFromCamelResource();
}, [entitiesContext, isDisabled, props.vizNode]);

return (
<ContextMenuItem onClick={onToggleDisableNode} data-testid={props['data-testid']}>
{isDisabled ? (
<>
<CheckIcon /> Enable
</>
) : (
<>
<BanIcon /> Disable
</>
)}
</ContextMenuItem>
);
};
1 change: 1 addition & 0 deletions packages/ui/src/models/visualization/base-visual-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,5 @@ export interface NodeInteraction {
canReplaceStep: boolean;
canRemoveStep: boolean;
canRemoveFlow: boolean;
canBeDisabled: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'from' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -14,6 +15,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'intercept' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -26,6 +28,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'interceptFrom' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -38,6 +41,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'interceptSendToEndpoint' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -50,6 +54,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'log' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -62,6 +67,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'onCompletion' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -74,6 +80,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'onException' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -86,6 +93,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'route' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -98,6 +106,7 @@ exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct

exports[`AbstractCamelVisualEntity getNodeInteraction should return the correct interaction for the 'to' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor
path: 'interceptSendToEndpoint'
}' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -17,6 +18,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'from', path: 'from' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -29,6 +31,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'intercept', path: 'intercept' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -41,6 +44,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'interceptFrom', path: 'interceptFrom' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -53,6 +57,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'log', path: 'log' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -65,6 +70,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'onCompletion', path: 'onCompletion' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -77,6 +83,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'onException', path: 'onException' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -89,6 +96,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'route', path: 'route' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -101,6 +109,7 @@ exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the cor

exports[`CamelInterceptFromVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'to', path: 'to' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu
path: 'interceptSendToEndpoint'
}' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -17,6 +18,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'from', path: 'from' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -29,6 +31,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'intercept', path: 'intercept' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -41,6 +44,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'interceptFrom', path: 'interceptFrom' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -53,6 +57,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'log', path: 'log' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -65,6 +70,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'onCompletion', path: 'onCompletion' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -77,6 +83,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'onException', path: 'onException' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": true,
"canHaveNextStep": false,
"canHavePreviousStep": false,
Expand All @@ -89,6 +96,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'route', path: 'route' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand All @@ -101,6 +109,7 @@ exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should retu

exports[`CamelInterceptSendToEndpointVisualEntity getNodeInteraction should return the correct interaction for the '{ processorName: 'to', path: 'to' }' processor 1`] = `
{
"canBeDisabled": false,
"canHaveChildren": false,
"canHaveNextStep": true,
"canHavePreviousStep": true,
Expand Down
Loading

0 comments on commit 76cf246

Please sign in to comment.