From e81f7bd7239b73710da2a4ddec0da7805c13da06 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 22 Feb 2023 08:40:11 +0100 Subject: [PATCH] feat: add delete flows --- backend/windmill-api/openapi.yaml | 17 ++++++++ backend/windmill-api/src/flows.rs | 42 +++++++++++++++++-- backend/windmill-api/src/webhook_util.rs | 1 + backend/windmill-api/src/workspaces.rs | 1 - cli/flow.ts | 5 +-- cli/sync.ts | 1 - .../components/common/table/FlowRow.svelte | 22 +++++++++- .../(logged)/flows/get/[...path]/+page.svelte | 19 ++++++++- 8 files changed, 97 insertions(+), 11 deletions(-) diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 649afc254f..c3c746bb84 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2716,6 +2716,23 @@ paths: schema: type: string + /w/{workspace}/flows/delete/{path}: + delete: + summary: delete flow by path + operationId: deleteFlowByPath + tags: + - flow + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/ScriptPath" + responses: + "200": + description: flow delete + content: + text/plain: + schema: + type: string + /w/{workspace}/apps/list: get: summary: list all available apps diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index 747d8f2088..69e5a7e06a 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -11,7 +11,7 @@ use sql_builder::prelude::*; use axum::{ extract::{Extension, Path, Query}, - routing::{get, post}, + routing::{delete, get, post}, Json, Router, }; use sql_builder::SqlBuilder; @@ -41,6 +41,7 @@ pub fn workspaced_service() -> Router { .route("/create", post(create_flow)) .route("/update/*path", post(update_flow)) .route("/archive/*path", post(archive_flow_by_path)) + .route("/delete/*path", delete(delete_flow_by_path)) .route("/get/*path", get(get_flow_by_path)) .route("/exists/*path", get(exists_flow_by_path)) .route("/list_paths", get(list_paths)) @@ -446,8 +447,7 @@ async fn exists_flow_by_path( let path = path.to_path(); let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM flow WHERE path = $1 AND (workspace_id = $2 OR workspace_id \ - = 'starter'))", + "SELECT EXISTS(SELECT 1 FROM flow WHERE path = $1 AND workspace_id = $2)", path, w_id ) @@ -494,6 +494,42 @@ async fn archive_flow_by_path( Ok(format!("Flow {path} archived")) } +async fn delete_flow_by_path( + authed: Authed, + Extension(user_db): Extension, + Extension(webhook): Extension, + Path((w_id, path)): Path<(String, StripPath)>, +) -> Result { + let path = path.to_path(); + let mut tx = user_db.begin(&authed).await?; + + sqlx::query!( + "DELETE FROM flow WHERE path = $1 AND workspace_id = $2", + path, + &w_id + ) + .execute(&mut tx) + .await?; + + audit_log( + &mut tx, + &authed.username, + "flows.delete", + ActionKind::Delete, + &w_id, + Some(path), + Some([("workspace", w_id.as_str())].into()), + ) + .await?; + tx.commit().await?; + webhook.send_message( + w_id.clone(), + WebhookMessage::DeleteFlow { workspace: w_id, path: path.to_owned() }, + ); + + Ok(format!("Flow {path} deleted")) +} + #[cfg(test)] mod tests { diff --git a/backend/windmill-api/src/webhook_util.rs b/backend/windmill-api/src/webhook_util.rs index 5ce4de1ef0..a5439243fd 100644 --- a/backend/windmill-api/src/webhook_util.rs +++ b/backend/windmill-api/src/webhook_util.rs @@ -24,6 +24,7 @@ pub enum WebhookMessage { CreateFlow { workspace: String, path: String }, UpdateFlow { workspace: String, old_path: String, new_path: String }, ArchiveFlow { workspace: String, path: String }, + DeleteFlow { workspace: String, path: String }, CreateFolder { workspace: String, name: String }, UpdateFolder { workspace: String, name: String }, DeleteFolder { workspace: String, name: String }, diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 60137b1712..476cee4997 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -25,7 +25,6 @@ use axum::{ routing::{delete, get, post}, Json, Router, }; -use serde_json::to_string_pretty; use stripe::CustomerId; use windmill_audit::{audit_log, ActionKind}; use windmill_common::{ diff --git a/cli/flow.ts b/cli/flow.ts index 6488be3c93..9d1ff37656 100644 --- a/cli/flow.ts +++ b/cli/flow.ts @@ -48,10 +48,6 @@ export class FlowFile implements Resource, PushDiffs { path: remotePath, }) ) { - console.log({ - workspace: workspace, - path: remotePath, - }) console.log( colors.bold.yellow( `Applying ${diffs.length} diffs to existing flow... ${remotePath}`, @@ -126,6 +122,7 @@ export class FlowFile implements Resource, PushDiffs { path: remotePath, }); } catch { + remote = undefined; } await this.pushDiffs( diff --git a/cli/sync.ts b/cli/sync.ts index 1eb849705b..d6577868f6 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -511,7 +511,6 @@ async function push(opts: GlobalOptions & { raw: boolean, yes: boolean }) { remotePath = parts[0]; } } - console.log(diffs) return file.pushDiffs(workspace, remotePath, diffs); } } diff --git a/frontend/src/lib/components/common/table/FlowRow.svelte b/frontend/src/lib/components/common/table/FlowRow.svelte index 40743a14dd..49ad50cbd4 100644 --- a/frontend/src/lib/components/common/table/FlowRow.svelte +++ b/frontend/src/lib/components/common/table/FlowRow.svelte @@ -17,7 +17,8 @@ faFileExport, faList, faPlay, - faShare + faShare, + faTrashAlt } from '@fortawesome/free-solid-svg-icons' import { MoreVertical } from 'lucide-svelte' import { createEventDispatcher } from 'svelte' @@ -43,6 +44,16 @@ sendUserToast(`Could not archive this flow ${err.body}`, true) } } + + async function deleteFlow(path: string): Promise { + try { + await FlowService.deleteFlowByPath({ workspace: $workspaceStore!, path }) + dispatch('change') + sendUserToast(`Deleted flow ${path}`) + } catch (err) { + sendUserToast(`Could not delete this flow ${err.body}`, true) + } + } let scheduleEditor: ScheduleEditor @@ -166,6 +177,15 @@ }, type: 'delete', disabled: !canWrite + }, + { + displayName: 'Delete', + icon: faTrashAlt, + action: () => { + path ? deleteFlow(path) : null + }, + type: 'delete', + disabled: !canWrite } ]} > diff --git a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte index 7b9f015311..c121de4a27 100644 --- a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte @@ -22,7 +22,8 @@ faCodeFork, faClipboard, faChevronUp, - faChevronDown + faChevronDown, + faTrash } from '@fortawesome/free-solid-svg-icons' import Tooltip from '$lib/components/Tooltip.svelte' @@ -85,6 +86,12 @@ loadFlow() } + async function deleteFlow(): Promise { + await FlowService.deleteFlowByPath({ workspace: $workspaceStore!, path }) + sendUserToast('Flow deleted') + goto('/') + } + async function setScheduleEnabled(path: string, enabled: boolean): Promise { try { await ScheduleService.setScheduleEnabled({ @@ -416,6 +423,16 @@ > Archive + {/if}