mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-21 00:01:22 +02:00
Actually call template functions
This commit is contained in:
@@ -7,7 +7,8 @@
|
|||||||
</scripts>
|
</scripts>
|
||||||
<node-interpreter value="project" />
|
<node-interpreter value="project" />
|
||||||
<envs>
|
<envs>
|
||||||
|
<env name="RUST_BACKTRACE" value="1" />
|
||||||
</envs>
|
</envs>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
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.6",
|
"@yaakapp/api": "^0.1.7",
|
||||||
"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.6",
|
"version": "0.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.7.tgz",
|
||||||
"integrity": "sha512-5lYXKcOVmLzVUrkfU4JOCbz+CBV5Dm/cALoZvfbelvZWOVu3sTrBxS9cbNVQQq2B6WwLInSevk7pMq58GqIj5Q==",
|
"integrity": "sha512-6dheXUuhX3o1KwZ7ngtB/OcQ4qCiXxg3LN2t1jA28nnZBlGCek+h9yndiF/PGWl5yReMcXy8rn4pq4W9zAGHLg==",
|
||||||
"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.6",
|
"@yaakapp/api": "^0.1.7",
|
||||||
"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",
|
||||||
|
|||||||
4
plugin-runtime-types/package-lock.json
generated
4
plugin-runtime-types/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@yaakapp/api",
|
"name": "@yaakapp/api",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@yaakapp/api",
|
"name": "@yaakapp/api",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^22.0.0"
|
"@types/node": "^22.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@yaakapp/api",
|
"name": "@yaakapp/api",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"typings": "./lib/index.d.ts",
|
"typings": "./lib/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
import type { CallTemplateFunctionArgs } from "./CallTemplateFunctionArgs";
|
import type { CallTemplateFunctionArgs } from "./CallTemplateFunctionArgs";
|
||||||
|
|
||||||
export type CallTemplateFunctionRequest = { name: string, pluginRefId: string, args: CallTemplateFunctionArgs, };
|
export type CallTemplateFunctionRequest = { name: string, args: CallTemplateFunctionArgs, };
|
||||||
|
|||||||
@@ -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 CallTemplateFunctionResponse = { value: string | null, };
|
||||||
@@ -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 GetHttpRequestActionsRequest = Record<string, never>;
|
||||||
@@ -3,12 +3,14 @@ import type { BootRequest } from "./BootRequest";
|
|||||||
import type { BootResponse } from "./BootResponse";
|
import type { BootResponse } from "./BootResponse";
|
||||||
import type { CallHttpRequestActionRequest } from "./CallHttpRequestActionRequest";
|
import type { CallHttpRequestActionRequest } from "./CallHttpRequestActionRequest";
|
||||||
import type { CallTemplateFunctionRequest } from "./CallTemplateFunctionRequest";
|
import type { CallTemplateFunctionRequest } from "./CallTemplateFunctionRequest";
|
||||||
|
import type { CallTemplateFunctionResponse } from "./CallTemplateFunctionResponse";
|
||||||
import type { CopyTextRequest } from "./CopyTextRequest";
|
import type { CopyTextRequest } from "./CopyTextRequest";
|
||||||
import type { EmptyResponse } from "./EmptyResponse";
|
import type { EmptyResponse } from "./EmptyResponse";
|
||||||
import type { ExportHttpRequestRequest } from "./ExportHttpRequestRequest";
|
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 { GetHttpRequestActionsRequest } from "./GetHttpRequestActionsRequest";
|
||||||
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
|
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
|
||||||
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
|
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
|
||||||
import type { GetHttpRequestByIdResponse } from "./GetHttpRequestByIdResponse";
|
import type { GetHttpRequestByIdResponse } from "./GetHttpRequestByIdResponse";
|
||||||
@@ -21,4 +23,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" } | { "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": "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": "empty_response" } & EmptyResponse;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export * from './gen/CallHttpRequestActionArgs';
|
|||||||
export * from './gen/CallTemplateFunctionPurpose';
|
export * from './gen/CallTemplateFunctionPurpose';
|
||||||
export * from './gen/CallHttpRequestActionRequest';
|
export * from './gen/CallHttpRequestActionRequest';
|
||||||
export * from './gen/CallTemplateFunctionRequest';
|
export * from './gen/CallTemplateFunctionRequest';
|
||||||
|
export * from './gen/CallTemplateFunctionResponse';
|
||||||
export * from './gen/CallTemplateFunctionArgs';
|
export * from './gen/CallTemplateFunctionArgs';
|
||||||
export * from './gen/Cookie';
|
export * from './gen/Cookie';
|
||||||
export * from './gen/CookieDomain';
|
export * from './gen/CookieDomain';
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
return sendPayload({ type: 'empty_response' }, replyId);
|
return sendPayload({ type: 'empty_response' }, replyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPayload(payload: InternalEventPayload, replyId: string | null = null): string {
|
function sendPayload(payload: InternalEventPayload, replyId: string | null): string {
|
||||||
const event = buildEventToSend(payload, replyId);
|
const event = buildEventToSend(payload, replyId);
|
||||||
sendEvent(event);
|
sendEvent(event);
|
||||||
return event.id;
|
return event.id;
|
||||||
@@ -233,9 +233,10 @@ new Promise<void>(async (resolve, reject) => {
|
|||||||
Array.isArray(mod.plugin?.templateFunctions)
|
Array.isArray(mod.plugin?.templateFunctions)
|
||||||
) {
|
) {
|
||||||
const action = mod.plugin.templateFunctions.find((a) => a.name === payload.name);
|
const action = mod.plugin.templateFunctions.find((a) => a.name === payload.name);
|
||||||
if (typeof action?.onRender() === 'function') {
|
if (typeof action?.onRender === 'function') {
|
||||||
await action.onRender(ctx, payload.args);
|
const result = await action.onRender(ctx, payload.args);
|
||||||
sendEmpty(replyId);
|
console.log('GOT VALUE', result);
|
||||||
|
sendPayload({ type: 'call_template_function_response', value: result ?? null }, replyId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::str::FromStr;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::render::render_request;
|
use crate::render::render_http_request;
|
||||||
use crate::response_err;
|
use crate::response_err;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use http::header::{ACCEPT, USER_AGENT};
|
use http::header::{ACCEPT, USER_AGENT};
|
||||||
@@ -37,7 +37,13 @@ pub async fn send_http_request<R: Runtime>(
|
|||||||
let workspace = get_workspace(window, &request.workspace_id)
|
let workspace = get_workspace(window, &request.workspace_id)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get Workspace");
|
.expect("Failed to get Workspace");
|
||||||
let rendered_request = render_request(&request, &workspace, environment.as_ref()).await;
|
let rendered_request = render_http_request(
|
||||||
|
window.app_handle(),
|
||||||
|
&request,
|
||||||
|
&workspace,
|
||||||
|
environment.as_ref(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let mut url_string = rendered_request.url;
|
let mut url_string = rendered_request.url;
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ use crate::export_resources::{get_workspace_export_resources, WorkspaceExportRes
|
|||||||
use crate::grpc::metadata_to_map;
|
use crate::grpc::metadata_to_map;
|
||||||
use crate::http_request::send_http_request;
|
use crate::http_request::send_http_request;
|
||||||
use crate::notifications::YaakNotifier;
|
use crate::notifications::YaakNotifier;
|
||||||
use crate::render::{render_request, render_template, variables_from_environment};
|
use crate::render::{render_grpc_request, render_http_request, render_template};
|
||||||
|
use crate::template_callback::PluginTemplateCallback;
|
||||||
use crate::updates::{UpdateMode, YaakUpdater};
|
use crate::updates::{UpdateMode, YaakUpdater};
|
||||||
use crate::window_menu::app_menu;
|
use crate::window_menu::app_menu;
|
||||||
use yaak_models::models::{
|
use yaak_models::models::{
|
||||||
@@ -70,7 +71,7 @@ mod notifications;
|
|||||||
mod render;
|
mod render;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
mod tauri_plugin_mac_window;
|
mod tauri_plugin_mac_window;
|
||||||
mod template_fns;
|
mod template_callback;
|
||||||
mod updates;
|
mod updates;
|
||||||
mod window_menu;
|
mod window_menu;
|
||||||
|
|
||||||
@@ -128,7 +129,13 @@ async fn cmd_render_template(
|
|||||||
let workspace = get_workspace(&window, &workspace_id)
|
let workspace = get_workspace(&window, &workspace_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let rendered = render_template(template, &workspace, environment.as_ref()).await;
|
let rendered = render_template(
|
||||||
|
window.app_handle(),
|
||||||
|
template,
|
||||||
|
&workspace,
|
||||||
|
environment.as_ref(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
Ok(rendered)
|
Ok(rendered)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,9 +187,6 @@ async fn cmd_grpc_go(
|
|||||||
window: WebviewWindow,
|
window: WebviewWindow,
|
||||||
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let req = get_grpc_request(&window, request_id)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
let environment = match environment_id {
|
let environment = match environment_id {
|
||||||
Some(id) => Some(
|
Some(id) => Some(
|
||||||
get_environment(&window, id)
|
get_environment(&window, id)
|
||||||
@@ -191,13 +195,17 @@ async fn cmd_grpc_go(
|
|||||||
),
|
),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
let req = get_grpc_request(&window, request_id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
let workspace = get_workspace(&window, &req.workspace_id)
|
let workspace = get_workspace(&window, &req.workspace_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
let req =
|
||||||
|
render_grpc_request(window.app_handle(), &req, &workspace, environment.as_ref()).await;
|
||||||
let mut metadata = HashMap::new();
|
let mut metadata = HashMap::new();
|
||||||
let vars = variables_from_environment(&workspace, environment.as_ref()).await;
|
|
||||||
|
|
||||||
// Add rest of metadata
|
// Add the rest of metadata
|
||||||
for h in req.clone().metadata {
|
for h in req.clone().metadata {
|
||||||
if h.name.is_empty() && h.value.is_empty() {
|
if h.name.is_empty() && h.value.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@@ -207,10 +215,7 @@ async fn cmd_grpc_go(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = render::render(&h.name, &vars).await;
|
metadata.insert(h.name, h.value);
|
||||||
let value = render::render(&h.value, &vars).await;
|
|
||||||
|
|
||||||
metadata.insert(name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(b) = &req.authentication_type {
|
if let Some(b) = &req.authentication_type {
|
||||||
@@ -219,25 +224,22 @@ async fn cmd_grpc_go(
|
|||||||
let a = req.authentication;
|
let a = req.authentication;
|
||||||
|
|
||||||
if b == "basic" {
|
if b == "basic" {
|
||||||
let raw_username = a
|
let username = a
|
||||||
.get("username")
|
.get("username")
|
||||||
.unwrap_or(empty_value)
|
.unwrap_or(empty_value)
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
let raw_password = a
|
let password = a
|
||||||
.get("password")
|
.get("password")
|
||||||
.unwrap_or(empty_value)
|
.unwrap_or(empty_value)
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
let username = render::render(raw_username, &vars).await;
|
|
||||||
let password = render::render(raw_password, &vars).await;
|
|
||||||
|
|
||||||
let auth = format!("{username}:{password}");
|
let auth = format!("{username}:{password}");
|
||||||
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
|
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
|
||||||
metadata.insert("Authorization".to_string(), format!("Basic {}", encoded));
|
metadata.insert("Authorization".to_string(), format!("Basic {}", encoded));
|
||||||
} else if b == "bearer" {
|
} else if b == "bearer" {
|
||||||
let raw_token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
|
let token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
|
||||||
let token = render::render(raw_token, &vars).await;
|
|
||||||
metadata.insert("Authorization".to_string(), format!("Bearer {token}"));
|
metadata.insert("Authorization".to_string(), format!("Bearer {token}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,7 +333,6 @@ async fn cmd_grpc_go(
|
|||||||
let w = window.clone();
|
let w = window.clone();
|
||||||
let base_msg = base_msg.clone();
|
let base_msg = base_msg.clone();
|
||||||
let method_desc = method_desc.clone();
|
let method_desc = method_desc.clone();
|
||||||
let vars = vars.clone();
|
|
||||||
|
|
||||||
move |ev: tauri::Event| {
|
move |ev: tauri::Event| {
|
||||||
if *cancelled_rx.borrow() {
|
if *cancelled_rx.borrow() {
|
||||||
@@ -351,14 +352,10 @@ async fn cmd_grpc_go(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match serde_json::from_str::<IncomingMsg>(ev.payload()) {
|
match serde_json::from_str::<IncomingMsg>(ev.payload()) {
|
||||||
Ok(IncomingMsg::Message(raw_msg)) => {
|
Ok(IncomingMsg::Message(msg)) => {
|
||||||
let w = w.clone();
|
let w = w.clone();
|
||||||
let base_msg = base_msg.clone();
|
let base_msg = base_msg.clone();
|
||||||
let method_desc = method_desc.clone();
|
let method_desc = method_desc.clone();
|
||||||
let vars = vars.clone();
|
|
||||||
let msg = tauri::async_runtime::block_on(async move {
|
|
||||||
render::render(raw_msg.as_str(), &vars).await
|
|
||||||
});
|
|
||||||
let d_msg: DynamicMessage = match deserialize_message(msg.as_str(), method_desc)
|
let d_msg: DynamicMessage = match deserialize_message(msg.as_str(), method_desc)
|
||||||
{
|
{
|
||||||
Ok(d_msg) => d_msg,
|
Ok(d_msg) => d_msg,
|
||||||
@@ -410,13 +407,11 @@ async fn cmd_grpc_go(
|
|||||||
let w = window.clone();
|
let w = window.clone();
|
||||||
let base_event = base_msg.clone();
|
let base_event = base_msg.clone();
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
let vars = vars.clone();
|
let msg = if req.message.is_empty() {
|
||||||
let raw_msg = if req.message.is_empty() {
|
|
||||||
"{}".to_string()
|
"{}".to_string()
|
||||||
} else {
|
} else {
|
||||||
req.message
|
req.message
|
||||||
};
|
};
|
||||||
let msg = render::render(&raw_msg, &vars).await;
|
|
||||||
|
|
||||||
upsert_grpc_event(
|
upsert_grpc_event(
|
||||||
&w,
|
&w,
|
||||||
@@ -772,7 +767,7 @@ async fn cmd_filter_response(
|
|||||||
|
|
||||||
// TODO: Have plugins register their own content type (regex?)
|
// TODO: Have plugins register their own content type (regex?)
|
||||||
plugin_manager
|
plugin_manager
|
||||||
.run_filter(filter, &body, &content_type)
|
.filter_data(filter, &body, &content_type)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
@@ -787,7 +782,7 @@ async fn cmd_import_data(
|
|||||||
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
||||||
let file_contents = file.as_str();
|
let file_contents = file.as_str();
|
||||||
let (import_result, plugin_name) = plugin_manager
|
let (import_result, plugin_name) = plugin_manager
|
||||||
.run_import(file_contents)
|
.import_data(file_contents)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
@@ -912,7 +907,7 @@ async fn cmd_http_request_actions(
|
|||||||
plugin_manager: State<'_, PluginManager>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
) -> Result<Vec<GetHttpRequestActionsResponse>, String> {
|
) -> Result<Vec<GetHttpRequestActionsResponse>, String> {
|
||||||
plugin_manager
|
plugin_manager
|
||||||
.run_http_request_actions()
|
.get_http_request_actions()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
@@ -922,7 +917,7 @@ async fn cmd_template_functions(
|
|||||||
plugin_manager: State<'_, PluginManager>,
|
plugin_manager: State<'_, PluginManager>,
|
||||||
) -> Result<Vec<GetTemplateFunctionsResponse>, String> {
|
) -> Result<Vec<GetTemplateFunctionsResponse>, String> {
|
||||||
plugin_manager
|
plugin_manager
|
||||||
.run_template_functions()
|
.get_template_functions()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
@@ -947,7 +942,7 @@ async fn cmd_curl_to_request(
|
|||||||
) -> Result<HttpRequest, String> {
|
) -> Result<HttpRequest, String> {
|
||||||
let (import_result, plugin_name) = {
|
let (import_result, plugin_name) = {
|
||||||
plugin_manager
|
plugin_manager
|
||||||
.run_import(command)
|
.import_data(command)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?
|
.map_err(|e| e.to_string())?
|
||||||
};
|
};
|
||||||
@@ -1661,6 +1656,10 @@ pub fn run() {
|
|||||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||||
app.manage(Mutex::new(grpc_handle));
|
app.manage(Mutex::new(grpc_handle));
|
||||||
|
|
||||||
|
// Plugin template callback
|
||||||
|
let plugin_cb = PluginTemplateCallback::new(app.app_handle().clone());
|
||||||
|
app.manage(plugin_cb);
|
||||||
|
|
||||||
let app_handle = app.app_handle().clone();
|
let app_handle = app.app_handle().clone();
|
||||||
monitor_plugin_events(&app_handle);
|
monitor_plugin_events(&app_handle);
|
||||||
|
|
||||||
@@ -1999,8 +1998,13 @@ async fn handle_plugin_event<R: Runtime>(
|
|||||||
None => None,
|
None => None,
|
||||||
Some(id) => get_environment(w, id.as_str()).await.ok(),
|
Some(id) => get_environment(w, id.as_str()).await.ok(),
|
||||||
};
|
};
|
||||||
let rendered_http_request =
|
let rendered_http_request = render_http_request(
|
||||||
render_request(&req.http_request, &workspace, environment.as_ref()).await;
|
app_handle,
|
||||||
|
&req.http_request,
|
||||||
|
&workspace,
|
||||||
|
environment.as_ref(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
Some(InternalEventPayload::RenderHttpRequestResponse(
|
Some(InternalEventPayload::RenderHttpRequestResponse(
|
||||||
RenderHttpRequestResponse {
|
RenderHttpRequestResponse {
|
||||||
http_request: rendered_http_request,
|
http_request: rendered_http_request,
|
||||||
|
|||||||
@@ -1,80 +1,126 @@
|
|||||||
use crate::template_fns::timestamp;
|
use crate::template_callback::PluginTemplateCallback;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use yaak_models::models::{
|
use tauri::{AppHandle, Manager, Runtime};
|
||||||
Environment, EnvironmentVariable, 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(template: &str, w: &Workspace, e: Option<&Environment>) -> String {
|
pub async fn render_template<R: Runtime>(
|
||||||
let vars = &variables_from_environment(w, e).await;
|
app_handle: &AppHandle<R>,
|
||||||
render(template, vars).await
|
template: &str,
|
||||||
|
w: &Workspace,
|
||||||
|
e: Option<&Environment>,
|
||||||
|
) -> String {
|
||||||
|
let cb = &*app_handle.state::<PluginTemplateCallback>();
|
||||||
|
let vars = &variables_from_environment(w, e, cb).await;
|
||||||
|
render(template, vars, cb).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render_request(
|
pub async fn render_grpc_request<R: Runtime>(
|
||||||
|
app_handle: &AppHandle<R>,
|
||||||
|
r: &GrpcRequest,
|
||||||
|
w: &Workspace,
|
||||||
|
e: Option<&Environment>,
|
||||||
|
) -> GrpcRequest {
|
||||||
|
let cb = &*app_handle.state::<PluginTemplateCallback>();
|
||||||
|
let vars = &variables_from_environment(w, e, cb).await;
|
||||||
|
|
||||||
|
let mut metadata = Vec::new();
|
||||||
|
for p in r.metadata.clone() {
|
||||||
|
metadata.push(GrpcMetadataEntry {
|
||||||
|
enabled: p.enabled,
|
||||||
|
name: render(p.name.as_str(), vars, cb).await,
|
||||||
|
value: render(p.value.as_str(), vars, cb).await,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut authentication = HashMap::new();
|
||||||
|
for (k, v) in r.authentication.clone() {
|
||||||
|
let v = if v.is_string() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
GrpcRequest{
|
||||||
|
url,
|
||||||
|
metadata,
|
||||||
|
authentication,
|
||||||
|
..r.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn render_http_request<R: Runtime>(
|
||||||
|
app_handle: &AppHandle<R>,
|
||||||
r: &HttpRequest,
|
r: &HttpRequest,
|
||||||
w: &Workspace,
|
w: &Workspace,
|
||||||
e: Option<&Environment>,
|
e: Option<&Environment>,
|
||||||
) -> HttpRequest {
|
) -> HttpRequest {
|
||||||
let r = r.clone();
|
let cb = &*app_handle.state::<PluginTemplateCallback>();
|
||||||
let vars = &variables_from_environment(w, e).await;
|
let vars = &variables_from_environment(w, e, cb).await;
|
||||||
|
|
||||||
let mut url_parameters = Vec::new();
|
let mut url_parameters = Vec::new();
|
||||||
for p in r.url_parameters {
|
for p in r.url_parameters.clone() {
|
||||||
url_parameters.push(HttpUrlParameter {
|
url_parameters.push(HttpUrlParameter {
|
||||||
enabled: p.enabled,
|
enabled: p.enabled,
|
||||||
name: render(p.name.as_str(), vars).await,
|
name: render(p.name.as_str(), vars, cb).await,
|
||||||
value: render(p.value.as_str(), vars).await,
|
value: render(p.value.as_str(), vars, cb).await,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut headers = Vec::new();
|
let mut headers = Vec::new();
|
||||||
for p in r.headers {
|
for p in r.headers.clone() {
|
||||||
headers.push(HttpRequestHeader {
|
headers.push(HttpRequestHeader {
|
||||||
enabled: p.enabled,
|
enabled: p.enabled,
|
||||||
name: render(p.name.as_str(), vars).await,
|
name: render(p.name.as_str(), vars, cb).await,
|
||||||
value: render(p.value.as_str(), vars).await,
|
value: render(p.value.as_str(), vars, cb).await,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut body = HashMap::new();
|
let mut body = HashMap::new();
|
||||||
for (k, v) in r.body {
|
for (k, v) in r.body.clone() {
|
||||||
let v = if v.is_string() {
|
let v = if v.is_string() {
|
||||||
render(v.as_str().unwrap(), vars).await
|
render(v.as_str().unwrap(), vars, cb).await
|
||||||
} else {
|
} else {
|
||||||
v.to_string()
|
v.to_string()
|
||||||
};
|
};
|
||||||
body.insert(render(k.as_str(), vars).await, Value::from(v));
|
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 {
|
for (k, v) in r.authentication.clone() {
|
||||||
let v = if v.is_string() {
|
let v = if v.is_string() {
|
||||||
render(v.as_str().unwrap(), vars).await
|
render(v.as_str().unwrap(), vars, cb).await
|
||||||
} else {
|
} else {
|
||||||
v.to_string()
|
v.to_string()
|
||||||
};
|
};
|
||||||
authentication.insert(render(k.as_str(), vars).await, Value::from(v));
|
authentication.insert(render(k.as_str(), vars, cb).await, Value::from(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let url = render(r.url.clone().as_str(), vars, cb).await;
|
||||||
HttpRequest {
|
HttpRequest {
|
||||||
url: render(r.url.as_str(), vars).await,
|
url,
|
||||||
url_parameters,
|
url_parameters,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
authentication,
|
authentication,
|
||||||
..r
|
..r.to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recursively_render_variables<'s>(
|
pub async fn recursively_render_variables<'s, T: TemplateCallback>(
|
||||||
m: &HashMap<String, String>,
|
m: &HashMap<String, String>,
|
||||||
render_count: usize,
|
render_count: usize,
|
||||||
|
cb: &T,
|
||||||
) -> HashMap<String, String> {
|
) -> HashMap<String, String> {
|
||||||
let mut did_render = false;
|
let mut did_render = false;
|
||||||
let mut new_map = m.clone();
|
let mut new_map = m.clone();
|
||||||
for (k, v) in m.clone() {
|
for (k, v) in m.clone() {
|
||||||
let rendered = Box::pin(render(v.as_str(), m)).await;
|
let rendered = Box::pin(render(v.as_str(), m, cb)).await;
|
||||||
if rendered != v {
|
if rendered != v {
|
||||||
did_render = true
|
did_render = true
|
||||||
}
|
}
|
||||||
@@ -82,15 +128,16 @@ pub async fn recursively_render_variables<'s>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if did_render && render_count <= 3 {
|
if did_render && render_count <= 3 {
|
||||||
new_map = Box::pin(recursively_render_variables(&new_map, render_count + 1)).await;
|
new_map = Box::pin(recursively_render_variables(&new_map, render_count + 1, cb)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_map
|
new_map
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn variables_from_environment(
|
pub async fn variables_from_environment<T: TemplateCallback>(
|
||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
environment: Option<&Environment>,
|
environment: Option<&Environment>,
|
||||||
|
cb: &T,
|
||||||
) -> HashMap<String, String> {
|
) -> HashMap<String, String> {
|
||||||
let mut variables = HashMap::new();
|
let mut variables = HashMap::new();
|
||||||
variables = add_variable_to_map(variables, &workspace.variables);
|
variables = add_variable_to_map(variables, &workspace.variables);
|
||||||
@@ -99,23 +146,15 @@ pub async fn variables_from_environment(
|
|||||||
variables = add_variable_to_map(variables, &e.variables);
|
variables = add_variable_to_map(variables, &e.variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursively_render_variables(&variables, 0).await
|
recursively_render_variables(&variables, 0, cb).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render(template: &str, vars: &HashMap<String, String>) -> String {
|
pub async fn render<T: TemplateCallback>(
|
||||||
parse_and_render(template, vars, &Box::new(PluginTemplateCallback::default())).await
|
template: &str,
|
||||||
}
|
vars: &HashMap<String, String>,
|
||||||
|
cb: &T,
|
||||||
#[derive(Default)]
|
) -> String {
|
||||||
struct PluginTemplateCallback {}
|
parse_and_render(template, vars, cb).await
|
||||||
|
|
||||||
impl TemplateCallback for PluginTemplateCallback {
|
|
||||||
async fn run(&self, fn_name: &str, args: HashMap<String, String>) -> Result<String, String> {
|
|
||||||
match fn_name {
|
|
||||||
"timestamp" => timestamp(args),
|
|
||||||
_ => Err(format!("Unknown template function {fn_name}")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_variable_to_map(
|
fn add_variable_to_map(
|
||||||
|
|||||||
25
src-tauri/src/template_callback.rs
Normal file
25
src-tauri/src/template_callback.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use tauri::{AppHandle, Manager};
|
||||||
|
use yaak_plugin_runtime::manager::PluginManager;
|
||||||
|
use yaak_templates::TemplateCallback;
|
||||||
|
|
||||||
|
pub struct PluginTemplateCallback {
|
||||||
|
app_handle: AppHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginTemplateCallback {
|
||||||
|
pub fn new(app_handle: AppHandle) -> PluginTemplateCallback {
|
||||||
|
PluginTemplateCallback { app_handle }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TemplateCallback for PluginTemplateCallback {
|
||||||
|
async fn run(&self, fn_name: &str, args: HashMap<String, String>) -> Result<String, String> {
|
||||||
|
let plugin_manager = self.app_handle.state::<PluginManager>();
|
||||||
|
let resp = plugin_manager
|
||||||
|
.call_template_function(fn_name, args)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
Ok(resp.unwrap_or_default())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
use chrono::{DateTime, Utc};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub fn timestamp(args: HashMap<String, String>) -> Result<String, String> {
|
|
||||||
let from = args.get("from").map(|v| v.as_str()).unwrap_or("now");
|
|
||||||
let format = args.get("format").map(|v| v.as_str()).unwrap_or("rfc3339");
|
|
||||||
|
|
||||||
let dt = match from {
|
|
||||||
"now" => {
|
|
||||||
let now = Utc::now();
|
|
||||||
now
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let json_from = serde_json::to_string(from).unwrap_or_default();
|
|
||||||
let now: DateTime<Utc> = match serde_json::from_str(json_from.as_str()) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
now
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = match format {
|
|
||||||
"rfc3339" => dt.to_rfc3339(),
|
|
||||||
"unix" => dt.timestamp().to_string(),
|
|
||||||
"unix_millis" => dt.timestamp_millis().to_string(),
|
|
||||||
_ => "".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test it
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::template_fns::timestamp;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn timestamp_empty() {
|
|
||||||
let args = HashMap::new();
|
|
||||||
assert_ne!(timestamp(args), Ok("".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn timestamp_from() {
|
|
||||||
let mut args = HashMap::new();
|
|
||||||
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
|
|
||||||
assert_eq!(
|
|
||||||
timestamp(args),
|
|
||||||
Ok("2024-07-31T14:16:41.983+00:00".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn timestamp_format_unix() {
|
|
||||||
let mut args = HashMap::new();
|
|
||||||
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
|
|
||||||
args.insert("format".to_string(), "unix".to_string());
|
|
||||||
assert_eq!(timestamp(args), Ok("1722435401".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn timestamp_format_unix_millis() {
|
|
||||||
let mut args = HashMap::new();
|
|
||||||
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
|
|
||||||
args.insert("format".to_string(), "unix_millis".to_string());
|
|
||||||
assert_eq!(timestamp(args), Ok("1722435401983".to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
|
|
||||||
use yaak_models::models::{
|
use yaak_models::models::{
|
||||||
@@ -36,13 +36,14 @@ pub enum InternalEventPayload {
|
|||||||
SendHttpRequestRequest(SendHttpRequestRequest),
|
SendHttpRequestRequest(SendHttpRequestRequest),
|
||||||
SendHttpRequestResponse(SendHttpRequestResponse),
|
SendHttpRequestResponse(SendHttpRequestResponse),
|
||||||
|
|
||||||
GetHttpRequestActionsRequest,
|
GetHttpRequestActionsRequest(GetHttpRequestActionsRequest),
|
||||||
GetHttpRequestActionsResponse(GetHttpRequestActionsResponse),
|
GetHttpRequestActionsResponse(GetHttpRequestActionsResponse),
|
||||||
CallHttpRequestActionRequest(CallHttpRequestActionRequest),
|
CallHttpRequestActionRequest(CallHttpRequestActionRequest),
|
||||||
|
|
||||||
GetTemplateFunctionsRequest,
|
GetTemplateFunctionsRequest,
|
||||||
GetTemplateFunctionsResponse(GetTemplateFunctionsResponse),
|
GetTemplateFunctionsResponse(GetTemplateFunctionsResponse),
|
||||||
CallTemplateFunctionRequest(CallTemplateFunctionRequest),
|
CallTemplateFunctionRequest(CallTemplateFunctionRequest),
|
||||||
|
CallTemplateFunctionResponse(CallTemplateFunctionResponse),
|
||||||
|
|
||||||
CopyTextRequest(CopyTextRequest),
|
CopyTextRequest(CopyTextRequest),
|
||||||
|
|
||||||
@@ -262,10 +263,16 @@ pub struct TemplateFunctionSelectOption {
|
|||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
pub struct CallTemplateFunctionRequest {
|
pub struct CallTemplateFunctionRequest {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub plugin_ref_id: String,
|
|
||||||
pub args: CallTemplateFunctionArgs,
|
pub args: CallTemplateFunctionArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default, rename_all = "camelCase")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct CallTemplateFunctionResponse {
|
||||||
|
pub value: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[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)]
|
||||||
@@ -282,12 +289,17 @@ pub enum CallTemplateFunctionPurpose {
|
|||||||
Preview,
|
Preview,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CallTemplateFunctionPurpose{
|
impl Default for CallTemplateFunctionPurpose {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CallTemplateFunctionPurpose::Preview
|
CallTemplateFunctionPurpose::Preview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(default)]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct GetHttpRequestActionsRequest {}
|
||||||
|
|
||||||
#[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)]
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::events::{CallHttpRequestActionRequest, CallTemplateFunctionRequest, FilterRequest, FilterResponse, GetHttpRequestActionsResponse, GetTemplateFunctionsResponse, ImportRequest, ImportResponse, InternalEvent, InternalEventPayload};
|
use crate::events::{
|
||||||
|
CallHttpRequestActionRequest, CallTemplateFunctionArgs, CallTemplateFunctionPurpose,
|
||||||
|
CallTemplateFunctionRequest, CallTemplateFunctionResponse, FilterRequest, FilterResponse,
|
||||||
|
GetHttpRequestActionsRequest, GetHttpRequestActionsResponse, GetTemplateFunctionsResponse,
|
||||||
|
ImportRequest, ImportResponse, InternalEvent, InternalEventPayload,
|
||||||
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::error::Error::PluginErr;
|
use crate::error::Error::PluginErr;
|
||||||
use crate::nodejs::start_nodejs_plugin_runtime;
|
use crate::nodejs::start_nodejs_plugin_runtime;
|
||||||
@@ -57,11 +63,13 @@ impl PluginManager {
|
|||||||
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
|
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_http_request_actions(&self) -> Result<Vec<GetHttpRequestActionsResponse>> {
|
pub async fn get_http_request_actions(&self) -> Result<Vec<GetHttpRequestActionsResponse>> {
|
||||||
let reply_events = self
|
let reply_events = self
|
||||||
.server
|
.server
|
||||||
.send_and_wait(&InternalEventPayload::GetHttpRequestActionsRequest)
|
.send_and_wait(&InternalEventPayload::GetHttpRequestActionsRequest(
|
||||||
|
GetHttpRequestActionsRequest {},
|
||||||
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut all_actions = Vec::new();
|
let mut all_actions = Vec::new();
|
||||||
@@ -74,7 +82,7 @@ impl PluginManager {
|
|||||||
Ok(all_actions)
|
Ok(all_actions)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_template_functions(&self) -> Result<Vec<GetTemplateFunctionsResponse>> {
|
pub async fn get_template_functions(&self) -> Result<Vec<GetTemplateFunctionsResponse>> {
|
||||||
let reply_events = self
|
let reply_events = self
|
||||||
.server
|
.server
|
||||||
.send_and_wait(&InternalEventPayload::GetTemplateFunctionsRequest)
|
.send_and_wait(&InternalEventPayload::GetTemplateFunctionsRequest)
|
||||||
@@ -91,20 +99,47 @@ impl PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call_http_request_action(&self, req: CallHttpRequestActionRequest) -> Result<()> {
|
pub async fn call_http_request_action(&self, req: CallHttpRequestActionRequest) -> Result<()> {
|
||||||
let plugin = self.server.plugin_by_ref_id(req.plugin_ref_id.as_str()).await?;
|
let plugin = self
|
||||||
let event = plugin.build_event_to_send(&InternalEventPayload::CallHttpRequestActionRequest(req), None);
|
.server
|
||||||
|
.plugin_by_ref_id(req.plugin_ref_id.as_str())
|
||||||
|
.await?;
|
||||||
|
let event = plugin.build_event_to_send(
|
||||||
|
&InternalEventPayload::CallHttpRequestActionRequest(req),
|
||||||
|
None,
|
||||||
|
);
|
||||||
plugin.send(&event).await?;
|
plugin.send(&event).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call_template_function(&self, req: CallTemplateFunctionRequest) -> Result<()> {
|
pub async fn call_template_function(
|
||||||
let plugin = self.server.plugin_by_ref_id(req.plugin_ref_id.as_str()).await?;
|
&self,
|
||||||
let event = plugin.build_event_to_send(&InternalEventPayload::CallTemplateFunctionRequest(req), None);
|
fn_name: &str,
|
||||||
plugin.send(&event).await?;
|
args: HashMap<String, String>,
|
||||||
Ok(())
|
) -> Result<Option<String>> {
|
||||||
|
let req = CallTemplateFunctionRequest {
|
||||||
|
name: fn_name.to_string(),
|
||||||
|
args: CallTemplateFunctionArgs {
|
||||||
|
purpose: CallTemplateFunctionPurpose::Preview,
|
||||||
|
values: args,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let events = self
|
||||||
|
.server
|
||||||
|
.send_and_wait(&InternalEventPayload::CallTemplateFunctionRequest(req))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let value = events.into_iter().find_map(|e| match e.payload {
|
||||||
|
InternalEventPayload::CallTemplateFunctionResponse(CallTemplateFunctionResponse {
|
||||||
|
value,
|
||||||
|
}) => value,
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_import(&self, content: &str) -> Result<(ImportResponse, String)> {
|
pub async fn import_data(&self, content: &str) -> Result<(ImportResponse, String)> {
|
||||||
let reply_events = self
|
let reply_events = self
|
||||||
.server
|
.server
|
||||||
.send_and_wait(&InternalEventPayload::ImportRequest(ImportRequest {
|
.send_and_wait(&InternalEventPayload::ImportRequest(ImportRequest {
|
||||||
@@ -113,19 +148,22 @@ impl PluginManager {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// TODO: Don't just return the first valid response
|
// TODO: Don't just return the first valid response
|
||||||
for event in reply_events {
|
let result = reply_events.into_iter().find_map(|e| match e.payload {
|
||||||
if let InternalEventPayload::ImportResponse(resp) = event.payload {
|
InternalEventPayload::ImportResponse(resp) => Some((resp, e.plugin_ref_id)),
|
||||||
let ref_id = event.plugin_ref_id.as_str();
|
_ => None,
|
||||||
let plugin = self.server.plugin_by_ref_id(ref_id).await?;
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
None => Err(PluginErr("No import responses found".to_string())),
|
||||||
|
Some((resp, ref_id)) => {
|
||||||
|
let plugin = self.server.plugin_by_ref_id(ref_id.as_str()).await?;
|
||||||
let plugin_name = plugin.name().await;
|
let plugin_name = plugin.name().await;
|
||||||
return Ok((resp, plugin_name));
|
Ok((resp, plugin_name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(PluginErr("No import responses found".to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_filter(
|
pub async fn filter_data(
|
||||||
&self,
|
&self,
|
||||||
filter: &str,
|
filter: &str,
|
||||||
content: &str,
|
content: &str,
|
||||||
|
|||||||
@@ -4,26 +4,28 @@ use std::collections::HashMap;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
pub trait TemplateCallback {
|
pub trait TemplateCallback {
|
||||||
fn run(&self, fn_name: &str, args: HashMap<String, String>) -> impl Future<Output = Result<String, String>> + Send;
|
fn run(
|
||||||
|
&self,
|
||||||
|
fn_name: &str,
|
||||||
|
args: HashMap<String, String>,
|
||||||
|
) -> impl Future<Output = Result<String, String>> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse_and_render<T>(
|
pub async fn parse_and_render<T: TemplateCallback>(
|
||||||
template: &str,
|
template: &str,
|
||||||
vars: &HashMap<String, String>,
|
vars: &HashMap<String, String>,
|
||||||
cb: &Box<T>,
|
cb: &T,
|
||||||
) -> String
|
) -> String {
|
||||||
where
|
|
||||||
T: TemplateCallback,
|
|
||||||
{
|
|
||||||
let mut p = Parser::new(template);
|
let mut p = Parser::new(template);
|
||||||
let tokens = p.parse();
|
let tokens = p.parse();
|
||||||
render(tokens, vars, cb).await
|
render(tokens, vars, cb).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render<T>(tokens: Tokens, vars: &HashMap<String, String>, cb: &Box<T>) -> String
|
pub async fn render<T: TemplateCallback>(
|
||||||
where
|
tokens: Tokens,
|
||||||
T: TemplateCallback,
|
vars: &HashMap<String, String>,
|
||||||
{
|
cb: &T,
|
||||||
|
) -> String {
|
||||||
let mut doc_str: Vec<String> = Vec::new();
|
let mut doc_str: Vec<String> = Vec::new();
|
||||||
|
|
||||||
for t in tokens.tokens {
|
for t in tokens.tokens {
|
||||||
@@ -37,10 +39,11 @@ where
|
|||||||
doc_str.join("")
|
doc_str.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn render_tag<T>(val: Val, vars: &HashMap<String, String>, cb: &Box<T>) -> String
|
async fn render_tag<T: TemplateCallback>(
|
||||||
where
|
val: Val,
|
||||||
T: TemplateCallback,
|
vars: &HashMap<String, String>,
|
||||||
{
|
cb: &T,
|
||||||
|
) -> String {
|
||||||
match val {
|
match val {
|
||||||
Val::Str { text } => text.into(),
|
Val::Str { text } => text.into(),
|
||||||
Val::Var { name } => match vars.get(name.as_str()) {
|
Val::Var { name } => match vars.get(name.as_str()) {
|
||||||
@@ -94,14 +97,18 @@ mod tests {
|
|||||||
struct EmptyCB {}
|
struct EmptyCB {}
|
||||||
|
|
||||||
impl TemplateCallback for EmptyCB {
|
impl TemplateCallback for EmptyCB {
|
||||||
async fn run(&self, _fn_name: &str, _args: HashMap<String, String>) -> Result<String, String>{
|
async fn run(
|
||||||
|
&self,
|
||||||
|
_fn_name: &str,
|
||||||
|
_args: HashMap<String, String>,
|
||||||
|
) -> Result<String, String> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn render_empty() {
|
async fn render_empty() {
|
||||||
let empty_cb = Box::new(EmptyCB {});
|
let empty_cb = EmptyCB {};
|
||||||
let template = "";
|
let template = "";
|
||||||
let vars = HashMap::new();
|
let vars = HashMap::new();
|
||||||
let result = "";
|
let result = "";
|
||||||
@@ -113,7 +120,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn render_text_only() {
|
async fn render_text_only() {
|
||||||
let empty_cb = Box::new(EmptyCB {});
|
let empty_cb = EmptyCB {};
|
||||||
let template = "Hello World!";
|
let template = "Hello World!";
|
||||||
let vars = HashMap::new();
|
let vars = HashMap::new();
|
||||||
let result = "Hello World!";
|
let result = "Hello World!";
|
||||||
@@ -125,7 +132,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn render_simple() {
|
async fn render_simple() {
|
||||||
let empty_cb = Box::new(EmptyCB {});
|
let empty_cb = EmptyCB {};
|
||||||
let template = "${[ foo ]}";
|
let template = "${[ foo ]}";
|
||||||
let vars = HashMap::from([("foo".to_string(), "bar".to_string())]);
|
let vars = HashMap::from([("foo".to_string(), "bar".to_string())]);
|
||||||
let result = "bar";
|
let result = "bar";
|
||||||
@@ -137,7 +144,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn render_surrounded() {
|
async fn render_surrounded() {
|
||||||
let empty_cb = Box::new(EmptyCB {});
|
let empty_cb = EmptyCB {};
|
||||||
let template = "hello ${[ word ]} world!";
|
let template = "hello ${[ word ]} world!";
|
||||||
let vars = HashMap::from([("word".to_string(), "cruel".to_string())]);
|
let vars = HashMap::from([("word".to_string(), "cruel".to_string())]);
|
||||||
let result = "hello cruel world!";
|
let result = "hello cruel world!";
|
||||||
@@ -168,10 +175,7 @@ mod tests {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(parse_and_render(template, &vars, &CB {}).await, result);
|
||||||
parse_and_render(template, &vars, &Box::new(CB {})).await,
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -195,7 +199,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_and_render(template, &vars, &Box::new(CB {})).await,
|
parse_and_render(template, &vars, &CB {}).await,
|
||||||
result.to_string()
|
result.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -218,7 +222,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_and_render(template, &vars, &Box::new(CB {})).await,
|
parse_and_render(template, &vars, &CB {}).await,
|
||||||
result.to_string()
|
result.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defaultKeymap } from '@codemirror/commands';
|
import { defaultKeymap } from '@codemirror/commands';
|
||||||
import { Compartment, EditorState, type Extension } from '@codemirror/state';
|
import { Compartment, EditorState, type Extension } from '@codemirror/state';
|
||||||
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
|
||||||
import type { EnvironmentVariable } from '@yaakapp/api';
|
import type { EnvironmentVariable, TemplateFunction } from '@yaakapp/api';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import type { MutableRefObject, ReactNode } from 'react';
|
import type { MutableRefObject, ReactNode } from 'react';
|
||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
||||||
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
||||||
import { useSettings } from '../../../hooks/useSettings';
|
import { useSettings } from '../../../hooks/useSettings';
|
||||||
import { type TemplateFunction, useTemplateFunctions } from '../../../hooks/useTemplateFunctions';
|
import { useTemplateFunctions } from '../../../hooks/useTemplateFunctions';
|
||||||
import { useDialog } from '../../DialogContext';
|
import { useDialog } from '../../DialogContext';
|
||||||
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
||||||
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
||||||
|
|||||||
Reference in New Issue
Block a user