mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-31 06:23:08 +02:00
Variables under Environment, and render all props
This commit is contained in:
2
src-tauri/migrations/20231028161007_variables.sql
Normal file
2
src-tauri/migrations/20231028161007_variables.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE environments DROP COLUMN data;
|
||||||
|
ALTER TABLE environments ADD COLUMN variables DEFAULT '[]' NOT NULL;
|
||||||
@@ -160,6 +160,16 @@
|
|||||||
},
|
},
|
||||||
"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<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE workspace_id = ?\n ORDER BY created_at DESC\n "
|
"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<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE workspace_id = ?\n ORDER BY created_at DESC\n "
|
||||||
},
|
},
|
||||||
|
"3ec4710d28a7f38608c96798d971217ac97788bcb639089d0c5750c0d339bc9a": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n UPDATE environments\n SET (name, variables, updated_at) = (?, ?, CURRENT_TIMESTAMP)\n WHERE id = ?;\n "
|
||||||
|
},
|
||||||
"448a1d1f1866ab42c0f81fcf8eb2930bf21dfdd43ca4831bc1a198cf45ac3732": {
|
"448a1d1f1866ab42c0f81fcf8eb2930bf21dfdd43ca4831bc1a198cf45ac3732": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -282,6 +292,60 @@
|
|||||||
},
|
},
|
||||||
"query": "\n UPDATE http_responses SET (\n elapsed,\n url,\n status,\n status_reason,\n content_length,\n body,\n body_path,\n error,\n headers,\n updated_at\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;\n "
|
"query": "\n UPDATE http_responses SET (\n elapsed,\n url,\n status,\n status_reason,\n content_length,\n body,\n body_path,\n error,\n headers,\n updated_at\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;\n "
|
||||||
},
|
},
|
||||||
|
"689bcc92b914f50c14921faa796c07a256deb84c832fc3d90200b393fb159417": {
|
||||||
|
"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": "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "Null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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<Vec<EnvironmentVariable>>\"\n FROM environments\n WHERE id = ?\n "
|
||||||
|
},
|
||||||
"6f0cb5a6d1e8dbc8cdfcc3c7e7944b2c83c22cb795b9d6b98fe067dabec9680b": {
|
"6f0cb5a6d1e8dbc8cdfcc3c7e7944b2c83c22cb795b9d6b98fe067dabec9680b": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -378,16 +442,6 @@
|
|||||||
},
|
},
|
||||||
"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<HashMap<String, JsonValue>>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpRequestHeader>>\"\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 authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n authentication_type,\n sort_priority,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpRequestHeader>>\"\n FROM http_requests\n WHERE workspace_id = ?\n "
|
||||||
},
|
},
|
||||||
"6f12b56113b09966b472431b6cb95c354bea51b4dfb22a96517655c0fca0ab05": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n UPDATE environments\n SET (name, data, updated_at) = (?, ?, CURRENT_TIMESTAMP)\n WHERE id = ?;\n "
|
|
||||||
},
|
|
||||||
"84be2b954870ab181738656ecd4d03fca2ff21012947014c79626abfce8e999b": {
|
"84be2b954870ab181738656ecd4d03fca2ff21012947014c79626abfce8e999b": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -398,6 +452,16 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM workspaces\n WHERE id = ?\n "
|
"query": "\n DELETE FROM workspaces\n WHERE id = ?\n "
|
||||||
},
|
},
|
||||||
|
"86e32d6a6fadf35436f19b577a659c203a8d143cb3a8d6122951c5bf54a0888d": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n INSERT INTO environments (id, workspace_id, name, variables)\n VALUES (?, ?, ?, ?)\n "
|
||||||
|
},
|
||||||
"8947a2a90478277c42fe9b06bc1fa98197642a4d281a3dbc101be2c9c1fec36c": {
|
"8947a2a90478277c42fe9b06bc1fa98197642a4d281a3dbc101be2c9c1fec36c": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -408,7 +472,27 @@
|
|||||||
},
|
},
|
||||||
"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 "
|
"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 "
|
||||||
},
|
},
|
||||||
"986763e31599881f287ef378002fc35d8e983af10a30a9aa4ade606dacf83260": {
|
"aeb0712785a9964d516dc8939bc54aa8206ad852e608b362d014b67a0f21b0ed": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -442,9 +526,9 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "data!: Json<HashMap<String, JsonValue>>",
|
"name": "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>",
|
||||||
"ordinal": 6,
|
"ordinal": 6,
|
||||||
"type_info": "Text"
|
"type_info": "Null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"nullable": [
|
"nullable": [
|
||||||
@@ -460,37 +544,7 @@
|
|||||||
"Right": 1
|
"Right": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "\n SELECT id, workspace_id, model, created_at, updated_at, name,\n data AS \"data!: Json<HashMap<String, JsonValue>>\"\n FROM environments\n WHERE workspace_id = ?\n "
|
"query": "\n SELECT id, workspace_id, model, created_at, updated_at, name,\n variables AS \"variables!: sqlx::types::Json<Vec<EnvironmentVariable>>\"\n FROM environments\n WHERE workspace_id = ?\n "
|
||||||
},
|
|
||||||
"ab7294b681f1202ef06aaa26885147ead2db6ac740023793cda1e1c92665d996": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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": [],
|
|
||||||
"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 "
|
|
||||||
},
|
},
|
||||||
"c23c61b05a4c9e04ab0c1fc2c579d6f2a82a37aeed8addf9861b4985f2a5422e": {
|
"c23c61b05a4c9e04ab0c1fc2c579d6f2a82a37aeed8addf9861b4985f2a5422e": {
|
||||||
"describe": {
|
"describe": {
|
||||||
@@ -815,59 +869,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "\n INSERT INTO workspaces (id, name, description)\n VALUES (?, ?, ?)\n "
|
"query": "\n INSERT INTO workspaces (id, name, description)\n VALUES (?, ?, ?)\n "
|
||||||
},
|
|
||||||
"fb89f653780b3f3ab0dd0bb2af30c8d3945203819cb9df7bdd331df56a6ae690": {
|
|
||||||
"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": "data!: Json<HashMap<String, JsonValue>>",
|
|
||||||
"ordinal": 6,
|
|
||||||
"type_info": "Text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n SELECT\n id,\n model,\n workspace_id,\n created_at,\n updated_at,\n name,\n data AS \"data!: Json<HashMap<String, JsonValue>>\"\n FROM environments\n WHERE id = ?\n "
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ use reqwest::redirect::Policy;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::migrate::Migrator;
|
||||||
use sqlx::sqlite::SqlitePoolOptions;
|
use sqlx::sqlite::SqlitePoolOptions;
|
||||||
use sqlx::types::{Json, JsonValue};
|
use sqlx::types::Json;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
@@ -81,14 +81,10 @@ async fn actually_send_ephemeral_request(
|
|||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<models::HttpResponse, String> {
|
) -> Result<models::HttpResponse, String> {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let environment = models::get_environment(environment_id, pool).await.ok();
|
let environment = models::get_environment(environment_id, pool).await.ok();
|
||||||
|
let environment_ref = environment.as_ref();
|
||||||
|
|
||||||
// TODO: Use active environment
|
let mut url_string = render::render(&request.url, environment.as_ref());
|
||||||
let mut url_string = match environment {
|
|
||||||
Some(e) => render::render(&request.url, e.clone()),
|
|
||||||
None => request.url.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if !url_string.starts_with("http://") && !url_string.starts_with("https://") {
|
if !url_string.starts_with("http://") && !url_string.starts_with("https://") {
|
||||||
url_string = format!("http://{}", url_string);
|
url_string = format!("http://{}", url_string);
|
||||||
@@ -110,57 +106,54 @@ async fn actually_send_ephemeral_request(
|
|||||||
if h.name.is_empty() && h.value.is_empty() {
|
if h.name.is_empty() && h.value.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !h.enabled {
|
if !h.enabled {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let header_name = match HeaderName::from_bytes(h.name.as_bytes()) {
|
|
||||||
|
let name = render::render(&h.name, environment_ref);
|
||||||
|
let value = render::render(&h.value, environment_ref);
|
||||||
|
|
||||||
|
let header_name = match HeaderName::from_bytes(name.as_bytes()) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to create header name: {}", e);
|
eprintln!("Failed to create header name: {}", e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let header_value = match HeaderValue::from_str(h.value.as_str()) {
|
let header_value = match HeaderValue::from_str(value.as_str()) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to create header value: {}", e);
|
eprintln!("Failed to create header value: {}", e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
headers.insert(header_name, header_value);
|
headers.insert(header_name, header_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(b) = &request.authentication_type {
|
if let Some(b) = &request.authentication_type {
|
||||||
let empty_value = &serde_json::to_value("").unwrap();
|
let empty_value = &serde_json::to_value("").unwrap();
|
||||||
|
let a = request.authentication.0;
|
||||||
|
|
||||||
if b == "basic" {
|
if b == "basic" {
|
||||||
let a = request.authentication.0;
|
let raw_username = a.get("username").unwrap_or(empty_value).as_str().unwrap_or("");
|
||||||
let auth = format!(
|
let raw_password = a.get("password").unwrap_or(empty_value).as_str().unwrap_or("");
|
||||||
"{}:{}",
|
let username = render::render(raw_username, environment_ref);
|
||||||
a.get("username")
|
let password = render::render(raw_password, environment_ref);
|
||||||
.unwrap_or(empty_value)
|
|
||||||
.as_str()
|
let auth = format!( "{username}:{password}");
|
||||||
.unwrap_or(""),
|
|
||||||
a.get("password")
|
|
||||||
.unwrap_or(empty_value)
|
|
||||||
.as_str()
|
|
||||||
.unwrap_or(""),
|
|
||||||
);
|
|
||||||
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
|
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
|
||||||
headers.insert(
|
headers.insert(
|
||||||
"Authorization",
|
"Authorization",
|
||||||
HeaderValue::from_str(&format!("Basic {}", encoded)).unwrap(),
|
HeaderValue::from_str(&format!("Basic {}", encoded)).unwrap(),
|
||||||
);
|
);
|
||||||
} else if b == "bearer" {
|
} else if b == "bearer" {
|
||||||
let token = request
|
let raw_token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
|
||||||
.authentication
|
let token = render::render(raw_token, environment_ref);
|
||||||
.0
|
|
||||||
.get("token")
|
|
||||||
.unwrap_or(empty_value)
|
|
||||||
.as_str()
|
|
||||||
.unwrap_or("");
|
|
||||||
headers.insert(
|
headers.insert(
|
||||||
"Authorization",
|
"Authorization",
|
||||||
HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
|
HeaderValue::from_str(&format!("Bearer {token}")).unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,7 +163,10 @@ async fn actually_send_ephemeral_request(
|
|||||||
let builder = client.request(m, url_string.to_string()).headers(headers);
|
let builder = client.request(m, url_string.to_string()).headers(headers);
|
||||||
|
|
||||||
let sendable_req_result = match (request.body, request.body_type) {
|
let sendable_req_result = match (request.body, request.body_type) {
|
||||||
(Some(b), Some(_)) => builder.body(b).build(),
|
(Some(raw_body), Some(_)) => {
|
||||||
|
let body = render::render(&raw_body, environment_ref);
|
||||||
|
builder.body(body).build()
|
||||||
|
},
|
||||||
_ => builder.build(),
|
_ => builder.build(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -341,8 +337,8 @@ async fn create_environment(
|
|||||||
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
|
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
|
||||||
) -> Result<models::Environment, String> {
|
) -> Result<models::Environment, String> {
|
||||||
let pool = &*db_instance.lock().await;
|
let pool = &*db_instance.lock().await;
|
||||||
let data: HashMap<String, JsonValue> = HashMap::new();
|
let variables = Vec::new();
|
||||||
let created_environment = models::create_environment(workspace_id, name, data, pool)
|
let created_environment = models::create_environment(workspace_id, name, variables, pool)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create environment");
|
.expect("Failed to create environment");
|
||||||
|
|
||||||
@@ -418,7 +414,7 @@ async fn update_environment(
|
|||||||
let updated_environment = models::update_environment(
|
let updated_environment = models::update_environment(
|
||||||
environment.id.as_str(),
|
environment.id.as_str(),
|
||||||
environment.name.as_str(),
|
environment.name.as_str(),
|
||||||
environment.data.0,
|
environment.variables.0,
|
||||||
pool,
|
pool,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -27,7 +27,30 @@ pub struct Environment {
|
|||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: NaiveDateTime,
|
pub updated_at: NaiveDateTime,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data: Json<HashMap<String, JsonValue>>,
|
pub variables: Json<Vec<EnvironmentVariable>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct EnvironmentVariable {
|
||||||
|
#[serde(default)]
|
||||||
|
pub enabled: bool,
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Variable {
|
||||||
|
pub id: String,
|
||||||
|
pub workspace_id: String,
|
||||||
|
pub environment_id: String,
|
||||||
|
pub model: String,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
pub sort_priority: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -213,7 +236,7 @@ pub async fn find_environments(
|
|||||||
Environment,
|
Environment,
|
||||||
r#"
|
r#"
|
||||||
SELECT id, workspace_id, model, created_at, updated_at, name,
|
SELECT id, workspace_id, model, created_at, updated_at, name,
|
||||||
data AS "data!: Json<HashMap<String, JsonValue>>"
|
variables AS "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>"
|
||||||
FROM environments
|
FROM environments
|
||||||
WHERE workspace_id = ?
|
WHERE workspace_id = ?
|
||||||
"#,
|
"#,
|
||||||
@@ -226,26 +249,21 @@ pub async fn find_environments(
|
|||||||
pub async fn create_environment(
|
pub async fn create_environment(
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
data: HashMap<String, JsonValue>,
|
variables: Vec<EnvironmentVariable>,
|
||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<Environment, sqlx::Error> {
|
) -> Result<Environment, sqlx::Error> {
|
||||||
let id = generate_id(Some("en"));
|
let id = generate_id(Some("en"));
|
||||||
let data_json = Json(data);
|
|
||||||
let trimmed_name = name.trim();
|
let trimmed_name = name.trim();
|
||||||
|
let variables_json = Json(variables);
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO environments (
|
INSERT INTO environments (id, workspace_id, name, variables)
|
||||||
id,
|
|
||||||
workspace_id,
|
|
||||||
name,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?)
|
||||||
"#,
|
"#,
|
||||||
id,
|
id,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
trimmed_name,
|
trimmed_name,
|
||||||
data_json,
|
variables_json,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -270,18 +288,18 @@ pub async fn delete_environment(id: &str, pool: &Pool<Sqlite>) -> Result<Environ
|
|||||||
pub async fn update_environment(
|
pub async fn update_environment(
|
||||||
id: &str,
|
id: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
data: HashMap<String, JsonValue>,
|
variables: Vec<EnvironmentVariable>,
|
||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<Environment, sqlx::Error> {
|
) -> Result<Environment, sqlx::Error> {
|
||||||
let json_data = Json(data);
|
let variables_json = Json(variables);
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
UPDATE environments
|
UPDATE environments
|
||||||
SET (name, data, updated_at) = (?, ?, CURRENT_TIMESTAMP)
|
SET (name, variables, updated_at) = (?, ?, CURRENT_TIMESTAMP)
|
||||||
WHERE id = ?;
|
WHERE id = ?;
|
||||||
"#,
|
"#,
|
||||||
name,
|
name,
|
||||||
json_data,
|
variables_json,
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
@@ -300,7 +318,7 @@ pub async fn get_environment(id: &str, pool: &Pool<Sqlite>) -> Result<Environmen
|
|||||||
created_at,
|
created_at,
|
||||||
updated_at,
|
updated_at,
|
||||||
name,
|
name,
|
||||||
data AS "data!: Json<HashMap<String, JsonValue>>"
|
variables AS "variables!: sqlx::types::Json<Vec<EnvironmentVariable>>"
|
||||||
FROM environments
|
FROM environments
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
"#,
|
"#,
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
|
use crate::models::Environment;
|
||||||
|
use std::collections::HashMap;
|
||||||
use tauri::regex::Regex;
|
use tauri::regex::Regex;
|
||||||
|
|
||||||
use crate::models::Environment;
|
pub fn render(template: &str, environment: Option<&Environment>) -> String {
|
||||||
|
match environment {
|
||||||
|
Some(environment) => render_with_environment(template, environment),
|
||||||
|
None => template.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_with_environment(template: &str, environment: &Environment) -> String {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
let variables = &environment.variables.0;
|
||||||
|
for variable in variables {
|
||||||
|
map.insert(variable.name.as_str(), variable.value.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render(template: &str, environment: Environment) -> String {
|
|
||||||
let variables = environment.data;
|
|
||||||
Regex::new(r"\$\{\[\s*([^]\s]+)\s*]}")
|
Regex::new(r"\$\{\[\s*([^]\s]+)\s*]}")
|
||||||
.expect("Failed to create regex")
|
.expect("Failed to create regex")
|
||||||
.replace(template, |caps: &tauri::regex::Captures| {
|
.replace(template, |caps: &tauri::regex::Captures| {
|
||||||
let key = caps.get(1).unwrap().as_str();
|
let key = caps.get(1).unwrap().as_str();
|
||||||
match variables.get(key) {
|
map.get(key).unwrap_or(&"")
|
||||||
Some(v) => {
|
|
||||||
if v.is_string() {
|
|
||||||
v.as_str().expect("Should be string").to_string()
|
|
||||||
} else {
|
|
||||||
v.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => "".to_string(),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export function BasicAuth({ requestId, authentication }: Props) {
|
|||||||
return (
|
return (
|
||||||
<VStack className="my-2" space={2}>
|
<VStack className="my-2" space={2}>
|
||||||
<Input
|
<Input
|
||||||
|
useTemplating
|
||||||
label="Username"
|
label="Username"
|
||||||
name="username"
|
name="username"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -26,6 +27,7 @@ export function BasicAuth({ requestId, authentication }: Props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
|
useTemplating
|
||||||
label="Password"
|
label="Password"
|
||||||
name="password"
|
name="password"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export function BearerAuth({ requestId, authentication }: Props) {
|
|||||||
return (
|
return (
|
||||||
<VStack className="my-2" space={2}>
|
<VStack className="my-2" space={2}>
|
||||||
<Input
|
<Input
|
||||||
|
useTemplating
|
||||||
label="Token"
|
label="Token"
|
||||||
name="token"
|
name="token"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -4,16 +4,11 @@ import { Button } from './core/Button';
|
|||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { InlineCode } from './core/InlineCode';
|
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
|
|
||||||
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from './DialogContext';
|
||||||
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
import { useDeleteEnvironment } from '../hooks/useDeleteEnvironment';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -24,62 +19,23 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
const activeEnvironment = useActiveEnvironment();
|
const activeEnvironment = useActiveEnvironment();
|
||||||
const updateEnvironment = useUpdateEnvironment(activeEnvironment?.id ?? null);
|
|
||||||
const deleteEnvironment = useDeleteEnvironment(activeEnvironment);
|
|
||||||
const createEnvironment = useCreateEnvironment();
|
|
||||||
const prompt = usePrompt();
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
|
|
||||||
const items: DropdownItem[] = useMemo(() => {
|
const items: DropdownItem[] = useMemo(
|
||||||
const environmentItems: DropdownItem[] = environments.map(
|
() => [
|
||||||
(e) => ({
|
...environments.map(
|
||||||
key: e.id,
|
(e) => ({
|
||||||
label: e.name,
|
key: e.id,
|
||||||
rightSlot: e.id === activeEnvironment?.id ? <Icon icon="check" /> : undefined,
|
label: e.name,
|
||||||
onSelect: async () => {
|
rightSlot: e.id === activeEnvironment?.id ? <Icon icon="check" /> : undefined,
|
||||||
routes.setEnvironment(e);
|
onSelect: async () => {
|
||||||
},
|
routes.setEnvironment(e);
|
||||||
}),
|
},
|
||||||
[activeEnvironment?.id],
|
}),
|
||||||
);
|
[activeEnvironment?.id],
|
||||||
|
),
|
||||||
return [
|
{ type: 'separator', label: 'Environments' },
|
||||||
...environmentItems,
|
|
||||||
...((environmentItems.length > 0
|
|
||||||
? [{ type: 'separator', label: activeEnvironment?.name }]
|
|
||||||
: []) as DropdownItem[]),
|
|
||||||
...((activeEnvironment != null
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: 'rename',
|
|
||||||
label: 'Rename',
|
|
||||||
leftSlot: <Icon icon="pencil" />,
|
|
||||||
onSelect: async () => {
|
|
||||||
const name = await prompt({
|
|
||||||
title: 'Rename Environment',
|
|
||||||
description: (
|
|
||||||
<>
|
|
||||||
Enter a new name for <InlineCode>{activeEnvironment?.name}</InlineCode>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
name: 'name',
|
|
||||||
label: 'Name',
|
|
||||||
defaultValue: activeEnvironment?.name,
|
|
||||||
});
|
|
||||||
updateEnvironment.mutate({ name });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'delete',
|
|
||||||
label: 'Delete',
|
|
||||||
leftSlot: <Icon icon="trash" />,
|
|
||||||
onSelect: deleteEnvironment.mutate,
|
|
||||||
variant: 'danger',
|
|
||||||
},
|
|
||||||
{ type: 'separator' },
|
|
||||||
]
|
|
||||||
: []) as DropdownItem[]),
|
|
||||||
...((environments.length > 0
|
...((environments.length > 0
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
@@ -95,32 +51,9 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []) as DropdownItem[]),
|
: []) as DropdownItem[]),
|
||||||
{
|
],
|
||||||
key: 'create-environment',
|
[activeEnvironment, dialog, environments, routes],
|
||||||
label: 'Create Environment',
|
);
|
||||||
leftSlot: <Icon icon="plus" />,
|
|
||||||
onSelect: async () => {
|
|
||||||
const name = await prompt({
|
|
||||||
name: 'name',
|
|
||||||
label: 'Name',
|
|
||||||
defaultValue: 'My Environment',
|
|
||||||
description: 'Enter a name for the new environment',
|
|
||||||
title: 'Create Environment',
|
|
||||||
});
|
|
||||||
createEnvironment.mutate({ name });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [
|
|
||||||
activeEnvironment,
|
|
||||||
createEnvironment,
|
|
||||||
deleteEnvironment,
|
|
||||||
dialog,
|
|
||||||
environments,
|
|
||||||
prompt,
|
|
||||||
routes,
|
|
||||||
updateEnvironment,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown items={items}>
|
<Dropdown items={items}>
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
import { usePrompt } from '../hooks/usePrompt';
|
||||||
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
|
|
||||||
import type { Environment } from '../lib/models';
|
import type { Environment } from '../lib/models';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Editor } from './core/Editor';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||||
|
import { PairEditor } from './core/PairEditor';
|
||||||
|
import type { PairEditorProps } from './core/PairEditor';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
|
||||||
|
|
||||||
export const EnvironmentEditDialog = function() {
|
export const EnvironmentEditDialog = function () {
|
||||||
const routes = useAppRoutes();
|
const routes = useAppRoutes();
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
const environments = useEnvironments();
|
const environments = useEnvironments();
|
||||||
@@ -58,21 +59,21 @@ export const EnvironmentEditDialog = function() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const EnvironmentEditor = function({ environment }: { environment: Environment }) {
|
const EnvironmentEditor = function ({ environment }: { environment: Environment }) {
|
||||||
const updateEnvironment = useUpdateEnvironment(environment.id);
|
const updateEnvironment = useUpdateEnvironment(environment.id);
|
||||||
|
const handleChange = useCallback<PairEditorProps['onChange']>(
|
||||||
|
(variables) => {
|
||||||
|
updateEnvironment.mutate({ variables });
|
||||||
|
},
|
||||||
|
[updateEnvironment],
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Editor
|
<div>
|
||||||
contentType="application/json"
|
<PairEditor
|
||||||
className="w-full min-h-[40px] !bg-gray-50"
|
forceUpdateKey={environment.id}
|
||||||
defaultValue={JSON.stringify(environment.data, null, 2)}
|
pairs={environment.variables}
|
||||||
forceUpdateKey={environment.id}
|
onChange={handleChange}
|
||||||
onChange={(data) => {
|
/>
|
||||||
try {
|
</div>
|
||||||
updateEnvironment.mutate({ data: JSON.parse(data) });
|
|
||||||
} catch (err) {
|
|
||||||
// That's okay
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,5 +63,7 @@ const validateHttpHeader = (v: string) => {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hi = v.replace(/\$\{\[\s*[^\]\s]+\s*]}/gi, 'fo');
|
||||||
|
console.log('V', v, '-->', hi);
|
||||||
return v.match(/^[a-zA-Z0-9-_]+$/) !== null;
|
return v.match(/^[a-zA-Z0-9-_]+$/) !== null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,6 +54,8 @@
|
|||||||
|
|
||||||
/* Bring above on hover */
|
/* Bring above on hover */
|
||||||
@apply hover:z-10 relative;
|
@apply hover:z-10 relative;
|
||||||
|
|
||||||
|
-webkit-text-security: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import './Editor.css';
|
|||||||
import { baseExtensions, getLanguageExtension, multiLineExtensions } from './extensions';
|
import { baseExtensions, getLanguageExtension, multiLineExtensions } from './extensions';
|
||||||
import type { GenericCompletionConfig } from './genericCompletion';
|
import type { GenericCompletionConfig } from './genericCompletion';
|
||||||
import { singleLineExt } from './singleLine';
|
import { singleLineExt } from './singleLine';
|
||||||
import { useEnvironments } from '../../../hooks/useEnvironments';
|
|
||||||
import { useActiveEnvironment } from '../../../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../../../hooks/useActiveEnvironment';
|
||||||
|
|
||||||
// Export some things so all the code-split parts are in this file
|
// Export some things so all the code-split parts are in this file
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const placeholderMatcher = new BetterMatchDecorator({
|
|||||||
if (groupMatch == null) {
|
if (groupMatch == null) {
|
||||||
// Should never happen, but make TS happy
|
// Should never happen, but make TS happy
|
||||||
console.warn('Group match was empty', match);
|
console.warn('Group match was empty', match);
|
||||||
return Decoration.replace({});;
|
return Decoration.replace({});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Decoration.replace({
|
return Decoration.replace({
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import { twigCompletion } from './completion';
|
|||||||
import { parser as twigParser } from './twig';
|
import { parser as twigParser } from './twig';
|
||||||
import type { Environment } from '../../../../lib/models';
|
import type { Environment } from '../../../../lib/models';
|
||||||
|
|
||||||
export function twig(base: LanguageSupport, environment: Environment | null, autocomplete?: GenericCompletionConfig) {
|
export function twig(
|
||||||
// TODO: fill variables here
|
base: LanguageSupport,
|
||||||
const data = environment?.data ?? {};
|
environment: Environment | null,
|
||||||
const options = Object.keys(data).map(key => ({ name: key }));
|
autocomplete?: GenericCompletionConfig,
|
||||||
const completions = twigCompletion({ options });
|
) {
|
||||||
|
const variables = environment?.variables ?? [];
|
||||||
|
const completions = twigCompletion({ options: variables });
|
||||||
|
|
||||||
const language = mixLanguage(base);
|
const language = mixLanguage(base);
|
||||||
const completion = language.data.of({ autocomplete: completions });
|
const completion = language.data.of({ autocomplete: completions });
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { XYCoord } from 'react-dnd';
|
import type { XYCoord } from 'react-dnd';
|
||||||
import { useDrag, useDrop } from 'react-dnd';
|
import { useDrag, useDrop } from 'react-dnd';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
@@ -24,7 +24,8 @@ export type PairEditorProps = {
|
|||||||
valueValidate?: InputProps['validate'];
|
valueValidate?: InputProps['validate'];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Pair = {
|
export type Pair = {
|
||||||
|
id?: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -342,6 +343,8 @@ const FormRow = memo(function FormRow({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const newPairContainer = (pair?: Pair): PairContainer => {
|
const newPairContainer = (initialPair?: Pair): PairContainer => {
|
||||||
return { pair: pair ?? { name: '', value: '', enabled: true }, id: uuid() };
|
const id = initialPair?.id ?? uuid();
|
||||||
|
const pair = initialPair ?? { name: '', value: '', enabled: true };
|
||||||
|
return { id, pair };
|
||||||
};
|
};
|
||||||
|
|||||||
18
src-web/hooks/useVariables.ts
Normal file
18
src-web/hooks/useVariables.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
|
import type { Variable } from '../lib/models';
|
||||||
|
|
||||||
|
export function variablesQueryKey({ environmentId }: { environmentId: string }) {
|
||||||
|
return ['variables', { environmentId }];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useVariables({ environmentId }: { environmentId: string }) {
|
||||||
|
return (
|
||||||
|
useQuery({
|
||||||
|
queryKey: variablesQueryKey({ environmentId }),
|
||||||
|
queryFn: async () => {
|
||||||
|
return (await invoke('list_variables', { environmentId })) as Variable[];
|
||||||
|
},
|
||||||
|
}).data ?? []
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ export interface Workspace extends BaseModel {
|
|||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HttpHeader {
|
export interface EnvironmentVariable {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
@@ -32,7 +32,13 @@ export interface Environment extends BaseModel {
|
|||||||
readonly workspaceId: string;
|
readonly workspaceId: string;
|
||||||
readonly model: 'environment';
|
readonly model: 'environment';
|
||||||
name: string;
|
name: string;
|
||||||
data: Record<string, string | number | boolean | null | undefined>;
|
variables: EnvironmentVariable[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HttpHeader {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
enabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HttpRequest extends BaseModel {
|
export interface HttpRequest extends BaseModel {
|
||||||
|
|||||||
Reference in New Issue
Block a user