mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-10 03:03:37 +02:00
Extract base environment (#149)
This commit is contained in:
45
src-tauri/migrations/20241219140051_base-environments.sql
Normal file
45
src-tauri/migrations/20241219140051_base-environments.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
-- Add the new field
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN environment_id TEXT REFERENCES environments (id) ON DELETE CASCADE;
|
||||
|
||||
-- Create temporary column so we know which rows are meant to be base environments. We'll use this to update
|
||||
-- child environments to point to them.
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN migrated_base_env BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
||||
-- Create a base environment for each workspace
|
||||
INSERT INTO environments (id, workspace_id, name, variables, migrated_base_env)
|
||||
SELECT (
|
||||
-- This is the best way to generate a random string in SQLite, apparently
|
||||
'ev_' || SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1)
|
||||
),
|
||||
workspaces.id,
|
||||
'Global Variables',
|
||||
variables,
|
||||
TRUE
|
||||
FROM workspaces;
|
||||
|
||||
-- Update all non-base environments to point to newly created base environments
|
||||
UPDATE environments
|
||||
SET environment_id = ( SELECT base_env.id
|
||||
FROM environments AS base_env
|
||||
WHERE base_env.workspace_id = environments.workspace_id
|
||||
AND base_env.migrated_base_env IS TRUE )
|
||||
WHERE migrated_base_env IS FALSE;
|
||||
|
||||
-- Drop temporary column
|
||||
ALTER TABLE environments
|
||||
DROP COLUMN migrated_base_env;
|
||||
|
||||
-- Drop the old variables column
|
||||
-- IMPORTANT: Skip to give the user the option to roll back to a previous app version. We can drop it once the migration working in the real world
|
||||
-- ALTER TABLE workspaces DROP COLUMN variables;
|
||||
@@ -34,7 +34,7 @@ pub async fn get_workspace_export_resources(
|
||||
let app_handle = window.app_handle();
|
||||
let mut data = WorkspaceExport {
|
||||
yaak_version: app_handle.package_info().version.clone().to_string(),
|
||||
yaak_schema: 2,
|
||||
yaak_schema: 3,
|
||||
timestamp: chrono::Utc::now().naive_utc(),
|
||||
resources: WorkspaceExportResources {
|
||||
workspaces: Vec::new(),
|
||||
|
||||
@@ -28,8 +28,8 @@ use yaak_models::models::{
|
||||
HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||
};
|
||||
use yaak_models::queries::{
|
||||
get_http_response, get_or_create_settings, get_workspace, update_response_if_id,
|
||||
upsert_cookie_jar,
|
||||
get_base_environment, get_http_response, get_or_create_settings, get_workspace,
|
||||
update_response_if_id, upsert_cookie_jar,
|
||||
};
|
||||
use yaak_plugin_runtime::events::{RenderPurpose, WindowContext};
|
||||
|
||||
@@ -43,6 +43,9 @@ pub async fn send_http_request<R: Runtime>(
|
||||
) -> Result<HttpResponse, String> {
|
||||
let workspace =
|
||||
get_workspace(window, &request.workspace_id).await.expect("Failed to get Workspace");
|
||||
let base_environment = get_base_environment(window, &request.workspace_id)
|
||||
.await
|
||||
.expect("Failed to get base environment");
|
||||
let settings = get_or_create_settings(window).await;
|
||||
let cb = PluginTemplateCallback::new(
|
||||
window.app_handle(),
|
||||
@@ -54,7 +57,7 @@ pub async fn send_http_request<R: Runtime>(
|
||||
let response = Arc::new(Mutex::new(og_response.clone()));
|
||||
|
||||
let rendered_request =
|
||||
render_http_request(&request, &workspace, environment.as_ref(), &cb).await;
|
||||
render_http_request(&request, &base_environment, environment.as_ref(), &cb).await;
|
||||
|
||||
let mut url_string = rendered_request.url;
|
||||
|
||||
|
||||
@@ -56,14 +56,15 @@ use yaak_models::queries::{
|
||||
delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection,
|
||||
delete_grpc_request, delete_http_request, delete_http_response, delete_plugin,
|
||||
delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request,
|
||||
generate_id, generate_model_id, get_cookie_jar, get_environment, get_folder,
|
||||
get_grpc_connection, get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
||||
get_or_create_settings, get_plugin, get_workspace, list_cookie_jars, list_environments,
|
||||
list_folders, list_grpc_connections_for_workspace, list_grpc_events, list_grpc_requests,
|
||||
list_http_requests, list_http_responses_for_request, list_http_responses_for_workspace,
|
||||
list_plugins, list_workspaces, set_key_value_raw, update_response_if_id, update_settings,
|
||||
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
||||
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_plugin, upsert_workspace,
|
||||
generate_id, generate_model_id, get_base_environment, get_cookie_jar, get_environment,
|
||||
get_folder, get_grpc_connection, get_grpc_request, get_http_request, get_http_response,
|
||||
get_key_value_raw, get_or_create_settings, get_plugin, get_workspace, list_cookie_jars,
|
||||
list_environments, list_folders, list_grpc_connections_for_workspace, list_grpc_events,
|
||||
list_grpc_requests, list_http_requests, list_http_responses_for_request,
|
||||
list_http_responses_for_workspace, list_plugins, list_workspaces, set_key_value_raw,
|
||||
update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment, upsert_folder,
|
||||
upsert_grpc_connection, upsert_grpc_event, upsert_grpc_request, upsert_http_request,
|
||||
upsert_plugin, upsert_workspace,
|
||||
};
|
||||
use yaak_plugin_runtime::events::{
|
||||
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
||||
@@ -143,10 +144,11 @@ async fn cmd_render_template<R: Runtime>(
|
||||
Some(id) => Some(get_environment(&window, id).await.map_err(|e| e.to_string())?),
|
||||
None => None,
|
||||
};
|
||||
let workspace = get_workspace(&window, &workspace_id).await.map_err(|e| e.to_string())?;
|
||||
let base_environment =
|
||||
get_base_environment(&window, &workspace_id).await.map_err(|e| e.to_string())?;
|
||||
let rendered = render_template(
|
||||
template,
|
||||
&workspace,
|
||||
&base_environment,
|
||||
environment.as_ref(),
|
||||
&PluginTemplateCallback::new(
|
||||
&app_handle,
|
||||
@@ -208,10 +210,11 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or("Failed to find GRPC request")?;
|
||||
let workspace = get_workspace(&window, &req.workspace_id).await.map_err(|e| e.to_string())?;
|
||||
let base_environment =
|
||||
get_base_environment(&window, &req.workspace_id).await.map_err(|e| e.to_string())?;
|
||||
let req = render_grpc_request(
|
||||
&req,
|
||||
&workspace,
|
||||
&base_environment,
|
||||
environment.as_ref(),
|
||||
&PluginTemplateCallback::new(
|
||||
window.app_handle(),
|
||||
@@ -337,7 +340,7 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let cb = {
|
||||
let cancelled_rx = cancelled_rx.clone();
|
||||
let window = window.clone();
|
||||
let workspace = workspace.clone();
|
||||
let workspace = base_environment.clone();
|
||||
let environment = environment.clone();
|
||||
let base_msg = base_msg.clone();
|
||||
let method_desc = method_desc.clone();
|
||||
@@ -433,7 +436,7 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let msg = if req.message.is_empty() { "{}".to_string() } else { req.message };
|
||||
let msg = render_template(
|
||||
msg.as_str(),
|
||||
&workspace.clone(),
|
||||
&base_environment.clone(),
|
||||
environment.as_ref(),
|
||||
&PluginTemplateCallback::new(
|
||||
window.app_handle(),
|
||||
@@ -852,12 +855,31 @@ async fn cmd_import_data<R: Runtime>(
|
||||
}
|
||||
info!("Imported {} workspaces", imported_resources.workspaces.len());
|
||||
|
||||
for mut v in resources.environments {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeEnvironment, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
let x = upsert_environment(&window, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.environments.push(x.clone());
|
||||
// Environments can foreign-key to themselves, so we need to import from
|
||||
// the top of the tree to the bottom to avoid foreign key conflicts.
|
||||
// We do this by looping until we've imported them all, only importing if:
|
||||
// - The parent has been imported
|
||||
// - The environment hasn't already been imported
|
||||
// The loop exits when imported.len == to_import.len
|
||||
while imported_resources.environments.len() < resources.environments.len() {
|
||||
for mut v in resources.environments.clone() {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeEnvironment, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.environment_id =
|
||||
maybe_gen_id_opt(v.environment_id, ModelType::TypeEnvironment, &mut id_map);
|
||||
if let Some(fid) = v.environment_id.clone() {
|
||||
let imported_parent = imported_resources.environments.iter().find(|f| f.id == fid);
|
||||
if imported_parent.is_none() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(_) = imported_resources.environments.iter().find(|f| f.id == v.id) {
|
||||
continue;
|
||||
}
|
||||
let x = upsert_environment(&window, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.environments.push(x.clone());
|
||||
}
|
||||
}
|
||||
info!("Imported {} environments", imported_resources.environments.len());
|
||||
|
||||
@@ -2109,9 +2131,17 @@ async fn handle_plugin_event<R: Runtime>(
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let base_environment = get_base_environment(&window, workspace.id.as_str())
|
||||
.await
|
||||
.expect("Failed to get base environment");
|
||||
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
|
||||
let http_request =
|
||||
render_http_request(&req.http_request, &workspace, environment.as_ref(), &cb).await;
|
||||
let http_request = render_http_request(
|
||||
&req.http_request,
|
||||
&base_environment,
|
||||
environment.as_ref(),
|
||||
&cb,
|
||||
)
|
||||
.await;
|
||||
Some(InternalEventPayload::RenderHttpRequestResponse(RenderHttpRequestResponse {
|
||||
http_request,
|
||||
}))
|
||||
@@ -2124,8 +2154,12 @@ async fn handle_plugin_event<R: Runtime>(
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let base_environment = get_base_environment(&window, workspace.id.as_str())
|
||||
.await
|
||||
.expect("Failed to get base environment");
|
||||
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
|
||||
let data = render_json_value(req.data, &workspace, environment.as_ref(), &cb).await;
|
||||
let data =
|
||||
render_json_value(req.data, &base_environment, environment.as_ref(), &cb).await;
|
||||
Some(InternalEventPayload::TemplateRenderResponse(TemplateRenderResponse { data }))
|
||||
}
|
||||
InternalEventPayload::ReloadResponse => {
|
||||
|
||||
@@ -3,37 +3,37 @@ use serde_json::{json, Map, Value};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use yaak_models::models::{
|
||||
Environment, EnvironmentVariable, GrpcMetadataEntry, GrpcRequest, HttpRequest,
|
||||
HttpRequestHeader, HttpUrlParameter, Workspace,
|
||||
HttpRequestHeader, HttpUrlParameter,
|
||||
};
|
||||
use yaak_templates::{parse_and_render, TemplateCallback};
|
||||
|
||||
pub async fn render_template<T: TemplateCallback>(
|
||||
template: &str,
|
||||
w: &Workspace,
|
||||
e: Option<&Environment>,
|
||||
base_environment: &Environment,
|
||||
environment: Option<&Environment>,
|
||||
cb: &T,
|
||||
) -> String {
|
||||
let vars = &make_vars_hashmap(w, e);
|
||||
let vars = &make_vars_hashmap(base_environment, environment);
|
||||
render(template, vars, cb).await
|
||||
}
|
||||
|
||||
pub async fn render_json_value<T: TemplateCallback>(
|
||||
value: Value,
|
||||
w: &Workspace,
|
||||
e: Option<&Environment>,
|
||||
base_environment: &Environment,
|
||||
environment: Option<&Environment>,
|
||||
cb: &T,
|
||||
) -> Value {
|
||||
let vars = &make_vars_hashmap(w, e);
|
||||
let vars = &make_vars_hashmap(base_environment, environment);
|
||||
render_json_value_raw(value, vars, cb).await
|
||||
}
|
||||
|
||||
pub async fn render_grpc_request<T: TemplateCallback>(
|
||||
r: &GrpcRequest,
|
||||
w: &Workspace,
|
||||
e: Option<&Environment>,
|
||||
base_environment: &Environment,
|
||||
environment: Option<&Environment>,
|
||||
cb: &T,
|
||||
) -> GrpcRequest {
|
||||
let vars = &make_vars_hashmap(w, e);
|
||||
let vars = &make_vars_hashmap(base_environment, environment);
|
||||
|
||||
let mut metadata = Vec::new();
|
||||
for p in r.metadata.clone() {
|
||||
@@ -61,11 +61,11 @@ pub async fn render_grpc_request<T: TemplateCallback>(
|
||||
|
||||
pub async fn render_http_request(
|
||||
r: &HttpRequest,
|
||||
w: &Workspace,
|
||||
e: Option<&Environment>,
|
||||
base_environment: &Environment,
|
||||
environment: Option<&Environment>,
|
||||
cb: &PluginTemplateCallback,
|
||||
) -> HttpRequest {
|
||||
let vars = &make_vars_hashmap(w, e);
|
||||
let vars = &make_vars_hashmap(base_environment, environment);
|
||||
|
||||
let mut url_parameters = Vec::new();
|
||||
for p in r.url_parameters.clone() {
|
||||
@@ -110,11 +110,11 @@ pub async fn render_http_request(
|
||||
}
|
||||
|
||||
pub fn make_vars_hashmap(
|
||||
workspace: &Workspace,
|
||||
base_environment: &Environment,
|
||||
environment: Option<&Environment>,
|
||||
) -> HashMap<String, String> {
|
||||
let mut variables = HashMap::new();
|
||||
variables = add_variable_to_map(variables, &workspace.variables);
|
||||
variables = add_variable_to_map(variables, &base_environment.variables);
|
||||
|
||||
if let Some(e) = environment {
|
||||
variables = add_variable_to_map(variables, &e.variables);
|
||||
|
||||
@@ -7233,19 +7233,15 @@ function pluginHookImport(ctx, contents) {
|
||||
};
|
||||
const workspacesToImport = parsed.resources.filter(isWorkspace);
|
||||
for (const workspaceToImport of workspacesToImport) {
|
||||
const baseEnvironment = parsed.resources.find(
|
||||
(r) => isEnvironment(r) && r.parentId === workspaceToImport._id
|
||||
);
|
||||
resources.workspaces.push({
|
||||
id: convertId(workspaceToImport._id),
|
||||
createdAt: new Date(workspacesToImport.created ?? Date.now()).toISOString().replace("Z", ""),
|
||||
updatedAt: new Date(workspacesToImport.updated ?? Date.now()).toISOString().replace("Z", ""),
|
||||
model: "workspace",
|
||||
name: workspaceToImport.name,
|
||||
variables: baseEnvironment ? parseVariables(baseEnvironment.data) : []
|
||||
name: workspaceToImport.name
|
||||
});
|
||||
const environmentsToImport = parsed.resources.filter(
|
||||
(r) => isEnvironment(r) && r.parentId === baseEnvironment?._id
|
||||
(r) => isEnvironment(r)
|
||||
);
|
||||
resources.environments.push(
|
||||
...environmentsToImport.map((r) => importEnvironment(r, workspaceToImport._id))
|
||||
@@ -7394,13 +7390,6 @@ function importHttpRequest(r, workspaceId, sortPriority = 0) {
|
||||
})).filter(({ name, value }) => name !== "" || value !== "")
|
||||
};
|
||||
}
|
||||
function parseVariables(data) {
|
||||
return Object.entries(data).map(([name, value]) => ({
|
||||
enabled: true,
|
||||
name,
|
||||
value: `${value}`
|
||||
}));
|
||||
}
|
||||
function convertSyntax(variable) {
|
||||
if (!isJSString(variable)) return variable;
|
||||
return variable.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}");
|
||||
|
||||
@@ -145878,13 +145878,20 @@ function pluginHookImport(_ctx, contents) {
|
||||
model: "workspace",
|
||||
id: generateId("workspace"),
|
||||
name: info.name || "Postman Import",
|
||||
description: info.description?.content ?? info.description ?? "",
|
||||
description: info.description?.content ?? info.description ?? ""
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
const environment = {
|
||||
model: "environment",
|
||||
id: generateId("environment"),
|
||||
name: "Global Variables",
|
||||
workspaceId: workspace.id,
|
||||
variables: root.variable?.map((v) => ({
|
||||
name: v.key,
|
||||
value: v.value
|
||||
})) ?? []
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
exportResources.environments.push(environment);
|
||||
const importItem = (v, folderId = null) => {
|
||||
if (typeof v.name === "string" && Array.isArray(v.item)) {
|
||||
const folder = {
|
||||
|
||||
@@ -45,13 +45,20 @@ function pluginHookImport(_ctx, contents) {
|
||||
model: "workspace",
|
||||
id: generateId("workspace"),
|
||||
name: info.name || "Postman Import",
|
||||
description: info.description?.content ?? info.description ?? "",
|
||||
description: info.description?.content ?? info.description ?? ""
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
const environment = {
|
||||
model: "environment",
|
||||
id: generateId("environment"),
|
||||
name: "Global Variables",
|
||||
workspaceId: workspace.id,
|
||||
variables: root.variable?.map((v) => ({
|
||||
name: v.key,
|
||||
value: v.value
|
||||
})) ?? []
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
exportResources.environments.push(environment);
|
||||
const importItem = (v, folderId = null) => {
|
||||
if (typeof v.name === "string" && Array.isArray(v.item)) {
|
||||
const folder = {
|
||||
|
||||
@@ -41,6 +41,24 @@ function pluginHookImport(_ctx, contents) {
|
||||
parsed.resources.httpRequests = parsed.resources.requests;
|
||||
delete parsed.resources["requests"];
|
||||
}
|
||||
for (const workspace of parsed.resources.workspaces ?? []) {
|
||||
if ("variables" in workspace) {
|
||||
const baseEnvironment = {
|
||||
id: `GENERATE_ID::base_env_${workspace["id"]}`,
|
||||
name: "Global Variables",
|
||||
variables: workspace.variables,
|
||||
workspaceId: workspace.id
|
||||
};
|
||||
parsed.resources.environments = parsed.resources.environments ?? [];
|
||||
parsed.resources.environments.push(baseEnvironment);
|
||||
delete workspace.variables;
|
||||
for (const environment of parsed.resources.environments) {
|
||||
if (environment.workspaceId === workspace.id && environment.id !== baseEnvironment.id) {
|
||||
environment.environmentId = baseEnvironment.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { resources: parsed.resources };
|
||||
}
|
||||
function isJSObject(obj) {
|
||||
|
||||
@@ -10,7 +10,7 @@ export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
||||
|
||||
export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array<Cookie>, name: string, };
|
||||
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, environmentId: string | null, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
||||
|
||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, };
|
||||
|
||||
@@ -50,4 +50,4 @@ export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, telemetry: boolean, theme: string, themeDark: string, themeLight: string, updateChannel: string, proxy: ProxySetting | null, };
|
||||
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, variables: Array<EnvironmentVariable>, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
|
||||
@@ -110,7 +110,6 @@ pub struct Workspace {
|
||||
pub updated_at: NaiveDateTime,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub variables: Vec<EnvironmentVariable>,
|
||||
|
||||
// Settings
|
||||
#[serde(default = "default_true")]
|
||||
@@ -134,14 +133,12 @@ pub enum WorkspaceIden {
|
||||
SettingFollowRedirects,
|
||||
SettingRequestTimeout,
|
||||
SettingValidateCertificates,
|
||||
Variables,
|
||||
}
|
||||
|
||||
impl<'s> TryFrom<&Row<'s>> for Workspace {
|
||||
type Error = rusqlite::Error;
|
||||
|
||||
fn try_from(r: &Row<'s>) -> Result<Self, Self::Error> {
|
||||
let variables: String = r.get("variables")?;
|
||||
Ok(Workspace {
|
||||
id: r.get("id")?,
|
||||
model: r.get("model")?,
|
||||
@@ -149,7 +146,6 @@ impl<'s> TryFrom<&Row<'s>> for Workspace {
|
||||
updated_at: r.get("updated_at")?,
|
||||
name: r.get("name")?,
|
||||
description: r.get("description")?,
|
||||
variables: serde_json::from_str(variables.as_str()).unwrap_or_default(),
|
||||
setting_validate_certificates: r.get("setting_validate_certificates")?,
|
||||
setting_follow_redirects: r.get("setting_follow_redirects")?,
|
||||
setting_request_timeout: r.get("setting_request_timeout")?,
|
||||
@@ -248,6 +244,7 @@ pub struct Environment {
|
||||
pub model: String,
|
||||
pub id: String,
|
||||
pub workspace_id: String,
|
||||
pub environment_id: Option<String>,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
|
||||
@@ -263,6 +260,7 @@ pub enum EnvironmentIden {
|
||||
Id,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
EnvironmentId,
|
||||
WorkspaceId,
|
||||
|
||||
Name,
|
||||
@@ -278,6 +276,7 @@ impl<'s> TryFrom<&Row<'s>> for Environment {
|
||||
id: r.get("id")?,
|
||||
model: r.get("model")?,
|
||||
workspace_id: r.get("workspace_id")?,
|
||||
environment_id: r.get("environment_id")?,
|
||||
created_at: r.get("created_at")?,
|
||||
updated_at: r.get("updated_at")?,
|
||||
name: r.get("name")?,
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::models::{
|
||||
Settings, SettingsIden, Workspace, WorkspaceIden,
|
||||
};
|
||||
use crate::plugin::SqliteConnection;
|
||||
use log::{debug, error};
|
||||
use log::{debug, error, info};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use rusqlite::OptionalExtension;
|
||||
use sea_query::ColumnRef::Asterisk;
|
||||
@@ -191,7 +191,6 @@ pub async fn upsert_workspace<R: Runtime>(
|
||||
WorkspaceIden::UpdatedAt,
|
||||
WorkspaceIden::Name,
|
||||
WorkspaceIden::Description,
|
||||
WorkspaceIden::Variables,
|
||||
WorkspaceIden::SettingRequestTimeout,
|
||||
WorkspaceIden::SettingFollowRedirects,
|
||||
WorkspaceIden::SettingValidateCertificates,
|
||||
@@ -202,7 +201,6 @@ pub async fn upsert_workspace<R: Runtime>(
|
||||
CurrentTimestamp.into(),
|
||||
trimmed_name.into(),
|
||||
workspace.description.into(),
|
||||
serde_json::to_string(&workspace.variables)?.into(),
|
||||
workspace.setting_request_timeout.into(),
|
||||
workspace.setting_follow_redirects.into(),
|
||||
workspace.setting_validate_certificates.into(),
|
||||
@@ -213,7 +211,6 @@ pub async fn upsert_workspace<R: Runtime>(
|
||||
WorkspaceIden::UpdatedAt,
|
||||
WorkspaceIden::Name,
|
||||
WorkspaceIden::Description,
|
||||
WorkspaceIden::Variables,
|
||||
WorkspaceIden::SettingRequestTimeout,
|
||||
WorkspaceIden::SettingFollowRedirects,
|
||||
WorkspaceIden::SettingValidateCertificates,
|
||||
@@ -739,21 +736,41 @@ pub async fn upsert_cookie_jar<R: Runtime>(
|
||||
}
|
||||
|
||||
pub async fn list_environments<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
window: &WebviewWindow<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<Environment>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let mut environments: Vec<Environment> = {
|
||||
let dbm = &*window.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
.from(EnvironmentIden::Table)
|
||||
.cond_where(Expr::col(EnvironmentIden::WorkspaceId).eq(workspace_id))
|
||||
.column(Asterisk)
|
||||
.order_by(EnvironmentIden::CreatedAt, Order::Desc)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = db.prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), |row| row.try_into())?;
|
||||
items.map(|v| v.unwrap()).collect()
|
||||
};
|
||||
|
||||
let (sql, params) = Query::select()
|
||||
.from(EnvironmentIden::Table)
|
||||
.cond_where(Expr::col(EnvironmentIden::WorkspaceId).eq(workspace_id))
|
||||
.column(Asterisk)
|
||||
.order_by(EnvironmentIden::CreatedAt, Order::Desc)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = db.prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), |row| row.try_into())?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
let base_environment =
|
||||
environments.iter().find(|e| e.environment_id == None && e.workspace_id == workspace_id);
|
||||
|
||||
if let None = base_environment {
|
||||
let base_environment = upsert_environment(
|
||||
window,
|
||||
Environment {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
name: "Global Variables".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
info!("Created base environment for {workspace_id}");
|
||||
environments.push(base_environment);
|
||||
}
|
||||
|
||||
Ok(environments)
|
||||
}
|
||||
|
||||
pub async fn delete_environment<R: Runtime>(
|
||||
@@ -839,7 +856,7 @@ pub async fn update_settings<R: Runtime>(
|
||||
None => None,
|
||||
Some(p) => Some(serde_json::to_string(&p)?),
|
||||
})
|
||||
.into(),
|
||||
.into(),
|
||||
),
|
||||
])
|
||||
.returning_all()
|
||||
@@ -869,6 +886,7 @@ pub async fn upsert_environment<R: Runtime>(
|
||||
EnvironmentIden::Id,
|
||||
EnvironmentIden::CreatedAt,
|
||||
EnvironmentIden::UpdatedAt,
|
||||
EnvironmentIden::EnvironmentId,
|
||||
EnvironmentIden::WorkspaceId,
|
||||
EnvironmentIden::Name,
|
||||
EnvironmentIden::Variables,
|
||||
@@ -877,7 +895,8 @@ pub async fn upsert_environment<R: Runtime>(
|
||||
id.as_str().into(),
|
||||
CurrentTimestamp.into(),
|
||||
CurrentTimestamp.into(),
|
||||
environment.workspace_id.as_str().into(),
|
||||
environment.environment_id.into(),
|
||||
environment.workspace_id.into(),
|
||||
trimmed_name.into(),
|
||||
serde_json::to_string(&environment.variables)?.into(),
|
||||
])
|
||||
@@ -911,6 +930,26 @@ pub async fn get_environment<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Res
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn get_base_environment<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Environment> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
let (sql, params) = Query::select()
|
||||
.from(EnvironmentIden::Table)
|
||||
.column(Asterisk)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(EnvironmentIden::WorkspaceId).eq(workspace_id))
|
||||
.add(Expr::col(EnvironmentIden::EnvironmentId).is_null()),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = db.prepare(sql.as_str())?;
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn get_plugin<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Plugin> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
@@ -1142,7 +1181,7 @@ pub async fn duplicate_folder<R: Runtime>(
|
||||
..src_folder.clone()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await?;
|
||||
|
||||
for m in http_requests {
|
||||
upsert_http_request(
|
||||
@@ -1154,7 +1193,7 @@ pub async fn duplicate_folder<R: Runtime>(
|
||||
..m
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await?;
|
||||
}
|
||||
for m in grpc_requests {
|
||||
upsert_grpc_request(
|
||||
@@ -1166,7 +1205,7 @@ pub async fn duplicate_folder<R: Runtime>(
|
||||
..m
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.await?;
|
||||
}
|
||||
for m in folders {
|
||||
// Recurse down
|
||||
@@ -1177,7 +1216,7 @@ pub async fn duplicate_folder<R: Runtime>(
|
||||
..m
|
||||
},
|
||||
))
|
||||
.await?;
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1336,7 +1375,7 @@ pub async fn create_default_http_response<R: Runtime>(
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, environmentId: string | null, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
||||
|
||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, };
|
||||
|
||||
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, name: string, sortPriority: number, };
|
||||
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, name: string, description: string, sortPriority: number, };
|
||||
|
||||
export type GrpcMetadataEntry = { enabled?: boolean, name: string, value: string, };
|
||||
|
||||
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, message: string, metadata: Array<GrpcMetadataEntry>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
||||
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, description: string, message: string, metadata: Array<GrpcMetadataEntry>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
||||
|
||||
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, description: string, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
|
||||
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, };
|
||||
|
||||
@@ -22,4 +22,4 @@ export type HttpResponseState = "initialized" | "connected" | "closed";
|
||||
|
||||
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, };
|
||||
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, variables: Array<EnvironmentVariable>, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
|
||||
Reference in New Issue
Block a user