Skip to content

Commit

Permalink
feat: move save workflow logic into a provider
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgrittner committed Nov 2, 2024
1 parent f6995c9 commit 92b9bb6
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 178 deletions.
104 changes: 4 additions & 100 deletions web/src/components/save-workflow-button/save-workflow-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,116 +2,20 @@

import { Button } from "@radix-ui/themes";
import { DiscIcon } from "@radix-ui/react-icons";
import { useSaveWorkflowApi } from "@/hooks/use-save-workflow-api";
import { useWorkflowStore } from "@/stores/workflow-store";
import { useEffect } from "react";
import { AxiosError } from "axios";
import { useEditorActionStore } from "@/stores/editor-action-store";
import { EditorWorkflowNodeType } from "@/types/react-flow";
import { useToast } from "@/providers/toast";
import {
isValidWorkflowName,
WORKFLOW_NAME_VALIDATION_ERROR_MESSAGE,
} from "@/lib/workflow-validation";
import useSaveWorkflow from "@/providers/save-workflow";

export default function SaveWorkflowButton() {
const { getWorkflow, updateWebhookIdAndSecret } = useWorkflowStore();
const { actionsIndex } = useEditorActionStore();
const saveWorkflow = useSaveWorkflowApi();
const { errorToast, infoToast } = useToast();

useEffect(() => {
if (saveWorkflow.isSuccess) {
infoToast("Workflow saved.");
const { webhookId, webhookSecret } = saveWorkflow.data;
if (webhookId && webhookSecret) {
updateWebhookIdAndSecret(webhookId, webhookSecret);
}
saveWorkflow.reset();
}
if (saveWorkflow.isError) {
if (
saveWorkflow.error instanceof AxiosError &&
(
(saveWorkflow.error as AxiosError).response?.data as any
).detail.startsWith("A workflow with the name")
) {
errorToast(
((saveWorkflow.error as AxiosError).response?.data as any)
.detail,
);
} else {
errorToast("Failed to save workflow. Please try again.");
}
saveWorkflow.reset();
}
}, [saveWorkflow, updateWebhookIdAndSecret]);

const handleSaveWorkflow = () => {
const workflow = getWorkflow();
if (Object.keys(actionsIndex).length === 0) {
errorToast("Editor actions must be loaded to save the workflow.");
return;
}
if (workflow.workflowName.length === 0) {
errorToast(
"Workflow name must not be empty. Go to settings to set one.",
);
return;
}
if (!isValidWorkflowName(workflow.workflowName)) {
errorToast(WORKFLOW_NAME_VALIDATION_ERROR_MESSAGE);
return;
}

if (workflow.controls) {
workflow.controls = workflow.controls.filter(
(control) => control.trim() !== "",
);
}

// Make sure that we only save args which are present in the current
// action definition. If an action is updated and an argument is
// removed, we want to clean it up here.
const nodes = workflow.nodes.map((node) => {
if (node.type === EditorWorkflowNodeType.ACTION) {
const argsFilter = new Set(
actionsIndex[node.actionType].arguments.map(
(arg) => arg.argName,
),
);
const args = Object.keys(node.args)
.filter((argName) => argsFilter.has(argName))
.reduce(
(acc, argName) => {
acc[argName] = node.args[argName];
return acc;
},
{} as Record<string, string>,
);
return {
...node,
args,
};
}
return node;
});

saveWorkflow.mutate({
...workflow,
nodes,
});
};
const { saveWorkflow, isPending } = useSaveWorkflow();

return (
<Button
variant="solid"
size="2"
onClick={handleSaveWorkflow}
onClick={saveWorkflow}
style={{
cursor: "pointer",
}}
loading={saveWorkflow.isPending}
loading={isPending}
>
<DiscIcon />
Save
Expand Down
159 changes: 81 additions & 78 deletions web/src/components/workflow-editor/workflow-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import RunWorkflowButton from "../run-workflow/run-workflow-button";
import { useToast } from "@/providers/toast";
import { AxiosError } from "axios";
import { useRouter } from "next/navigation";
import { SaveWorkflowProvider } from "@/providers/save-workflow";

type View = "workflowBuilder" | "runHistory";

Expand Down Expand Up @@ -102,83 +103,85 @@ export default function WorkflowEditor({
}

return (
<Grid rows="50px 1fr" width="auto" height="100%" align="center">
<Box width="100%" height="100%">
<Grid
pb="2"
pt="2"
pl="4"
pr="4"
columns="1fr 200px 1fr"
className="border-b-2 border-gray-200"
align="center"
height="56px"
width="calc(100% - 56px)"
style={{
position: "fixed",
backgroundColor: "white",
zIndex: 100,
}}
>
<Flex justify="start" align="center" gap="4">
<Link href="/">
<BackIcon />
</Link>

<Text size="4" weight="medium">
Workflow Editor
</Text>
</Flex>

<Flex justify="center" align="center">
<Tabs.Root
value={view}
onValueChange={(page) => setView(page as View)}
>
<Tabs.List size="1">
<Tabs.Trigger
value="workflowBuilder"
style={{ cursor: "pointer" }}
>
Workflow Builder
</Tabs.Trigger>
<Tabs.Trigger
value="runHistory"
style={{ cursor: "pointer" }}
>
Run History
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
</Flex>

<Flex justify="end" align="center" gap="3">
<RunWorkflowButton />

<SaveWorkflowButton />

<WorkflowSettingsButton />

<Box width="105px">
<PublishWorkflowToggleEditor />
</Box>
</Flex>
</Grid>
</Box>

<WorkflowEditorActionEditSidebar apiBaseUrl={apiBaseUrl} />

<Box height="100%" width="100%">
{view === "workflowBuilder" && (
<>
<WorkflowEditorBuilder />
<WorkflowEditorActionsSidebar />
</>
)}
{view === "runHistory" && (
<WorkflowRunHistory workflowId={workflowId} />
)}
</Box>
</Grid>
<SaveWorkflowProvider>
<Grid rows="50px 1fr" width="auto" height="100%" align="center">
<Box width="100%" height="100%">
<Grid
pb="2"
pt="2"
pl="4"
pr="4"
columns="1fr 200px 1fr"
className="border-b-2 border-gray-200"
align="center"
height="56px"
width="calc(100% - 56px)"
style={{
position: "fixed",
backgroundColor: "white",
zIndex: 100,
}}
>
<Flex justify="start" align="center" gap="4">
<Link href="/">
<BackIcon />
</Link>

<Text size="4" weight="medium">
Workflow Editor
</Text>
</Flex>

<Flex justify="center" align="center">
<Tabs.Root
value={view}
onValueChange={(page) => setView(page as View)}
>
<Tabs.List size="1">
<Tabs.Trigger
value="workflowBuilder"
style={{ cursor: "pointer" }}
>
Workflow Builder
</Tabs.Trigger>
<Tabs.Trigger
value="runHistory"
style={{ cursor: "pointer" }}
>
Run History
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
</Flex>

<Flex justify="end" align="center" gap="3">
<RunWorkflowButton />

<SaveWorkflowButton />

<WorkflowSettingsButton />

<Box width="105px">
<PublishWorkflowToggleEditor />
</Box>
</Flex>
</Grid>
</Box>

<WorkflowEditorActionEditSidebar apiBaseUrl={apiBaseUrl} />

<Box height="100%" width="100%">
{view === "workflowBuilder" && (
<>
<WorkflowEditorBuilder />
<WorkflowEditorActionsSidebar />
</>
)}
{view === "runHistory" && (
<WorkflowRunHistory workflowId={workflowId} />
)}
</Box>
</Grid>
</SaveWorkflowProvider>
);
}
Loading

0 comments on commit 92b9bb6

Please sign in to comment.