Keep workflow nodes selected unless side panel is closed (#16029)
This PR no longer relies on Reactflow's `selected` property to determine whether a node is selected. Instead, we rely on the pre-existing `workflowSelectedNodeComponentState` state. It makes it easier to to synchronize what's displayed in the side panel and which node is styled as being selected. ## Demo - workflows https://github.com/user-attachments/assets/3848c5f9-df51-48e2-8b9c-f083d25d14ed ## Demo - workflow versions https://github.com/user-attachments/assets/9ac9ec6c-e6b1-4f24-a817-a7349e1b70d6 ## Demo - workflow runs https://github.com/user-attachments/assets/54f955cf-dacc-43f8-b684-01e8a6c15f3b
This commit is contained in:
committed by
GitHub
parent
86aff36035
commit
ee761a2594
+3
-15
@@ -7,6 +7,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { WorkflowDiagramRightClickCommandMenu } from '@/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu';
|
||||
import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds';
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
|
||||
import { workflowDiagramWaitingNodesDimensionsComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState';
|
||||
@@ -24,7 +25,6 @@ import { WorkflowDiagramConnection } from '@/workflow/workflow-diagram/workflow-
|
||||
import { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
@@ -170,12 +170,10 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
const setWorkflowDiagram = useSetRecoilComponentState(
|
||||
workflowDiagramComponentState,
|
||||
);
|
||||
const setWorkflowInsertStepIds = useSetRecoilComponentState(
|
||||
workflowInsertStepIdsComponentState,
|
||||
);
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const { resetWorkflowInsertStepIds } = useResetWorkflowInsertStepIds();
|
||||
const workflowDiagramWaitingNodesDimensionsState =
|
||||
useRecoilComponentCallbackState(
|
||||
workflowDiagramWaitingNodesDimensionsComponentState,
|
||||
@@ -217,17 +215,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
};
|
||||
|
||||
useListenToSidePanelClosing(() => {
|
||||
reactflow.setNodes((nodes) =>
|
||||
nodes.map((node) => ({ ...node, selected: false })),
|
||||
);
|
||||
reactflow.setEdges((edges) =>
|
||||
edges.map((edge) => ({ ...edge, selected: false })),
|
||||
);
|
||||
setWorkflowInsertStepIds({
|
||||
parentStepId: undefined,
|
||||
nextStepId: undefined,
|
||||
position: undefined,
|
||||
});
|
||||
resetWorkflowInsertStepIds();
|
||||
setWorkflowSelectedNode(undefined);
|
||||
});
|
||||
|
||||
|
||||
+18
-2
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import '@xyflow/react/dist/style.css';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
@@ -18,6 +19,9 @@ export default meta;
|
||||
type Story = StoryObj<typeof WorkflowDiagramEmptyTriggerEditable>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
id: 'trigger-node',
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div style={{ position: 'relative' }}>
|
||||
@@ -36,10 +40,22 @@ export const Default: Story = {
|
||||
};
|
||||
|
||||
export const Selected: Story = {
|
||||
args: {
|
||||
id: 'trigger-node',
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="selectable selected" style={{ position: 'relative' }}>
|
||||
<RecoilRoot>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<RecoilRoot
|
||||
initializeState={({ set }) => {
|
||||
set(
|
||||
workflowSelectedNodeComponentState.atomFamily({
|
||||
instanceId: 'workflow-visualizer-instance-id',
|
||||
}),
|
||||
'trigger-node',
|
||||
);
|
||||
}}
|
||||
>
|
||||
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'workflow-visualizer-instance-id' }}
|
||||
>
|
||||
|
||||
+14
-2
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import '@xyflow/react/dist/style.css';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
@@ -149,8 +150,19 @@ export const Catalog: CatalogStory<
|
||||
decorators: [
|
||||
(Story, { args }) => {
|
||||
return (
|
||||
<div className={`selectable ${args.selected ? 'selected' : ''}`}>
|
||||
<RecoilRoot>
|
||||
<div>
|
||||
<RecoilRoot
|
||||
initializeState={({ set }) => {
|
||||
if (args.selected) {
|
||||
set(
|
||||
workflowSelectedNodeComponentState.atomFamily({
|
||||
instanceId: 'workflow-visualizer-instance-id',
|
||||
}),
|
||||
args.id,
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'workflow-visualizer-instance-id' }}
|
||||
>
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useResetWorkflowInsertStepIds = () => {
|
||||
const workflowInsertStepIdsState = useRecoilComponentCallbackState(
|
||||
workflowInsertStepIdsComponentState,
|
||||
);
|
||||
|
||||
const resetWorkflowInsertStepIds = useRecoilCallback(
|
||||
({ reset }) =>
|
||||
() => {
|
||||
reset(workflowInsertStepIdsState);
|
||||
},
|
||||
[workflowInsertStepIdsState],
|
||||
);
|
||||
|
||||
return { resetWorkflowInsertStepIds };
|
||||
};
|
||||
+9
@@ -3,7 +3,9 @@ import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandM
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { type WorkflowStepConnectionOptions } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowStepConnectionOptions';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useCallback, useContext } from 'react';
|
||||
@@ -16,6 +18,10 @@ export const useStartNodeCreation = () => {
|
||||
const [workflowInsertStepIds, setWorkflowInsertStepIds] =
|
||||
useRecoilComponentState(workflowInsertStepIdsComponentState);
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
|
||||
const { openWorkflowCreateStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||
@@ -49,6 +55,8 @@ export const useStartNodeCreation = () => {
|
||||
connectionOptions,
|
||||
});
|
||||
|
||||
setWorkflowSelectedNode(undefined);
|
||||
|
||||
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||
return;
|
||||
}
|
||||
@@ -61,6 +69,7 @@ export const useStartNodeCreation = () => {
|
||||
},
|
||||
[
|
||||
setWorkflowInsertStepIds,
|
||||
setWorkflowSelectedNode,
|
||||
workflowVisualizerWorkflowId,
|
||||
isInRightDrawer,
|
||||
openWorkflowCreateStepInCommandMenu,
|
||||
|
||||
+22
-3
@@ -1,9 +1,12 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId';
|
||||
import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { WorkflowNodeContainer } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeContainer';
|
||||
import { WorkflowNodeIconContainer } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeIconContainer';
|
||||
import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabel';
|
||||
@@ -15,7 +18,7 @@ import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const WorkflowDiagramEmptyTriggerEditable = () => {
|
||||
export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const { openWorkflowTriggerTypeInCommandMenu } = useWorkflowCommandMenu();
|
||||
@@ -24,17 +27,28 @@ export const WorkflowDiagramEmptyTriggerEditable = () => {
|
||||
workflowVisualizerWorkflowIdComponentState,
|
||||
);
|
||||
|
||||
const [workflowSelectedNode, setWorkflowSelectedNode] =
|
||||
useRecoilComponentState(workflowSelectedNodeComponentState);
|
||||
|
||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||
|
||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const selected = workflowSelectedNode === id;
|
||||
|
||||
const { resetWorkflowInsertStepIds } = useResetWorkflowInsertStepIds();
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isInRightDrawer) {
|
||||
setCommandMenuNavigationStack([]);
|
||||
}
|
||||
|
||||
resetWorkflowInsertStepIds();
|
||||
|
||||
setWorkflowSelectedNode(id);
|
||||
|
||||
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||
return;
|
||||
}
|
||||
@@ -46,15 +60,20 @@ export const WorkflowDiagramEmptyTriggerEditable = () => {
|
||||
<WorkflowNodeContainer
|
||||
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
||||
onClick={handleClick}
|
||||
selected={selected}
|
||||
>
|
||||
<WorkflowNodeIconContainer />
|
||||
|
||||
<WorkflowNodeRightPart>
|
||||
<WorkflowNodeLabelWithCounterPart>
|
||||
<WorkflowNodeLabel>{t`Trigger`}</WorkflowNodeLabel>
|
||||
<WorkflowNodeLabel selected={selected}>
|
||||
{t`Trigger`}
|
||||
</WorkflowNodeLabel>
|
||||
</WorkflowNodeLabelWithCounterPart>
|
||||
|
||||
<WorkflowNodeTitle>{t`Add a Trigger`}</WorkflowNodeTitle>
|
||||
<WorkflowNodeTitle selected={selected}>
|
||||
{t`Add a Trigger`}
|
||||
</WorkflowNodeTitle>
|
||||
</WorkflowNodeRightPart>
|
||||
</WorkflowNodeContainer>
|
||||
);
|
||||
|
||||
+14
-8
@@ -1,8 +1,8 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
||||
import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId';
|
||||
@@ -20,7 +20,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
export const WorkflowDiagramEmptyTriggerReadonly = () => {
|
||||
export const WorkflowDiagramEmptyTriggerReadonly = ({ id }: { id: string }) => {
|
||||
const { getIcon } = useIcons();
|
||||
const { t } = useLingui();
|
||||
|
||||
@@ -31,18 +31,19 @@ export const WorkflowDiagramEmptyTriggerReadonly = () => {
|
||||
workflowVisualizerWorkflowVersionIdComponentState,
|
||||
);
|
||||
|
||||
const [workflowSelectedNode, setWorkflowSelectedNode] =
|
||||
useRecoilComponentState(workflowSelectedNodeComponentState);
|
||||
|
||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||
|
||||
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
|
||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const selected = workflowSelectedNode === id;
|
||||
|
||||
const handleClick = () => {
|
||||
if (
|
||||
!isDefined(workflowVisualizerWorkflowId) ||
|
||||
@@ -72,15 +73,20 @@ export const WorkflowDiagramEmptyTriggerReadonly = () => {
|
||||
<WorkflowNodeContainer
|
||||
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
||||
onClick={handleClick}
|
||||
selected={selected}
|
||||
>
|
||||
<WorkflowNodeIconContainer />
|
||||
|
||||
<WorkflowNodeRightPart>
|
||||
<WorkflowNodeLabelWithCounterPart>
|
||||
<WorkflowNodeLabel>{t`Trigger`}</WorkflowNodeLabel>
|
||||
<WorkflowNodeLabel selected={selected}>
|
||||
{t`Trigger`}
|
||||
</WorkflowNodeLabel>
|
||||
</WorkflowNodeLabelWithCounterPart>
|
||||
|
||||
<WorkflowNodeTitle>{t`Add a Trigger`}</WorkflowNodeTitle>
|
||||
<WorkflowNodeTitle selected={selected}>
|
||||
{t`Add a Trigger`}
|
||||
</WorkflowNodeTitle>
|
||||
</WorkflowNodeRightPart>
|
||||
</WorkflowNodeContainer>
|
||||
);
|
||||
|
||||
+31
-25
@@ -1,9 +1,10 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||
@@ -16,11 +17,9 @@ import { useIcons } from 'twenty-ui/display';
|
||||
export const WorkflowDiagramStepNodeEditable = ({
|
||||
id,
|
||||
data,
|
||||
selected,
|
||||
}: {
|
||||
id: string;
|
||||
data: WorkflowDiagramStepNodeData;
|
||||
selected?: boolean;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
@@ -28,41 +27,48 @@ export const WorkflowDiagramStepNodeEditable = ({
|
||||
workflowVisualizerWorkflowIdComponentState,
|
||||
);
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const [workflowSelectedNode, setWorkflowSelectedNode] =
|
||||
useRecoilComponentState(workflowSelectedNodeComponentState);
|
||||
|
||||
const selected = workflowSelectedNode === id;
|
||||
|
||||
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const { resetWorkflowInsertStepIds } = useResetWorkflowInsertStepIds();
|
||||
|
||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||
|
||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isInRightDrawer) {
|
||||
setCommandMenuNavigationStack([]);
|
||||
}
|
||||
|
||||
resetWorkflowInsertStepIds();
|
||||
|
||||
setWorkflowSelectedNode(id);
|
||||
|
||||
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||
openWorkflowEditStepInCommandMenu(
|
||||
workflowVisualizerWorkflowId,
|
||||
data.name,
|
||||
getIcon(getWorkflowNodeIconKey(data)),
|
||||
id,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<WorkflowDiagramStepNodeEditableContent
|
||||
id={id}
|
||||
data={data}
|
||||
selected={selected ?? false}
|
||||
onClick={() => {
|
||||
if (!isInRightDrawer) {
|
||||
setCommandMenuNavigationStack([]);
|
||||
}
|
||||
|
||||
setWorkflowSelectedNode(id);
|
||||
|
||||
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||
openWorkflowEditStepInCommandMenu(
|
||||
workflowVisualizerWorkflowId,
|
||||
data.name,
|
||||
getIcon(getWorkflowNodeIconKey(data)),
|
||||
id,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}}
|
||||
selected={selected}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+8
-2
@@ -87,6 +87,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
isConnectable={isNodeConnectable}
|
||||
selected={selected}
|
||||
>
|
||||
<WorkflowDiagramHandleTarget isConnectable={isNodeConnectable} />
|
||||
|
||||
@@ -96,10 +97,15 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
|
||||
<WorkflowNodeRightPart>
|
||||
<WorkflowNodeLabelWithCounterPart>
|
||||
<WorkflowNodeLabel>{capitalize(data.nodeType)}</WorkflowNodeLabel>
|
||||
<WorkflowNodeLabel selected={selected}>
|
||||
{capitalize(data.nodeType)}
|
||||
</WorkflowNodeLabel>
|
||||
</WorkflowNodeLabelWithCounterPart>
|
||||
|
||||
<WorkflowNodeTitle highlight={nodeTitleHighlighted}>
|
||||
<WorkflowNodeTitle
|
||||
highlight={nodeTitleHighlighted}
|
||||
selected={selected}
|
||||
>
|
||||
{data.name}
|
||||
</WorkflowNodeTitle>
|
||||
</WorkflowNodeRightPart>
|
||||
|
||||
+13
-8
@@ -1,8 +1,8 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
||||
import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId';
|
||||
@@ -28,11 +28,9 @@ import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
export const WorkflowDiagramStepNodeReadonly = ({
|
||||
id,
|
||||
selected,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
selected: boolean;
|
||||
data: WorkflowDiagramStepNodeData;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
@@ -44,9 +42,10 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
||||
workflowVisualizerWorkflowVersionIdComponentState,
|
||||
);
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const [workflowSelectedNode, setWorkflowSelectedNode] =
|
||||
useRecoilComponentState(workflowSelectedNodeComponentState);
|
||||
|
||||
const selected = workflowSelectedNode === id;
|
||||
|
||||
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
@@ -89,6 +88,7 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
||||
<WorkflowNodeContainer
|
||||
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
||||
onClick={handleClick}
|
||||
selected={selected}
|
||||
>
|
||||
<WorkflowDiagramHandleTarget />
|
||||
<WorkflowNodeIconContainer>
|
||||
@@ -97,10 +97,15 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
||||
|
||||
<WorkflowNodeRightPart>
|
||||
<WorkflowNodeLabelWithCounterPart>
|
||||
<WorkflowNodeLabel>{capitalize(data.nodeType)}</WorkflowNodeLabel>
|
||||
<WorkflowNodeLabel selected={selected}>
|
||||
{capitalize(data.nodeType)}
|
||||
</WorkflowNodeLabel>
|
||||
</WorkflowNodeLabelWithCounterPart>
|
||||
|
||||
<WorkflowNodeTitle highlight={nodeTitleHighlighted}>
|
||||
<WorkflowNodeTitle
|
||||
highlight={nodeTitleHighlighted}
|
||||
selected={selected}
|
||||
>
|
||||
{data.name}
|
||||
</WorkflowNodeTitle>
|
||||
</WorkflowNodeRightPart>
|
||||
|
||||
+23
-21
@@ -6,6 +6,7 @@ import styled from '@emotion/styled';
|
||||
const StyledNodeContainer = styled.div<{
|
||||
runStatus?: WorkflowRunStepStatus;
|
||||
isConnectable?: boolean;
|
||||
selected: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@@ -21,30 +22,31 @@ const StyledNodeContainer = styled.div<{
|
||||
position: relative;
|
||||
transition: border-color 0.1s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
${({ theme }) => theme.background.transparent.lighter} 0%,
|
||||
${({ theme }) => theme.background.transparent.lighter} 100%
|
||||
),
|
||||
${({ theme }) => theme.background.secondary};
|
||||
${({ theme, isConnectable }) =>
|
||||
isConnectable &&
|
||||
css`
|
||||
border-color: ${theme.color.blue} !important;
|
||||
`};
|
||||
}
|
||||
|
||||
${({ theme, runStatus }) => {
|
||||
${({ theme, runStatus, selected, isConnectable }) => {
|
||||
const colors = getWorkflowDiagramColors({ theme, runStatus });
|
||||
|
||||
return css`
|
||||
border-color: ${colors.unselected.borderColor};
|
||||
background: ${colors.unselected.background};
|
||||
const background = selected
|
||||
? colors.selected.background
|
||||
: colors.unselected.background;
|
||||
|
||||
.selected & {
|
||||
background-color: ${colors.selected.background};
|
||||
border-color: ${colors.selected.borderColor};
|
||||
return css`
|
||||
background: ${background};
|
||||
border-color: ${selected
|
||||
? colors.selected.borderColor
|
||||
: colors.unselected.borderColor};
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
${theme.background.transparent.lighter} 0%,
|
||||
${theme.background.transparent.lighter} 100%
|
||||
),
|
||||
${background};
|
||||
|
||||
${isConnectable &&
|
||||
css`
|
||||
border-color: ${theme.color.blue} !important;
|
||||
`};
|
||||
}
|
||||
`;
|
||||
}}
|
||||
|
||||
+6
-9
@@ -1,24 +1,21 @@
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { Label } from 'twenty-ui/display';
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { css } from '@emotion/react';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
|
||||
const StyledNodeLabel = styled(Label)<{
|
||||
runStatus?: WorkflowRunStepStatus;
|
||||
selected: boolean;
|
||||
}>`
|
||||
box-sizing: border-box;
|
||||
flex: 1 0 0;
|
||||
|
||||
${({ theme, runStatus }) => {
|
||||
${({ theme, runStatus, selected }) => {
|
||||
const colors = getWorkflowDiagramColors({ theme, runStatus });
|
||||
|
||||
return css`
|
||||
color: ${colors.unselected.color};
|
||||
|
||||
.selected & {
|
||||
color: ${colors.selected.color};
|
||||
}
|
||||
color: ${selected ? colors.selected.color : colors.unselected.color};
|
||||
`;
|
||||
}}
|
||||
`;
|
||||
|
||||
+7
-8
@@ -1,11 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { css } from '@emotion/react';
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledNodeTitle = styled.div<{
|
||||
highlight?: boolean;
|
||||
runStatus?: WorkflowRunStepStatus;
|
||||
selected: boolean;
|
||||
}>`
|
||||
box-sizing: border-box;
|
||||
-webkit-box-orient: vertical;
|
||||
@@ -17,7 +18,7 @@ const StyledNodeTitle = styled.div<{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
${({ theme, highlight, runStatus }) => {
|
||||
${({ theme, highlight, runStatus, selected }) => {
|
||||
const colors = getWorkflowDiagramColors({ theme, runStatus });
|
||||
|
||||
if (true === highlight) {
|
||||
@@ -27,11 +28,9 @@ const StyledNodeTitle = styled.div<{
|
||||
}
|
||||
|
||||
return css`
|
||||
color: ${colors.unselected.titleColor};
|
||||
|
||||
.selected & {
|
||||
color: ${colors.selected.titleColor};
|
||||
}
|
||||
color: ${selected
|
||||
? colors.selected.titleColor
|
||||
: colors.unselected.titleColor};
|
||||
`;
|
||||
}}
|
||||
`;
|
||||
|
||||
+8
-8
@@ -1,8 +1,8 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
@@ -80,11 +80,9 @@ const StyledRightPartContainer = styled.div`
|
||||
export const WorkflowRunDiagramStepNode = ({
|
||||
id,
|
||||
data,
|
||||
selected,
|
||||
}: {
|
||||
id: string;
|
||||
data: WorkflowRunDiagramStepNodeData;
|
||||
selected: boolean;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
const theme = useTheme();
|
||||
@@ -94,9 +92,10 @@ export const WorkflowRunDiagramStepNode = ({
|
||||
);
|
||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const [workflowSelectedNode, setWorkflowSelectedNode] =
|
||||
useRecoilComponentState(workflowSelectedNodeComponentState);
|
||||
|
||||
const selected = workflowSelectedNode === id;
|
||||
|
||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
@@ -142,6 +141,7 @@ export const WorkflowRunDiagramStepNode = ({
|
||||
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
||||
runStatus={data.runStatus}
|
||||
onClick={handleClick}
|
||||
selected={selected}
|
||||
>
|
||||
<WorkflowDiagramHandleTarget />
|
||||
<WorkflowNodeIconContainer>
|
||||
@@ -150,7 +150,7 @@ export const WorkflowRunDiagramStepNode = ({
|
||||
|
||||
<WorkflowNodeRightPart>
|
||||
<StyledNodeLabelWithCounterPart>
|
||||
<WorkflowNodeLabel runStatus={data.runStatus}>
|
||||
<WorkflowNodeLabel runStatus={data.runStatus} selected={selected}>
|
||||
{capitalize(data.nodeType)}
|
||||
</WorkflowNodeLabel>
|
||||
|
||||
@@ -187,7 +187,7 @@ export const WorkflowRunDiagramStepNode = ({
|
||||
</StyledRightPartContainer>
|
||||
</StyledNodeLabelWithCounterPart>
|
||||
|
||||
<WorkflowNodeTitle runStatus={data.runStatus}>
|
||||
<WorkflowNodeTitle runStatus={data.runStatus} selected={selected}>
|
||||
{data.name}
|
||||
</WorkflowNodeTitle>
|
||||
</WorkflowNodeRightPart>
|
||||
|
||||
Reference in New Issue
Block a user