diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs index b8ed039c17..9cd3d0930c 100644 --- a/backend/windmill-api-workspaces/src/workspaces.rs +++ b/backend/windmill-api-workspaces/src/workspaces.rs @@ -1323,9 +1323,14 @@ async fn get_datatable_schema(db: &DB, w_id: &str, datatable_name: &str) -> Resu Ok(schema_map) } -/// Export the schema of a datatable using pg_dump. -/// Returns a list of SQL statements that recreate the entire schema (no data). -pub async fn dump_datatable(db: &DB, w_id: &str, datatable_name: &str) -> Result { +/// Export a datatable using pg_dump. +/// If `schema_only` is true, only the schema is exported. Otherwise, schema and data are exported. +pub async fn dump_datatable( + db: &DB, + w_id: &str, + datatable_name: &str, + schema_only: bool, +) -> Result { let db_resource = get_datatable_resource_from_db_unchecked(db, w_id, datatable_name).await?; let pg_db: PgDatabase = serde_json::from_value(db_resource) @@ -1337,9 +1342,11 @@ pub async fn dump_datatable(db: &DB, w_id: &str, datatable_name: &str) -> Result let dbname = &pg_db.dbname; let mut cmd = tokio::process::Command::new("pg_dump"); - cmd.arg("--format=plain") - .arg("--schema-only") - .arg("--host") + cmd.arg("--format=plain"); + if schema_only { + cmd.arg("--schema-only"); + } + cmd.arg("--host") .arg(host) .arg("--port") .arg(&port) @@ -1376,6 +1383,8 @@ struct ForkDatatableRequest { source_datatable_name: String, new_datatable_name: String, new_custom_instance_database_name: String, + #[serde(default)] + include_data: bool, } async fn fork_datatable( @@ -1480,7 +1489,7 @@ async fn fork_datatable( serde_json::to_value(new_settings).map_err(|err| Error::internal_err(err.to_string()))?; // Export the schema from the source BEFORE updating the config (which points to the new empty DB) - let dump = dump_datatable(&db, &w_id, &req.source_datatable_name).await?; + let dump = dump_datatable(&db, &w_id, &req.source_datatable_name, !req.include_data).await?; sqlx::query!( "UPDATE workspace_settings SET datatable = $1 WHERE workspace_id = $2", diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 67a13d0aa6..5941c4ffe4 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -3357,6 +3357,10 @@ paths: new_custom_instance_database_name: type: string description: "Name for the new database. Use $current_name to interpolate the original database name." + include_data: + type: boolean + default: false + description: "If true, fork both schema and data. If false (default), fork schema only." responses: "200": description: status diff --git a/frontend/src/lib/components/workspaceSettings/CreateWorkspace.svelte b/frontend/src/lib/components/workspaceSettings/CreateWorkspace.svelte index bad623f88b..0814d98262 100644 --- a/frontend/src/lib/components/workspaceSettings/CreateWorkspace.svelte +++ b/frontend/src/lib/components/workspaceSettings/CreateWorkspace.svelte @@ -195,29 +195,35 @@ workspace: $workspaceStore! }) if (datatables.includes('main')) { + const forkDatatableAction = async (includeData: boolean) => { + try { + await WorkspaceService.forkDatatable({ + workspace: prefixed_id, + requestBody: { + source_datatable_name: 'main', + new_datatable_name: 'main', + new_custom_instance_database_name: `__wmfork__${prefixed_id.replace(/-/g, '_')}__$current_name`, + include_data: includeData + } + }) + sendUserToast( + `Successfully forked "main" datatable${includeData ? ' with data' : ''} to workspace "${prefixed_id}"` + ) + } catch (e) { + sendUserToast(`Failed to fork datatable: ${e?.body ?? e}`, 'error') + } + } sendUserToast( - `Fork the main datatable ?`, + `Fork the main datatable?`, 'info', [ { label: 'Fork schema only', - callback: async () => { - try { - await WorkspaceService.forkDatatable({ - workspace: prefixed_id, - requestBody: { - source_datatable_name: 'main', - new_datatable_name: 'main', - new_custom_instance_database_name: `__wmfork__${prefixed_id.replace(/-/g, '_')}__$current_name` - } - }) - sendUserToast( - `Successfully forked "main" datatable to workspace "${prefixed_id}"` - ) - } catch (e) { - sendUserToast(`Failed to fork datatable: ${e?.body ?? e}`, 'error') - } - } + callback: () => forkDatatableAction(false) + }, + { + label: 'Fork schema and data', + callback: () => forkDatatableAction(true) } ], undefined,