mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-25 10:08:29 +02:00
plugin:yaak-models|upsert PoC
This commit is contained in:
@@ -50,8 +50,9 @@
|
||||
"opener:allow-open-url",
|
||||
"opener:allow-reveal-item-in-dir",
|
||||
"shell:allow-open",
|
||||
"yaak-license:default",
|
||||
"yaak-git:default",
|
||||
"yaak-license:default",
|
||||
"yaak-models:default",
|
||||
"yaak-sync:default",
|
||||
"yaak-ws:default"
|
||||
]
|
||||
|
||||
2
src-tauri/gen/schemas/acl-manifests.json
generated
2
src-tauri/gen/schemas/acl-manifests.json
generated
File diff suppressed because one or more lines are too long
2
src-tauri/gen/schemas/capabilities.json
generated
2
src-tauri/gen/schemas/capabilities.json
generated
@@ -1 +1 @@
|
||||
{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["core:event:allow-emit","core:event:allow-listen","core:event:allow-unlisten","os:allow-os-type","clipboard-manager:allow-clear","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","fs:allow-read-dir","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"clipboard-manager:allow-read-text","clipboard-manager:allow-write-text","core:webview:allow-set-webview-zoom","core:window:allow-close","core:window:allow-internal-toggle-maximize","core:window:allow-is-fullscreen","core:window:allow-is-maximized","core:window:allow-maximize","core:window:allow-minimize","core:window:allow-set-decorations","core:window:allow-set-title","core:window:allow-show","core:window:allow-start-dragging","core:window:allow-theme","core:window:allow-unmaximize","opener:allow-default-urls","opener:allow-open-path","opener:allow-open-url","opener:allow-reveal-item-in-dir","shell:allow-open","yaak-license:default","yaak-git:default","yaak-sync:default","yaak-ws:default"]}}
|
||||
{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["core:event:allow-emit","core:event:allow-listen","core:event:allow-unlisten","os:allow-os-type","clipboard-manager:allow-clear","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","fs:allow-read-dir","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"clipboard-manager:allow-read-text","clipboard-manager:allow-write-text","core:webview:allow-set-webview-zoom","core:window:allow-close","core:window:allow-internal-toggle-maximize","core:window:allow-is-fullscreen","core:window:allow-is-maximized","core:window:allow-maximize","core:window:allow-minimize","core:window:allow-set-decorations","core:window:allow-set-title","core:window:allow-show","core:window:allow-start-dragging","core:window:allow-theme","core:window:allow-unmaximize","opener:allow-default-urls","opener:allow-open-path","opener:allow-open-url","opener:allow-reveal-item-in-dir","shell:allow-open","yaak-git:default","yaak-license:default","yaak-models:default","yaak-sync:default","yaak-ws:default"]}}
|
||||
20
src-tauri/gen/schemas/desktop-schema.json
generated
20
src-tauri/gen/schemas/desktop-schema.json
generated
@@ -5642,41 +5642,21 @@
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
|
||||
20
src-tauri/gen/schemas/macOS-schema.json
generated
20
src-tauri/gen/schemas/macOS-schema.json
generated
@@ -5642,41 +5642,21 @@
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
|
||||
@@ -33,11 +33,11 @@ use yaak_grpc::{deserialize_message, serialize_message, Code, ServiceDefinition}
|
||||
use yaak_models::models::{
|
||||
CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection, GrpcConnectionState,
|
||||
GrpcEvent, GrpcEventType, GrpcRequest, HttpRequest, HttpResponse, HttpResponseState, KeyValue,
|
||||
ModelType, Plugin, Settings, WebsocketRequest, Workspace, WorkspaceMeta,
|
||||
Plugin, Settings, WebsocketRequest, Workspace, WorkspaceMeta,
|
||||
};
|
||||
use yaak_models::query_manager::QueryManagerExt;
|
||||
use yaak_models::util::{
|
||||
generate_model_id, get_workspace_export_resources, BatchUpsertResult, UpdateSource,
|
||||
get_workspace_export_resources, maybe_gen_id, maybe_gen_id_opt, BatchUpsertResult, UpdateSource,
|
||||
};
|
||||
use yaak_plugins::events::{
|
||||
BootResponse, CallHttpAuthenticationRequest, CallHttpRequestActionRequest, FilterResponse,
|
||||
@@ -792,39 +792,13 @@ async fn cmd_import_data<R: Runtime>(
|
||||
|
||||
let mut id_map: BTreeMap<String, String> = BTreeMap::new();
|
||||
|
||||
fn maybe_gen_id(id: &str, model: ModelType, ids: &mut BTreeMap<String, String>) -> String {
|
||||
if !id.starts_with("GENERATE_ID::") {
|
||||
return id.to_string();
|
||||
}
|
||||
|
||||
let unique_key = id.replace("GENERATE_ID", "");
|
||||
if let Some(existing) = ids.get(unique_key.as_str()) {
|
||||
existing.to_string()
|
||||
} else {
|
||||
let new_id = generate_model_id(model);
|
||||
ids.insert(unique_key, new_id.clone());
|
||||
new_id
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_gen_id_opt(
|
||||
id: Option<String>,
|
||||
model: ModelType,
|
||||
ids: &mut BTreeMap<String, String>,
|
||||
) -> Option<String> {
|
||||
match id {
|
||||
Some(id) => Some(maybe_gen_id(id.as_str(), model, ids)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
let resources = import_result.resources;
|
||||
|
||||
let workspaces: Vec<Workspace> = resources
|
||||
.workspaces
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.id = maybe_gen_id::<Workspace>(v.id.as_str(), &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -833,11 +807,9 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.environments
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
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);
|
||||
v.id = maybe_gen_id::<Environment>(v.id.as_str(), &mut id_map);
|
||||
v.workspace_id = maybe_gen_id::<Workspace>(v.workspace_id.as_str(), &mut id_map);
|
||||
v.environment_id = maybe_gen_id_opt::<Environment>(v.environment_id, &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -846,10 +818,9 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.folders
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeFolder, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
v.id = maybe_gen_id::<Folder>(v.id.as_str(), &mut id_map);
|
||||
v.workspace_id = maybe_gen_id::<Workspace>(v.workspace_id.as_str(), &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt::<Folder>(v.folder_id, &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -858,10 +829,9 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.http_requests
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeHttpRequest, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
v.id = maybe_gen_id::<HttpRequest>(v.id.as_str(), &mut id_map);
|
||||
v.workspace_id = maybe_gen_id::<Workspace>(v.workspace_id.as_str(), &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt::<Folder>(v.folder_id, &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -870,10 +840,9 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.grpc_requests
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeGrpcRequest, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
v.id = maybe_gen_id::<GrpcRequest>(v.id.as_str(), &mut id_map);
|
||||
v.workspace_id = maybe_gen_id::<Workspace>(v.workspace_id.as_str(), &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt::<Folder>(v.folder_id, &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -882,10 +851,9 @@ async fn cmd_import_data<R: Runtime>(
|
||||
.websocket_requests
|
||||
.into_iter()
|
||||
.map(|mut v| {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWebsocketRequest, &mut id_map);
|
||||
v.workspace_id =
|
||||
maybe_gen_id(v.workspace_id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
v.id = maybe_gen_id::<WebsocketRequest>(v.id.as_str(), &mut id_map);
|
||||
v.workspace_id = maybe_gen_id::<Workspace>(v.workspace_id.as_str(), &mut id_map);
|
||||
v.folder_id = maybe_gen_id_opt::<Folder>(v.folder_id, &mut id_map);
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
@@ -1605,10 +1573,11 @@ async fn cmd_list_workspaces<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> YaakResult<Vec<Workspace>> {
|
||||
let queries = app_handle.db();
|
||||
let workspaces = queries.find_all::<Workspace>()?;
|
||||
let db = app_handle.db();
|
||||
let mut workspaces = db.find_all::<Workspace>()?;
|
||||
|
||||
if workspaces.is_empty() {
|
||||
let workspace = queries.upsert_workspace(
|
||||
workspaces.push(db.upsert_workspace(
|
||||
&Workspace {
|
||||
name: "Yaak".to_string(),
|
||||
setting_follow_redirects: true,
|
||||
@@ -1616,11 +1585,10 @@ async fn cmd_list_workspaces<R: Runtime>(
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)?;
|
||||
Ok(vec![workspace])
|
||||
} else {
|
||||
Ok(workspaces)
|
||||
)?);
|
||||
}
|
||||
|
||||
Ok(workspaces)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -1990,10 +1958,10 @@ fn workspace_id_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<Str
|
||||
}
|
||||
}
|
||||
|
||||
async fn workspace_from_window<R: Runtime>(window: &WebviewWindow<R>) -> YaakResult<Workspace> {
|
||||
fn workspace_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<Workspace> {
|
||||
match workspace_id_from_window(&window) {
|
||||
None => Err(GenericError("Failed to get workspace ID from window".to_string())),
|
||||
Some(id) => Ok(window.db().get_workspace(id.as_str())?),
|
||||
None => None,
|
||||
Some(id) => window.db().get_workspace(&id).ok(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2003,7 +1971,7 @@ fn environment_id_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<S
|
||||
query_pairs.find(|(k, _v)| k == "environment_id").map(|(_k, v)| v.to_string())
|
||||
}
|
||||
|
||||
async fn environment_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<Environment> {
|
||||
fn environment_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<Environment> {
|
||||
match environment_id_from_window(&window) {
|
||||
None => None,
|
||||
Some(id) => window.db().get_environment(&id).ok(),
|
||||
@@ -2016,7 +1984,7 @@ fn cookie_jar_id_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<St
|
||||
query_pairs.find(|(k, _v)| k == "cookie_jar_id").map(|(_k, v)| v.to_string())
|
||||
}
|
||||
|
||||
async fn cookie_jar_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<CookieJar> {
|
||||
fn cookie_jar_from_window<R: Runtime>(window: &WebviewWindow<R>) -> Option<CookieJar> {
|
||||
match cookie_jar_id_from_window(&window) {
|
||||
None => None,
|
||||
Some(id) => window.db().get_cookie_jar(&id).ok(),
|
||||
|
||||
@@ -73,10 +73,9 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
let window = get_window_from_window_context(app_handle, &window_context)
|
||||
.expect("Failed to find window for render http request");
|
||||
|
||||
let workspace = workspace_from_window(&window)
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let workspace =
|
||||
workspace_from_window(&window).expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window);
|
||||
let base_environment = app_handle
|
||||
.db()
|
||||
.get_base_environment(&workspace.id)
|
||||
@@ -98,10 +97,9 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
let window = get_window_from_window_context(app_handle, &window_context)
|
||||
.expect("Failed to find window for render");
|
||||
|
||||
let workspace = workspace_from_window(&window)
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let workspace =
|
||||
workspace_from_window(&window).expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window);
|
||||
let base_environment = app_handle
|
||||
.db()
|
||||
.get_base_environment(&workspace.id)
|
||||
@@ -132,8 +130,6 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
None
|
||||
}
|
||||
InternalEventPayload::ReloadResponse(_) => {
|
||||
let window = get_window_from_window_context(app_handle, &window_context)
|
||||
.expect("Failed to find window for plugin reload");
|
||||
let plugins = app_handle.db().list_plugins().unwrap();
|
||||
for plugin in plugins {
|
||||
if plugin.directory != plugin_handle.dir {
|
||||
@@ -147,7 +143,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
app_handle.db().upsert_plugin(&new_plugin, &UpdateSource::Plugin).unwrap();
|
||||
}
|
||||
let toast_event = plugin_handle.build_event_to_send(
|
||||
&WindowContext::from_window(&window),
|
||||
&event.window_context,
|
||||
&InternalEventPayload::ShowToastRequest(ShowToastRequest {
|
||||
message: format!("Reloaded plugin {}", plugin_handle.dir),
|
||||
icon: Some(Icon::Info),
|
||||
@@ -162,11 +158,10 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
let window = get_window_from_window_context(app_handle, &window_context)
|
||||
.expect("Failed to find window for sending HTTP request");
|
||||
let mut http_request = req.http_request;
|
||||
let workspace = workspace_from_window(&window)
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let cookie_jar = cookie_jar_from_window(&window).await;
|
||||
let environment = environment_from_window(&window).await;
|
||||
let workspace =
|
||||
workspace_from_window(&window).expect("Failed to get workspace_id from window URL");
|
||||
let cookie_jar = cookie_jar_from_window(&window);
|
||||
let environment = environment_from_window(&window);
|
||||
|
||||
if http_request.workspace_id.is_empty() {
|
||||
http_request.workspace_id = workspace.id;
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { AnyModel } from './bindings/gen_models';
|
||||
|
||||
export * from './bindings/gen_models';
|
||||
|
||||
export async function upsertAnyModel(model: AnyModel): Promise<String> {
|
||||
return invoke<String>('plugin:yaak-models|upsert', { model });
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-delete-model"
|
||||
description = "Enables the delete_model command without any pre-configured scope."
|
||||
commands.allow = ["delete_model"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-delete-model"
|
||||
description = "Denies the delete_model command without any pre-configured scope."
|
||||
commands.deny = ["delete_model"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-upsert-model"
|
||||
description = "Enables the upsert_model command without any pre-configured scope."
|
||||
commands.allow = ["upsert_model"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-upsert-model"
|
||||
description = "Denies the upsert_model command without any pre-configured scope."
|
||||
commands.deny = ["upsert_model"]
|
||||
@@ -43,32 +43,6 @@ Denies the delete command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-delete-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the delete_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-delete-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the delete_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-upsert`
|
||||
|
||||
</td>
|
||||
@@ -89,32 +63,6 @@ Enables the upsert command without any pre-configured scope.
|
||||
|
||||
Denies the upsert command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-upsert-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the upsert_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-upsert-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the upsert_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -304,16 +304,6 @@
|
||||
"type": "string",
|
||||
"const": "deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -324,16 +314,6 @@
|
||||
"type": "string",
|
||||
"const": "deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::error::Error::GenericError;
|
||||
use crate::error::Result;
|
||||
use crate::query_manager::QueryManagerExt;
|
||||
use crate::models::AnyModel;
|
||||
use crate::query_manager::QueryManagerExt;
|
||||
use crate::util::UpdateSource;
|
||||
use tauri::{Runtime, WebviewWindow};
|
||||
|
||||
@@ -9,15 +10,44 @@ pub(crate) async fn upsert<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
model: AnyModel,
|
||||
) -> Result<String> {
|
||||
let db = window.db();
|
||||
let source = &UpdateSource::from_window(&window);
|
||||
let id = match model {
|
||||
AnyModel::HttpRequest(r) => window.db().upsert(&r, &UpdateSource::from_window(&window))?.id,
|
||||
_ => todo!(),
|
||||
AnyModel::HttpRequest(m) => db.upsert_http_request(&m, source)?.id,
|
||||
AnyModel::CookieJar(m) => db.upsert_cookie_jar(&m, source)?.id,
|
||||
AnyModel::Environment(m) => db.upsert_environment(&m, source)?.id,
|
||||
AnyModel::Folder(m) => db.upsert_folder(&m, source)?.id,
|
||||
AnyModel::GrpcRequest(m) => db.upsert_grpc_request(&m, source)?.id,
|
||||
AnyModel::HttpResponse(m) => db.upsert_http_response(&m, source)?.id,
|
||||
AnyModel::Plugin(m) => db.upsert_plugin(&m, source)?.id,
|
||||
AnyModel::Settings(m) => db.upsert_settings(&m, source)?.id,
|
||||
AnyModel::WebsocketRequest(m) => db.upsert_websocket_request(&m, source)?.id,
|
||||
AnyModel::Workspace(m) => db.upsert_workspace(&m, source)?.id,
|
||||
AnyModel::WorkspaceMeta(m) => db.upsert_workspace_meta(&m, source)?.id,
|
||||
a => return Err(GenericError(format!("Cannot upsert AnyModel {a:?})"))),
|
||||
};
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn delete() -> Result<()> {
|
||||
Ok(())
|
||||
pub(crate) fn delete<R: Runtime>(window: WebviewWindow<R>, model: AnyModel) -> Result<String> {
|
||||
let db = window.db();
|
||||
let source = &UpdateSource::from_window(&window);
|
||||
let id = match model {
|
||||
AnyModel::HttpRequest(m) => db.delete_http_request(&m, source)?.id,
|
||||
AnyModel::CookieJar(m) => db.delete_cookie_jar(&m, source)?.id,
|
||||
AnyModel::Environment(m) => db.delete_environment(&m, source)?.id,
|
||||
AnyModel::Folder(m) => db.delete_folder(&m, source)?.id,
|
||||
AnyModel::GrpcConnection(m) => db.delete_grpc_connection(&m, source)?.id,
|
||||
AnyModel::GrpcRequest(m) => db.delete_grpc_request(&m, source)?.id,
|
||||
AnyModel::HttpResponse(m) => db.delete_http_response(&m, source)?.id,
|
||||
AnyModel::Plugin(m) => db.delete_plugin(&m, source)?.id,
|
||||
AnyModel::WebsocketConnection(m) => db.delete_websocket_connection(&m, source)?.id,
|
||||
AnyModel::WebsocketRequest(m) => db.delete_websocket_request(&m, source)?.id,
|
||||
AnyModel::Workspace(m) => db.delete_workspace(&m, source)?.id,
|
||||
a => return Err(GenericError(format!("Cannot delete AnyModel {a:?})"))),
|
||||
};
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::connection_or_tx::ConnectionOrTx;
|
||||
use crate::error::Error::RowNotFound;
|
||||
use crate::models::{AnyModel, ModelType, UpsertModelInfo};
|
||||
use crate::util::{generate_model_id, ModelChangeEvent, ModelPayload, UpdateSource};
|
||||
use crate::models::{AnyModel, UpsertModelInfo};
|
||||
use crate::util::{ModelChangeEvent, ModelPayload, UpdateSource};
|
||||
use rusqlite::OptionalExtension;
|
||||
use sea_query::{
|
||||
Asterisk, Expr, IntoColumnRef, IntoIden, IntoTableRef, OnConflict, Query, SimpleExpr,
|
||||
@@ -100,7 +100,6 @@ impl<'a> DbContext<'a> {
|
||||
M::table_name(),
|
||||
M::id_column(),
|
||||
model.get_id().as_str(),
|
||||
|| generate_model_id(ModelType::TypeEnvironment),
|
||||
model.clone().insert_values(source)?,
|
||||
M::update_columns(),
|
||||
source,
|
||||
@@ -112,7 +111,6 @@ impl<'a> DbContext<'a> {
|
||||
table: impl IntoTableRef,
|
||||
id_col: impl IntoIden + Eq + Clone,
|
||||
id_val: &str,
|
||||
gen_id: fn() -> String,
|
||||
other_values: Vec<(impl IntoIden + Eq, impl Into<SimpleExpr>)>,
|
||||
update_columns: Vec<impl IntoIden>,
|
||||
source: &UpdateSource,
|
||||
@@ -122,7 +120,8 @@ impl<'a> DbContext<'a> {
|
||||
{
|
||||
let id_iden = id_col.into_iden();
|
||||
let mut column_vec = vec![id_iden.clone()];
|
||||
let mut value_vec = vec![if id_val == "" { gen_id().into() } else { id_val.into() }];
|
||||
let mut value_vec =
|
||||
vec![if id_val == "" { M::generate_id().into() } else { id_val.into() }];
|
||||
|
||||
for (col, val) in other_values {
|
||||
value_vec.push(val.into());
|
||||
|
||||
@@ -37,7 +37,7 @@ impl SqliteConnection {
|
||||
}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("yaak_models")
|
||||
tauri::plugin::Builder::new("yaak-models")
|
||||
.invoke_handler(generate_handler![upsert, delete])
|
||||
.setup(|app_handle, _api| {
|
||||
let app_path = app_handle.path().app_data_dir().unwrap();
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::models::HttpRequestIden::{
|
||||
Authentication, AuthenticationType, Body, BodyType, CreatedAt, Description, FolderId, Headers,
|
||||
Method, Name, SortPriority, UpdatedAt, Url, UrlParameters, WorkspaceId,
|
||||
};
|
||||
use crate::util::UpdateSource;
|
||||
use crate::util::{generate_prefixed_id, UpdateSource};
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use rusqlite::Row;
|
||||
use sea_query::{enum_def, IntoIden, IntoTableRef, SimpleExpr};
|
||||
@@ -121,6 +121,10 @@ impl UpsertModelInfo for Settings {
|
||||
SettingsIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
panic!("Settings does not have unique IDs")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -227,6 +231,10 @@ impl UpsertModelInfo for Workspace {
|
||||
WorkspaceIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("wk")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -312,6 +320,10 @@ impl UpsertModelInfo for WorkspaceMeta {
|
||||
WorkspaceMetaIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("wm")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -401,6 +413,10 @@ impl UpsertModelInfo for CookieJar {
|
||||
CookieJarIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("cj")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -470,6 +486,10 @@ impl UpsertModelInfo for Environment {
|
||||
EnvironmentIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("ev")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -555,6 +575,10 @@ impl UpsertModelInfo for Folder {
|
||||
FolderIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("fl")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -667,6 +691,10 @@ impl UpsertModelInfo for HttpRequest {
|
||||
HttpRequestIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("rq")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.to_string()
|
||||
}
|
||||
@@ -786,6 +814,10 @@ impl UpsertModelInfo for WebsocketConnection {
|
||||
WebsocketConnectionIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("wc")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -892,6 +924,10 @@ impl UpsertModelInfo for WebsocketRequest {
|
||||
WebsocketRequestIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("wr")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1009,6 +1045,10 @@ impl UpsertModelInfo for WebsocketEvent {
|
||||
WebsocketEventIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("we")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1118,6 +1158,10 @@ impl UpsertModelInfo for HttpResponse {
|
||||
HttpResponseIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("rs")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1242,6 +1286,10 @@ impl UpsertModelInfo for GrpcRequest {
|
||||
GrpcRequestIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("gr")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1361,6 +1409,10 @@ impl UpsertModelInfo for GrpcConnection {
|
||||
GrpcConnectionIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("gc")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1473,6 +1525,10 @@ impl UpsertModelInfo for GrpcEvent {
|
||||
GrpcEventIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("ge")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1556,6 +1612,10 @@ impl UpsertModelInfo for Plugin {
|
||||
PluginIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("pg")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1630,6 +1690,10 @@ impl UpsertModelInfo for SyncState {
|
||||
SyncStateIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("ss")
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
@@ -1748,47 +1812,6 @@ fn default_http_method() -> String {
|
||||
"GET".to_string()
|
||||
}
|
||||
|
||||
pub enum ModelType {
|
||||
TypeCookieJar,
|
||||
TypeEnvironment,
|
||||
TypeFolder,
|
||||
TypeGrpcConnection,
|
||||
TypeGrpcEvent,
|
||||
TypeGrpcRequest,
|
||||
TypeHttpRequest,
|
||||
TypeHttpResponse,
|
||||
TypePlugin,
|
||||
TypeSyncState,
|
||||
TypeWebSocketConnection,
|
||||
TypeWebSocketEvent,
|
||||
TypeWebsocketRequest,
|
||||
TypeWorkspace,
|
||||
TypeWorkspaceMeta,
|
||||
}
|
||||
|
||||
impl ModelType {
|
||||
pub fn id_prefix(&self) -> String {
|
||||
match self {
|
||||
ModelType::TypeCookieJar => "cj",
|
||||
ModelType::TypeEnvironment => "ev",
|
||||
ModelType::TypeFolder => "fl",
|
||||
ModelType::TypeGrpcConnection => "gc",
|
||||
ModelType::TypeGrpcEvent => "ge",
|
||||
ModelType::TypeGrpcRequest => "gr",
|
||||
ModelType::TypeHttpRequest => "rq",
|
||||
ModelType::TypeHttpResponse => "rs",
|
||||
ModelType::TypePlugin => "pg",
|
||||
ModelType::TypeWorkspace => "wk",
|
||||
ModelType::TypeWorkspaceMeta => "wm",
|
||||
ModelType::TypeSyncState => "ss",
|
||||
ModelType::TypeWebSocketConnection => "wc",
|
||||
ModelType::TypeWebSocketEvent => "we",
|
||||
ModelType::TypeWebsocketRequest => "wr",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_any_model {
|
||||
($($type:ident),* $(,)?) => {
|
||||
@@ -1850,34 +1873,19 @@ impl<'de> Deserialize<'de> for AnyModel {
|
||||
{
|
||||
let value = Value::deserialize(deserializer)?;
|
||||
let model = value.as_object().unwrap();
|
||||
use serde_json::from_value as fv;
|
||||
|
||||
let model = match model.get("model") {
|
||||
Some(m) if m == "http_request" => {
|
||||
AnyModel::HttpRequest(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "grpc_request" => {
|
||||
AnyModel::GrpcRequest(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "workspace" => {
|
||||
AnyModel::Workspace(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "environment" => {
|
||||
AnyModel::Environment(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "folder" => AnyModel::Folder(serde_json::from_value(value).unwrap()),
|
||||
Some(m) if m == "key_value" => {
|
||||
AnyModel::KeyValue(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "grpc_connection" => {
|
||||
AnyModel::GrpcConnection(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "grpc_event" => {
|
||||
AnyModel::GrpcEvent(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "cookie_jar" => {
|
||||
AnyModel::CookieJar(serde_json::from_value(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "plugin" => AnyModel::Plugin(serde_json::from_value(value).unwrap()),
|
||||
Some(m) if m == "http_request" => AnyModel::HttpRequest(fv(value).unwrap()),
|
||||
Some(m) if m == "grpc_request" => AnyModel::GrpcRequest(fv(value).unwrap()),
|
||||
Some(m) if m == "workspace" => AnyModel::Workspace(fv(value).unwrap()),
|
||||
Some(m) if m == "environment" => AnyModel::Environment(fv(value).unwrap()),
|
||||
Some(m) if m == "folder" => AnyModel::Folder(fv(value).unwrap()),
|
||||
Some(m) if m == "key_value" => AnyModel::KeyValue(fv(value).unwrap()),
|
||||
Some(m) if m == "grpc_connection" => AnyModel::GrpcConnection(fv(value).unwrap()),
|
||||
Some(m) if m == "grpc_event" => AnyModel::GrpcEvent(fv(value).unwrap()),
|
||||
Some(m) if m == "cookie_jar" => AnyModel::CookieJar(fv(value).unwrap()),
|
||||
Some(m) if m == "plugin" => AnyModel::Plugin(fv(value).unwrap()),
|
||||
Some(m) => {
|
||||
return Err(serde::de::Error::custom(format!("Unknown model {}", m)));
|
||||
}
|
||||
@@ -1920,6 +1928,7 @@ impl AnyModel {
|
||||
pub trait UpsertModelInfo {
|
||||
fn table_name() -> impl IntoTableRef;
|
||||
fn id_column() -> impl IntoIden + Eq + Clone;
|
||||
fn generate_id() -> String;
|
||||
fn get_id(&self) -> String;
|
||||
fn insert_values(
|
||||
self,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::db_context::DbContext;
|
||||
use crate::error::Result;
|
||||
use crate::models::{KeyValue, KeyValueIden};
|
||||
use crate::util::{ModelChangeEvent, ModelPayload, UpdateSource};
|
||||
@@ -5,7 +6,6 @@ use log::error;
|
||||
use sea_query::Keyword::CurrentTimestamp;
|
||||
use sea_query::{Asterisk, Cond, Expr, OnConflict, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
use crate::db_context::DbContext;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn list_key_values_raw(&self) -> Result<Vec<KeyValue>> {
|
||||
@@ -92,8 +92,39 @@ impl<'a> DbContext<'a> {
|
||||
value: &str,
|
||||
source: &UpdateSource,
|
||||
) -> (KeyValue, bool) {
|
||||
let existing = self.get_key_value_raw(namespace, key);
|
||||
match self.get_key_value_raw(namespace, key) {
|
||||
None => (
|
||||
self.upsert_key_value(
|
||||
&KeyValue {
|
||||
namespace: namespace.to_string(),
|
||||
key: key.to_string(),
|
||||
value: value.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
source,
|
||||
)
|
||||
.expect("Failed to create key value"),
|
||||
true,
|
||||
),
|
||||
Some(kv) => (
|
||||
self.upsert_key_value(
|
||||
&KeyValue {
|
||||
value: value.to_string(),
|
||||
..kv
|
||||
},
|
||||
source,
|
||||
)
|
||||
.expect("Failed to update key value"),
|
||||
false,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upsert_key_value(
|
||||
&self,
|
||||
key_value: &KeyValue,
|
||||
source: &UpdateSource,
|
||||
) -> Result<KeyValue> {
|
||||
let (sql, params) = Query::insert()
|
||||
.into_table(KeyValueIden::Table)
|
||||
.columns([
|
||||
@@ -106,9 +137,9 @@ impl<'a> DbContext<'a> {
|
||||
.values_panic([
|
||||
CurrentTimestamp.into(),
|
||||
CurrentTimestamp.into(),
|
||||
namespace.into(),
|
||||
key.into(),
|
||||
value.into(),
|
||||
key_value.namespace.clone().into(),
|
||||
key_value.key.clone().into(),
|
||||
key_value.value.clone().into(),
|
||||
])
|
||||
.on_conflict(
|
||||
OnConflict::new()
|
||||
@@ -130,7 +161,7 @@ impl<'a> DbContext<'a> {
|
||||
};
|
||||
self.tx.try_send(payload).unwrap();
|
||||
|
||||
(m, existing.is_none())
|
||||
Ok(m)
|
||||
}
|
||||
|
||||
pub fn delete_key_value(
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
use std::collections::BTreeMap;
|
||||
use crate::error::Result;
|
||||
use crate::models::{
|
||||
AnyModel, Environment, Folder, GrpcRequest, HttpRequest, ModelType, WebsocketRequest,
|
||||
Workspace, WorkspaceIden,
|
||||
};
|
||||
use crate::models::{AnyModel, Environment, Folder, GrpcRequest, HttpRequest, UpsertModelInfo, WebsocketRequest, Workspace, WorkspaceIden};
|
||||
use crate::query_manager::QueryManagerExt;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use log::warn;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, Listener, Runtime, WebviewWindow};
|
||||
use ts_rs::TS;
|
||||
use crate::query_manager::QueryManagerExt;
|
||||
|
||||
pub fn generate_model_id(model: ModelType) -> String {
|
||||
let id = generate_id();
|
||||
format!("{}_{}", model.id_prefix(), id)
|
||||
pub fn generate_prefixed_id(prefix: &str) -> String {
|
||||
format!("{prefix}_{}", generate_id())
|
||||
}
|
||||
|
||||
pub fn generate_id() -> String {
|
||||
@@ -151,3 +148,28 @@ pub async fn get_workspace_export_resources<R: Runtime>(
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn maybe_gen_id<M: UpsertModelInfo>(id: &str, ids: &mut BTreeMap<String, String>) -> String {
|
||||
if !id.starts_with("GENERATE_ID::") {
|
||||
return id.to_string();
|
||||
}
|
||||
|
||||
let unique_key = id.replace("GENERATE_ID", "");
|
||||
if let Some(existing) = ids.get(unique_key.as_str()) {
|
||||
existing.to_string()
|
||||
} else {
|
||||
let new_id = M::generate_id();
|
||||
ids.insert(unique_key, new_id.clone());
|
||||
new_id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_gen_id_opt<M: UpsertModelInfo>(
|
||||
id: Option<String>,
|
||||
ids: &mut BTreeMap<String, String>,
|
||||
) -> Option<String> {
|
||||
match id {
|
||||
Some(id) => Some(maybe_gen_id::<M>(id.as_str(), ids)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
},
|
||||
[activeRequestId, setActiveTabs],
|
||||
);
|
||||
console.log("ACTIVE RESPONSE", activeResponse);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -152,7 +152,9 @@ export const SidebarItem = memo(function SidebarItem({
|
||||
if (request == null) return;
|
||||
await upsertWebsocketRequest.mutateAsync({ ...request, name: el.value });
|
||||
}
|
||||
setEditing(false);
|
||||
|
||||
// Slight delay for the model to propagate to the local store
|
||||
setTimeout(() => setEditing(false));
|
||||
},
|
||||
[itemId, itemModel, updateGrpcRequest, updateHttpRequest],
|
||||
);
|
||||
@@ -268,10 +270,7 @@ export const SidebarItem = memo(function SidebarItem({
|
||||
size="sm"
|
||||
icon="chevron_right"
|
||||
color="secondary"
|
||||
className={classNames(
|
||||
'transition-transform',
|
||||
!collapsed && 'transform rotate-90',
|
||||
)}
|
||||
className={classNames('transition-transform', !collapsed && 'transform rotate-90')}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import type { CookieJar } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { cookieJarsAtom } from './useCookieJars';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { removeModelById } from './useSyncModelStores';
|
||||
|
||||
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
const setCookieJars = useSetAtom(cookieJarsAtom);
|
||||
|
||||
return useFastMutation<CookieJar | null, string>({
|
||||
mutationKey: ['delete_cookie_jar', cookieJar?.id],
|
||||
mutationFn: async () => {
|
||||
@@ -25,10 +20,5 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
},
|
||||
onSuccess: (cookieJar) => {
|
||||
if (cookieJar == null) return;
|
||||
|
||||
setCookieJars(removeModelById(cookieJar));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import type { Environment } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { environmentsAtom } from './useEnvironments';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { removeModelById } from './useSyncModelStores';
|
||||
|
||||
export function useDeleteEnvironment(environment: Environment | null) {
|
||||
const setEnvironments = useSetAtom(environmentsAtom);
|
||||
|
||||
return useFastMutation<Environment | null, string>({
|
||||
mutationKey: ['delete_environment', environment?.id],
|
||||
mutationFn: async () => {
|
||||
@@ -25,10 +20,5 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
|
||||
},
|
||||
onSuccess: (environment) => {
|
||||
if (environment == null) return;
|
||||
|
||||
setEnvironments(removeModelById(environment));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import type { Folder } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { showConfirmDelete } from '../lib/confirm';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { foldersAtom, getFolder } from './useFolders';
|
||||
import { removeModelById } from './useSyncModelStores';
|
||||
import { getFolder } from './useFolders';
|
||||
|
||||
export function useDeleteFolder(id: string | null) {
|
||||
const setFolders = useSetAtom(foldersAtom);
|
||||
|
||||
return useFastMutation<Folder | null, string>({
|
||||
mutationKey: ['delete_folder', id],
|
||||
mutationFn: async () => {
|
||||
@@ -26,10 +22,5 @@ export function useDeleteFolder(id: string | null) {
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_folder', { folderId: id });
|
||||
},
|
||||
onSuccess: (folder) => {
|
||||
if (folder == null) return;
|
||||
|
||||
setFolders(removeModelById(folder));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { GrpcConnection } from '@yaakapp-internal/models';
|
||||
import {useSetAtom} from "jotai";
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import {grpcConnectionsAtom} from "./useGrpcConnections";
|
||||
import {removeModelById} from "./useSyncModelStores";
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
|
||||
export function useDeleteGrpcConnection(id: string | null) {
|
||||
const setGrpcConnections = useSetAtom(grpcConnectionsAtom);
|
||||
return useFastMutation<GrpcConnection>({
|
||||
mutationKey: ['delete_grpc_connection', id],
|
||||
mutationFn: async () => {
|
||||
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
|
||||
},
|
||||
onSuccess: (connection) => {
|
||||
if (connection == null) return;
|
||||
|
||||
setGrpcConnections(removeModelById(connection));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import {useSetAtom} from "jotai";
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import {httpResponsesAtom} from "./useHttpResponses";
|
||||
import {removeModelById} from "./useSyncModelStores";
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
|
||||
export function useDeleteHttpResponse(id: string | null) {
|
||||
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
||||
return useFastMutation<HttpResponse>({
|
||||
mutationKey: ['delete_http_response', id],
|
||||
mutationFn: async () => {
|
||||
return await invokeCmd('cmd_delete_http_response', { id: id });
|
||||
},
|
||||
onSuccess: (response) => {
|
||||
setHttpResponses(removeModelById(response));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ export function useSyncModelStores() {
|
||||
});
|
||||
}
|
||||
|
||||
export function updateModelList<T extends AnyModel>(model: T) {
|
||||
function updateModelList<T extends AnyModel>(model: T) {
|
||||
// Mark these models as DESC instead of ASC
|
||||
const pushToFront =
|
||||
model.model === 'http_response' ||
|
||||
@@ -152,7 +152,7 @@ export function updateModelList<T extends AnyModel>(model: T) {
|
||||
};
|
||||
}
|
||||
|
||||
export function removeModelById<T extends { id: string }>(model: T) {
|
||||
function removeModelById<T extends { id: string }>(model: T) {
|
||||
return (prevEntries: T[] | undefined) => {
|
||||
const entries = prevEntries?.filter((e) => e.id !== model.id) ?? [];
|
||||
|
||||
@@ -165,7 +165,7 @@ export function removeModelById<T extends { id: string }>(model: T) {
|
||||
};
|
||||
}
|
||||
|
||||
export function removeModelByKv(model: KeyValue) {
|
||||
function removeModelByKv(model: KeyValue) {
|
||||
return (prevEntries: KeyValue[] | undefined) =>
|
||||
prevEntries?.filter(
|
||||
(e) =>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { Folder } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { foldersAtom, getFolder } from './useFolders';
|
||||
import { updateModelList } from './useSyncModelStores';
|
||||
import { getFolder } from './useFolders';
|
||||
|
||||
export function useUpdateAnyFolder() {
|
||||
const setFolders = useSetAtom(foldersAtom);
|
||||
return useFastMutation<Folder, unknown, { id: string; update: (r: Folder) => Folder }>({
|
||||
mutationKey: ['update_any_folder'],
|
||||
mutationFn: async ({ id, update }) => {
|
||||
@@ -17,8 +14,5 @@ export function useUpdateAnyFolder() {
|
||||
|
||||
return invokeCmd<Folder>('cmd_update_folder', { folder: update(folder) });
|
||||
},
|
||||
onSuccess: async (folder) => {
|
||||
setFolders(updateModelList(folder));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { getGrpcRequest, grpcRequestsAtom } from './useGrpcRequests';
|
||||
import { updateModelList } from './useSyncModelStores';
|
||||
import { getGrpcRequest } from './useGrpcRequests';
|
||||
|
||||
export function useUpdateAnyGrpcRequest() {
|
||||
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
||||
return useFastMutation<
|
||||
GrpcRequest,
|
||||
unknown,
|
||||
@@ -23,8 +20,5 @@ export function useUpdateAnyGrpcRequest() {
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
return invokeCmd<GrpcRequest>('cmd_update_grpc_request', { request: patchedRequest });
|
||||
},
|
||||
onSuccess: (request) => {
|
||||
setGrpcRequests(updateModelList(request));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { upsertAnyModel } from '@yaakapp-internal/models';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { getHttpRequest, httpRequestsAtom } from './useHttpRequests';
|
||||
import { updateModelList } from './useSyncModelStores';
|
||||
import { getHttpRequest } from './useHttpRequests';
|
||||
|
||||
export function useUpdateAnyHttpRequest() {
|
||||
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
||||
return useFastMutation<
|
||||
HttpRequest,
|
||||
void,
|
||||
unknown,
|
||||
{ id: string; update: Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest) }
|
||||
>({
|
||||
@@ -21,10 +18,7 @@ export function useUpdateAnyHttpRequest() {
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
return invokeCmd<HttpRequest>('cmd_upsert_http_request', { request: patchedRequest });
|
||||
},
|
||||
onSuccess: async (request) => {
|
||||
setHttpRequests(updateModelList(request));
|
||||
await upsertAnyModel(patchedRequest);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { CookieJar } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { cookieJarsAtom, getCookieJar } from './useCookieJars';
|
||||
import { updateModelList } from './useSyncModelStores';
|
||||
import { getCookieJar } from './useCookieJars';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
|
||||
export function useUpdateCookieJar(id: string | null) {
|
||||
const setCookieJars = useSetAtom(cookieJarsAtom);
|
||||
return useFastMutation<CookieJar, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
|
||||
mutationKey: ['update_cookie_jar', id],
|
||||
mutationFn: async (v) => {
|
||||
@@ -18,8 +15,5 @@ export function useUpdateCookieJar(id: string | null) {
|
||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
||||
return invokeCmd<CookieJar>('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||
},
|
||||
onSuccess: (cookieJar) => {
|
||||
setCookieJars(updateModelList(cookieJar));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { Environment } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { environmentsAtom, getEnvironment } from './useEnvironments';
|
||||
import { getEnvironment } from './useEnvironments';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { updateModelList } from './useSyncModelStores';
|
||||
|
||||
export function useUpdateEnvironment(id: string | null) {
|
||||
const setEnvironments = useSetAtom(environmentsAtom);
|
||||
return useFastMutation<
|
||||
Environment,
|
||||
unknown,
|
||||
@@ -22,8 +19,5 @@ export function useUpdateEnvironment(id: string | null) {
|
||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||
return invokeCmd<Environment>('cmd_update_environment', { environment: newEnvironment });
|
||||
},
|
||||
onSuccess: async (environment) => {
|
||||
setEnvironments(updateModelList(environment));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user