Display workflow visualizer on show page (#6894)
- Removed the route I previously used to visualize workflows - Created another tab in the `<ShowPageRightContainer />` component in which we display the visualizer Questions: - Should I use a feature flag to hide the feature? Closes #6858
This commit is contained in:
committed by
GitHub
parent
78d8df6a68
commit
cddc92c00f
@ -50,7 +50,6 @@ import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace';
|
|||||||
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
||||||
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
||||||
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
||||||
import { WorkflowShowPage } from '~/pages/workflows/WorkflowShowPage';
|
|
||||||
import { SettingsRoutes } from '~/SettingsRoutes';
|
import { SettingsRoutes } from '~/SettingsRoutes';
|
||||||
import { getPageTitleFromPath } from '~/utils/title-utils';
|
import { getPageTitleFromPath } from '~/utils/title-utils';
|
||||||
|
|
||||||
@ -103,7 +102,6 @@ const createRouter = (
|
|||||||
isBillingEnabled?: boolean,
|
isBillingEnabled?: boolean,
|
||||||
isCRMMigrationEnabled?: boolean,
|
isCRMMigrationEnabled?: boolean,
|
||||||
isServerlessFunctionSettingsEnabled?: boolean,
|
isServerlessFunctionSettingsEnabled?: boolean,
|
||||||
isWorkflowEnabled?: boolean,
|
|
||||||
) =>
|
) =>
|
||||||
createBrowserRouter(
|
createBrowserRouter(
|
||||||
createRoutesFromElements(
|
createRoutesFromElements(
|
||||||
@ -131,12 +129,6 @@ const createRouter = (
|
|||||||
<Route path={AppPath.Impersonate} element={<ImpersonateEffect />} />
|
<Route path={AppPath.Impersonate} element={<ImpersonateEffect />} />
|
||||||
<Route path={AppPath.RecordIndexPage} element={<RecordIndexPage />} />
|
<Route path={AppPath.RecordIndexPage} element={<RecordIndexPage />} />
|
||||||
<Route path={AppPath.RecordShowPage} element={<RecordShowPage />} />
|
<Route path={AppPath.RecordShowPage} element={<RecordShowPage />} />
|
||||||
{isWorkflowEnabled === true ? (
|
|
||||||
<Route
|
|
||||||
path={AppPath.WorkflowShowPage}
|
|
||||||
element={<WorkflowShowPage />}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<Route
|
<Route
|
||||||
path={AppPath.SettingsCatchAll}
|
path={AppPath.SettingsCatchAll}
|
||||||
element={
|
element={
|
||||||
@ -165,7 +157,6 @@ export const App = () => {
|
|||||||
const isServerlessFunctionSettingsEnabled = useIsFeatureEnabled(
|
const isServerlessFunctionSettingsEnabled = useIsFeatureEnabled(
|
||||||
'IS_FUNCTION_SETTINGS_ENABLED',
|
'IS_FUNCTION_SETTINGS_ENABLED',
|
||||||
);
|
);
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
|
||||||
|
|
||||||
const isBillingPageEnabled =
|
const isBillingPageEnabled =
|
||||||
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
||||||
@ -176,7 +167,6 @@ export const App = () => {
|
|||||||
isBillingPageEnabled,
|
isBillingPageEnabled,
|
||||||
isCRMMigrationEnabled,
|
isCRMMigrationEnabled,
|
||||||
isServerlessFunctionSettingsEnabled,
|
isServerlessFunctionSettingsEnabled,
|
||||||
isWorkflowEnabled,
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -244,17 +244,6 @@ const testCases = [
|
|||||||
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
|
|||||||
@ -26,8 +26,6 @@ export enum AppPath {
|
|||||||
Developers = `developers`,
|
Developers = `developers`,
|
||||||
DevelopersCatchAll = `/${Developers}/*`,
|
DevelopersCatchAll = `/${Developers}/*`,
|
||||||
|
|
||||||
WorkflowShowPage = `/workflow/:workflowId`,
|
|
||||||
|
|
||||||
// Impersonate
|
// Impersonate
|
||||||
Impersonate = '/impersonate/:userId',
|
Impersonate = '/impersonate/:userId',
|
||||||
|
|
||||||
|
|||||||
@ -254,17 +254,6 @@ const testCases = [
|
|||||||
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
|
||||||
{ loc: AppPath.WorkflowShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
IconMail,
|
IconMail,
|
||||||
IconNotes,
|
IconNotes,
|
||||||
IconPaperclip,
|
IconPaperclip,
|
||||||
|
IconSettings,
|
||||||
IconTimelineEvent,
|
IconTimelineEvent,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
@ -22,6 +23,8 @@ import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/Show
|
|||||||
import { TabList } from '@/ui/layout/tab/components/TabList';
|
import { TabList } from '@/ui/layout/tab/components/TabList';
|
||||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
|
import { Workflow } from '@/workflow/components/Workflow';
|
||||||
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
|
||||||
const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -95,6 +98,12 @@ export const ShowPageRightContainer = ({
|
|||||||
CoreObjectNameSingular.Person,
|
CoreObjectNameSingular.Person,
|
||||||
].includes(targetObjectNameSingular);
|
].includes(targetObjectNameSingular);
|
||||||
|
|
||||||
|
const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');
|
||||||
|
const isWorkflow =
|
||||||
|
isWorkflowEnabled &&
|
||||||
|
targetableObject.targetObjectNameSingular ===
|
||||||
|
CoreObjectNameSingular.Workflow;
|
||||||
|
|
||||||
const shouldDisplayCalendarTab = isCompanyOrPerson;
|
const shouldDisplayCalendarTab = isCompanyOrPerson;
|
||||||
const shouldDisplayEmailsTab = emails && isCompanyOrPerson;
|
const shouldDisplayEmailsTab = emails && isCompanyOrPerson;
|
||||||
|
|
||||||
@ -122,7 +131,7 @@ export const ShowPageRightContainer = ({
|
|||||||
id: 'timeline',
|
id: 'timeline',
|
||||||
title: 'Timeline',
|
title: 'Timeline',
|
||||||
Icon: IconTimelineEvent,
|
Icon: IconTimelineEvent,
|
||||||
hide: !timeline || isInRightDrawer,
|
hide: !timeline || isInRightDrawer || isWorkflow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tasks',
|
id: 'tasks',
|
||||||
@ -133,7 +142,8 @@ export const ShowPageRightContainer = ({
|
|||||||
targetableObject.targetObjectNameSingular ===
|
targetableObject.targetObjectNameSingular ===
|
||||||
CoreObjectNameSingular.Note ||
|
CoreObjectNameSingular.Note ||
|
||||||
targetableObject.targetObjectNameSingular ===
|
targetableObject.targetObjectNameSingular ===
|
||||||
CoreObjectNameSingular.Task,
|
CoreObjectNameSingular.Task ||
|
||||||
|
isWorkflow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'notes',
|
id: 'notes',
|
||||||
@ -144,13 +154,14 @@ export const ShowPageRightContainer = ({
|
|||||||
targetableObject.targetObjectNameSingular ===
|
targetableObject.targetObjectNameSingular ===
|
||||||
CoreObjectNameSingular.Note ||
|
CoreObjectNameSingular.Note ||
|
||||||
targetableObject.targetObjectNameSingular ===
|
targetableObject.targetObjectNameSingular ===
|
||||||
CoreObjectNameSingular.Task,
|
CoreObjectNameSingular.Task ||
|
||||||
|
isWorkflow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'files',
|
id: 'files',
|
||||||
title: 'Files',
|
title: 'Files',
|
||||||
Icon: IconPaperclip,
|
Icon: IconPaperclip,
|
||||||
hide: !notes,
|
hide: !notes || isWorkflow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'emails',
|
id: 'emails',
|
||||||
@ -164,6 +175,12 @@ export const ShowPageRightContainer = ({
|
|||||||
Icon: IconCalendarEvent,
|
Icon: IconCalendarEvent,
|
||||||
hide: !shouldDisplayCalendarTab,
|
hide: !shouldDisplayCalendarTab,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'workflow',
|
||||||
|
title: 'Workflow',
|
||||||
|
Icon: IconSettings,
|
||||||
|
hide: !isWorkflow,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
const renderActiveTabContent = () => {
|
const renderActiveTabContent = () => {
|
||||||
switch (activeTabId) {
|
switch (activeTabId) {
|
||||||
@ -202,6 +219,8 @@ export const ShowPageRightContainer = ({
|
|||||||
return <EmailThreads targetableObject={targetableObject} />;
|
return <EmailThreads targetableObject={targetableObject} />;
|
||||||
case 'calendar':
|
case 'calendar':
|
||||||
return <Calendar targetableObject={targetableObject} />;
|
return <Calendar targetableObject={targetableObject} />;
|
||||||
|
case 'workflow':
|
||||||
|
return <Workflow targetableObject={targetableObject} />;
|
||||||
default:
|
default:
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||||
|
import { WorkflowDiagramCanvas } from '@/workflow/components/WorkflowDiagramCanvas';
|
||||||
|
import { WorkflowShowPageEffect } from '@/workflow/components/WorkflowShowPageEffect';
|
||||||
|
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import '@xyflow/react/dist/style.css';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
const StyledFlowContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
/* Below we reset the default styling of Reactflow */
|
||||||
|
.react-flow__node-input,
|
||||||
|
.react-flow__node-default,
|
||||||
|
.react-flow__node-output,
|
||||||
|
.react-flow__node-group {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
--xy-node-border-radius: none;
|
||||||
|
--xy-node-border: none;
|
||||||
|
--xy-node-background-color: none;
|
||||||
|
--xy-node-boxshadow-hover: none;
|
||||||
|
--xy-node-boxshadow-selected: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Workflow = ({
|
||||||
|
targetableObject,
|
||||||
|
}: {
|
||||||
|
targetableObject: ActivityTargetableObject;
|
||||||
|
}) => {
|
||||||
|
const workflowId = targetableObject.id;
|
||||||
|
|
||||||
|
const workflowDiagram = useRecoilValue(workflowDiagramState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<WorkflowShowPageEffect workflowId={workflowId} />
|
||||||
|
|
||||||
|
<StyledFlowContainer>
|
||||||
|
{workflowDiagram === undefined ? null : (
|
||||||
|
<WorkflowDiagramCanvas diagram={workflowDiagram} />
|
||||||
|
)}
|
||||||
|
</StyledFlowContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,64 +0,0 @@
|
|||||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
|
||||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
|
||||||
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
|
||||||
import { WorkflowDiagramCanvas } from '@/workflow/components/WorkflowDiagramCanvas';
|
|
||||||
import { WorkflowShowPageEffect } from '@/workflow/components/WorkflowShowPageEffect';
|
|
||||||
import { WorkflowShowPageHeader } from '@/workflow/components/WorkflowShowPageHeader';
|
|
||||||
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import '@xyflow/react/dist/style.css';
|
|
||||||
import { useParams } from 'react-router-dom';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { IconSettingsAutomation } from 'twenty-ui';
|
|
||||||
|
|
||||||
const StyledFlowContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
/* Below we reset the default styling of Reactflow */
|
|
||||||
.react-flow__node-input,
|
|
||||||
.react-flow__node-default,
|
|
||||||
.react-flow__node-output,
|
|
||||||
.react-flow__node-group {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
--xy-node-border-radius: none;
|
|
||||||
--xy-node-border: none;
|
|
||||||
--xy-node-background-color: none;
|
|
||||||
--xy-node-boxshadow-hover: none;
|
|
||||||
--xy-node-boxshadow-selected: none;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const WorkflowShowPage = () => {
|
|
||||||
const parameters = useParams<{
|
|
||||||
workflowId: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const workflowName = 'Test Workflow';
|
|
||||||
|
|
||||||
const workflowDiagram = useRecoilValue(workflowDiagramState);
|
|
||||||
|
|
||||||
if (parameters.workflowId === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer>
|
|
||||||
<WorkflowShowPageEffect workflowId={parameters.workflowId} />
|
|
||||||
|
|
||||||
<PageTitle title={workflowName} />
|
|
||||||
<WorkflowShowPageHeader
|
|
||||||
workflowName={workflowName}
|
|
||||||
headerIcon={IconSettingsAutomation}
|
|
||||||
/>
|
|
||||||
<PageBody>
|
|
||||||
<StyledFlowContainer>
|
|
||||||
{workflowDiagram === undefined ? null : (
|
|
||||||
<WorkflowDiagramCanvas diagram={workflowDiagram} />
|
|
||||||
)}
|
|
||||||
</StyledFlowContainer>
|
|
||||||
</PageBody>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user