From ae21a359a3eeda9a95586c878711485220d5730d Mon Sep 17 00:00:00 2001 From: Ivy Date: Mon, 27 Jan 2025 11:24:51 -0500 Subject: [PATCH] enhance: option to delete workflow triggers with workflow deletion (#1446) * enhance: option to delete workflow triggers with workflow deletion * delete-triggers in apiRoutes --- .../composed/ConfirmationDialog.tsx | 6 +- .../components/workflow/DeleteWorkflow.tsx | 92 +++++++++++++++---- ui/admin/app/lib/routers/apiRoutes.ts | 2 + .../app/lib/service/api/workflowService.ts | 9 ++ .../routes/_auth.workflow-triggers._index.tsx | 15 +-- 5 files changed, 100 insertions(+), 24 deletions(-) diff --git a/ui/admin/app/components/composed/ConfirmationDialog.tsx b/ui/admin/app/components/composed/ConfirmationDialog.tsx index e22d675f6..77c172d69 100644 --- a/ui/admin/app/components/composed/ConfirmationDialog.tsx +++ b/ui/admin/app/components/composed/ConfirmationDialog.tsx @@ -20,6 +20,7 @@ export type ConfirmationDialogProps = ComponentProps & { onConfirm: (e: React.MouseEvent) => void; onCancel?: (e: React.MouseEvent) => void; confirmProps?: Omit>, "onClick">; + cancelProps?: Omit>, "onClick">; closeOnConfirm?: boolean; }; @@ -31,6 +32,7 @@ export function ConfirmationDialog({ onConfirm, onCancel, confirmProps, + cancelProps, closeOnConfirm = true, ...dialogProps }: ConfirmationDialogProps) { @@ -49,7 +51,9 @@ export function ConfirmationDialog({ - + {closeOnConfirm ? ( diff --git a/ui/admin/app/components/workflow/DeleteWorkflow.tsx b/ui/admin/app/components/workflow/DeleteWorkflow.tsx index c740c8d7a..bd34355ea 100644 --- a/ui/admin/app/components/workflow/DeleteWorkflow.tsx +++ b/ui/admin/app/components/workflow/DeleteWorkflow.tsx @@ -11,7 +11,9 @@ import { TooltipContent, TooltipTrigger, } from "~/components/ui/tooltip"; +import { useConfirmationDialog } from "~/hooks/component-helpers/useConfirmationDialog"; import { useAsync } from "~/hooks/useAsync"; +import { useWorkflowTriggers } from "~/hooks/workflow-triggers/useWorkflowTriggers"; type DeleteWorkflowButtonProps = { id: string; @@ -22,35 +24,91 @@ export function DeleteWorkflowButton({ id, onSuccess, }: DeleteWorkflowButtonProps) { + const deleteAssociatedTriggersConfirm = useConfirmationDialog(); + const deleteWorkflowConfirm = useConfirmationDialog(); + + const { workflowTriggers } = useWorkflowTriggers({ workflowId: id }); + + const handleSuccess = () => { + mutate(WorkflowService.getWorkflows.key()); + toast.success("Workflow deleted"); + onSuccess?.(); + }; + const deleteWorkflow = useAsync(WorkflowService.deleteWorkflow, { - onSuccess: () => { - mutate(WorkflowService.getWorkflows.key()); - toast.success("Workflow deleted"); - onSuccess?.(); - }, - onError: () => toast.error("Failed to delete workflow"), + onSuccess: handleSuccess, }); + const deleteWorkflowWithTriggers = useAsync( + WorkflowService.deleteWorkflowWithTriggers, + { + onSuccess: handleSuccess, + } + ); + + const handleDelete = async (deleteTriggers: boolean) => { + if (deleteTriggers) { + await deleteWorkflowWithTriggers.execute(id); + } else { + await deleteWorkflow.execute(id); + } + }; + + const handleConfirmDeleteWorkflow = () => { + const handleConfirm = async () => { + if (workflowTriggers.length > 0) { + deleteAssociatedTriggersConfirm.interceptAsync( + async () => handleDelete(true), + { + onCancel: async () => handleDelete(false), + } + ); + } else { + await handleDelete(false); + } + }; + + deleteWorkflowConfirm.interceptAsync(handleConfirm); + }; + return ( - - deleteWorkflow.execute(id)} - confirmProps={{ variant: "destructive", children: "Delete" }} - description="This action cannot be undone." - > + <> + e.stopPropagation()} asChild> - - Delete Workflow - + Delete Workflow + + + + ); } diff --git a/ui/admin/app/lib/routers/apiRoutes.ts b/ui/admin/app/lib/routers/apiRoutes.ts index 2d6c1adc7..89600919b 100644 --- a/ui/admin/app/lib/routers/apiRoutes.ts +++ b/ui/admin/app/lib/routers/apiRoutes.ts @@ -167,6 +167,8 @@ export const ApiRoutes = { getById: (workflowId: string) => buildUrl(`/workflows/${workflowId}`), authenticate: (workflowId: string) => buildUrl(`/workflows/${workflowId}/authenticate`), + deleteWithTriggers: (workflowId: string) => + buildUrl(`/workflows/${workflowId}`, { "delete-triggers": "true" }), }, toolAuthentication: { authenticate: (namespace: AssistantNamespace, entityId: string) => diff --git a/ui/admin/app/lib/service/api/workflowService.ts b/ui/admin/app/lib/service/api/workflowService.ts index b8baa7f73..04679c4b7 100644 --- a/ui/admin/app/lib/service/api/workflowService.ts +++ b/ui/admin/app/lib/service/api/workflowService.ts @@ -66,6 +66,14 @@ async function deleteWorkflow(id: string) { }); } +async function deleteWorkflowWithTriggers(id: string) { + await request({ + url: ApiRoutes.workflows.deleteWithTriggers(id).url, + method: "DELETE", + errorMessage: "Failed to delete workflow and triggers", + }); +} + const revalidateWorkflows = () => revalidateWhere((url) => url.includes(ApiRoutes.workflows.base().path)); @@ -93,6 +101,7 @@ export const WorkflowService = { createWorkflow, updateWorkflow, deleteWorkflow, + deleteWorkflowWithTriggers, revalidateWorkflows, authenticateWorkflow, }; diff --git a/ui/admin/app/routes/_auth.workflow-triggers._index.tsx b/ui/admin/app/routes/_auth.workflow-triggers._index.tsx index 1397085b1..cf3a7b293 100644 --- a/ui/admin/app/routes/_auth.workflow-triggers._index.tsx +++ b/ui/admin/app/routes/_auth.workflow-triggers._index.tsx @@ -106,12 +106,15 @@ export default function WorkflowTriggersPage() { columnHelper.accessor((row) => row.type as string, { header: "Type", }), - columnHelper.accessor( - (row) => workflowMap[row.workflow]?.name ?? row.workflow, - { - header: "Workflow", - } - ), + columnHelper.accessor((row) => workflowMap[row.workflow]?.name, { + header: "Workflow", + cell: ({ getValue }) => + getValue() ?? ( + + Workflow Not Available + + ), + }), columnHelper.display({ id: "actions", cell: ({ row }) => (