Skip to content

Commit

Permalink
feat: added error handling for xstate visualizer (#2601)
Browse files Browse the repository at this point in the history
Co-authored-by: Alon Peretz <8467965+alonp99@users.noreply.github.com>
  • Loading branch information
chesterkmr and alonp99 committed Aug 3, 2024
1 parent 971a3b3 commit c0d7e98
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 45 deletions.
1 change: 1 addition & 0 deletions apps/workflows-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"react": "^18.2.0",
"react-custom-scrollbars": "^4.2.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.43.9",
"react-json-view": "^1.21.3",
"react-router-dom": "^6.11.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,53 @@ import { deserializeStateDefinition } from '@/components/organisms/XstateVisuali
import { inspect } from '@xstate/inspect';
import { useInterpret, useMachine } from '@xstate/react';
import { memo, useLayoutEffect, useMemo, useRef } from 'react';
import { withErrorBoundary } from 'react-error-boundary';
import { createMachine } from 'xstate';

interface Props {
stateDefinition: Record<string, any>;
state?: string;
}

export const XstateVisualizer = memo(({ stateDefinition, state }: Props) => {
const _machine = useMemo(
() =>
createMachine(
deserializeStateDefinition({
...stateDefinition,
initial: state || stateDefinition.initial,
}),
),
[stateDefinition, state],
);
const [stateMachine] = useMachine(_machine);
export const XstateVisualizer = memo(
withErrorBoundary(
({ stateDefinition, state }: Props) => {
const _machine = useMemo(
() =>
createMachine(
deserializeStateDefinition({
...stateDefinition,
initial: state || stateDefinition.initial,
}),
),
[stateDefinition, state],
);
const [stateMachine] = useMachine(_machine);

useInterpret(_machine, { devTools: true });
useInterpret(_machine, { devTools: true });

const iframeRef = useRef<HTMLIFrameElement | null>(null);
const iframeRef = useRef<HTMLIFrameElement | null>(null);

useLayoutEffect(() => {
if (!iframeRef.current) return;
useLayoutEffect(() => {
if (!iframeRef.current) return;

inspect({ iframe: iframeRef.current });
}, [iframeRef, state, stateMachine.value]);
inspect({ iframe: iframeRef.current });
}, [iframeRef, state, stateMachine.value]);

return (
<div className="h-full w-full">
<iframe
ref={iframeRef}
data-xstate
style={{ width: 'calc(100% + clamp(40rem, 40rem + 0px, 100%))' }}
// width="100%"
height="100%"
/>
</div>
);
});
return (
<div className="h-full w-full">
<iframe
ref={iframeRef}
data-xstate
style={{ width: 'calc(100% + clamp(40rem, 40rem + 0px, 100%))' }}
// width="100%"
height="100%"
/>
</div>
);
},
{
fallbackRender: ({ error }) => <span>{error.message}</span>,
},
),
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DashboardLayout } from '@/components/layouts/DashboardLayout';
import { XstateVisualizer } from '@/components/organisms/XstateVisualizer';
import { IWorkflow } from '@/domains/workflows/api/workflow';
import { EditorCard } from '@/pages/WorkflowDefinition/components/EditorCard';
import { WorkflowDefinitionEditor } from '@/pages/WorkflowDefinition/components/WorkflowDefinitionEditor/WorkflowDefinitionEditor';
import { WorkflowDefinitionSummaryCard } from '@/pages/WorkflowDefinition/components/WorkflowDefinitionSummaryCard';
import { useUpgradeWorkflowDefinitionVersionMutation } from '@/pages/WorkflowDefinition/hooks/useUpgradeWorkflowDefinitionVersionMutation';
import { useWorkflowDefinitionEdit } from '@/pages/WorkflowDefinition/hooks/useWorkflowDefinitionEdit';
Expand Down Expand Up @@ -83,12 +84,7 @@ export const WorkflowDefinition = () => {
</div>
<div className="flex flex-row gap-2">
<div className="w-1/2">
<EditorCard
title="Workflow Definition"
value={workflowDefinitionValue || {}}
onSave={workflowDefinitionValue ? handleWorkflowDefinitionSave : undefined}
onUpgrade={() => upgradeWorkflowDefinitionVersion({ workflowDefinitionId: data.id! })}
/>
<WorkflowDefinitionEditor workflowDefinition={data} />
</div>
<div className="w-1/2">
<EditorCard
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { IWorkflowDefinition } from '@/domains/workflow-definitions';
import { EditorCard } from '@/pages/WorkflowDefinition/components/EditorCard';
import { useUpgradeWorkflowDefinitionVersionMutation } from '@/pages/WorkflowDefinition/hooks/useUpgradeWorkflowDefinitionVersionMutation';
import { useWorkflowDefinitionEdit } from '@/pages/WorkflowDefinition/hooks/useWorkflowDefinitionEdit';
import { FunctionComponent } from 'react';

interface WorkflowDefinitionEditorProps {
workflowDefinition: IWorkflowDefinition;
}

export const WorkflowDefinitionEditor: FunctionComponent<WorkflowDefinitionEditorProps> = ({
workflowDefinition,
}) => {
const { workflowDefinitionValue, handleWorkflowDefinitionSave } =
useWorkflowDefinitionEdit(workflowDefinition);
const { mutate: upgradeWorkflowDefinitionVersion } =
useUpgradeWorkflowDefinitionVersionMutation();

return (
<EditorCard
title="Workflow Definition"
value={workflowDefinitionValue || {}}
onSave={
workflowDefinitionValue
? definition => handleWorkflowDefinitionSave(definition as any)
: undefined
}
onUpgrade={() =>
upgradeWorkflowDefinitionVersion({ workflowDefinitionId: workflowDefinition.id })
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './WorkflowDefinitionEditor';
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ export const useWorkflowDefinitionEdit = (workflowDefinition: IWorkflowDefinitio
const [workflowDefinitionValue, setWorkflowDefinitionValue] = useState(
workflowDefinition?.definition,
);
const [validationError, setValidationError] = useState<string | null>(null);
const { mutate, isLoading } = useWorkflowDefinitionUpdateMutation();

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

const handleWorkflowDefinitionSave = useCallback(
(value: object) => {
(definition: object) => {
if (!workflowDefinition) return;

setWorkflowDefinitionValue(value);
setWorkflowDefinitionValue(definition);

mutate({
workflowDefinitionId: workflowDefinition.id!,
definition: value,
definition: definition,
});
},
[workflowDefinition],
Expand Down
15 changes: 9 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c0d7e98

Please sign in to comment.