diff --git a/index.html b/index.html
index 934cca9b..8f77583a 100644
--- a/index.html
+++ b/index.html
@@ -1,17 +1,28 @@
-
-
-
-
- Yaak App
-
-
+
+
+
+
+ Yaak App
+
+
+
+
+
+
+
+
+
+
diff --git a/src-tauri/migrations/20230225181302_init.sql b/src-tauri/migrations/20230225181302_init.sql
index 15f8d1e9..52fa79e7 100644
--- a/src-tauri/migrations/20230225181302_init.sql
+++ b/src-tauri/migrations/20230225181302_init.sql
@@ -1,39 +1,65 @@
+CREATE TABLE key_values
+(
+ model TEXT DEFAULT 'key_value' NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ deleted_at DATETIME,
+ namespace TEXT NOT NULL,
+ key TEXT NOT NULL,
+ value TEXT NOT NULL,
+ PRIMARY KEY (namespace, key)
+);
+
CREATE TABLE workspaces
(
- id TEXT NOT NULL PRIMARY KEY,
- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ id TEXT NOT NULL
+ PRIMARY KEY,
+ model TEXT DEFAULT 'workspace' NOT NULL,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted_at DATETIME,
- name TEXT NOT NULL,
- description TEXT NOT NULL
+ name TEXT NOT NULL,
+ description TEXT NOT NULL
);
CREATE TABLE http_requests
(
- id TEXT NOT NULL PRIMARY KEY,
- workspace_id TEXT NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE,
- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ id TEXT NOT NULL
+ PRIMARY KEY,
+ model TEXT DEFAULT 'http_request' NOT NULL,
+ workspace_id TEXT NOT NULL
+ REFERENCES workspaces
+ ON DELETE CASCADE,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted_at DATETIME,
- name TEXT NOT NULL,
- url TEXT NOT NULL,
- method TEXT NOT NULL,
- headers TEXT NOT NULL,
- body TEXT
+ name TEXT NOT NULL,
+ url TEXT NOT NULL,
+ method TEXT NOT NULL,
+ headers TEXT NOT NULL,
+ body TEXT,
+ body_type TEXT
);
CREATE TABLE http_responses
(
- id TEXT NOT NULL PRIMARY KEY,
- request_id TEXT NOT NULL REFERENCES http_requests (id) ON DELETE CASCADE,
- workspace_id TEXT NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE,
- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ id TEXT NOT NULL
+ PRIMARY KEY,
+ model TEXT DEFAULT 'http_response' NOT NULL,
+ request_id TEXT NOT NULL
+ REFERENCES http_requests
+ ON DELETE CASCADE,
+ workspace_id TEXT NOT NULL
+ REFERENCES workspaces
+ ON DELETE CASCADE,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted_at DATETIME,
- elapsed INTEGER NOT NULL,
- status INTEGER NOT NULL,
+ elapsed INTEGER NOT NULL,
+ status INTEGER NOT NULL,
status_reason TEXT,
- url TEXT NOT NULL,
- body TEXT NOT NULL,
- headers TEXT NOT NULL
+ url TEXT NOT NULL,
+ body TEXT NOT NULL,
+ headers TEXT NOT NULL,
+ error TEXT
);
diff --git a/src-tauri/migrations/20230301163450_add-response-error.sql b/src-tauri/migrations/20230301163450_add-response-error.sql
deleted file mode 100644
index 578d876b..00000000
--- a/src-tauri/migrations/20230301163450_add-response-error.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE http_responses ADD COLUMN error TEXT NULL;
diff --git a/src-tauri/migrations/20230314160400_add-body-type.sql b/src-tauri/migrations/20230314160400_add-body-type.sql
deleted file mode 100644
index 77d27a1b..00000000
--- a/src-tauri/migrations/20230314160400_add-body-type.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE http_requests ADD COLUMN body_type TEXT NULL;
diff --git a/src-tauri/migrations/20230316052652_key-values.sql b/src-tauri/migrations/20230316052652_key-values.sql
deleted file mode 100644
index 54943962..00000000
--- a/src-tauri/migrations/20230316052652_key-values.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE key_values
-(
- model TEXT NOT NULL DEFAULT 'key_value',
- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- deleted_at DATETIME,
- namespace TEXT NOT NULL,
- key TEXT NOT NULL,
- value TEXT NOT NULL,
-
- PRIMARY KEY (namespace, key)
-);
diff --git a/src-tauri/migrations/20230316062901_model-fields.sql b/src-tauri/migrations/20230316062901_model-fields.sql
deleted file mode 100644
index 14ef6f90..00000000
--- a/src-tauri/migrations/20230316062901_model-fields.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE http_responses ADD COLUMN model TEXT DEFAULT 'http_response';
-ALTER TABLE http_requests ADD COLUMN model TEXT DEFAULT 'http_request';
-ALTER TABLE workspaces ADD COLUMN model TEXT DEFAULT 'workspace';
diff --git a/src-tauri/sqlx-data.json b/src-tauri/sqlx-data.json
index b82264b2..7b0bf4fc 100644
--- a/src-tauri/sqlx-data.json
+++ b/src-tauri/sqlx-data.json
@@ -1,6 +1,6 @@
{
"db": "SQLite",
- "032c7a3861630c499f3e9785687be303aa95c023548e170572ad36eba90ecf84": {
+ "06aaf8f4a17566f1d25da2a60f0baf4b5fc28c3cf0c001a84e25edf9eab3c7e3": {
"describe": {
"columns": [
{
@@ -18,24 +18,19 @@
"ordinal": 2,
"type_info": "Datetime"
},
- {
- "name": "deleted_at",
- "ordinal": 3,
- "type_info": "Datetime"
- },
{
"name": "namespace",
- "ordinal": 4,
+ "ordinal": 3,
"type_info": "Text"
},
{
"name": "key",
- "ordinal": 5,
+ "ordinal": 4,
"type_info": "Text"
},
{
"name": "value",
- "ordinal": 6,
+ "ordinal": 5,
"type_info": "Text"
}
],
@@ -43,7 +38,6 @@
false,
false,
false,
- true,
false,
false,
false
@@ -52,7 +46,7 @@
"Right": 2
}
},
- "query": "\n SELECT model, created_at, updated_at, deleted_at, namespace, key, value\n FROM key_values\n WHERE namespace = ? AND key = ?\n "
+ "query": "\n SELECT model, created_at, updated_at, namespace, key, value\n FROM key_values\n WHERE namespace = ? AND key = ?\n "
},
"07d1a1c7b4f3d9625a766e60fd57bb779b71dae30e5bbce34885a911a5a42428": {
"describe": {
@@ -84,7 +78,7 @@
},
"query": "\n DELETE FROM http_requests\n WHERE id = ?\n "
},
- "8423faeb5ce376acffe4c24804e0332c334edf929d9cea0086ee00c108e833fb": {
+ "68b7b17a25d415ce90b33aef16418d668f7ff6275b383bf21c16cafb38cca342": {
"describe": {
"columns": [
{
@@ -103,9 +97,9 @@
"type_info": "Text"
},
{
- "name": "request_id",
+ "name": "created_at",
"ordinal": 3,
- "type_info": "Text"
+ "type_info": "Datetime"
},
{
"name": "updated_at",
@@ -113,48 +107,33 @@
"type_info": "Datetime"
},
{
- "name": "deleted_at",
+ "name": "name",
"ordinal": 5,
- "type_info": "Datetime"
+ "type_info": "Text"
},
{
- "name": "created_at",
+ "name": "url",
"ordinal": 6,
- "type_info": "Datetime"
+ "type_info": "Text"
},
{
- "name": "status",
+ "name": "method",
"ordinal": 7,
- "type_info": "Int64"
- },
- {
- "name": "status_reason",
- "ordinal": 8,
"type_info": "Text"
},
{
"name": "body",
+ "ordinal": 8,
+ "type_info": "Text"
+ },
+ {
+ "name": "body_type",
"ordinal": 9,
"type_info": "Text"
},
{
- "name": "elapsed",
+ "name": "headers!: sqlx::types::Json>",
"ordinal": 10,
- "type_info": "Int64"
- },
- {
- "name": "url",
- "ordinal": 11,
- "type_info": "Text"
- },
- {
- "name": "error",
- "ordinal": 12,
- "type_info": "Text"
- },
- {
- "name": "headers!: sqlx::types::Json>",
- "ordinal": 13,
"type_info": "Text"
}
],
@@ -164,13 +143,10 @@
false,
false,
false,
- true,
+ false,
false,
false,
true,
- false,
- false,
- false,
true,
false
],
@@ -178,7 +154,7 @@
"Right": 1
}
},
- "query": "\n SELECT id, model, workspace_id, request_id, updated_at, deleted_at,\n created_at, status, status_reason, body, elapsed, url, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE request_id = ?\n ORDER BY created_at ASC\n "
+ "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 headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n "
},
"913f3c3a46b1834c4cd8367aed9d5a9659a1d775d8771e9f5bf9a5aa41197356": {
"describe": {
@@ -190,60 +166,6 @@
},
"query": "\n INSERT INTO http_requests (\n id,\n workspace_id,\n name,\n url,\n method,\n body,\n body_type,\n headers\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 url = excluded.url\n "
},
- "9fcbf8317858427b2e75b29ce64deeed1cc77ef22a35463ab65eee89eb25fa02": {
- "describe": {
- "columns": [
- {
- "name": "id",
- "ordinal": 0,
- "type_info": "Text"
- },
- {
- "name": "model",
- "ordinal": 1,
- "type_info": "Text"
- },
- {
- "name": "created_at",
- "ordinal": 2,
- "type_info": "Datetime"
- },
- {
- "name": "updated_at",
- "ordinal": 3,
- "type_info": "Datetime"
- },
- {
- "name": "deleted_at",
- "ordinal": 4,
- "type_info": "Datetime"
- },
- {
- "name": "name",
- "ordinal": 5,
- "type_info": "Text"
- },
- {
- "name": "description",
- "ordinal": 6,
- "type_info": "Text"
- }
- ],
- "nullable": [
- false,
- false,
- false,
- false,
- true,
- false,
- false
- ],
- "parameters": {
- "Right": 1
- }
- },
- "query": "\n SELECT id, model, created_at, updated_at, deleted_at, name, description\n FROM workspaces\n WHERE id = ?\n "
- },
"a83698dcf9a815b881097133edb31a34ba25e7c6c114d463c495342a85371639": {
"describe": {
"columns": [],
@@ -254,7 +176,7 @@
},
"query": "\n UPDATE http_responses SET (elapsed, url, status, status_reason, body, error, headers, updated_at) =\n (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;\n "
},
- "bca6dd1eec0cdf4de57323f7b88e8578ebe44b6c9606e38cbaacc3e0094b434d": {
+ "caf3f21bf291dfbd36446592066e96c1f83abe96f6ea9211a3e049eb9c58a8c8": {
"describe": {
"columns": [
{
@@ -267,54 +189,24 @@
"ordinal": 1,
"type_info": "Text"
},
- {
- "name": "workspace_id",
- "ordinal": 2,
- "type_info": "Text"
- },
{
"name": "created_at",
- "ordinal": 3,
+ "ordinal": 2,
"type_info": "Datetime"
},
{
"name": "updated_at",
- "ordinal": 4,
- "type_info": "Datetime"
- },
- {
- "name": "deleted_at",
- "ordinal": 5,
+ "ordinal": 3,
"type_info": "Datetime"
},
{
"name": "name",
- "ordinal": 6,
+ "ordinal": 4,
"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": "headers!: sqlx::types::Json>",
- "ordinal": 11,
+ "name": "description",
+ "ordinal": 5,
"type_info": "Text"
}
],
@@ -324,31 +216,63 @@
false,
false,
false,
- true,
- false,
- false,
- false,
- true,
- true,
false
],
"parameters": {
"Right": 1
}
},
- "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n deleted_at,\n name,\n url,\n method,\n body,\n body_type,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n "
+ "query": "\n SELECT id, model, created_at, updated_at, name, description\n FROM workspaces WHERE id = ?\n "
},
- "d80c09497771e3641022e73ec6c6a87e73a551f88a948a5445d754922b82b50b": {
+ "cea4cae52f16ec78aca9a47b17117422d4f165e5a3b308c70fd1a180382475ea": {
"describe": {
- "columns": [],
- "nullable": [],
+ "columns": [
+ {
+ "name": "id",
+ "ordinal": 0,
+ "type_info": "Text"
+ },
+ {
+ "name": "model",
+ "ordinal": 1,
+ "type_info": "Text"
+ },
+ {
+ "name": "created_at",
+ "ordinal": 2,
+ "type_info": "Datetime"
+ },
+ {
+ "name": "updated_at",
+ "ordinal": 3,
+ "type_info": "Datetime"
+ },
+ {
+ "name": "name",
+ "ordinal": 4,
+ "type_info": "Text"
+ },
+ {
+ "name": "description",
+ "ordinal": 5,
+ "type_info": "Text"
+ }
+ ],
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ ],
"parameters": {
- "Right": 3
+ "Right": 0
}
},
- "query": "\n INSERT INTO key_values (namespace, key, value)\n VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n value = excluded.value\n "
+ "query": "\n SELECT id, model, created_at, updated_at, name, description\n FROM workspaces\n "
},
- "d9b614f9f0de223474464e0a30e663f6f4467f85d6f6abaacd8b76d9289ba38f": {
+ "d5ad6d5f82fe837fa9215bd4619ec18a7c95b3088d4fbf9825f2d1d28069d1ce": {
"describe": {
"columns": [
{
@@ -377,48 +301,43 @@
"type_info": "Datetime"
},
{
- "name": "deleted_at",
+ "name": "created_at",
"ordinal": 5,
"type_info": "Datetime"
},
- {
- "name": "created_at",
- "ordinal": 6,
- "type_info": "Datetime"
- },
{
"name": "status",
- "ordinal": 7,
+ "ordinal": 6,
"type_info": "Int64"
},
{
"name": "status_reason",
- "ordinal": 8,
+ "ordinal": 7,
"type_info": "Text"
},
{
"name": "body",
- "ordinal": 9,
+ "ordinal": 8,
"type_info": "Text"
},
{
"name": "elapsed",
- "ordinal": 10,
+ "ordinal": 9,
"type_info": "Int64"
},
{
"name": "url",
- "ordinal": 11,
+ "ordinal": 10,
"type_info": "Text"
},
{
"name": "error",
- "ordinal": 12,
+ "ordinal": 11,
"type_info": "Text"
},
{
"name": "headers!: sqlx::types::Json>",
- "ordinal": 13,
+ "ordinal": 12,
"type_info": "Text"
}
],
@@ -428,7 +347,6 @@
false,
false,
false,
- true,
false,
false,
true,
@@ -442,73 +360,19 @@
"Right": 1
}
},
- "query": "\n SELECT id, model, workspace_id, request_id, updated_at, deleted_at, created_at,\n status, status_reason, body, elapsed, url, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE id = ?\n "
+ "query": "\n SELECT id, model, workspace_id, request_id, updated_at,\n created_at, status, status_reason, body, elapsed, url, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE request_id = ?\n ORDER BY created_at ASC\n "
},
- "e767522f92c8c49cd2e563e58737a05092daf9b1dc763bacc82a5c14d696d78e": {
+ "d80c09497771e3641022e73ec6c6a87e73a551f88a948a5445d754922b82b50b": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
- "Right": 9
+ "Right": 3
}
},
- "query": "\n INSERT INTO http_responses (id, request_id, workspace_id, elapsed, url, status, status_reason, body, headers)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);\n "
+ "query": "\n INSERT INTO key_values (namespace, key, value)\n VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n value = excluded.value\n "
},
- "eb7b10c632c871122d9e50cacba1f52604c366d888f014ac7f0a2642dbd27839": {
- "describe": {
- "columns": [
- {
- "name": "id",
- "ordinal": 0,
- "type_info": "Text"
- },
- {
- "name": "model",
- "ordinal": 1,
- "type_info": "Text"
- },
- {
- "name": "created_at",
- "ordinal": 2,
- "type_info": "Datetime"
- },
- {
- "name": "updated_at",
- "ordinal": 3,
- "type_info": "Datetime"
- },
- {
- "name": "deleted_at",
- "ordinal": 4,
- "type_info": "Datetime"
- },
- {
- "name": "name",
- "ordinal": 5,
- "type_info": "Text"
- },
- {
- "name": "description",
- "ordinal": 6,
- "type_info": "Text"
- }
- ],
- "nullable": [
- false,
- false,
- false,
- false,
- true,
- false,
- false
- ],
- "parameters": {
- "Right": 0
- }
- },
- "query": "\n SELECT id, model, created_at, updated_at, deleted_at, name, description\n FROM workspaces\n "
- },
- "eda13351c05e67885a71a1b9fc7f2d0641d94ca5f4be824d4a0edad5f1ec657e": {
+ "d9ea350bc21ac2f51f6dcb9713328ec330f0e12105da70bf5a6eff9601e32a85": {
"describe": {
"columns": [
{
@@ -536,39 +400,34 @@
"ordinal": 4,
"type_info": "Datetime"
},
- {
- "name": "deleted_at",
- "ordinal": 5,
- "type_info": "Datetime"
- },
{
"name": "name",
- "ordinal": 6,
+ "ordinal": 5,
"type_info": "Text"
},
{
"name": "url",
- "ordinal": 7,
+ "ordinal": 6,
"type_info": "Text"
},
{
"name": "method",
- "ordinal": 8,
+ "ordinal": 7,
"type_info": "Text"
},
{
"name": "body",
- "ordinal": 9,
+ "ordinal": 8,
"type_info": "Text"
},
{
"name": "body_type",
- "ordinal": 10,
+ "ordinal": 9,
"type_info": "Text"
},
{
"name": "headers!: sqlx::types::Json>",
- "ordinal": 11,
+ "ordinal": 10,
"type_info": "Text"
}
],
@@ -578,7 +437,6 @@
false,
false,
false,
- true,
false,
false,
false,
@@ -590,7 +448,107 @@
"Right": 1
}
},
- "query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n deleted_at,\n name,\n url,\n method,\n body,\n body_type,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE workspace_id = ?\n "
+ "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 headers AS \"headers!: sqlx::types::Json>\"\n FROM http_requests\n WHERE id = ?\n "
+ },
+ "e3ade0a69348d512e47e964bded9d7d890b92fdc1e01c6c22fa5e91f943639f2": {
+ "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": "request_id",
+ "ordinal": 3,
+ "type_info": "Text"
+ },
+ {
+ "name": "updated_at",
+ "ordinal": 4,
+ "type_info": "Datetime"
+ },
+ {
+ "name": "created_at",
+ "ordinal": 5,
+ "type_info": "Datetime"
+ },
+ {
+ "name": "status",
+ "ordinal": 6,
+ "type_info": "Int64"
+ },
+ {
+ "name": "status_reason",
+ "ordinal": 7,
+ "type_info": "Text"
+ },
+ {
+ "name": "body",
+ "ordinal": 8,
+ "type_info": "Text"
+ },
+ {
+ "name": "elapsed",
+ "ordinal": 9,
+ "type_info": "Int64"
+ },
+ {
+ "name": "url",
+ "ordinal": 10,
+ "type_info": "Text"
+ },
+ {
+ "name": "error",
+ "ordinal": 11,
+ "type_info": "Text"
+ },
+ {
+ "name": "headers!: sqlx::types::Json>",
+ "ordinal": 12,
+ "type_info": "Text"
+ }
+ ],
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ false
+ ],
+ "parameters": {
+ "Right": 1
+ }
+ },
+ "query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at,\n status, status_reason, body, elapsed, url, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE id = ?\n "
+ },
+ "e767522f92c8c49cd2e563e58737a05092daf9b1dc763bacc82a5c14d696d78e": {
+ "describe": {
+ "columns": [],
+ "nullable": [],
+ "parameters": {
+ "Right": 9
+ }
+ },
+ "query": "\n INSERT INTO http_responses (id, request_id, workspace_id, elapsed, url, status, status_reason, body, headers)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);\n "
},
"f116d8cf9aad828135bb8c3a4c8b8e6b857ae13303989e9133a33b2d1cf20e96": {
"describe": {
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index d1bb0b6c..f0cff84d 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -354,7 +354,7 @@ async fn workspaces(
.await
.expect("Failed to find workspaces");
if workspaces.is_empty() {
- let workspace = models::create_workspace("Default", "This is the default workspace", pool)
+ let workspace = models::create_workspace("My Project", "This is the default workspace", pool)
.await
.expect("Failed to create workspace");
Ok(vec![workspace])
diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs
index 33fd6583..4c5ed8bc 100644
--- a/src-tauri/src/models.rs
+++ b/src-tauri/src/models.rs
@@ -11,7 +11,6 @@ pub struct Workspace {
pub model: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
- pub deleted_at: Option,
pub name: String,
pub description: String,
}
@@ -30,7 +29,6 @@ pub struct HttpRequest {
pub model: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
- pub deleted_at: Option,
pub workspace_id: String,
pub name: String,
pub url: String,
@@ -56,7 +54,6 @@ pub struct HttpResponse {
pub request_id: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
- pub deleted_at: Option,
pub error: Option,
pub url: String,
pub elapsed: i64,
@@ -72,7 +69,6 @@ pub struct KeyValue {
pub model: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
- pub deleted_at: Option,
pub namespace: String,
pub key: String,
pub value: String,
@@ -106,7 +102,7 @@ pub async fn get_key_value(namespace: &str, key: &str, pool: &Pool) -> O
sqlx::query_as!(
KeyValue,
r#"
- SELECT model, created_at, updated_at, deleted_at, namespace, key, value
+ SELECT model, created_at, updated_at, namespace, key, value
FROM key_values
WHERE namespace = ? AND key = ?
"#,
@@ -122,7 +118,7 @@ pub async fn find_workspaces(pool: &Pool) -> Result, sqlx
sqlx::query_as!(
Workspace,
r#"
- SELECT id, model, created_at, updated_at, deleted_at, name, description
+ SELECT id, model, created_at, updated_at, name, description
FROM workspaces
"#,
)
@@ -134,9 +130,8 @@ pub async fn get_workspace(id: &str, pool: &Pool) -> Result) -> Result) -> Result>"
FROM http_responses
@@ -380,7 +373,7 @@ pub async fn find_responses(
sqlx::query_as!(
HttpResponse,
r#"
- SELECT id, model, workspace_id, request_id, updated_at, deleted_at,
+ SELECT id, model, workspace_id, request_id, updated_at,
created_at, status, status_reason, body, elapsed, url, error,
headers AS "headers!: sqlx::types::Json>"
FROM http_responses
diff --git a/src-web/components/App.tsx b/src-web/components/App.tsx
index af0dbe9c..dd7f2c98 100644
--- a/src-web/components/App.tsx
+++ b/src-web/components/App.tsx
@@ -5,10 +5,11 @@ import { listen } from '@tauri-apps/api/event';
import { MotionConfig } from 'framer-motion';
import { HelmetProvider } from 'react-helmet-async';
import { matchPath } from 'react-router-dom';
-import { keyValueQueryKey } from '../hooks/useKeyValues';
+import { keyValueQueryKey } from '../hooks/useKeyValue';
import { requestsQueryKey } from '../hooks/useRequests';
import { responsesQueryKey } from '../hooks/useResponses';
import { DEFAULT_FONT_SIZE } from '../lib/constants';
+import { extractKeyValue } from '../lib/keyValueStore';
import type { HttpRequest, HttpResponse, KeyValue } from '../lib/models';
import { convertDates } from '../lib/models';
import { AppRouter, WORKSPACE_REQUEST_PATH } from './AppRouter';
@@ -16,7 +17,7 @@ import { AppRouter, WORKSPACE_REQUEST_PATH } from './AppRouter';
const queryClient = new QueryClient();
await listen('updated_key_value', ({ payload: keyValue }: { payload: KeyValue }) => {
- queryClient.setQueryData(keyValueQueryKey(keyValue), keyValue);
+ queryClient.setQueryData(keyValueQueryKey(keyValue), extractKeyValue(keyValue));
});
await listen('updated_request', ({ payload: request }: { payload: HttpRequest }) => {
diff --git a/src-web/components/RequestPane.tsx b/src-web/components/RequestPane.tsx
index 9fe6ed3c..e7d39653 100644
--- a/src-web/components/RequestPane.tsx
+++ b/src-web/components/RequestPane.tsx
@@ -1,7 +1,8 @@
import classnames from 'classnames';
+import { act } from 'react-dom/test-utils';
import { useActiveRequest } from '../hooks/useActiveRequest';
import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
-import { useKeyValues } from '../hooks/useKeyValues';
+import { useKeyValue } from '../hooks/useKeyValue';
import { useSendRequest } from '../hooks/useSendRequest';
import { useUpdateRequest } from '../hooks/useUpdateRequest';
import { tryFormatJson } from '../lib/formatters';
@@ -21,7 +22,7 @@ export function RequestPane({ fullHeight, className }: Props) {
const updateRequest = useUpdateRequest(activeRequest);
const sendRequest = useSendRequest(activeRequest);
const responseLoading = useIsResponseLoading();
- const activeTab = useKeyValues({
+ const activeTab = useKeyValue({
key: ['active_request_body_tab', activeRequest?.id ?? 'n/a'],
initialValue: 'body',
});
@@ -61,7 +62,6 @@ export function RequestPane({ fullHeight, className }: Props) {
{ value: 'auth', label: 'Auth' },
]}
className="mt-2"
- defaultValue="body"
label="Request body"
>
diff --git a/src-web/components/Sidebar.tsx b/src-web/components/Sidebar.tsx
index 2cc0a912..eb9550a9 100644
--- a/src-web/components/Sidebar.tsx
+++ b/src-web/components/Sidebar.tsx
@@ -3,10 +3,11 @@ import React, { useRef, useState } from 'react';
import { useActiveRequest } from '../hooks/useActiveRequest';
import { useCreateRequest } from '../hooks/useCreateRequest';
import { useDeleteRequest } from '../hooks/useDeleteRequest';
-import { useKeyValues } from '../hooks/useKeyValues';
+import { useKeyValue } from '../hooks/useKeyValue';
import { useRequests } from '../hooks/useRequests';
import { useTheme } from '../hooks/useTheme';
import { useUpdateRequest } from '../hooks/useUpdateRequest';
+import { clamp } from '../lib/clamp';
import type { HttpRequest } from '../lib/models';
import { Button } from './core/Button';
import { Dropdown, DropdownMenuTrigger } from './core/Dropdown';
@@ -19,11 +20,12 @@ interface Props {
className?: string;
}
-const MIN_WIDTH = 130;
+const MIN_WIDTH = 110;
+const MAX_WIDTH = 500;
export function Sidebar({ className }: Props) {
const [isDragging, setIsDragging] = useState(false);
- const width = useKeyValues({ key: 'sidebar_width', initialValue: 200 });
+ const width = useKeyValue({ key: 'sidebar_width', initialValue: 200 });
const requests = useRequests();
const activeRequest = useActiveRequest();
const createRequest = useCreateRequest({ navigateAfter: true });
@@ -43,7 +45,7 @@ export function Sidebar({ className }: Props) {
const startWidth = width.value;
moveState.current = {
move: (e: MouseEvent) => {
- const newWidth = Math.max(MIN_WIDTH, startWidth + (e.clientX - mouseStartX));
+ const newWidth = clamp(startWidth + (e.clientX - mouseStartX), MIN_WIDTH, MAX_WIDTH);
width.set(newWidth);
},
up: () => {
@@ -73,8 +75,8 @@ export function Sidebar({ className }: Props) {
>
diff --git a/src-web/components/core/Tabs/Tabs.tsx b/src-web/components/core/Tabs/Tabs.tsx
index f61078dc..d3212261 100644
--- a/src-web/components/core/Tabs/Tabs.tsx
+++ b/src-web/components/core/Tabs/Tabs.tsx
@@ -10,7 +10,6 @@ import { HStack } from '../Stacks';
import './Tabs.css';
interface Props {
- defaultValue?: string;
label: string;
onChangeValue: (value: string) => void;
value: string;
@@ -31,7 +30,6 @@ interface Props {
export function Tabs({
value,
onChangeValue,
- defaultValue,
label,
children,
tabs,
@@ -40,7 +38,7 @@ export function Tabs({
}: Props) {
return (
diff --git a/src-web/hooks/useIsResponseLoading.ts b/src-web/hooks/useIsResponseLoading.ts
index bca79c5c..dbbc69b6 100644
--- a/src-web/hooks/useIsResponseLoading.ts
+++ b/src-web/hooks/useIsResponseLoading.ts
@@ -4,5 +4,5 @@ export function useIsResponseLoading(): boolean {
const responses = useResponses();
const response = responses[responses.length - 1];
if (!response) return false;
- return !(response.body || response.error);
+ return !(response.body || response.status || response.error);
}
diff --git a/src-web/hooks/useKeyValue.ts b/src-web/hooks/useKeyValue.ts
new file mode 100644
index 00000000..9ebf5885
--- /dev/null
+++ b/src-web/hooks/useKeyValue.ts
@@ -0,0 +1,39 @@
+import { useMutation, useQuery } from '@tanstack/react-query';
+import { buildKeyValueKey, getKeyValue, setKeyValue } from '../lib/keyValueStore';
+
+const DEFAULT_NAMESPACE = 'app';
+
+export function keyValueQueryKey({
+ namespace = DEFAULT_NAMESPACE,
+ key,
+}: {
+ namespace?: string;
+ key: string | string[];
+}) {
+ return ['key_value', { namespace, key: buildKeyValueKey(key) }];
+}
+
+export function useKeyValue({
+ namespace = DEFAULT_NAMESPACE,
+ key,
+ initialValue,
+}: {
+ namespace?: string;
+ key: string | string[];
+ initialValue: T;
+}) {
+ const query = useQuery({
+ initialData: initialValue,
+ queryKey: keyValueQueryKey({ namespace, key }),
+ queryFn: async () => getKeyValue({ namespace, key, fallback: initialValue }),
+ });
+
+ const mutate = useMutation({
+ mutationFn: (value) => setKeyValue({ namespace, key, value }),
+ });
+
+ return {
+ value: query.data,
+ set: (value: T) => mutate.mutate(value),
+ };
+}
diff --git a/src-web/hooks/useKeyValues.ts b/src-web/hooks/useKeyValues.ts
deleted file mode 100644
index 86e7294a..00000000
--- a/src-web/hooks/useKeyValues.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { useMutation, useQuery } from '@tanstack/react-query';
-import { invoke } from '@tauri-apps/api';
-import type { KeyValue } from '../lib/models';
-
-const DEFAULT_NAMESPACE = 'app';
-
-export function keyValueQueryKey({
- namespace = DEFAULT_NAMESPACE,
- key,
-}: {
- namespace?: string;
- key: string | string[];
-}) {
- return ['key_value', { namespace, key: buildKey(key) }];
-}
-
-export function useKeyValues({
- namespace = DEFAULT_NAMESPACE,
- key,
- initialValue,
-}: {
- namespace?: string;
- key: string | string[];
- initialValue: T;
-}) {
- const query = useQuery({
- initialData: null,
- queryKey: keyValueQueryKey({ namespace, key }),
- queryFn: async () => invoke('get_key_value', { namespace, key: buildKey(key) }),
- });
-
- const mutate = useMutation({
- mutationFn: (value) => {
- return invoke('set_key_value', {
- namespace,
- key: buildKey(key),
- value: JSON.stringify(value),
- });
- },
- });
-
- let value: T;
- try {
- value = JSON.parse(query.data?.value ?? JSON.stringify(initialValue));
- } catch (e) {
- value = initialValue;
- }
- return {
- value,
- set: (value: T) => mutate.mutate(value),
- };
-}
-
-function buildKey(key: string | string[]): string {
- if (typeof key === 'string') return key;
- return key.join('::');
-}
diff --git a/src-web/hooks/useResponseViewMode.ts b/src-web/hooks/useResponseViewMode.ts
index 3c434d30..6a03369f 100644
--- a/src-web/hooks/useResponseViewMode.ts
+++ b/src-web/hooks/useResponseViewMode.ts
@@ -1,7 +1,7 @@
-import { useKeyValues } from './useKeyValues';
+import { useKeyValue } from './useKeyValue';
export function useResponseViewMode(requestId?: string): [string, () => void] {
- const v = useKeyValues({
+ const v = useKeyValue({
namespace: 'app',
key: ['response_view_mode', requestId ?? 'n/a'],
initialValue: 'pretty',
diff --git a/src-web/hooks/useTheme.ts b/src-web/hooks/useTheme.ts
index 8d96fd42..de47c89e 100644
--- a/src-web/hooks/useTheme.ts
+++ b/src-web/hooks/useTheme.ts
@@ -1,3 +1,4 @@
+import { app } from '@tauri-apps/api';
import { useEffect } from 'react';
import type { Appearance } from '../lib/theme/window';
import {
@@ -5,10 +6,13 @@ import {
setAppearance,
subscribeToPreferredAppearanceChange,
} from '../lib/theme/window';
-import { useKeyValues } from './useKeyValues';
+import { useKeyValue } from './useKeyValue';
export function useTheme() {
- const appearanceKv = useKeyValues({ key: 'appearance', initialValue: getAppearance() });
+ const appearanceKv = useKeyValue({
+ key: 'appearance',
+ initialValue: getAppearance(),
+ });
const themeChange = (appearance: Appearance) => {
appearanceKv.set(appearance);
@@ -22,7 +26,7 @@ export function useTheme() {
useEffect(() => subscribeToPreferredAppearanceChange(themeChange), []);
// Sync appearance when k/v changes
- useEffect(() => setAppearance(appearanceKv.value as Appearance), [appearanceKv.value]);
+ useEffect(() => setAppearance(appearanceKv.value), [appearanceKv.value]);
return {
appearance: appearanceKv.value,
diff --git a/src-web/hooks/useWorkspaces.ts b/src-web/hooks/useWorkspaces.ts
index bb882b28..051541a7 100644
--- a/src-web/hooks/useWorkspaces.ts
+++ b/src-web/hooks/useWorkspaces.ts
@@ -6,6 +6,7 @@ import { useQuery } from '@tanstack/react-query';
export function useWorkspaces() {
return (
useQuery(['workspaces'], async () => {
+ console.log('INVOKING WORKSPACES');
const workspaces = (await invoke('workspaces')) as Workspace[];
return workspaces.map(convertDates);
}).data ?? []
diff --git a/src-web/lib/clamp.ts b/src-web/lib/clamp.ts
new file mode 100644
index 00000000..0210f95e
--- /dev/null
+++ b/src-web/lib/clamp.ts
@@ -0,0 +1,3 @@
+export function clamp(value: number, min: number, max: number): number {
+ return Math.min(Math.max(value, min), max);
+}
diff --git a/src-web/lib/keyValueStore.ts b/src-web/lib/keyValueStore.ts
new file mode 100644
index 00000000..329089b4
--- /dev/null
+++ b/src-web/lib/keyValueStore.ts
@@ -0,0 +1,62 @@
+import { invoke } from '@tauri-apps/api';
+import type { KeyValue } from './models';
+
+const DEFAULT_NAMESPACE = 'app';
+
+type KeyValueValue = string | number | boolean;
+
+export async function setKeyValue({
+ namespace = DEFAULT_NAMESPACE,
+ key,
+ value,
+}: {
+ namespace?: string;
+ key: string | string[];
+ value: T;
+}): Promise {
+ await invoke('set_key_value', {
+ namespace,
+ key: buildKeyValueKey(key),
+ value: JSON.stringify(value),
+ });
+ return value;
+}
+
+export async function getKeyValue({
+ namespace = DEFAULT_NAMESPACE,
+ key,
+ fallback,
+}: {
+ namespace?: string;
+ key: string | string[];
+ fallback: T;
+}) {
+ const kv = (await invoke('get_key_value', {
+ namespace,
+ key: buildKeyValueKey(key),
+ })) as KeyValue | null;
+ return extractKeyValueOrFallback(kv, fallback);
+}
+
+export function extractKeyValue(kv: KeyValue | null): T | undefined {
+ if (kv === null) return undefined;
+ try {
+ return JSON.parse(kv.value) as T;
+ } catch (err) {
+ return undefined;
+ }
+}
+
+export function extractKeyValueOrFallback(
+ kv: KeyValue | null,
+ fallback: T,
+): T {
+ const v = extractKeyValue(kv);
+ if (v === undefined) return fallback;
+ return v;
+}
+
+export function buildKeyValueKey(key: string | string[]): string {
+ if (typeof key === 'string') return key;
+ return key.join('::');
+}
diff --git a/src-web/lib/models.ts b/src-web/lib/models.ts
index 30b77f46..4d361938 100644
--- a/src-web/lib/models.ts
+++ b/src-web/lib/models.ts
@@ -3,7 +3,6 @@ export interface BaseModel {
readonly workspaceId: string;
readonly createdAt: Date;
readonly updatedAt: Date;
- readonly deletedAt: Date | null;
}
export interface Workspace extends BaseModel {
@@ -46,14 +45,11 @@ export interface HttpResponse extends BaseModel {
readonly headers: HttpHeader[];
}
-export function convertDates>(
- m: T,
-): T {
+export function convertDates>(m: T): T {
return {
...m,
createdAt: convertDate(m.createdAt),
updatedAt: convertDate(m.updatedAt),
- deletedAt: m.deletedAt ? convertDate(m.deletedAt) : null,
};
}
diff --git a/src-web/main.tsx b/src-web/main.tsx
index 87f9b0d7..d6d8f379 100644
--- a/src-web/main.tsx
+++ b/src-web/main.tsx
@@ -1,17 +1,11 @@
-import { invoke } from '@tauri-apps/api';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './components/App';
-import type { KeyValue } from './lib/models';
-import type { Appearance } from './lib/theme/window';
+import { getKeyValue } from './lib/keyValueStore';
import { getPreferredAppearance, setAppearance } from './lib/theme/window';
import './main.css';
-const appearance: KeyValue = await invoke('get_key_value', {
- namespace: 'app',
- key: 'appearance',
-});
-setAppearance((appearance?.value ?? getPreferredAppearance()) as Appearance);
+setAppearance(await getKeyValue({ key: 'appearance', fallback: getPreferredAppearance() }));
// root holds our app's root DOM Element:
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(