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 ? (
+