diff --git a/src-tauri/sqlx-data.json b/src-tauri/sqlx-data.json index 0f6a7439..780530e1 100644 --- a/src-tauri/sqlx-data.json +++ b/src-tauri/sqlx-data.json @@ -472,6 +472,16 @@ }, "query": "\n INSERT INTO environments (\n id,\n workspace_id,\n name,\n data\n )\n VALUES (?, ?, ?, ?)\n " }, + "aeb0712785a9964d516dc8939bc54aa8206ad852e608b362d014b67a0f21b0ed": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "\n DELETE FROM environments\n WHERE id = ?\n " + }, "b19c275180909a39342b13c3cdcf993781636913ae590967f5508c46a56dc961": { "describe": { "columns": [], diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index bc995472..1a84fd5e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -479,6 +479,19 @@ async fn delete_request( emit_and_return(&window, "deleted_model", req) } +#[tauri::command] +async fn delete_environment( + window: Window, + db_instance: State<'_, Mutex>>, + environment_id: &str, +) -> Result { + let pool = &*db_instance.lock().await; + let req = models::delete_environment(environment_id, pool) + .await + .expect("Failed to delete environment"); + emit_and_return(&window, "deleted_model", req) +} + #[tauri::command] async fn list_requests( workspace_id: &str, @@ -600,10 +613,10 @@ async fn new_window(window: Window, url: &str) -> Result<(), String> { async fn delete_workspace( window: Window, db_instance: State<'_, Mutex>>, - id: &str, + workspace_id: &str, ) -> Result { let pool = &*db_instance.lock().await; - let workspace = models::delete_workspace(id, pool) + let workspace = models::delete_workspace(workspace_id, pool) .await .expect("Failed to delete workspace"); emit_and_return(&window, "deleted_model", workspace) @@ -643,6 +656,7 @@ fn main() { create_request, create_workspace, delete_all_responses, + delete_environment, delete_request, delete_response, delete_workspace, diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index e725fea8..15108a15 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -252,13 +252,27 @@ pub async fn create_environment( get_environment(&id, pool).await } +pub async fn delete_environment(id: &str, pool: &Pool) -> Result { + let env = get_environment(id, pool).await?; + let _ = sqlx::query!( + r#" + DELETE FROM environments + WHERE id = ? + "#, + id, + ) + .execute(pool) + .await; + + Ok(env) +} + pub async fn update_environment( id: &str, name: &str, data: HashMap, pool: &Pool, ) -> Result { - println!("DATA: {}", data.clone().len()); let json_data = Json(data); sqlx::query!( r#" @@ -457,6 +471,10 @@ pub async fn get_request(id: &str, pool: &Pool) -> Result) -> Result { let req = get_request(id, pool).await?; + + // DB deletes will cascade but this will delete the files + delete_all_responses(id, pool).await?; + let _ = sqlx::query!( r#" DELETE FROM http_requests @@ -467,8 +485,6 @@ pub async fn delete_request(id: &str, pool: &Pool) -> Result { - const environmentItems = environments.map( + const environmentItems: DropdownItem[] = environments.map( (e) => ({ key: e.id, label: e.name, @@ -41,57 +43,58 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo }), [activeEnvironment?.id], ); - const activeEnvironmentItems: DropdownItem[] = - environments.length <= 1 - ? [] - : [ - ...environmentItems, - { - type: 'separator', - label: activeEnvironment?.name, - }, - ]; return [ - ...activeEnvironmentItems, - { - key: 'edit', - label: 'Edit', - leftSlot: , - onSelect: async () => { - dialog.show({ - title: 'Environments', - render: () => , - }); - }, - }, - { - key: 'rename', - label: 'Rename', - leftSlot: , - onSelect: async () => { - const name = await prompt({ - title: 'Rename Environment', - description: ( - <> - Enter a new name for {activeEnvironment?.name} - - ), - name: 'name', - label: 'Name', - defaultValue: activeEnvironment?.name, - }); - updateEnvironment.mutate({ name }); - }, - }, - // { - // key: 'delete', - // label: 'Delete', - // leftSlot: , - // onSelect: deleteEnv.mutate, - // variant: 'danger', - // }, - { type: 'separator' }, + ...environmentItems, + ...((environmentItems.length > 0 + ? [{ type: 'separator', label: activeEnvironment?.name }] + : []) as DropdownItem[]), + ...((activeEnvironment != null + ? [ + { + key: 'rename', + label: 'Rename', + leftSlot: , + onSelect: async () => { + const name = await prompt({ + title: 'Rename Environment', + description: ( + <> + Enter a new name for {activeEnvironment?.name} + + ), + name: 'name', + label: 'Name', + defaultValue: activeEnvironment?.name, + }); + updateEnvironment.mutate({ name }); + }, + }, + { + key: 'delete', + label: 'Delete', + leftSlot: , + onSelect: deleteEnvironment.mutate, + variant: 'danger', + }, + { type: 'separator' }, + ] + : []) as DropdownItem[]), + ...((environments.length > 0 + ? [ + { + key: 'edit', + label: 'Manage Environments', + leftSlot: , + onSelect: async () => { + dialog.show({ + title: 'Environments', + render: () => , + }); + }, + }, + ] + : []) as DropdownItem[]), { key: 'create-environment', label: 'Create Environment', @@ -110,12 +113,13 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo ]; }, [ // deleteEnvironment.mutate, - activeEnvironment?.name, + activeEnvironment, createEnvironment, dialog, environments, prompt, updateEnvironment, + deleteEnvironment, routes, ]); diff --git a/src-web/hooks/useCreateEnvironment.ts b/src-web/hooks/useCreateEnvironment.ts index 2ba84b61..f2d19865 100644 --- a/src-web/hooks/useCreateEnvironment.ts +++ b/src-web/hooks/useCreateEnvironment.ts @@ -3,11 +3,9 @@ import { invoke } from '@tauri-apps/api'; import type { Environment } from '../lib/models'; import { environmentsQueryKey } from './useEnvironments'; import { useActiveWorkspaceId } from './useActiveWorkspaceId'; -import { useActiveEnvironmentId } from './useActiveEnvironmentId'; import { useAppRoutes } from './useAppRoutes'; export function useCreateEnvironment() { - const environmentId = useActiveEnvironmentId(); const workspaceId = useActiveWorkspaceId(); const queryClient = useQueryClient(); const routes = useAppRoutes(); @@ -18,7 +16,7 @@ export function useCreateEnvironment() { }, onSuccess: async (environment) => { if (workspaceId == null) return; - routes.navigate('workspace', { workspaceId, environmentId }); + routes.setEnvironment(environment); queryClient.setQueryData( environmentsQueryKey({ workspaceId }), (environments) => [...(environments ?? []), environment], diff --git a/src-web/hooks/useDeleteEnvironment.tsx b/src-web/hooks/useDeleteEnvironment.tsx new file mode 100644 index 00000000..96133b76 --- /dev/null +++ b/src-web/hooks/useDeleteEnvironment.tsx @@ -0,0 +1,36 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { invoke } from '@tauri-apps/api'; +import { InlineCode } from '../components/core/InlineCode'; +import type { Environment, Workspace } from '../lib/models'; +import { useConfirm } from './useConfirm'; +import { environmentsQueryKey } from './useEnvironments'; + +export function useDeleteEnvironment(environment: Environment | null) { + const queryClient = useQueryClient(); + const confirm = useConfirm(); + + return useMutation({ + mutationFn: async () => { + const confirmed = await confirm({ + title: 'Delete Environment', + variant: 'delete', + description: ( + <> + Permanently delete {environment?.name}? + + ), + }); + if (!confirmed) return null; + return invoke('delete_environment', { environmentId: environment?.id }); + }, + onSuccess: async (environment) => { + if (environment === null) return; + + const { id: environmentId, workspaceId } = environment; + queryClient.setQueryData( + environmentsQueryKey({ workspaceId }), + (environments) => environments?.filter((e) => e.id !== environmentId), + ); + }, + }); +} diff --git a/src-web/hooks/useDeleteWorkspace.tsx b/src-web/hooks/useDeleteWorkspace.tsx index 8853d854..f0024cef 100644 --- a/src-web/hooks/useDeleteWorkspace.tsx +++ b/src-web/hooks/useDeleteWorkspace.tsx @@ -26,7 +26,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) { ), }); if (!confirmed) return null; - return invoke('delete_workspace', { id: workspace?.id }); + return invoke('delete_workspace', { workspaceId: workspace?.id }); }, onSuccess: async (workspace) => { if (workspace === null) return;