Create workflow version show page (#7466)

In this PR:

- Refactored components to clarify their behavior. For example, I
renamed the `Workflow` component to `WorkflowVisualizer`. This moved
forward the issue #7010.
- Create two variants of several workflow-related components: one
version for editing and another for viewing. For instance, there is
`WorkflowDiagramCanvasEditable.tsx` and
`WorkflowDiagramCanvasReadonly.tsx`
- Implement the show page for workflow versions. On this page, we
display a readonly workflow visualizer. Users can click on nodes and it
will expand the right drawer.
- I added buttons in the header of the RecordShowPage for workflow
versions: users can activate, deactivate or use the currently viewed
version as the next draft.

**There are many cache desynchronisation and I'll fix them really
soon.**

## Demo

(Turn sound on)


https://github.com/user-attachments/assets/97fafa48-8902-4dab-8b39-f40848bf041e
This commit is contained in:
Baptiste Devessier
2024-10-08 18:16:36 +02:00
committed by GitHub
parent d5bd320b8d
commit 1863636003
39 changed files with 856 additions and 310 deletions

View File

@ -2,11 +2,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { WorkflowVersion } from '@/workflow/types/Workflow';
export const useCreateNewWorkflowVersion = ({
workflowId,
}: {
workflowId: string;
}) => {
export const useCreateNewWorkflowVersion = () => {
const { createOneRecord: createOneWorkflowVersion } =
useCreateOneRecord<WorkflowVersion>({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
@ -15,13 +11,10 @@ export const useCreateNewWorkflowVersion = ({
const createNewWorkflowVersion = (
workflowVersionData: Pick<
WorkflowVersion,
'name' | 'status' | 'trigger' | 'steps'
'workflowId' | 'name' | 'status' | 'trigger' | 'steps'
>,
) => {
return createOneWorkflowVersion({
workflowId,
...workflowVersionData,
});
return createOneWorkflowVersion(workflowVersionData);
};
return {

View File

@ -32,9 +32,7 @@ export const useCreateStep = ({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
workflowId: workflow.id,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion();
const insertNodeAndSave = async ({
parentNodeId,
@ -66,6 +64,7 @@ export const useCreateStep = ({
}
await createNewWorkflowVersion({
workflowId: workflow.id,
name: `v${workflow.versions.length + 1}`,
status: 'DRAFT',
trigger: workflow.currentVersion.trigger,

View File

@ -20,9 +20,7 @@ export const useDeleteOneStep = ({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
workflowId: workflow.id,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion();
const deleteOneStep = async () => {
if (workflow.currentVersion.status !== 'DRAFT') {
@ -30,6 +28,7 @@ export const useDeleteOneStep = ({
if (stepId === TRIGGER_STEP_ID) {
await createNewWorkflowVersion({
workflowId: workflow.id,
name: newVersionName,
status: 'DRAFT',
trigger: null,
@ -37,6 +36,7 @@ export const useDeleteOneStep = ({
});
} else {
await createNewWorkflowVersion({
workflowId: workflow.id,
name: newVersionName,
status: 'DRAFT',
trigger: workflow.currentVersion.trigger,

View File

@ -0,0 +1,36 @@
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/states/workflowDiagramTriggerNodeSelectionState';
import {
WorkflowDiagramEdge,
WorkflowDiagramNode,
} from '@/workflow/types/WorkflowDiagram';
import { useReactFlow } from '@xyflow/react';
import { useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-ui';
export const useTriggerNodeSelection = () => {
const reactflow = useReactFlow<WorkflowDiagramNode, WorkflowDiagramEdge>();
const workflowDiagramTriggerNodeSelection = useRecoilValue(
workflowDiagramTriggerNodeSelectionState,
);
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilState(
workflowDiagramTriggerNodeSelectionState,
);
useEffect(() => {
if (!isDefined(workflowDiagramTriggerNodeSelection)) {
return;
}
reactflow.updateNode(workflowDiagramTriggerNodeSelection, {
selected: true,
});
setWorkflowDiagramTriggerNodeSelection(undefined);
}, [
reactflow,
setWorkflowDiagramTriggerNodeSelection,
workflowDiagramTriggerNodeSelection,
]);
};

View File

@ -21,9 +21,7 @@ export const useUpdateWorkflowVersionStep = ({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
workflowId: workflow.id,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion();
const updateStep = async <T extends WorkflowStep>(updatedStep: T) => {
if (!isDefined(workflow.currentVersion)) {
@ -48,6 +46,7 @@ export const useUpdateWorkflowVersionStep = ({
}
await createNewWorkflowVersion({
workflowId: workflow.id,
name: `v${workflow.versions.length + 1}`,
status: 'DRAFT',
trigger: workflow.currentVersion.trigger,

View File

@ -18,9 +18,7 @@ export const useUpdateWorkflowVersionTrigger = ({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
workflowId: workflow.id,
});
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion();
const updateTrigger = async (updatedTrigger: WorkflowTrigger) => {
if (!isDefined(workflow.currentVersion)) {
@ -39,6 +37,7 @@ export const useUpdateWorkflowVersionTrigger = ({
}
await createNewWorkflowVersion({
workflowId: workflow.id,
name: `v${workflow.versions.length + 1}`,
status: 'DRAFT',
trigger: updatedTrigger,

View File

@ -0,0 +1,36 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { Workflow, WorkflowVersion } from '@/workflow/types/Workflow';
export const useWorkflowVersion = (workflowVersionId: string) => {
const { record: workflowVersion } = useFindOneRecord<
WorkflowVersion & {
workflow: Omit<Workflow, 'versions'> & {
versions: Array<{ __typename: string }>;
};
}
>({
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
objectRecordId: workflowVersionId,
recordGqlFields: {
id: true,
name: true,
createdAt: true,
updatedAt: true,
workflowId: true,
trigger: true,
steps: true,
status: true,
workflow: {
id: true,
name: true,
statuses: true,
versions: {
totalCount: true,
},
},
},
});
return workflowVersion;
};