diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx index 972b2a75e3a2..a5640cfc045e 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx @@ -11,6 +11,7 @@ import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDraw import { ComponentByRightDrawerPage } from '@/ui/layout/right-drawer/types/ComponentByRightDrawerPage'; import { RightDrawerWorkflowEditStep } from '@/workflow/components/RightDrawerWorkflowEditStep'; import { RightDrawerWorkflowSelectAction } from '@/workflow/components/RightDrawerWorkflowSelectAction'; +import { RightDrawerWorkflowViewStep } from '@/workflow/components/RightDrawerWorkflowViewStep'; import { isDefined } from 'twenty-ui'; import { rightDrawerPageState } from '../states/rightDrawerPageState'; import { RightDrawerPages } from '../types/RightDrawerPages'; @@ -41,6 +42,7 @@ const RIGHT_DRAWER_PAGES_CONFIG: ComponentByRightDrawerPage = { ), [RightDrawerPages.WorkflowStepEdit]: , + [RightDrawerPages.WorkflowStepView]: , }; export const RightDrawerRouter = () => { diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts index 7fc5d9849d89..85dc75ee18b6 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts @@ -7,4 +7,5 @@ export const RIGHT_DRAWER_PAGE_ICONS = { [RightDrawerPages.Copilot]: 'IconSparkles', [RightDrawerPages.WorkflowStepEdit]: 'IconSparkles', [RightDrawerPages.WorkflowStepSelectAction]: 'IconSparkles', + [RightDrawerPages.WorkflowStepView]: 'IconSparkles', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts index 749fb10384fc..9cba79382a0a 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts @@ -7,4 +7,5 @@ export const RIGHT_DRAWER_PAGE_TITLES = { [RightDrawerPages.Copilot]: 'Copilot', [RightDrawerPages.WorkflowStepEdit]: 'Workflow', [RightDrawerPages.WorkflowStepSelectAction]: 'Workflow', + [RightDrawerPages.WorkflowStepView]: 'Workflow', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts index f016669b48a2..68e20913a4f6 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts @@ -4,5 +4,6 @@ export enum RightDrawerPages { ViewRecord = 'view-record', Copilot = 'copilot', WorkflowStepSelectAction = 'workflow-step-select-action', + WorkflowStepView = 'workflow-step-view', WorkflowStepEdit = 'workflow-step-edit', } diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx index dab0a2104e12..6088034bbc7a 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx @@ -15,7 +15,10 @@ import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/Show import { TabList } from '@/ui/layout/tab/components/TabList'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { Workflow } from '@/workflow/components/Workflow'; +import { WorkflowVersionVisualizer } from '@/workflow/components/WorkflowVersionVisualizer'; +import { WorkflowVersionVisualizerEffect } from '@/workflow/components/WorkflowVersionVisualizerEffect'; +import { WorkflowVisualizer } from '@/workflow/components/WorkflowVisualizer'; +import { WorkflowVisualizerEffect } from '@/workflow/components/WorkflowVisualizerEffect'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import styled from '@emotion/styled'; import { useState } from 'react'; @@ -130,6 +133,10 @@ export const ShowPageRightContainer = ({ isWorkflowEnabled && targetableObject.targetObjectNameSingular === CoreObjectNameSingular.Workflow; + const isWorkflowVersion = + isWorkflowEnabled && + targetableObject.targetObjectNameSingular === + CoreObjectNameSingular.WorkflowVersion; const shouldDisplayCalendarTab = isCompanyOrPerson; const shouldDisplayEmailsTab = emails && isCompanyOrPerson; @@ -162,7 +169,7 @@ export const ShowPageRightContainer = ({ id: 'timeline', title: 'Timeline', Icon: IconTimelineEvent, - hide: !timeline || isInRightDrawer || isWorkflow, + hide: !timeline || isInRightDrawer || isWorkflow || isWorkflowVersion, }, { id: 'tasks', @@ -174,7 +181,8 @@ export const ShowPageRightContainer = ({ CoreObjectNameSingular.Note || targetableObject.targetObjectNameSingular === CoreObjectNameSingular.Task || - isWorkflow, + isWorkflow || + isWorkflowVersion, }, { id: 'notes', @@ -186,13 +194,14 @@ export const ShowPageRightContainer = ({ CoreObjectNameSingular.Note || targetableObject.targetObjectNameSingular === CoreObjectNameSingular.Task || - isWorkflow, + isWorkflow || + isWorkflowVersion, }, { id: 'files', title: 'Files', Icon: IconPaperclip, - hide: !notes || isWorkflow, + hide: !notes || isWorkflow || isWorkflowVersion, }, { id: 'emails', @@ -212,6 +221,12 @@ export const ShowPageRightContainer = ({ Icon: IconSettings, hide: !isWorkflow, }, + { + id: 'workflowVersion', + title: 'Workflow Version', + Icon: IconSettings, + hide: !isWorkflowVersion, + }, ]; const renderActiveTabContent = () => { switch (activeTabId) { @@ -251,7 +266,25 @@ export const ShowPageRightContainer = ({ case 'calendar': return ; case 'workflow': - return ; + return ( + <> + + + + + ); + case 'workflowVersion': + return ( + <> + + + + + ); default: return <>; } diff --git a/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx index 4afb9839e7ea..cfea2f3b543e 100644 --- a/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx +++ b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx @@ -15,7 +15,7 @@ import { assertWorkflowWithCurrentVersionIsDefined } from '../utils/assertWorkfl export const RecordShowPageWorkflowHeader = ({ workflowId, }: { - workflowId: string | undefined; + workflowId: string; }) => { const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId); diff --git a/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx new file mode 100644 index 000000000000..d7d66c2dc878 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/RecordShowPageWorkflowVersionHeader.tsx @@ -0,0 +1,127 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { Button } from '@/ui/input/button/components/Button'; +import { useActivateWorkflowVersion } from '@/workflow/hooks/useActivateWorkflowVersion'; +import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion'; +import { useDeactivateWorkflowVersion } from '@/workflow/hooks/useDeactivateWorkflowVersion'; +import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; +import { Workflow, WorkflowVersion } from '@/workflow/types/Workflow'; +import { IconPencil, IconPlayerStop, IconPower, isDefined } from 'twenty-ui'; + +export const RecordShowPageWorkflowVersionHeader = ({ + workflowVersionId, +}: { + workflowVersionId: string; +}) => { + const workflowVersion = useWorkflowVersion(workflowVersionId); + + const workflowVersionRelatedWorkflowQuery = useFindOneRecord< + Pick + >({ + objectNameSingular: CoreObjectNameSingular.Workflow, + objectRecordId: workflowVersion?.workflowId, + recordGqlFields: { + id: true, + lastPublishedVersionId: true, + }, + skip: !isDefined(workflowVersion), + }); + + // TODO: In the future, use the workflow.status property to determine if there is a draft version + const { + records: draftWorkflowVersions, + loading: loadingDraftWorkflowVersions, + } = useFindManyRecords({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + filter: { + workflowId: { + eq: workflowVersion?.workflow.id, + }, + status: { + eq: 'DRAFT', + }, + }, + skip: !isDefined(workflowVersion), + limit: 1, + }); + + const showUseAsDraftButton = + !loadingDraftWorkflowVersions && + isDefined(workflowVersion) && + !workflowVersionRelatedWorkflowQuery.loading && + isDefined(workflowVersionRelatedWorkflowQuery.record) && + workflowVersion.status !== 'DRAFT' && + workflowVersion.id !== + workflowVersionRelatedWorkflowQuery.record.lastPublishedVersionId; + + const hasAlreadyDraftVersion = + !loadingDraftWorkflowVersions && draftWorkflowVersions.length > 0; + + const isWaitingForWorkflowVersion = !isDefined(workflowVersion); + + const { activateWorkflowVersion } = useActivateWorkflowVersion(); + const { deactivateWorkflowVersion } = useDeactivateWorkflowVersion(); + const { createNewWorkflowVersion } = useCreateNewWorkflowVersion(); + + const { updateOneRecord: updateOneWorkflowVersion } = + useUpdateOneRecord({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + }); + + return ( + <> + {showUseAsDraftButton ? ( +