From cf2fc4167e21a639608ee8a58c0437972d5005a3 Mon Sep 17 00:00:00 2001 From: Shuchang Zheng Date: Wed, 16 Oct 2024 16:02:29 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'skyvern-fronte?= =?UTF-8?q?nd/src/'=20with=20remote=20'skyvern-frontend/src/'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > [!IMPORTANT] > Add `ImportWorkflowButton` to import workflows from YAML/JSON files in the `Workflows` component. > > - **Feature Addition**: > - Adds `ImportWorkflowButton` component in `ImportWorkflowButton.tsx` to import workflows from YAML or JSON files. > - Integrates `ImportWorkflowButton` into `Workflows.tsx`, allowing users to import workflows directly from the UI. > - **Functionality**: > - Uses `useMutation` from `@tanstack/react-query` to handle file upload and server interaction. > - Converts JSON files to YAML before sending to the server. > - On success, navigates to the workflow edit page; on error, displays a toast notification. > - **UI Changes**: > - Adds tooltip to `ImportWorkflowButton` explaining its functionality. > - Adjusts layout in `Workflows.tsx` to accommodate the new import button. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=Skyvern-AI%2Fskyvern-cloud&utm_source=github&utm_medium=referral) for 2dde8b1c11929940899737561b50d8f21daa0696. It will automatically update as commits are pushed. --- .../routes/workflows/ImportWorkflowButton.tsx | 101 ++++++++++++++++++ .../src/routes/workflows/Workflows.tsx | 34 +++--- 2 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 skyvern-frontend/src/routes/workflows/ImportWorkflowButton.tsx diff --git a/skyvern-frontend/src/routes/workflows/ImportWorkflowButton.tsx b/skyvern-frontend/src/routes/workflows/ImportWorkflowButton.tsx new file mode 100644 index 0000000000..3afd39ae40 --- /dev/null +++ b/skyvern-frontend/src/routes/workflows/ImportWorkflowButton.tsx @@ -0,0 +1,101 @@ +import { getClient } from "@/api/AxiosClient"; +import { Label } from "@/components/ui/label"; +import { ReloadIcon, UploadIcon } from "@radix-ui/react-icons"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useId } from "react"; +import { stringify as convertToYAML } from "yaml"; +import { WorkflowApiResponse } from "./types/workflowTypes"; +import { useCredentialGetter } from "@/hooks/useCredentialGetter"; +import { useNavigate } from "react-router-dom"; +import { AxiosError } from "axios"; +import { toast } from "@/components/ui/use-toast"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +function isJsonString(str: string): boolean { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; +} + +function ImportWorkflowButton() { + const inputId = useId(); + const credentialGetter = useCredentialGetter(); + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + const createWorkflowFromYamlMutation = useMutation({ + mutationFn: async (yaml: string) => { + const client = await getClient(credentialGetter); + return client.post( + "/workflows", + yaml, + { + headers: { + "Content-Type": "text/plain", + }, + }, + ); + }, + onSuccess: (response) => { + queryClient.invalidateQueries({ + queryKey: ["workflows"], + }); + navigate(`/workflows/${response.data.workflow_permanent_id}/edit`); + }, + onError: (error: AxiosError) => { + toast({ + variant: "destructive", + title: "Error importing workflow", + description: error.message || "An error occurred", + }); + }, + }); + + return ( + + + + + + + Import a workflow from a YAML or JSON file + + + + ); +} + +export { ImportWorkflowButton }; diff --git a/skyvern-frontend/src/routes/workflows/Workflows.tsx b/skyvern-frontend/src/routes/workflows/Workflows.tsx index dee1212e53..265d64dd74 100644 --- a/skyvern-frontend/src/routes/workflows/Workflows.tsx +++ b/skyvern-frontend/src/routes/workflows/Workflows.tsx @@ -1,6 +1,7 @@ import { getClient } from "@/api/AxiosClient"; import { WorkflowApiResponse, WorkflowRunApiResponse } from "@/api/types"; import { StatusBadge } from "@/components/StatusBadge"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; import { Pagination, @@ -37,10 +38,10 @@ import { import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useNavigate, useSearchParams } from "react-router-dom"; import { stringify as convertToYAML } from "yaml"; +import { ImportWorkflowButton } from "./ImportWorkflowButton"; import { WorkflowCreateYAMLRequest } from "./types/workflowYamlTypes"; -import { WorkflowTitle } from "./WorkflowTitle"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { WorkflowActions } from "./WorkflowActions"; +import { WorkflowTitle } from "./WorkflowTitle"; const emptyWorkflowRequest: WorkflowCreateYAMLRequest = { title: "New Workflow", @@ -178,19 +179,22 @@ function Workflows() {

Workflows

- +
+ + +