mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-24 09:38:29 +02:00
A bunch of improvements to chaining
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -27,7 +27,7 @@
|
|||||||
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
|
||||||
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
|
||||||
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
|
||||||
"@yaakapp/api": "^0.1.7",
|
"@yaakapp/api": "^0.1.9",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"cm6-graphql": "^0.0.9",
|
"cm6-graphql": "^0.0.9",
|
||||||
@@ -2990,9 +2990,9 @@
|
|||||||
"integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="
|
"integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@yaakapp/api": {
|
"node_modules/@yaakapp/api": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.9.tgz",
|
||||||
"integrity": "sha512-6dheXUuhX3o1KwZ7ngtB/OcQ4qCiXxg3LN2t1jA28nnZBlGCek+h9yndiF/PGWl5yReMcXy8rn4pq4W9zAGHLg==",
|
"integrity": "sha512-5mgBoNplXUnNIUpLgGPCjcf6p/BcsU485cH3/MnIzcXIaMfFpZVVwHq5vf9cm+NDcr5hwYmPyIbwmBf9uVoV2Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^22.0.0"
|
"@types/node": "^22.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
|
||||||
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
|
||||||
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
|
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
|
||||||
"@yaakapp/api": "^0.1.7",
|
"@yaakapp/api": "^0.1.9",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"cm6-graphql": "^0.0.9",
|
"cm6-graphql": "^0.0.9",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@yaakapp/api",
|
"name": "@yaakapp/api",
|
||||||
"version": "0.1.7",
|
"version": "0.1.9",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"typings": "./lib/index.d.ts",
|
"typings": "./lib/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
3
plugin-runtime-types/src/gen/FindHttpResponsesRequest.ts
Normal file
3
plugin-runtime-types/src/gen/FindHttpResponsesRequest.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type FindHttpResponsesRequest = { requestId: string, limit: bigint | null, };
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { HttpResponse } from "./HttpResponse";
|
||||||
|
|
||||||
|
export type FindHttpResponsesResponse = { httpResponses: Array<HttpResponse>, };
|
||||||
@@ -10,6 +10,8 @@ import type { ExportHttpRequestRequest } from "./ExportHttpRequestRequest";
|
|||||||
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
|
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
|
||||||
import type { FilterRequest } from "./FilterRequest";
|
import type { FilterRequest } from "./FilterRequest";
|
||||||
import type { FilterResponse } from "./FilterResponse";
|
import type { FilterResponse } from "./FilterResponse";
|
||||||
|
import type { FindHttpResponsesRequest } from "./FindHttpResponsesRequest";
|
||||||
|
import type { FindHttpResponsesResponse } from "./FindHttpResponsesResponse";
|
||||||
import type { GetHttpRequestActionsRequest } from "./GetHttpRequestActionsRequest";
|
import type { GetHttpRequestActionsRequest } from "./GetHttpRequestActionsRequest";
|
||||||
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
|
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
|
||||||
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
|
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
|
||||||
@@ -23,4 +25,4 @@ import type { SendHttpRequestRequest } from "./SendHttpRequestRequest";
|
|||||||
import type { SendHttpRequestResponse } from "./SendHttpRequestResponse";
|
import type { SendHttpRequestResponse } from "./SendHttpRequestResponse";
|
||||||
import type { ShowToastRequest } from "./ShowToastRequest";
|
import type { ShowToastRequest } from "./ShowToastRequest";
|
||||||
|
|
||||||
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "empty_response" } & EmptyResponse;
|
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyResponse;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export * from './gen/ExportHttpRequestResponse';
|
|||||||
export * from './gen/FilterRequest';
|
export * from './gen/FilterRequest';
|
||||||
export * from './gen/FilterResponse';
|
export * from './gen/FilterResponse';
|
||||||
export * from './gen/Folder';
|
export * from './gen/Folder';
|
||||||
|
export * from './gen/FindHttpResponsesRequest';
|
||||||
|
export * from './gen/FindHttpResponsesResponse';
|
||||||
export * from './gen/GetHttpRequestActionsResponse';
|
export * from './gen/GetHttpRequestActionsResponse';
|
||||||
export * from './gen/GetHttpRequestByIdRequest';
|
export * from './gen/GetHttpRequestByIdRequest';
|
||||||
export * from './gen/GetHttpRequestByIdResponse';
|
export * from './gen/GetHttpRequestByIdResponse';
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { FindHttpResponsesRequest } from '../gen/FindHttpResponsesRequest';
|
||||||
|
import { FindHttpResponsesResponse } from '../gen/FindHttpResponsesResponse';
|
||||||
import { GetHttpRequestByIdRequest } from '../gen/GetHttpRequestByIdRequest';
|
import { GetHttpRequestByIdRequest } from '../gen/GetHttpRequestByIdRequest';
|
||||||
import { GetHttpRequestByIdResponse } from '../gen/GetHttpRequestByIdResponse';
|
import { GetHttpRequestByIdResponse } from '../gen/GetHttpRequestByIdResponse';
|
||||||
import { RenderHttpRequestRequest } from '../gen/RenderHttpRequestRequest';
|
import { RenderHttpRequestRequest } from '../gen/RenderHttpRequestRequest';
|
||||||
@@ -18,4 +20,7 @@ export type Context = {
|
|||||||
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
|
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
|
||||||
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse['httpRequest']>;
|
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse['httpRequest']>;
|
||||||
};
|
};
|
||||||
|
httpResponse: {
|
||||||
|
find(args: FindHttpResponsesRequest): Promise<FindHttpResponsesResponse['httpResponses']>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import { TemplateFunction } from '../gen/TemplateFunction';
|
|||||||
import { Context } from './Context';
|
import { Context } from './Context';
|
||||||
|
|
||||||
export type TemplateFunctionPlugin = TemplateFunction & {
|
export type TemplateFunctionPlugin = TemplateFunction & {
|
||||||
onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise<string>;
|
onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise<string | null>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
FindHttpResponsesResponse,
|
||||||
GetHttpRequestByIdResponse,
|
GetHttpRequestByIdResponse,
|
||||||
HttpRequestAction,
|
HttpRequestAction,
|
||||||
ImportResponse,
|
ImportResponse,
|
||||||
@@ -17,6 +18,7 @@ import { readFileSync } from 'node:fs';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import * as util from 'node:util';
|
import * as util from 'node:util';
|
||||||
import { parentPort, workerData } from 'node:worker_threads';
|
import { parentPort, workerData } from 'node:worker_threads';
|
||||||
|
import { text } from '../../src-web/components/core/Editor/text/extension';
|
||||||
|
|
||||||
new Promise<void>(async (resolve, reject) => {
|
new Promise<void>(async (resolve, reject) => {
|
||||||
const { pluginDir, pluginRefId } = workerData;
|
const { pluginDir, pluginRefId } = workerData;
|
||||||
@@ -101,6 +103,13 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
await sendAndWaitForReply({ type: 'show_toast_request', ...args });
|
await sendAndWaitForReply({ type: 'show_toast_request', ...args });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
httpResponse: {
|
||||||
|
async find(args) {
|
||||||
|
const payload = { type: 'find_http_responses_request', ...args } as const;
|
||||||
|
const { httpResponses } = await sendAndWaitForReply<FindHttpResponsesResponse>(payload);
|
||||||
|
return httpResponses;
|
||||||
|
},
|
||||||
|
},
|
||||||
httpRequest: {
|
httpRequest: {
|
||||||
async getById({ id }) {
|
async getById({ id }) {
|
||||||
const payload = { type: 'get_http_request_by_id_request', id } as const;
|
const payload = { type: 'get_http_request_by_id_request', id } as const;
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ use yaak_models::queries::{
|
|||||||
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
||||||
get_or_create_settings, get_workspace, list_cookie_jars, list_environments, list_folders,
|
get_or_create_settings, get_workspace, list_cookie_jars, list_environments, list_folders,
|
||||||
list_grpc_connections, list_grpc_events, list_grpc_requests, list_http_requests,
|
list_grpc_connections, list_grpc_events, list_grpc_requests, list_http_requests,
|
||||||
list_responses, list_workspaces, set_key_value_raw, update_response_if_id, update_settings,
|
list_http_responses, list_workspaces, set_key_value_raw, update_response_if_id,
|
||||||
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
||||||
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
|
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
|
||||||
};
|
};
|
||||||
use yaak_plugin_runtime::events::{
|
use yaak_plugin_runtime::events::{
|
||||||
CallHttpRequestActionRequest, FilterResponse, GetHttpRequestActionsResponse,
|
CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
||||||
GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, InternalEvent, InternalEventPayload,
|
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse,
|
||||||
RenderHttpRequestResponse, SendHttpRequestResponse,
|
InternalEvent, InternalEventPayload, RenderHttpRequestResponse, SendHttpRequestResponse,
|
||||||
};
|
};
|
||||||
use yaak_templates::{Parser, Tokens};
|
use yaak_templates::{Parser, Tokens};
|
||||||
|
|
||||||
@@ -1496,7 +1496,7 @@ async fn cmd_list_http_responses(
|
|||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
w: WebviewWindow,
|
w: WebviewWindow,
|
||||||
) -> Result<Vec<HttpResponse>, String> {
|
) -> Result<Vec<HttpResponse>, String> {
|
||||||
list_responses(&w, request_id, limit)
|
list_http_responses(&w, request_id, limit)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
@@ -1960,12 +1960,6 @@ async fn handle_plugin_event<R: Runtime>(
|
|||||||
event: &InternalEvent,
|
event: &InternalEvent,
|
||||||
) -> Option<InternalEventPayload> {
|
) -> Option<InternalEventPayload> {
|
||||||
let event = match event.clone().payload {
|
let event = match event.clone().payload {
|
||||||
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
|
||||||
let http_request = get_http_request(app_handle, req.id.as_str()).await.ok();
|
|
||||||
Some(InternalEventPayload::GetHttpRequestByIdResponse(
|
|
||||||
GetHttpRequestByIdResponse { http_request },
|
|
||||||
))
|
|
||||||
}
|
|
||||||
InternalEventPayload::CopyTextRequest(req) => {
|
InternalEventPayload::CopyTextRequest(req) => {
|
||||||
app_handle
|
app_handle
|
||||||
.clipboard()
|
.clipboard()
|
||||||
@@ -1979,6 +1973,21 @@ async fn handle_plugin_event<R: Runtime>(
|
|||||||
.expect("Failed to emit show_toast");
|
.expect("Failed to emit show_toast");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
InternalEventPayload::FindHttpResponsesRequest(req) => {
|
||||||
|
let http_responses =
|
||||||
|
list_http_responses(app_handle, req.request_id.as_str(), req.limit)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
Some(InternalEventPayload::FindHttpResponsesResponse(
|
||||||
|
FindHttpResponsesResponse { http_responses },
|
||||||
|
))
|
||||||
|
}
|
||||||
|
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
||||||
|
let http_request = get_http_request(app_handle, req.id.as_str()).await.ok();
|
||||||
|
Some(InternalEventPayload::GetHttpRequestByIdResponse(
|
||||||
|
GetHttpRequestByIdResponse { http_request },
|
||||||
|
))
|
||||||
|
}
|
||||||
InternalEventPayload::RenderHttpRequestRequest(req) => {
|
InternalEventPayload::RenderHttpRequestRequest(req) => {
|
||||||
let webview_windows = app_handle.get_focused_window()?.webview_windows();
|
let webview_windows = app_handle.get_focused_window()?.webview_windows();
|
||||||
let w = match webview_windows.iter().next() {
|
let w = match webview_windows.iter().next() {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use crate::template_callback::PluginTemplateCallback;
|
use crate::template_callback::PluginTemplateCallback;
|
||||||
use serde_json::Value;
|
use serde_json::{json, Map, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tauri::{AppHandle, Manager, Runtime};
|
use tauri::{AppHandle, Manager, Runtime};
|
||||||
use yaak_models::models::{Environment, EnvironmentVariable, GrpcMetadataEntry, GrpcRequest, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace};
|
use yaak_models::models::{
|
||||||
|
Environment, EnvironmentVariable, GrpcMetadataEntry, GrpcRequest, HttpRequest,
|
||||||
|
HttpRequestHeader, HttpUrlParameter, Workspace,
|
||||||
|
};
|
||||||
use yaak_templates::{parse_and_render, TemplateCallback};
|
use yaak_templates::{parse_and_render, TemplateCallback};
|
||||||
|
|
||||||
pub async fn render_template<R: Runtime>(
|
pub async fn render_template<R: Runtime>(
|
||||||
@@ -36,17 +39,12 @@ pub async fn render_grpc_request<R: Runtime>(
|
|||||||
|
|
||||||
let mut authentication = HashMap::new();
|
let mut authentication = HashMap::new();
|
||||||
for (k, v) in r.authentication.clone() {
|
for (k, v) in r.authentication.clone() {
|
||||||
let v = if v.is_string() {
|
authentication.insert(k, render_json_value(v, vars, cb).await);
|
||||||
render(v.as_str().unwrap(), vars, cb).await
|
|
||||||
} else {
|
|
||||||
v.to_string()
|
|
||||||
};
|
|
||||||
authentication.insert(render(k.as_str(), vars, cb).await, Value::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = render(r.url.as_str(), vars, cb).await;
|
let url = render(r.url.as_str(), vars, cb).await;
|
||||||
|
|
||||||
GrpcRequest{
|
GrpcRequest {
|
||||||
url,
|
url,
|
||||||
metadata,
|
metadata,
|
||||||
authentication,
|
authentication,
|
||||||
@@ -83,22 +81,12 @@ pub async fn render_http_request<R: Runtime>(
|
|||||||
|
|
||||||
let mut body = HashMap::new();
|
let mut body = HashMap::new();
|
||||||
for (k, v) in r.body.clone() {
|
for (k, v) in r.body.clone() {
|
||||||
let v = if v.is_string() {
|
body.insert(k, render_json_value(v, vars, cb).await);
|
||||||
render(v.as_str().unwrap(), vars, cb).await
|
|
||||||
} else {
|
|
||||||
v.to_string()
|
|
||||||
};
|
|
||||||
body.insert(render(k.as_str(), vars, cb).await, Value::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut authentication = HashMap::new();
|
let mut authentication = HashMap::new();
|
||||||
for (k, v) in r.authentication.clone() {
|
for (k, v) in r.authentication.clone() {
|
||||||
let v = if v.is_string() {
|
authentication.insert(k, render_json_value(v, vars, cb).await);
|
||||||
render(v.as_str().unwrap(), vars, cb).await
|
|
||||||
} else {
|
|
||||||
v.to_string()
|
|
||||||
};
|
|
||||||
authentication.insert(render(k.as_str(), vars, cb).await, Value::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = render(r.url.clone().as_str(), vars, cb).await;
|
let url = render(r.url.clone().as_str(), vars, cb).await;
|
||||||
@@ -173,3 +161,103 @@ fn add_variable_to_map(
|
|||||||
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn render_json_value<T: TemplateCallback>(
|
||||||
|
v: Value,
|
||||||
|
vars: &HashMap<String, String>,
|
||||||
|
cb: &T,
|
||||||
|
) -> Value {
|
||||||
|
match v {
|
||||||
|
Value::String(s) => json!(render(s.as_str(), vars, cb).await),
|
||||||
|
Value::Array(a) => {
|
||||||
|
let mut new_a = Vec::new();
|
||||||
|
for v in a {
|
||||||
|
new_a.push(Box::pin(render_json_value(v, vars, cb)).await)
|
||||||
|
}
|
||||||
|
json!(new_a)
|
||||||
|
}
|
||||||
|
Value::Object(o) => {
|
||||||
|
let mut new_o = Map::new();
|
||||||
|
for (k, v) in o {
|
||||||
|
let key = Box::pin(render(k.as_str(), vars, cb)).await;
|
||||||
|
let value = Box::pin(render_json_value(v, vars, cb)).await;
|
||||||
|
new_o.insert(key, value);
|
||||||
|
}
|
||||||
|
json!(new_o)
|
||||||
|
}
|
||||||
|
v => v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json::json;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use yaak_templates::TemplateCallback;
|
||||||
|
|
||||||
|
struct EmptyCB {}
|
||||||
|
|
||||||
|
impl TemplateCallback for EmptyCB {
|
||||||
|
async fn run(
|
||||||
|
&self,
|
||||||
|
_fn_name: &str,
|
||||||
|
_args: HashMap<String, String>,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn render_json_value_string() {
|
||||||
|
let v = json!("${[a]}");
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
vars.insert("a".to_string(), "aaa".to_string());
|
||||||
|
|
||||||
|
let result = super::render_json_value(v, &vars, &EmptyCB {}).await;
|
||||||
|
assert_eq!(result, json!("aaa"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn render_json_value_array() {
|
||||||
|
let v = json!(["${[a]}", "${[a]}"]);
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
vars.insert("a".to_string(), "aaa".to_string());
|
||||||
|
|
||||||
|
let result = super::render_json_value(v, &vars, &EmptyCB {}).await;
|
||||||
|
assert_eq!(result, json!(["aaa", "aaa"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn render_json_value_object() {
|
||||||
|
let v = json!({"${[a]}": "${[a]}"});
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
vars.insert("a".to_string(), "aaa".to_string());
|
||||||
|
|
||||||
|
let result = super::render_json_value(v, &vars, &EmptyCB {}).await;
|
||||||
|
assert_eq!(result, json!({"aaa": "aaa"}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn render_json_value_nested() {
|
||||||
|
let v = json!([
|
||||||
|
123,
|
||||||
|
{"${[a]}": "${[a]}"},
|
||||||
|
null,
|
||||||
|
"${[a]}",
|
||||||
|
false,
|
||||||
|
{"x": ["${[a]}"]}
|
||||||
|
]);
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
vars.insert("a".to_string(), "aaa".to_string());
|
||||||
|
|
||||||
|
let result = super::render_json_value(v, &vars, &EmptyCB {}).await;
|
||||||
|
assert_eq!(result, json!([
|
||||||
|
123,
|
||||||
|
{"aaa": "aaa"},
|
||||||
|
null,
|
||||||
|
"aaa",
|
||||||
|
false,
|
||||||
|
{"x": ["aaa"]}
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -720,6 +720,8 @@ pub async fn delete_environment<R: Runtime>(
|
|||||||
emit_deleted_model(window, env)
|
emit_deleted_model(window, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SETTINGS_ID: &str = "default";
|
||||||
|
|
||||||
async fn get_settings<R: Runtime>(mgr: &impl Manager<R>) -> Result<Settings> {
|
async fn get_settings<R: Runtime>(mgr: &impl Manager<R>) -> Result<Settings> {
|
||||||
let dbm = &*mgr.state::<SqliteConnection>();
|
let dbm = &*mgr.state::<SqliteConnection>();
|
||||||
let db = dbm.0.lock().await.get().unwrap();
|
let db = dbm.0.lock().await.get().unwrap();
|
||||||
@@ -727,7 +729,7 @@ async fn get_settings<R: Runtime>(mgr: &impl Manager<R>) -> Result<Settings> {
|
|||||||
let (sql, params) = Query::select()
|
let (sql, params) = Query::select()
|
||||||
.from(SettingsIden::Table)
|
.from(SettingsIden::Table)
|
||||||
.column(Asterisk)
|
.column(Asterisk)
|
||||||
.cond_where(Expr::col(SettingsIden::Id).eq("default"))
|
.cond_where(Expr::col(SettingsIden::Id).eq(SETTINGS_ID))
|
||||||
.build_rusqlite(SqliteQueryBuilder);
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
let mut stmt = db.prepare(sql.as_str())?;
|
let mut stmt = db.prepare(sql.as_str())?;
|
||||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||||
@@ -744,7 +746,7 @@ pub async fn get_or_create_settings<R: Runtime>(mgr: &impl Manager<R>) -> Settin
|
|||||||
let (sql, params) = Query::insert()
|
let (sql, params) = Query::insert()
|
||||||
.into_table(SettingsIden::Table)
|
.into_table(SettingsIden::Table)
|
||||||
.columns([SettingsIden::Id])
|
.columns([SettingsIden::Id])
|
||||||
.values_panic(["default".into()])
|
.values_panic([SETTINGS_ID.into()])
|
||||||
.returning_all()
|
.returning_all()
|
||||||
.build_rusqlite(SqliteQueryBuilder);
|
.build_rusqlite(SqliteQueryBuilder);
|
||||||
|
|
||||||
@@ -1324,13 +1326,13 @@ pub async fn delete_all_http_responses<R: Runtime>(
|
|||||||
window: &WebviewWindow<R>,
|
window: &WebviewWindow<R>,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for r in list_responses(window, request_id, None).await? {
|
for r in list_http_responses(window, request_id, None).await? {
|
||||||
delete_http_response(window, &r.id).await?;
|
delete_http_response(window, &r.id).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_responses<R: Runtime>(
|
pub async fn list_http_responses<R: Runtime>(
|
||||||
mgr: &impl Manager<R>,
|
mgr: &impl Manager<R>,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ pub enum InternalEventPayload {
|
|||||||
|
|
||||||
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
|
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
|
||||||
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
|
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
|
||||||
|
|
||||||
|
FindHttpResponsesRequest(FindHttpResponsesRequest),
|
||||||
|
FindHttpResponsesResponse(FindHttpResponsesResponse),
|
||||||
|
|
||||||
/// Returned when a plugin doesn't get run, just so the server
|
/// Returned when a plugin doesn't get run, just so the server
|
||||||
/// has something to listen for
|
/// has something to listen for
|
||||||
@@ -347,6 +350,21 @@ pub struct GetHttpRequestByIdResponse {
|
|||||||
pub http_request: Option<HttpRequest>,
|
pub http_request: Option<HttpRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct FindHttpResponsesRequest {
|
||||||
|
pub request_id: String,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct FindHttpResponsesResponse {
|
||||||
|
pub http_responses: Vec<HttpResponse>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase")]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
|
|||||||
@@ -169,9 +169,10 @@ impl PluginManager {
|
|||||||
content: &str,
|
content: &str,
|
||||||
content_type: &str,
|
content_type: &str,
|
||||||
) -> Result<FilterResponse> {
|
) -> Result<FilterResponse> {
|
||||||
let plugin_name = match content_type {
|
let plugin_name = if content_type.to_lowercase().contains("json") {
|
||||||
"application/json" => "filter-jsonpath",
|
"filter-jsonpath"
|
||||||
_ => "filter-xpath",
|
} else {
|
||||||
|
"filter-xpath"
|
||||||
};
|
};
|
||||||
|
|
||||||
let event = self
|
let event = self
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { HTML5Backend } from 'react-dnd-html5-backend';
|
|||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
import { AppRouter } from './AppRouter';
|
import { AppRouter } from './AppRouter';
|
||||||
|
|
||||||
|
const ENABLE_REACT_QUERY_DEVTOOLS = false;
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
@@ -20,7 +22,7 @@ const queryClient = new QueryClient({
|
|||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ReactQueryDevtools buttonPosition="bottom-left" />
|
{ENABLE_REACT_QUERY_DEVTOOLS && <ReactQueryDevtools buttonPosition="bottom-left" />}
|
||||||
<MotionConfig transition={{ duration: 0.1 }}>
|
<MotionConfig transition={{ duration: 0.1 }}>
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
|
|||||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||||
import { settingsQueryKey, useSettings } from '../hooks/useSettings';
|
import { settingsAtom, useSettings } from '../hooks/useSettings';
|
||||||
import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
||||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||||
import { workspacesAtom } from '../hooks/useWorkspaces';
|
import { workspacesAtom } from '../hooks/useWorkspaces';
|
||||||
@@ -65,6 +65,7 @@ export function GlobalHooks() {
|
|||||||
windowLabel: string;
|
windowLabel: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setSettings = useSetAtom(settingsAtom);
|
||||||
const setWorkspaces = useSetAtom(workspacesAtom);
|
const setWorkspaces = useSetAtom(workspacesAtom);
|
||||||
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
||||||
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
||||||
@@ -85,8 +86,6 @@ export function GlobalHooks() {
|
|||||||
? keyValueQueryKey(model)
|
? keyValueQueryKey(model)
|
||||||
: model.model === 'cookie_jar'
|
: model.model === 'cookie_jar'
|
||||||
? cookieJarsQueryKey(model)
|
? cookieJarsQueryKey(model)
|
||||||
: model.model === 'settings'
|
|
||||||
? settingsQueryKey()
|
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (model.model === 'http_request' && windowLabel !== getCurrentWebviewWindow().label) {
|
if (model.model === 'http_request' && windowLabel !== getCurrentWebviewWindow().label) {
|
||||||
@@ -107,6 +106,8 @@ export function GlobalHooks() {
|
|||||||
setGrpcRequests(updateModelList(model, pushToFront));
|
setGrpcRequests(updateModelList(model, pushToFront));
|
||||||
} else if (model.model === 'environment') {
|
} else if (model.model === 'environment') {
|
||||||
setEnvironments(updateModelList(model, pushToFront));
|
setEnvironments(updateModelList(model, pushToFront));
|
||||||
|
} else if (model.model === 'settings') {
|
||||||
|
setSettings(model);
|
||||||
} else if (queryKey != null) {
|
} else if (queryKey != null) {
|
||||||
// TODO: Convert all models to use Jotai
|
// TODO: Convert all models to use Jotai
|
||||||
queryClient.setQueryData(queryKey, (current: unknown) => {
|
queryClient.setQueryData(queryKey, (current: unknown) => {
|
||||||
@@ -146,8 +147,6 @@ export function GlobalHooks() {
|
|||||||
queryClient.setQueryData(keyValueQueryKey(model), undefined);
|
queryClient.setQueryData(keyValueQueryKey(model), undefined);
|
||||||
} else if (model.model === 'cookie_jar') {
|
} else if (model.model === 'cookie_jar') {
|
||||||
queryClient.setQueryData(cookieJarsQueryKey(model), undefined);
|
queryClient.setQueryData(cookieJarsQueryKey(model), undefined);
|
||||||
} else if (model.model === 'settings') {
|
|
||||||
queryClient.setQueryData(settingsQueryKey(), undefined);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const RecentResponsesDropdown = function ResponsePane({
|
|||||||
key: 'clear-all',
|
key: 'clear-all',
|
||||||
label: `Delete ${responses.length} ${pluralize('Response', responses.length)}`,
|
label: `Delete ${responses.length} ${pluralize('Response', responses.length)}`,
|
||||||
onSelect: deleteAllResponses.mutate,
|
onSelect: deleteAllResponses.mutate,
|
||||||
hidden: responses.length <= 1,
|
hidden: responses.length === 0,
|
||||||
disabled: responses.length === 0,
|
disabled: responses.length === 0,
|
||||||
},
|
},
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
|
||||||
import type { FnArg } from '../gen/FnArg';
|
|
||||||
import type { Tokens } from '../gen/Tokens';
|
|
||||||
import { useHttpRequests } from '../hooks/useHttpRequests';
|
|
||||||
import { useRenderTemplate } from '../hooks/useRenderTemplate';
|
|
||||||
import type {
|
import type {
|
||||||
TemplateFunction,
|
TemplateFunction,
|
||||||
TemplateFunctionArg,
|
TemplateFunctionArg,
|
||||||
TemplateFunctionHttpRequestArg,
|
TemplateFunctionHttpRequestArg,
|
||||||
TemplateFunctionSelectArg,
|
TemplateFunctionSelectArg,
|
||||||
TemplateFunctionTextArg,
|
TemplateFunctionTextArg,
|
||||||
} from '../hooks/useTemplateFunctions';
|
} from '@yaakapp/api';
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import type { FnArg } from '../gen/FnArg';
|
||||||
|
import type { Tokens } from '../gen/Tokens';
|
||||||
|
import { useDebouncedValue } from '../hooks/useDebouncedValue';
|
||||||
|
import { useHttpRequests } from '../hooks/useHttpRequests';
|
||||||
|
import { useRenderTemplate } from '../hooks/useRenderTemplate';
|
||||||
import { useTemplateTokensToString } from '../hooks/useTemplateTokensToString';
|
import { useTemplateTokensToString } from '../hooks/useTemplateTokensToString';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -86,7 +87,8 @@ export function TemplateFunctionDialog({ templateFunction, hide, initialTokens,
|
|||||||
hide();
|
hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
const rendered = useRenderTemplate(tagText.data ?? '');
|
const debouncedTagText = useDebouncedValue(tagText.data ?? '', 200);
|
||||||
|
const rendered = useRenderTemplate(debouncedTagText);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack className="pb-3" space={4}>
|
<VStack className="pb-3" space={4}>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class TemplateTagWidget extends WidgetType {
|
|||||||
|
|
||||||
export function templateTags(options: TwigCompletionOption[]) {
|
export function templateTags(options: TwigCompletionOption[]) {
|
||||||
const templateTagMatcher = new BetterMatchDecorator({
|
const templateTagMatcher = new BetterMatchDecorator({
|
||||||
regexp: /\$\{\[\s*([^\]]+)\s*]}/g,
|
regexp: /\$\{\[\s*(.+)(?!]})\s*]}/g,
|
||||||
decoration(match, view, matchStartPos) {
|
decoration(match, view, matchStartPos) {
|
||||||
const matchEndPos = matchStartPos + match[0].length - 1;
|
const matchEndPos = matchStartPos + match[0].length - 1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useDebouncedState } from './useDebouncedState';
|
import { useDebouncedState } from './useDebouncedState';
|
||||||
|
|
||||||
export function useDebouncedValue<T>(value: T, delay?: number) {
|
export function useDebouncedValue<T>(value: T, delay = 500) {
|
||||||
const [state, setState] = useDebouncedState<T>(value, delay);
|
const [state, setState] = useDebouncedState<T>(value, delay);
|
||||||
useEffect(() => setState(value), [setState, value]);
|
useEffect(() => setState(value), [setState, value]);
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useAtomValue } from 'jotai';
|
||||||
|
import { atom } from 'jotai/index';
|
||||||
import type { Settings } from '../lib/models/Settings';
|
import type { Settings } from '../lib/models/Settings';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { getSettings } from '../lib/store';
|
||||||
|
|
||||||
export function settingsQueryKey() {
|
const settings = await getSettings();
|
||||||
return ['settings'];
|
export const settingsAtom = atom<Settings>(settings);
|
||||||
}
|
|
||||||
|
|
||||||
export function useSettings() {
|
export function useSettings() {
|
||||||
return (
|
return useAtomValue(settingsAtom);
|
||||||
useQuery({
|
|
||||||
queryKey: settingsQueryKey(),
|
|
||||||
queryFn: async () => {
|
|
||||||
const settings = (await invokeCmd('cmd_get_settings')) as Settings;
|
|
||||||
return [settings];
|
|
||||||
},
|
|
||||||
}).data?.[0] ?? undefined
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { Settings } from '../lib/models';
|
import type { Settings } from '../lib/models';
|
||||||
|
import { getSettings } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useSettings } from './useSettings';
|
|
||||||
|
|
||||||
export function useUpdateSettings() {
|
export function useUpdateSettings() {
|
||||||
const settings = useSettings();
|
|
||||||
|
|
||||||
return useMutation<void, unknown, Partial<Settings>>({
|
return useMutation<void, unknown, Partial<Settings>>({
|
||||||
mutationKey: ['update_settings'],
|
mutationKey: ['update_settings'],
|
||||||
mutationFn: async (patch) => {
|
mutationFn: async (patch) => {
|
||||||
if (settings == null) return;
|
const settings = await getSettings();
|
||||||
const newSettings: Settings = { ...settings, ...patch };
|
const newSettings: Settings = { ...settings, ...patch };
|
||||||
await invokeCmd('cmd_update_settings', { settings: newSettings });
|
await invokeCmd('cmd_update_settings', { settings: newSettings });
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user