Automatically open pending form nodes in the side panel (#12332)
- Keep the side panel open when submitting a pending form node if the history isn't empty - Prevent the same pending Form step from being automatically opened several times - Prevent duplicated views of the same pending form in the side panel > [!WARNING] Switching from the side panel view to the full-screen view isn't robust, and I used a hack to make one use case work here. We'll have to improve that part later. ## Before https://github.com/user-attachments/assets/0f830e87-7681-49e9-acc8-a08178f631a2 ## After https://github.com/user-attachments/assets/bfd742d6-e38e-4981-a93b-8e895d3aa38a
This commit is contained in:
committed by
GitHub
parent
b90cb3e1f9
commit
1115f6fc57
@ -8,6 +8,7 @@ import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/wo
|
||||
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
|
||||
import { WorkflowRun } from '@/workflow/types/Workflow';
|
||||
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||
@ -96,6 +97,14 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
|
||||
stepToOpenByDefault.id,
|
||||
);
|
||||
|
||||
set(
|
||||
workflowRunDiagramAutomaticallyOpenedStepsComponentState.atomFamily({
|
||||
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||
recordId,
|
||||
}),
|
||||
}),
|
||||
(steps) => [...steps, stepToOpenByDefault.id],
|
||||
);
|
||||
openWorkflowRunViewStepInCommandMenu({
|
||||
workflowId: workflowRunRecord.workflowId,
|
||||
workflowRunId: workflowRunRecord.id,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
@ -11,24 +12,33 @@ import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states
|
||||
import { WorkflowRunOutput } from '@/workflow/types/Workflow';
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
||||
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
||||
import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||
import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
export const WorkflowRunVisualizerEffect = ({
|
||||
workflowRunId,
|
||||
}: {
|
||||
workflowRunId: string;
|
||||
}) => {
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||
const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId);
|
||||
|
||||
const setWorkflowRunId = useSetRecoilComponentStateV2(
|
||||
workflowVisualizerWorkflowRunIdComponentState,
|
||||
);
|
||||
const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackStateV2(
|
||||
workflowVisualizerWorkflowIdComponentState,
|
||||
);
|
||||
const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
|
||||
workflowVisualizerWorkflowIdComponentState,
|
||||
);
|
||||
@ -43,6 +53,15 @@ export const WorkflowRunVisualizerEffect = ({
|
||||
const workflowRunStepToOpenByDefaultState = useRecoilComponentCallbackStateV2(
|
||||
workflowRunStepToOpenByDefaultComponentState,
|
||||
);
|
||||
const workflowSelectedNodeState = useRecoilComponentCallbackStateV2(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const workflowRunDiagramAutomaticallyOpenedStepsState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
workflowRunDiagramAutomaticallyOpenedStepsComponentState,
|
||||
);
|
||||
|
||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
||||
|
||||
@ -65,11 +84,11 @@ export const WorkflowRunVisualizerEffect = ({
|
||||
({
|
||||
workflowRunOutput,
|
||||
workflowVersionId,
|
||||
skipNodeSelection,
|
||||
isInRightDrawer,
|
||||
}: {
|
||||
workflowRunOutput: WorkflowRunOutput | undefined;
|
||||
workflowVersionId: string | undefined;
|
||||
skipNodeSelection: boolean;
|
||||
isInRightDrawer: boolean;
|
||||
}) => {
|
||||
if (!(isDefined(workflowRunOutput) && isDefined(workflowVersionId))) {
|
||||
set(flowState, undefined);
|
||||
@ -100,17 +119,60 @@ export const WorkflowRunVisualizerEffect = ({
|
||||
stepsOutput: workflowRunOutput.stepsOutput,
|
||||
});
|
||||
|
||||
if (isDefined(stepToOpenByDefault) && !skipNodeSelection) {
|
||||
const workflowRunDiagram = selectWorkflowDiagramNode({
|
||||
diagram: baseWorkflowRunDiagram,
|
||||
nodeIdToSelect: stepToOpenByDefault.id,
|
||||
});
|
||||
if (isDefined(stepToOpenByDefault)) {
|
||||
if (isInRightDrawer) {
|
||||
set(workflowDiagramState, baseWorkflowRunDiagram);
|
||||
|
||||
set(workflowDiagramState, workflowRunDiagram);
|
||||
set(workflowRunStepToOpenByDefaultState, {
|
||||
id: stepToOpenByDefault.id,
|
||||
data: stepToOpenByDefault.data,
|
||||
});
|
||||
const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue(
|
||||
snapshot,
|
||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||
);
|
||||
const hasStepAlreadyBeenOpenedAutomatically =
|
||||
workflowRunDiagramAutomaticallyOpenedSteps.includes(
|
||||
stepToOpenByDefault.id,
|
||||
);
|
||||
|
||||
if (
|
||||
workflowDiagramStatus === 'done' &&
|
||||
!hasStepAlreadyBeenOpenedAutomatically
|
||||
) {
|
||||
set(workflowSelectedNodeState, stepToOpenByDefault.id);
|
||||
|
||||
const workflowVisualizerWorkflowId = getSnapshotValue(
|
||||
snapshot,
|
||||
workflowVisualizerWorkflowIdState,
|
||||
);
|
||||
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||
throw new Error(
|
||||
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
|
||||
);
|
||||
}
|
||||
|
||||
set(workflowRunDiagramAutomaticallyOpenedStepsState, [
|
||||
...workflowRunDiagramAutomaticallyOpenedSteps,
|
||||
stepToOpenByDefault.id,
|
||||
]);
|
||||
openWorkflowRunViewStepInCommandMenu({
|
||||
workflowId: workflowVisualizerWorkflowId,
|
||||
workflowRunId,
|
||||
title: stepToOpenByDefault.data.name,
|
||||
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
|
||||
workflowSelectedNode: stepToOpenByDefault.id,
|
||||
stepExecutionStatus: stepToOpenByDefault.data.runStatus,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const workflowRunDiagram = selectWorkflowDiagramNode({
|
||||
diagram: baseWorkflowRunDiagram,
|
||||
nodeIdToSelect: stepToOpenByDefault.id,
|
||||
});
|
||||
|
||||
set(workflowDiagramState, workflowRunDiagram);
|
||||
set(workflowRunStepToOpenByDefaultState, {
|
||||
id: stepToOpenByDefault.id,
|
||||
data: stepToOpenByDefault.data,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
set(workflowDiagramState, baseWorkflowRunDiagram);
|
||||
}
|
||||
@ -121,9 +183,15 @@ export const WorkflowRunVisualizerEffect = ({
|
||||
},
|
||||
[
|
||||
flowState,
|
||||
getIcon,
|
||||
openWorkflowRunViewStepInCommandMenu,
|
||||
workflowDiagramState,
|
||||
workflowDiagramStatusState,
|
||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||
workflowRunId,
|
||||
workflowRunStepToOpenByDefaultState,
|
||||
workflowSelectedNodeState,
|
||||
workflowVisualizerWorkflowIdState,
|
||||
],
|
||||
);
|
||||
|
||||
@ -131,7 +199,7 @@ export const WorkflowRunVisualizerEffect = ({
|
||||
handleWorkflowRunDiagramGeneration({
|
||||
workflowRunOutput: workflowRun?.output ?? undefined,
|
||||
workflowVersionId: workflowRun?.workflowVersionId,
|
||||
skipNodeSelection: isInRightDrawer,
|
||||
isInRightDrawer,
|
||||
});
|
||||
}, [
|
||||
handleWorkflowRunDiagramGeneration,
|
||||
|
||||
@ -5,6 +5,7 @@ import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/componen
|
||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
||||
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
||||
import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||
@ -33,6 +34,10 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
||||
const workflowSelectedNodeState = useRecoilComponentCallbackStateV2(
|
||||
workflowSelectedNodeComponentState,
|
||||
);
|
||||
const workflowRunDiagramAutomaticallyOpenedStepsState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
workflowRunDiagramAutomaticallyOpenedStepsComponentState,
|
||||
);
|
||||
|
||||
const handleWorkflowRunDiagramCanvasInit = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -72,16 +77,30 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
||||
|
||||
set(workflowSelectedNodeState, workflowStepToOpenByDefault.id);
|
||||
|
||||
openWorkflowRunViewStepInCommandMenu({
|
||||
workflowId: workflowVisualizerWorkflowId,
|
||||
workflowRunId,
|
||||
title: workflowStepToOpenByDefault.data.name,
|
||||
icon: getIcon(
|
||||
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
|
||||
),
|
||||
workflowSelectedNode: workflowStepToOpenByDefault.id,
|
||||
stepExecutionStatus: workflowStepToOpenByDefault.data.runStatus,
|
||||
});
|
||||
const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue(
|
||||
snapshot,
|
||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||
);
|
||||
const hasStepAlreadyBeenOpenedAutomatically =
|
||||
workflowRunDiagramAutomaticallyOpenedSteps.includes(
|
||||
workflowStepToOpenByDefault.id,
|
||||
);
|
||||
|
||||
// FIXME: This is a workaround to avoid opening a workflow run step twice when going from the side panel to the fullscreen show page.
|
||||
// The step is opened in the `handleSelectionChange` function of `WorkflowRunDiagramCanvasEffect`. I think it shouldn't be opened there but
|
||||
// we should keep opening the step here, in `handleWorkflowRunDiagramCanvasInit`.
|
||||
if (!hasStepAlreadyBeenOpenedAutomatically) {
|
||||
openWorkflowRunViewStepInCommandMenu({
|
||||
workflowId: workflowVisualizerWorkflowId,
|
||||
workflowRunId,
|
||||
title: workflowStepToOpenByDefault.data.name,
|
||||
icon: getIcon(
|
||||
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
|
||||
),
|
||||
workflowSelectedNode: workflowStepToOpenByDefault.id,
|
||||
stepExecutionStatus: workflowStepToOpenByDefault.data.runStatus,
|
||||
});
|
||||
}
|
||||
|
||||
set(workflowRunStepToOpenByDefaultState, undefined);
|
||||
}
|
||||
@ -92,6 +111,7 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
||||
workflowRunStepToOpenByDefaultState,
|
||||
workflowVisualizerWorkflowIdState,
|
||||
workflowSelectedNodeState,
|
||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||
openWorkflowRunViewStepInCommandMenu,
|
||||
workflowRunId,
|
||||
getIcon,
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||
|
||||
export const workflowRunDiagramAutomaticallyOpenedStepsComponentState =
|
||||
createComponentStateV2<string[]>({
|
||||
key: 'workflowRunDiagramAutomaticallyOpenedStepsComponentState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
import { CmdEnterActionButton } from '@/action-menu/components/CmdEnterActionButton';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistory';
|
||||
import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput';
|
||||
import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
@ -37,7 +37,7 @@ export const WorkflowEditActionFormFiller = ({
|
||||
const { submitFormStep } = useSubmitFormStep();
|
||||
const [formData, setFormData] = useState<FormData>(action.settings.input);
|
||||
const { workflowRunId } = useWorkflowStepContextOrThrow();
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
const { goBackFromCommandMenu } = useCommandMenuHistory();
|
||||
const { updateWorkflowRunStep } = useUpdateWorkflowRunStep();
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
const canSubmit = !actionOptions.readonly && !isDefined(error);
|
||||
@ -98,7 +98,7 @@ export const WorkflowEditActionFormFiller = ({
|
||||
response,
|
||||
});
|
||||
|
||||
closeCommandMenu();
|
||||
goBackFromCommandMenu();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user