From 60fa9dcf13f3b6a2ec55a2e92215cd632562a013 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Fri, 3 Nov 2023 07:49:44 -0700 Subject: [PATCH] Add folder model --- Makefile | 4 +- .../migrations/20231103142807_folders.sql | 19 + src-tauri/sqlx-data.json | 414 ++++++++++++------ src-tauri/src/main.rs | 79 ++++ src-tauri/src/models.rs | 118 ++++- src-web/components/Sidebar.tsx | 30 +- src-web/hooks/useFolders.ts | 22 + src-web/lib/models.ts | 9 + 8 files changed, 554 insertions(+), 141 deletions(-) create mode 100644 src-tauri/migrations/20231103142807_folders.sql create mode 100644 src-web/hooks/useFolders.ts diff --git a/Makefile b/Makefile index 928422de..10120b3e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: sqlx-prepare, dev +.PHONY: sqlx-prepare, dev, migrate, build sqlx-prepare: cd src-tauri && cargo sqlx prepare --database-url 'sqlite://db.sqlite' @@ -6,6 +6,8 @@ sqlx-prepare: dev: npm run tauri-dev +migrate: + cd src-tauri && cargo sqlx migrate run --database-url 'sqlite://db.sqlite?mode=rw' build: ./node_modules/.bin/tauri build diff --git a/src-tauri/migrations/20231103142807_folders.sql b/src-tauri/migrations/20231103142807_folders.sql new file mode 100644 index 00000000..5278e9e0 --- /dev/null +++ b/src-tauri/migrations/20231103142807_folders.sql @@ -0,0 +1,19 @@ +CREATE TABLE folders +( + id TEXT NOT NULL + PRIMARY KEY, + model TEXT DEFAULT 'folder' NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted_at DATETIME, + workspace_id TEXT NOT NULL + REFERENCES workspaces + ON DELETE CASCADE, + folder_id TEXT NULL + REFERENCES folders + ON DELETE CASCADE, + name TEXT NOT NULL, + sort_priority REAL DEFAULT 0 NOT NULL +); + +ALTER TABLE http_requests ADD COLUMN folder_id TEXT REFERENCES folders(id) ON DELETE CASCADE; diff --git a/src-tauri/sqlx-data.json b/src-tauri/sqlx-data.json index df202aa1..9afa85b4 100644 --- a/src-tauri/sqlx-data.json +++ b/src-tauri/sqlx-data.json @@ -1,5 +1,15 @@ { "db": "SQLite", + "02506ad41cc94cd937422ef1977a97174431f008a9fb4ce39667d587a858b876": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 5 + } + }, + "query": "\n INSERT INTO folders (\n id,\n workspace_id,\n folder_id,\n name,\n sort_priority\n )\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority\n " + }, "06aaf8f4a17566f1d25da2a60f0baf4b5fc28c3cf0c001a84e25edf9eab3c7e3": { "describe": { "columns": [ @@ -58,6 +68,126 @@ }, "query": "\n DELETE FROM http_responses\n WHERE id = ?\n " }, + "1428d25b6aa3d6ec55742a968571fa951da0406d7bb32408883c584eae7dd53c": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "model", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "workspace_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "created_at", + "ordinal": 3, + "type_info": "Datetime" + }, + { + "name": "updated_at", + "ordinal": 4, + "type_info": "Datetime" + }, + { + "name": "folder_id", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "sort_priority", + "ordinal": 7, + "type_info": "Float" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n folder_id,\n name,\n sort_priority\n FROM folders\n WHERE id = ?\n " + }, + "1517b0f86c841b5f1247bd40c3a9b38ab001d846a410b6e3cd36f9e844d50ddb": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "model", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "workspace_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "created_at", + "ordinal": 3, + "type_info": "Datetime" + }, + { + "name": "updated_at", + "ordinal": 4, + "type_info": "Datetime" + }, + { + "name": "folder_id", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "sort_priority", + "ordinal": 7, + "type_info": "Float" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n folder_id,\n name,\n sort_priority\n FROM folders\n WHERE workspace_id = ?\n " + }, "26072725d536c3cfdffd9a681d17c0ee2f246ca98e0459630a2430236d3bbdd2": { "describe": { "columns": [ @@ -400,7 +530,17 @@ }, "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n name,\n variables AS \"variables!: sqlx::types::Json>\"\n FROM environments\n WHERE id = ?\n " }, - "6f0cb5a6d1e8dbc8cdfcc3c7e7944b2c83c22cb795b9d6b98fe067dabec9680b": { + "84be2b954870ab181738656ecd4d03fca2ff21012947014c79626abfce8e999b": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "\n DELETE FROM workspaces\n WHERE id = ?\n " + }, + "854536c80af3f86bb9a63b8ce059ad724374b545cb23481bb3b2ce07d7414220": { "describe": { "columns": [ { @@ -419,58 +559,63 @@ "type_info": "Text" }, { - "name": "created_at", + "name": "folder_id", "ordinal": 3, - "type_info": "Datetime" + "type_info": "Text" }, { - "name": "updated_at", + "name": "created_at", "ordinal": 4, "type_info": "Datetime" }, { - "name": "name", + "name": "updated_at", "ordinal": 5, - "type_info": "Text" + "type_info": "Datetime" }, { - "name": "url", + "name": "name", "ordinal": 6, "type_info": "Text" }, { - "name": "method", + "name": "url", "ordinal": 7, "type_info": "Text" }, { - "name": "body", + "name": "method", "ordinal": 8, "type_info": "Text" }, { - "name": "body_type", + "name": "body", "ordinal": 9, "type_info": "Text" }, { - "name": "authentication!: Json>", + "name": "body_type", "ordinal": 10, "type_info": "Text" }, { - "name": "authentication_type", + "name": "authentication!: Json>", "ordinal": 11, "type_info": "Text" }, { - "name": "sort_priority", + "name": "authentication_type", "ordinal": 12, + "type_info": "Text" + }, + { + "name": "sort_priority", + "ordinal": 13, "type_info": "Float" }, { "name": "headers!: sqlx::types::Json>", - "ordinal": 13, + "ordinal": 14, "type_info": "Text" } ], @@ -478,6 +623,7 @@ false, false, false, + true, false, false, false, @@ -494,17 +640,7 @@ "Right": 1 } }, - "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n " - }, - "84be2b954870ab181738656ecd4d03fca2ff21012947014c79626abfce8e999b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 1 - } - }, - "query": "\n DELETE FROM workspaces\n WHERE id = ?\n " + "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n " }, "8947a2a90478277c42fe9b06bc1fa98197642a4d281a3dbc101be2c9c1fec36c": { "describe": { @@ -516,6 +652,118 @@ }, "query": "\n INSERT INTO http_responses (\n id,\n request_id,\n workspace_id,\n elapsed,\n url,\n status,\n status_reason,\n content_length,\n body,\n body_path,\n headers\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n " }, + "93aea3881dffb70a82325263740a0bb6477e78f27991ce7456b394e84383acb6": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "\n DELETE FROM folders\n WHERE id = ?\n " + }, + "a558e182f40286fe52bed5f03b2dc367b7229ab6bd9cda0a7ce219a438ccd5fd": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "model", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "workspace_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "folder_id", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "created_at", + "ordinal": 4, + "type_info": "Datetime" + }, + { + "name": "updated_at", + "ordinal": 5, + "type_info": "Datetime" + }, + { + "name": "name", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "url", + "ordinal": 7, + "type_info": "Text" + }, + { + "name": "method", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "body", + "ordinal": 9, + "type_info": "Text" + }, + { + "name": "body_type", + "ordinal": 10, + "type_info": "Text" + }, + { + "name": "authentication!: Json>", + "ordinal": 11, + "type_info": "Text" + }, + { + "name": "authentication_type", + "ordinal": 12, + "type_info": "Text" + }, + { + "name": "sort_priority", + "ordinal": 13, + "type_info": "Float" + }, + { + "name": "headers!: sqlx::types::Json>", + "ordinal": 14, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "\n SELECT\n id,\n model,\n workspace_id,\n folder_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n " + }, "aeb0712785a9964d516dc8939bc54aa8206ad852e608b362d014b67a0f21b0ed": { "describe": { "columns": [], @@ -526,16 +774,6 @@ }, "query": "\n DELETE FROM environments\n WHERE id = ?\n " }, - "b19c275180909a39342b13c3cdcf993781636913ae590967f5508c46a56dc961": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 11 - } - }, - "query": "\n INSERT INTO http_requests (\n id,\n workspace_id,\n name,\n url,\n method,\n body,\n body_type,\n authentication,\n authentication_type,\n headers,\n sort_priority\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n method = excluded.method,\n headers = excluded.headers,\n body = excluded.body,\n body_type = excluded.body_type,\n authentication = excluded.authentication,\n authentication_type = excluded.authentication_type,\n url = excluded.url,\n sort_priority = excluded.sort_priority\n " - }, "ba2b34a77723f24f86e4c3c45274dbfec6ca130e16e592f948844c037bdc0593": { "describe": { "columns": [ @@ -692,102 +930,6 @@ }, "query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body, body_path, elapsed, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE id = ?\n " }, - "ced098adb79c0ee64e223b6e02371ef253920a2c342275de0fa9c181529a4adc": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "model", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "workspace_id", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "created_at", - "ordinal": 3, - "type_info": "Datetime" - }, - { - "name": "updated_at", - "ordinal": 4, - "type_info": "Datetime" - }, - { - "name": "name", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "url", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "method", - "ordinal": 7, - "type_info": "Text" - }, - { - "name": "body", - "ordinal": 8, - "type_info": "Text" - }, - { - "name": "body_type", - "ordinal": 9, - "type_info": "Text" - }, - { - "name": "authentication!: Json>", - "ordinal": 10, - "type_info": "Text" - }, - { - "name": "authentication_type", - "ordinal": 11, - "type_info": "Text" - }, - { - "name": "sort_priority", - "ordinal": 12, - "type_info": "Float" - }, - { - "name": "headers!: sqlx::types::Json>", - "ordinal": 13, - "type_info": "Text" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Right": 1 - } - }, - "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n name,\n url,\n method,\n body,\n body_type,\n authentication AS \"authentication!: Json>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n " - }, "d80c09497771e3641022e73ec6c6a87e73a551f88a948a5445d754922b82b50b": { "describe": { "columns": [], @@ -861,5 +1003,15 @@ } }, "query": "\n INSERT INTO environments (\n id,\n workspace_id,\n name,\n variables\n )\n VALUES (?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n variables = excluded.variables\n " + }, + "e5b410442b00ee354bb58eb0e8fb2af06e9dea4bb24763d717c72a840450a759": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 12 + } + }, + "query": "\n INSERT INTO http_requests (\n id,\n workspace_id,\n folder_id,\n name,\n url,\n method,\n body,\n body_type,\n authentication,\n authentication_type,\n headers,\n sort_priority\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n method = excluded.method,\n headers = excluded.headers,\n body = excluded.body,\n body_type = excluded.body_type,\n authentication = excluded.authentication,\n authentication_type = excluded.authentication_type,\n url = excluded.url,\n sort_priority = excluded.sort_priority\n " } } \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 528450fb..989c843b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -492,6 +492,69 @@ async fn delete_request( emit_and_return(&window, "deleted_model", req) } +#[tauri::command] +async fn list_folders( + workspace_id: &str, + db_instance: State<'_, Mutex>>, +) -> Result, String> { + let pool = &*db_instance.lock().await; + models::find_folders(workspace_id, pool) + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +async fn create_folder( + workspace_id: &str, + name: &str, + sort_priority: f64, + folder_id: Option<&str>, + window: Window, + db_instance: State<'_, Mutex>>, +) -> Result { + let pool = &*db_instance.lock().await; + let created_request = models::upsert_folder( + pool, + models::Folder { + workspace_id: workspace_id.to_string(), + name: name.to_string(), + folder_id: folder_id.map(|s| s.to_string()), + sort_priority, + ..Default::default() + }, + ) + .await + .expect("Failed to create folder"); + + emit_and_return(&window, "created_model", created_request) +} + +#[tauri::command] +async fn update_folder( + folder: models::Folder, + window: Window, + db_instance: State<'_, Mutex>>, +) -> Result { + let pool = &*db_instance.lock().await; + let updated_folder = models::upsert_folder(pool, folder) + .await + .expect("Failed to update request"); + emit_and_return(&window, "updated_model", updated_folder) +} + +#[tauri::command] +async fn delete_folder( + window: Window, + db_instance: State<'_, Mutex>>, + folder_id: &str, +) -> Result { + let pool = &*db_instance.lock().await; + let req = models::delete_folder(folder_id, pool) + .await + .expect("Failed to delete folder"); + emit_and_return(&window, "deleted_model", req) +} + #[tauri::command] async fn delete_environment( window: Window, @@ -529,6 +592,17 @@ async fn list_environments( Ok(environments) } +#[tauri::command] +async fn get_folder( + id: &str, + db_instance: State<'_, Mutex>>, +) -> Result { + let pool = &*db_instance.lock().await; + models::get_folder(id, pool) + .await + .map_err(|e| e.to_string()) +} + #[tauri::command] async fn get_request( id: &str, @@ -705,20 +779,24 @@ fn main() { }) .invoke_handler(tauri::generate_handler![ create_environment, + create_folder, create_request, create_workspace, delete_all_responses, delete_environment, + delete_folder, delete_request, delete_response, delete_workspace, duplicate_request, get_key_value, get_environment, + get_folder, get_request, get_workspace, import_data, list_environments, + list_folders, list_requests, list_responses, list_workspaces, @@ -727,6 +805,7 @@ fn main() { send_request, set_key_value, update_environment, + update_folder, update_request, update_workspace, ]) diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index 47ebcee1..7cece3df 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -64,6 +64,7 @@ pub struct HttpRequest { pub updated_at: NaiveDateTime, pub id: String, pub workspace_id: String, + pub folder_id: Option, pub model: String, pub sort_priority: f64, pub name: String, @@ -77,6 +78,19 @@ pub struct HttpRequest { pub headers: Json>, } +#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)] +#[serde(default, rename_all = "camelCase")] +pub struct Folder { + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, + pub id: String, + pub workspace_id: String, + pub folder_id: Option, + pub model: String, + pub name: String, + pub sort_priority: f64, +} + #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default, rename_all = "camelCase")] pub struct HttpResponseHeader { @@ -292,6 +306,103 @@ pub async fn get_environment(id: &str, pool: &Pool) -> Result) -> Result { + sqlx::query_as!( + Folder, + r#" + SELECT + id, + model, + workspace_id, + created_at, + updated_at, + folder_id, + name, + sort_priority + FROM folders + WHERE id = ? + "#, + id, + ) + .fetch_one(pool) + .await +} + +pub async fn find_folders( + workspace_id: &str, + pool: &Pool, +) -> Result, sqlx::Error> { + sqlx::query_as!( + Folder, + r#" + SELECT + id, + model, + workspace_id, + created_at, + updated_at, + folder_id, + name, + sort_priority + FROM folders + WHERE workspace_id = ? + "#, + workspace_id, + ) + .fetch_all(pool) + .await +} + +pub async fn delete_folder(id: &str, pool: &Pool) -> Result { + let env = get_folder(id, pool).await?; + let _ = sqlx::query!( + r#" + DELETE FROM folders + WHERE id = ? + "#, + id, + ) + .execute(pool) + .await; + + Ok(env) +} + +pub async fn upsert_folder(pool: &Pool, r: Folder) -> Result { + let id = match r.id.as_str() { + "" => generate_id(Some("fl")), + _ => r.id.to_string(), + }; + let trimmed_name = r.name.trim(); + + sqlx::query!( + r#" + INSERT INTO folders ( + id, + workspace_id, + folder_id, + name, + sort_priority + ) + VALUES (?, ?, ?, ?, ?) + ON CONFLICT (id) DO UPDATE SET + updated_at = CURRENT_TIMESTAMP, + name = excluded.name, + folder_id = excluded.folder_id, + sort_priority = excluded.sort_priority + "#, + id, + r.workspace_id, + r.folder_id, + trimmed_name, + r.sort_priority, + ) + .execute(pool) + .await?; + + get_folder(&id, pool).await +} + pub async fn duplicate_request(id: &str, pool: &Pool) -> Result { let mut request = get_request(id, pool).await?.clone(); request.id = "".to_string(); @@ -315,6 +426,7 @@ pub async fn upsert_request( INSERT INTO http_requests ( id, workspace_id, + folder_id, name, url, method, @@ -325,10 +437,11 @@ pub async fn upsert_request( headers, sort_priority ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET updated_at = CURRENT_TIMESTAMP, name = excluded.name, + folder_id = excluded.folder_id, method = excluded.method, headers = excluded.headers, body = excluded.body, @@ -340,6 +453,7 @@ pub async fn upsert_request( "#, id, r.workspace_id, + r.folder_id, trimmed_name, r.url, r.method, @@ -367,6 +481,7 @@ pub async fn find_requests( id, model, workspace_id, + folder_id, created_at, updated_at, name, @@ -395,6 +510,7 @@ pub async fn get_request(id: &str, pool: &Pool) -> Result - - + ); }); @@ -242,7 +238,7 @@ function SidebarItems({ ); return ( - <> + {requests.map((r, i) => ( {hoveredIndex === i && } @@ -259,7 +255,25 @@ function SidebarItems({ ))} {hoveredIndex === requests.length && } - + + {requests.slice(0, 1).map((r, i) => ( + + {hoveredIndex === i && } + + + ))} + {hoveredIndex === requests.length && } + + ); } diff --git a/src-web/hooks/useFolders.ts b/src-web/hooks/useFolders.ts new file mode 100644 index 00000000..e68a4330 --- /dev/null +++ b/src-web/hooks/useFolders.ts @@ -0,0 +1,22 @@ +import { useQuery } from '@tanstack/react-query'; +import { invoke } from '@tauri-apps/api'; +import type { Folder, HttpRequest } from '../lib/models'; +import { useActiveWorkspaceId } from './useActiveWorkspaceId'; + +export function foldersQueryKey({ workspaceId }: { workspaceId: string }) { + return ['folders', { workspaceId }]; +} + +export function useFolders() { + const workspaceId = useActiveWorkspaceId(); + return ( + useQuery({ + enabled: workspaceId != null, + queryKey: foldersQueryKey({ workspaceId: workspaceId ?? 'n/a' }), + queryFn: async () => { + if (workspaceId == null) return []; + return (await invoke('list_folders', { workspaceId })) as Folder[]; + }, + }).data ?? [] + ); +} diff --git a/src-web/lib/models.ts b/src-web/lib/models.ts index d234157e..8d2a191c 100644 --- a/src-web/lib/models.ts +++ b/src-web/lib/models.ts @@ -29,6 +29,14 @@ export interface EnvironmentVariable { enabled?: boolean; } +export interface Folder extends BaseModel { + readonly workspaceId: string; + readonly model: 'folder'; + folderId: string | null; + sortPriority: number; + name: string; +} + export interface Environment extends BaseModel { readonly workspaceId: string; readonly model: 'environment'; @@ -45,6 +53,7 @@ export interface HttpHeader { export interface HttpRequest extends BaseModel { readonly workspaceId: string; readonly model: 'http_request'; + folderId: string | null; sortPriority: number; name: string; url: string;