diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx
index 20a2db8841a..c97542a7b22 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx
+++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx
@@ -11,6 +11,7 @@ import { SeeActiveVersionWorkflowSingleRecordAction } from '@/action-menu/action
import { SeeRunsWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/SeeRunsWorkflowSingleRecordAction';
import { SeeVersionsWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/SeeVersionsWorkflowSingleRecordAction';
import { TestWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/TestWorkflowSingleRecordAction';
+import { TidyUpWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction';
import { WorkflowSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys';
import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
@@ -32,6 +33,7 @@ import {
IconPlayerPlay,
IconPlus,
IconPower,
+ IconReorder,
IconVersions,
} from 'twenty-ui/display';
@@ -209,6 +211,21 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
availableOn: [ActionViewType.SHOW_PAGE],
component: ,
},
+ [WorkflowSingleRecordActionKeys.TIDY_UP]: {
+ key: WorkflowSingleRecordActionKeys.TIDY_UP,
+ label: msg`Tidy up workflow`,
+ shortLabel: msg`Tidy up`,
+ isPinned: false,
+ position: 9,
+ Icon: IconReorder,
+ type: ActionType.Standard,
+ scope: ActionScope.RecordSelection,
+ shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) =>
+ areWorkflowTriggerAndStepsDefined(workflowWithCurrentVersion) &&
+ !isDefined(selectedRecord?.deletedAt),
+ availableOn: [ActionViewType.SHOW_PAGE],
+ component: ,
+ },
[NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS]: {
type: ActionType.Navigation,
scope: ActionScope.Global,
@@ -260,82 +277,82 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
label: msg`Create new workflow`,
},
[SingleRecordActionKeys.ADD_TO_FAVORITES]: {
- position: 9,
- },
- [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
position: 10,
},
- [SingleRecordActionKeys.DELETE]: {
+ [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
position: 11,
+ },
+ [SingleRecordActionKeys.DELETE]: {
+ position: 12,
label: msg`Delete workflow`,
},
[MultipleRecordsActionKeys.DELETE]: {
- position: 12,
+ position: 13,
label: msg`Delete workflows`,
},
[SingleRecordActionKeys.DESTROY]: {
- position: 13,
+ position: 14,
label: msg`Permanently destroy workflow`,
},
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
- position: 14,
+ position: 15,
label: msg`Export workflow`,
shouldBeRegistered: ({ selectedRecord }) =>
!isDefined(selectedRecord?.deletedAt),
},
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
- position: 15,
+ position: 16,
label: msg`Export workflow`,
},
[MultipleRecordsActionKeys.EXPORT]: {
- position: 16,
+ position: 17,
label: msg`Export workflows`,
},
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
- position: 16,
+ position: 17,
label: msg`Export view`,
},
[MultipleRecordsActionKeys.DESTROY]: {
- position: 17,
+ position: 18,
label: msg`Permanently destroy workflows`,
},
[SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
- position: 18,
+ position: 19,
label: msg`Navigate to previous workflow`,
},
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
- position: 19,
+ position: 20,
label: msg`Navigate to next workflow`,
},
[NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
- position: 20,
+ position: 21,
label: msg`See deleted workflows`,
},
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
- position: 21,
+ position: 22,
label: msg`Hide deleted workflows`,
},
[NoSelectionRecordActionKeys.IMPORT_RECORDS]: {
- position: 22,
+ position: 23,
label: msg`Import workflows`,
},
[NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
- position: 23,
- },
- [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
position: 24,
},
- [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
+ [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
position: 25,
},
- [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
+ [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
position: 26,
},
- [NoSelectionRecordActionKeys.GO_TO_TASKS]: {
+ [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
position: 27,
},
- [NoSelectionRecordActionKeys.GO_TO_NOTES]: {
+ [NoSelectionRecordActionKeys.GO_TO_TASKS]: {
position: 28,
},
+ [NoSelectionRecordActionKeys.GO_TO_NOTES]: {
+ position: 29,
+ },
},
});
diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx
new file mode 100644
index 00000000000..113ae2d7a2e
--- /dev/null
+++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx
@@ -0,0 +1,41 @@
+import { Action } from '@/action-menu/actions/components/Action';
+import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
+import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
+import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion';
+import { useRecoilCallback } from 'recoil';
+import { isDefined } from 'twenty-shared/utils';
+
+export const TidyUpWorkflowSingleRecordAction = () => {
+ const recordId = useSelectedRecordIdOrThrow();
+ const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion();
+ const instanceId = getWorkflowVisualizerComponentInstanceId({
+ recordId,
+ });
+ const { getUpdatableWorkflowVersion } =
+ useGetUpdatableWorkflowVersionOrThrow(instanceId);
+
+ const onClick = useRecoilCallback(
+ ({ snapshot }) =>
+ async () => {
+ const workflowDiagramState = workflowDiagramComponentState.atomFamily({
+ instanceId,
+ });
+ const workflowDiagram = snapshot
+ .getLoadable(workflowDiagramState)
+ .getValue();
+
+ if (!isDefined(workflowDiagram)) {
+ return;
+ }
+
+ const workflowVersionId = await getUpdatableWorkflowVersion();
+
+ await tidyUpWorkflowVersion(workflowVersionId, workflowDiagram);
+ },
+ [getUpdatableWorkflowVersion, tidyUpWorkflowVersion, instanceId],
+ );
+
+ return ;
+};
diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys.ts
index 25863b2e24e..dd0030910ea 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys.ts
+++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys.ts
@@ -7,4 +7,5 @@ export enum WorkflowSingleRecordActionKeys {
SEE_VERSIONS = 'see-versions-workflow-single-record',
TEST = 'test-workflow-single-record',
ADD_NODE = 'add-node-workflow-single-record',
+ TIDY_UP = 'tidy-up-workflow-single-record',
}
diff --git a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts
index 7e1eac57bf6..05e1e72d239 100644
--- a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts
+++ b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts
@@ -4,11 +4,12 @@ import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithC
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { isDefined } from 'twenty-shared/utils';
-export const useGetUpdatableWorkflowVersionOrThrow = () => {
+export const useGetUpdatableWorkflowVersionOrThrow = (instanceId?: string) => {
const { createDraftFromWorkflowVersion } =
useCreateDraftFromWorkflowVersion();
const workflowVisualizerWorkflowId = useRecoilComponentValue(
workflowVisualizerWorkflowIdComponentState,
+ instanceId,
);
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx
index 0c1e729a9d7..bb2d498c60c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx
@@ -3,7 +3,7 @@ import { useCloseRightClickMenu } from '@/workflow/workflow-diagram/hooks/useClo
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
import { useWorkflowDiagramScreenToFlowPosition } from '@/workflow/workflow-diagram/hooks/useWorkflowDiagramScreenToFlowPosition';
import { workflowDiagramRightClickMenuPositionState } from '@/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState';
-import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion';
+import { useTidyUp } from '@/workflow/workflow-version/hooks/useTidyUp';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRef } from 'react';
@@ -41,10 +41,10 @@ export const WorkflowDiagramRightClickCommandMenu = () => {
workflowDiagramRightClickMenuPositionState,
);
- const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion();
+ const { tidyUp } = useTidyUp();
const handleReorderWorkflowDiagram = async () => {
- await tidyUpWorkflowVersion();
+ await tidyUp();
closeRightClickMenu();
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts
new file mode 100644
index 00000000000..85e0faa4448
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts
@@ -0,0 +1,34 @@
+import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
+import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
+import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion';
+import { isDefined } from 'twenty-shared/utils';
+
+export const useTidyUp = () => {
+ const [workflowDiagram, setWorkflowDiagram] = useRecoilComponentState(
+ workflowDiagramComponentState,
+ );
+
+ const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion();
+ const { getUpdatableWorkflowVersion } =
+ useGetUpdatableWorkflowVersionOrThrow();
+
+ const tidyUp = async () => {
+ if (!isDefined(workflowDiagram)) {
+ return;
+ }
+
+ const workflowVersionId = await getUpdatableWorkflowVersion();
+
+ const tidiedUpDiagram = await tidyUpWorkflowVersion(
+ workflowVersionId,
+ workflowDiagram,
+ );
+
+ if (isDefined(tidiedUpDiagram)) {
+ setWorkflowDiagram(tidiedUpDiagram);
+ }
+ };
+
+ return { tidyUp };
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts
index 8bd2d8570c2..cdc072301ab 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts
@@ -1,5 +1,5 @@
-import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
import { type WorkflowVersion } from '@/workflow/types/Workflow';
+import { type WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { useMutation } from '@apollo/client';
import { isDefined } from 'twenty-shared/utils';
import {
@@ -15,16 +15,10 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
-import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
-import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
import { getOrganizedDiagram } from '@/workflow/workflow-diagram/utils/getOrganizedDiagram';
import { UPDATE_WORKFLOW_VERSION_POSITIONS } from '@/workflow/workflow-version/graphql/mutations/updateWorkflowVersionPositions';
export const useTidyUpWorkflowVersion = () => {
- const [workflowDiagram, setWorkflowDiagram] = useRecoilComponentState(
- workflowDiagramComponentState,
- );
-
const apolloCoreClient = useApolloCoreClient();
const { objectMetadataItems } = useObjectMetadataItems();
@@ -42,14 +36,10 @@ export const useTidyUpWorkflowVersion = () => {
UpdateWorkflowVersionPositionsMutationVariables
>(UPDATE_WORKFLOW_VERSION_POSITIONS, { client: apolloCoreClient });
- const { getUpdatableWorkflowVersion } =
- useGetUpdatableWorkflowVersionOrThrow();
-
const updateWorkflowVersionPosition = async (
+ workflowVersionId: string,
positions: { id: string; position: { x: number; y: number } }[],
) => {
- const workflowVersionId = await getUpdatableWorkflowVersion();
-
await mutate({ variables: { input: { workflowVersionId, positions } } });
const cachedRecord = getRecordFromCache(workflowVersionId);
@@ -100,7 +90,10 @@ export const useTidyUpWorkflowVersion = () => {
});
};
- const tidyUpWorkflowVersion = async () => {
+ const tidyUpWorkflowVersion = async (
+ workflowVersionId: string,
+ workflowDiagram: WorkflowDiagram,
+ ) => {
if (!isDefined(workflowDiagram)) {
return;
}
@@ -112,9 +105,9 @@ export const useTidyUpWorkflowVersion = () => {
position: node.position,
}));
- await updateWorkflowVersionPosition(positions);
+ await updateWorkflowVersionPosition(workflowVersionId, positions);
- setWorkflowDiagram(tidiedUpDiagram);
+ return tidiedUpDiagram;
};
return { tidyUpWorkflowVersion };