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 };