Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c0d7e98

Browse files
chesterkmralonp99
andauthoredAug 3, 2024··
feat: added error handling for xstate visualizer (#2601)
Co-authored-by: Alon Peretz <[email protected]>
1 parent 971a3b3 commit c0d7e98

File tree

7 files changed

+88
-45
lines changed

7 files changed

+88
-45
lines changed
 

‎apps/workflows-dashboard/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"react": "^18.2.0",
4646
"react-custom-scrollbars": "^4.2.1",
4747
"react-dom": "^18.2.0",
48+
"react-error-boundary": "^4.0.13",
4849
"react-hook-form": "^7.43.9",
4950
"react-json-view": "^1.21.3",
5051
"react-router-dom": "^6.11.2",

‎apps/workflows-dashboard/src/components/organisms/XstateVisualizer/XstateVisualizer.tsx

+38-30
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,53 @@ import { deserializeStateDefinition } from '@/components/organisms/XstateVisuali
22
import { inspect } from '@xstate/inspect';
33
import { useInterpret, useMachine } from '@xstate/react';
44
import { memo, useLayoutEffect, useMemo, useRef } from 'react';
5+
import { withErrorBoundary } from 'react-error-boundary';
56
import { createMachine } from 'xstate';
67

78
interface Props {
89
stateDefinition: Record<string, any>;
910
state?: string;
1011
}
1112

12-
export const XstateVisualizer = memo(({ stateDefinition, state }: Props) => {
13-
const _machine = useMemo(
14-
() =>
15-
createMachine(
16-
deserializeStateDefinition({
17-
...stateDefinition,
18-
initial: state || stateDefinition.initial,
19-
}),
20-
),
21-
[stateDefinition, state],
22-
);
23-
const [stateMachine] = useMachine(_machine);
13+
export const XstateVisualizer = memo(
14+
withErrorBoundary(
15+
({ stateDefinition, state }: Props) => {
16+
const _machine = useMemo(
17+
() =>
18+
createMachine(
19+
deserializeStateDefinition({
20+
...stateDefinition,
21+
initial: state || stateDefinition.initial,
22+
}),
23+
),
24+
[stateDefinition, state],
25+
);
26+
const [stateMachine] = useMachine(_machine);
2427

25-
useInterpret(_machine, { devTools: true });
28+
useInterpret(_machine, { devTools: true });
2629

27-
const iframeRef = useRef<HTMLIFrameElement | null>(null);
30+
const iframeRef = useRef<HTMLIFrameElement | null>(null);
2831

29-
useLayoutEffect(() => {
30-
if (!iframeRef.current) return;
32+
useLayoutEffect(() => {
33+
if (!iframeRef.current) return;
3134

32-
inspect({ iframe: iframeRef.current });
33-
}, [iframeRef, state, stateMachine.value]);
35+
inspect({ iframe: iframeRef.current });
36+
}, [iframeRef, state, stateMachine.value]);
3437

35-
return (
36-
<div className="h-full w-full">
37-
<iframe
38-
ref={iframeRef}
39-
data-xstate
40-
style={{ width: 'calc(100% + clamp(40rem, 40rem + 0px, 100%))' }}
41-
// width="100%"
42-
height="100%"
43-
/>
44-
</div>
45-
);
46-
});
38+
return (
39+
<div className="h-full w-full">
40+
<iframe
41+
ref={iframeRef}
42+
data-xstate
43+
style={{ width: 'calc(100% + clamp(40rem, 40rem + 0px, 100%))' }}
44+
// width="100%"
45+
height="100%"
46+
/>
47+
</div>
48+
);
49+
},
50+
{
51+
fallbackRender: ({ error }) => <span>{error.message}</span>,
52+
},
53+
),
54+
);

‎apps/workflows-dashboard/src/pages/WorkflowDefinition/WorkflowDefinition.tsx

+2-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { DashboardLayout } from '@/components/layouts/DashboardLayout';
55
import { XstateVisualizer } from '@/components/organisms/XstateVisualizer';
66
import { IWorkflow } from '@/domains/workflows/api/workflow';
77
import { EditorCard } from '@/pages/WorkflowDefinition/components/EditorCard';
8+
import { WorkflowDefinitionEditor } from '@/pages/WorkflowDefinition/components/WorkflowDefinitionEditor/WorkflowDefinitionEditor';
89
import { WorkflowDefinitionSummaryCard } from '@/pages/WorkflowDefinition/components/WorkflowDefinitionSummaryCard';
910
import { useUpgradeWorkflowDefinitionVersionMutation } from '@/pages/WorkflowDefinition/hooks/useUpgradeWorkflowDefinitionVersionMutation';
1011
import { useWorkflowDefinitionEdit } from '@/pages/WorkflowDefinition/hooks/useWorkflowDefinitionEdit';
@@ -83,12 +84,7 @@ export const WorkflowDefinition = () => {
8384
</div>
8485
<div className="flex flex-row gap-2">
8586
<div className="w-1/2">
86-
<EditorCard
87-
title="Workflow Definition"
88-
value={workflowDefinitionValue || {}}
89-
onSave={workflowDefinitionValue ? handleWorkflowDefinitionSave : undefined}
90-
onUpgrade={() => upgradeWorkflowDefinitionVersion({ workflowDefinitionId: data.id! })}
91-
/>
87+
<WorkflowDefinitionEditor workflowDefinition={data} />
9288
</div>
9389
<div className="w-1/2">
9490
<EditorCard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { IWorkflowDefinition } from '@/domains/workflow-definitions';
2+
import { EditorCard } from '@/pages/WorkflowDefinition/components/EditorCard';
3+
import { useUpgradeWorkflowDefinitionVersionMutation } from '@/pages/WorkflowDefinition/hooks/useUpgradeWorkflowDefinitionVersionMutation';
4+
import { useWorkflowDefinitionEdit } from '@/pages/WorkflowDefinition/hooks/useWorkflowDefinitionEdit';
5+
import { FunctionComponent } from 'react';
6+
7+
interface WorkflowDefinitionEditorProps {
8+
workflowDefinition: IWorkflowDefinition;
9+
}
10+
11+
export const WorkflowDefinitionEditor: FunctionComponent<WorkflowDefinitionEditorProps> = ({
12+
workflowDefinition,
13+
}) => {
14+
const { workflowDefinitionValue, handleWorkflowDefinitionSave } =
15+
useWorkflowDefinitionEdit(workflowDefinition);
16+
const { mutate: upgradeWorkflowDefinitionVersion } =
17+
useUpgradeWorkflowDefinitionVersionMutation();
18+
19+
return (
20+
<EditorCard
21+
title="Workflow Definition"
22+
value={workflowDefinitionValue || {}}
23+
onSave={
24+
workflowDefinitionValue
25+
? definition => handleWorkflowDefinitionSave(definition as any)
26+
: undefined
27+
}
28+
onUpgrade={() =>
29+
upgradeWorkflowDefinitionVersion({ workflowDefinitionId: workflowDefinition.id })
30+
}
31+
/>
32+
);
33+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './WorkflowDefinitionEditor';

‎apps/workflows-dashboard/src/pages/WorkflowDefinition/hooks/useWorkflowDefinitionEdit/useWorkflowDefinitionEdit.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@ export const useWorkflowDefinitionEdit = (workflowDefinition: IWorkflowDefinitio
66
const [workflowDefinitionValue, setWorkflowDefinitionValue] = useState(
77
workflowDefinition?.definition,
88
);
9+
const [validationError, setValidationError] = useState<string | null>(null);
910
const { mutate, isLoading } = useWorkflowDefinitionUpdateMutation();
1011

1112
useEffect(() => {
1213
setWorkflowDefinitionValue(workflowDefinition?.definition);
1314
}, [workflowDefinition]);
1415

1516
const handleWorkflowDefinitionSave = useCallback(
16-
(value: object) => {
17+
(definition: object) => {
1718
if (!workflowDefinition) return;
1819

19-
setWorkflowDefinitionValue(value);
20+
setWorkflowDefinitionValue(definition);
2021

2122
mutate({
2223
workflowDefinitionId: workflowDefinition.id!,
23-
definition: value,
24+
definition: definition,
2425
});
2526
},
2627
[workflowDefinition],

‎pnpm-lock.yaml

+9-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.