1
1
import { getClient } from "@/api/AxiosClient" ;
2
+ import { GarbageIcon } from "@/components/icons/GarbageIcon" ;
2
3
import { Button } from "@/components/ui/button" ;
3
4
import {
4
5
Dialog ,
@@ -14,35 +15,67 @@ import {
14
15
DropdownMenu ,
15
16
DropdownMenuContent ,
16
17
DropdownMenuItem ,
18
+ DropdownMenuPortal ,
19
+ DropdownMenuSub ,
20
+ DropdownMenuSubContent ,
21
+ DropdownMenuSubTrigger ,
17
22
DropdownMenuTrigger ,
18
23
} from "@/components/ui/dropdown-menu" ;
19
24
import { toast } from "@/components/ui/use-toast" ;
20
25
import { useCredentialGetter } from "@/hooks/useCredentialGetter" ;
21
26
import {
22
27
CopyIcon ,
23
28
DotsHorizontalIcon ,
29
+ DownloadIcon ,
24
30
ReloadIcon ,
25
31
} from "@radix-ui/react-icons" ;
26
32
import { useMutation , useQueryClient } from "@tanstack/react-query" ;
27
33
import { AxiosError } from "axios" ;
28
- import { useWorkflowQuery } from "./hooks/useWorkflowQuery " ;
34
+ import { useNavigate } from "react-router-dom " ;
29
35
import { stringify as convertToYAML } from "yaml" ;
36
+ import { convert } from "./editor/workflowEditorUtils" ;
37
+ import { useWorkflowQuery } from "./hooks/useWorkflowQuery" ;
30
38
import { WorkflowApiResponse } from "./types/workflowTypes" ;
31
- import { useNavigate } from "react-router-dom" ;
32
39
import { WorkflowCreateYAMLRequest } from "./types/workflowYamlTypes" ;
33
- import { convert } from "./editor/workflowEditorUtils" ;
34
- import { GarbageIcon } from "@/components/icons/GarbageIcon" ;
35
40
36
41
type Props = {
37
42
id : string ;
38
43
} ;
39
44
45
+ function downloadFile ( fileName : string , contents : string ) {
46
+ const element = document . createElement ( "a" ) ;
47
+ element . setAttribute (
48
+ "href" ,
49
+ "data:text/plain;charset=utf-8," + encodeURIComponent ( contents ) ,
50
+ ) ;
51
+ element . setAttribute ( "download" , fileName ) ;
52
+
53
+ element . style . display = "none" ;
54
+ document . body . appendChild ( element ) ;
55
+
56
+ element . click ( ) ;
57
+
58
+ document . body . removeChild ( element ) ;
59
+ }
60
+
40
61
function WorkflowActions ( { id } : Props ) {
41
62
const credentialGetter = useCredentialGetter ( ) ;
42
63
const queryClient = useQueryClient ( ) ;
43
64
const { data : workflow } = useWorkflowQuery ( { workflowPermanentId : id } ) ;
44
65
const navigate = useNavigate ( ) ;
45
66
67
+ function handleExport ( type : "json" | "yaml" ) {
68
+ if ( ! workflow ) {
69
+ return ;
70
+ }
71
+ const fileName = `${ workflow . title } .${ type } ` ;
72
+ const contents =
73
+ type === "json"
74
+ ? JSON . stringify ( convert ( workflow ) , null , 2 )
75
+ : convertToYAML ( convert ( workflow ) ) ;
76
+ downloadFile ( fileName , contents ) ;
77
+ }
78
+
46
79
const createWorkflowMutation = useMutation ( {
47
80
mutationFn : async ( workflow : WorkflowCreateYAMLRequest ) => {
48
81
const client = await getClient ( credentialGetter ) ;
@@ -98,14 +131,42 @@ function WorkflowActions({ id }: Props) {
98
131
if ( ! workflow ) {
99
132
return ;
100
133
}
101
- const clonedWorkflow = convert ( workflow ) ;
134
+ const clonedWorkflow = convert ( {
135
+ ...workflow ,
136
+ title : `Copy of ${ workflow . title } ` ,
137
+ } ) ;
102
138
createWorkflowMutation . mutate ( clonedWorkflow ) ;
103
139
} }
104
140
className = "p-2"
105
141
>
106
142
< CopyIcon className = "mr-2 h-4 w-4" />
107
143
Clone Workflow
108
144
</ DropdownMenuItem >
145
+ < DropdownMenuSub >
146
+ < DropdownMenuSubTrigger >
147
+ < DownloadIcon className = "mr-2 h-4 w-4" />
148
+ Export as...
149
+ </ DropdownMenuSubTrigger >
150
+ < DropdownMenuPortal >
151
+ < DropdownMenuSubContent >
152
+ < DropdownMenuItem
153
+ onSelect = { ( ) => {
154
+ handleExport ( "yaml" ) ;
155
+ } }
156
+ >
157
+ YAML
158
+ </ DropdownMenuItem >
159
+ < DropdownMenuItem
160
+ onSelect = { ( ) => {
161
+ handleExport ( "json" ) ;
162
+ } }
163
+ >
164
+ JSON
165
+ </ DropdownMenuItem >
166
+ </ DropdownMenuSubContent >
167
+ </ DropdownMenuPortal >
168
+ </ DropdownMenuSub >
169
+
109
170
< DialogTrigger >
110
171
< DropdownMenuItem className = "p-2" >
111
172
< GarbageIcon className = "mr-2 h-4 w-4 text-destructive" />
0 commit comments