diff --git a/.run/Dev Desktop.run.xml b/.run/Dev Desktop.run.xml
index ea4d7d29..0565ccb0 100644
--- a/.run/Dev Desktop.run.xml
+++ b/.run/Dev Desktop.run.xml
@@ -7,7 +7,8 @@
+
-
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index a46edb70..d8a226b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,7 @@
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
"@tauri-apps/plugin-os": "^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",
"classnames": "^2.3.2",
"cm6-graphql": "^0.0.9",
@@ -2990,9 +2990,9 @@
"integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="
},
"node_modules/@yaakapp/api": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.6.tgz",
- "integrity": "sha512-5lYXKcOVmLzVUrkfU4JOCbz+CBV5Dm/cALoZvfbelvZWOVu3sTrBxS9cbNVQQq2B6WwLInSevk7pMq58GqIj5Q==",
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.1.7.tgz",
+ "integrity": "sha512-6dheXUuhX3o1KwZ7ngtB/OcQ4qCiXxg3LN2t1jA28nnZBlGCek+h9yndiF/PGWl5yReMcXy8rn4pq4W9zAGHLg==",
"dependencies": {
"@types/node": "^22.0.0"
}
diff --git a/package.json b/package.json
index 946929c9..4f78e09a 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
"@tauri-apps/plugin-os": "^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",
"classnames": "^2.3.2",
"cm6-graphql": "^0.0.9",
diff --git a/plugin-runtime-types/package-lock.json b/plugin-runtime-types/package-lock.json
index 03a3cfc4..0c060be2 100644
--- a/plugin-runtime-types/package-lock.json
+++ b/plugin-runtime-types/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@yaakapp/api",
- "version": "0.1.6",
+ "version": "0.1.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@yaakapp/api",
- "version": "0.1.6",
+ "version": "0.1.7",
"dependencies": {
"@types/node": "^22.0.0"
},
diff --git a/plugin-runtime-types/package.json b/plugin-runtime-types/package.json
index 0e1a641b..97222c40 100644
--- a/plugin-runtime-types/package.json
+++ b/plugin-runtime-types/package.json
@@ -1,6 +1,6 @@
{
"name": "@yaakapp/api",
- "version": "0.1.6",
+ "version": "0.1.7",
"main": "lib/index.js",
"typings": "./lib/index.d.ts",
"files": [
diff --git a/plugin-runtime-types/src/gen/CallTemplateFunctionRequest.ts b/plugin-runtime-types/src/gen/CallTemplateFunctionRequest.ts
index 9c33bd35..0e1e640e 100644
--- a/plugin-runtime-types/src/gen/CallTemplateFunctionRequest.ts
+++ b/plugin-runtime-types/src/gen/CallTemplateFunctionRequest.ts
@@ -1,4 +1,4 @@
// 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";
-export type CallTemplateFunctionRequest = { name: string, pluginRefId: string, args: CallTemplateFunctionArgs, };
+export type CallTemplateFunctionRequest = { name: string, args: CallTemplateFunctionArgs, };
diff --git a/plugin-runtime-types/src/gen/CallTemplateFunctionResponse.ts b/plugin-runtime-types/src/gen/CallTemplateFunctionResponse.ts
new file mode 100644
index 00000000..f89ef42f
--- /dev/null
+++ b/plugin-runtime-types/src/gen/CallTemplateFunctionResponse.ts
@@ -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, };
diff --git a/plugin-runtime-types/src/gen/GetHttpRequestActionsRequest.ts b/plugin-runtime-types/src/gen/GetHttpRequestActionsRequest.ts
new file mode 100644
index 00000000..570d7b77
--- /dev/null
+++ b/plugin-runtime-types/src/gen/GetHttpRequestActionsRequest.ts
@@ -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;
diff --git a/plugin-runtime-types/src/gen/InternalEventPayload.ts b/plugin-runtime-types/src/gen/InternalEventPayload.ts
index 6d8f45cd..e619fb24 100644
--- a/plugin-runtime-types/src/gen/InternalEventPayload.ts
+++ b/plugin-runtime-types/src/gen/InternalEventPayload.ts
@@ -3,12 +3,14 @@ import type { BootRequest } from "./BootRequest";
import type { BootResponse } from "./BootResponse";
import type { CallHttpRequestActionRequest } from "./CallHttpRequestActionRequest";
import type { CallTemplateFunctionRequest } from "./CallTemplateFunctionRequest";
+import type { CallTemplateFunctionResponse } from "./CallTemplateFunctionResponse";
import type { CopyTextRequest } from "./CopyTextRequest";
import type { EmptyResponse } from "./EmptyResponse";
import type { ExportHttpRequestRequest } from "./ExportHttpRequestRequest";
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
import type { FilterRequest } from "./FilterRequest";
import type { FilterResponse } from "./FilterResponse";
+import type { GetHttpRequestActionsRequest } from "./GetHttpRequestActionsRequest";
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
import type { GetHttpRequestByIdResponse } from "./GetHttpRequestByIdResponse";
@@ -21,4 +23,4 @@ import type { SendHttpRequestRequest } from "./SendHttpRequestRequest";
import type { SendHttpRequestResponse } from "./SendHttpRequestResponse";
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;
diff --git a/plugin-runtime-types/src/index.ts b/plugin-runtime-types/src/index.ts
index 3d496ed3..aaf02a52 100644
--- a/plugin-runtime-types/src/index.ts
+++ b/plugin-runtime-types/src/index.ts
@@ -8,6 +8,7 @@ export * from './gen/CallHttpRequestActionArgs';
export * from './gen/CallTemplateFunctionPurpose';
export * from './gen/CallHttpRequestActionRequest';
export * from './gen/CallTemplateFunctionRequest';
+export * from './gen/CallTemplateFunctionResponse';
export * from './gen/CallTemplateFunctionArgs';
export * from './gen/Cookie';
export * from './gen/CookieDomain';
diff --git a/plugin-runtime/src/index.worker.ts b/plugin-runtime/src/index.worker.ts
index 75c3f1e4..2a8ee9c8 100644
--- a/plugin-runtime/src/index.worker.ts
+++ b/plugin-runtime/src/index.worker.ts
@@ -56,7 +56,7 @@ new Promise(async (resolve, reject) => {
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);
sendEvent(event);
return event.id;
@@ -233,9 +233,10 @@ new Promise(async (resolve, reject) => {
Array.isArray(mod.plugin?.templateFunctions)
) {
const action = mod.plugin.templateFunctions.find((a) => a.name === payload.name);
- if (typeof action?.onRender() === 'function') {
- await action.onRender(ctx, payload.args);
- sendEmpty(replyId);
+ if (typeof action?.onRender === 'function') {
+ const result = await action.onRender(ctx, payload.args);
+ console.log('GOT VALUE', result);
+ sendPayload({ type: 'call_template_function_response', value: result ?? null }, replyId);
return;
}
}
diff --git a/src-tauri/src/http_request.rs b/src-tauri/src/http_request.rs
index 1984f574..52e6d6ac 100644
--- a/src-tauri/src/http_request.rs
+++ b/src-tauri/src/http_request.rs
@@ -7,7 +7,7 @@ use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
-use crate::render::render_request;
+use crate::render::render_http_request;
use crate::response_err;
use base64::Engine;
use http::header::{ACCEPT, USER_AGENT};
@@ -37,7 +37,13 @@ pub async fn send_http_request(
let workspace = get_workspace(window, &request.workspace_id)
.await
.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;
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 554ca776..7b53d6e0 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -35,7 +35,8 @@ use crate::export_resources::{get_workspace_export_resources, WorkspaceExportRes
use crate::grpc::metadata_to_map;
use crate::http_request::send_http_request;
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::window_menu::app_menu;
use yaak_models::models::{
@@ -70,7 +71,7 @@ mod notifications;
mod render;
#[cfg(target_os = "macos")]
mod tauri_plugin_mac_window;
-mod template_fns;
+mod template_callback;
mod updates;
mod window_menu;
@@ -128,7 +129,13 @@ async fn cmd_render_template(
let workspace = get_workspace(&window, &workspace_id)
.await
.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)
}
@@ -180,9 +187,6 @@ async fn cmd_grpc_go(
window: WebviewWindow,
grpc_handle: State<'_, Mutex>,
) -> Result {
- let req = get_grpc_request(&window, request_id)
- .await
- .map_err(|e| e.to_string())?;
let environment = match environment_id {
Some(id) => Some(
get_environment(&window, id)
@@ -191,13 +195,17 @@ async fn cmd_grpc_go(
),
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)
.await
.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 vars = variables_from_environment(&workspace, environment.as_ref()).await;
- // Add rest of metadata
+ // Add the rest of metadata
for h in req.clone().metadata {
if h.name.is_empty() && h.value.is_empty() {
continue;
@@ -207,10 +215,7 @@ async fn cmd_grpc_go(
continue;
}
- let name = render::render(&h.name, &vars).await;
- let value = render::render(&h.value, &vars).await;
-
- metadata.insert(name, value);
+ metadata.insert(h.name, h.value);
}
if let Some(b) = &req.authentication_type {
@@ -219,25 +224,22 @@ async fn cmd_grpc_go(
let a = req.authentication;
if b == "basic" {
- let raw_username = a
+ let username = a
.get("username")
.unwrap_or(empty_value)
.as_str()
.unwrap_or("");
- let raw_password = a
+ let password = a
.get("password")
.unwrap_or(empty_value)
.as_str()
.unwrap_or("");
- let username = render::render(raw_username, &vars).await;
- let password = render::render(raw_password, &vars).await;
let auth = format!("{username}:{password}");
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
metadata.insert("Authorization".to_string(), format!("Basic {}", encoded));
} else if b == "bearer" {
- let raw_token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
- let token = render::render(raw_token, &vars).await;
+ let token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
metadata.insert("Authorization".to_string(), format!("Bearer {token}"));
}
}
@@ -331,7 +333,6 @@ async fn cmd_grpc_go(
let w = window.clone();
let base_msg = base_msg.clone();
let method_desc = method_desc.clone();
- let vars = vars.clone();
move |ev: tauri::Event| {
if *cancelled_rx.borrow() {
@@ -351,14 +352,10 @@ async fn cmd_grpc_go(
};
match serde_json::from_str::(ev.payload()) {
- Ok(IncomingMsg::Message(raw_msg)) => {
+ Ok(IncomingMsg::Message(msg)) => {
let w = w.clone();
let base_msg = base_msg.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)
{
Ok(d_msg) => d_msg,
@@ -410,13 +407,11 @@ async fn cmd_grpc_go(
let w = window.clone();
let base_event = base_msg.clone();
let req = req.clone();
- let vars = vars.clone();
- let raw_msg = if req.message.is_empty() {
+ let msg = if req.message.is_empty() {
"{}".to_string()
} else {
req.message
};
- let msg = render::render(&raw_msg, &vars).await;
upsert_grpc_event(
&w,
@@ -772,7 +767,7 @@ async fn cmd_filter_response(
// TODO: Have plugins register their own content type (regex?)
plugin_manager
- .run_filter(filter, &body, &content_type)
+ .filter_data(filter, &body, &content_type)
.await
.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));
let file_contents = file.as_str();
let (import_result, plugin_name) = plugin_manager
- .run_import(file_contents)
+ .import_data(file_contents)
.await
.map_err(|e| e.to_string())?;
@@ -912,7 +907,7 @@ async fn cmd_http_request_actions(
plugin_manager: State<'_, PluginManager>,
) -> Result, String> {
plugin_manager
- .run_http_request_actions()
+ .get_http_request_actions()
.await
.map_err(|e| e.to_string())
}
@@ -922,7 +917,7 @@ async fn cmd_template_functions(
plugin_manager: State<'_, PluginManager>,
) -> Result, String> {
plugin_manager
- .run_template_functions()
+ .get_template_functions()
.await
.map_err(|e| e.to_string())
}
@@ -947,7 +942,7 @@ async fn cmd_curl_to_request(
) -> Result {
let (import_result, plugin_name) = {
plugin_manager
- .run_import(command)
+ .import_data(command)
.await
.map_err(|e| e.to_string())?
};
@@ -1661,6 +1656,10 @@ pub fn run() {
let grpc_handle = GrpcHandle::new(&app.app_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();
monitor_plugin_events(&app_handle);
@@ -1999,8 +1998,13 @@ async fn handle_plugin_event(
None => None,
Some(id) => get_environment(w, id.as_str()).await.ok(),
};
- let rendered_http_request =
- render_request(&req.http_request, &workspace, environment.as_ref()).await;
+ let rendered_http_request = render_http_request(
+ app_handle,
+ &req.http_request,
+ &workspace,
+ environment.as_ref(),
+ )
+ .await;
Some(InternalEventPayload::RenderHttpRequestResponse(
RenderHttpRequestResponse {
http_request: rendered_http_request,
diff --git a/src-tauri/src/render.rs b/src-tauri/src/render.rs
index 13086c2b..e2456fc1 100644
--- a/src-tauri/src/render.rs
+++ b/src-tauri/src/render.rs
@@ -1,80 +1,126 @@
-use crate::template_fns::timestamp;
+use crate::template_callback::PluginTemplateCallback;
use serde_json::Value;
use std::collections::HashMap;
-use yaak_models::models::{
- Environment, EnvironmentVariable, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace,
-};
+use tauri::{AppHandle, Manager, Runtime};
+use yaak_models::models::{Environment, EnvironmentVariable, GrpcMetadataEntry, GrpcRequest, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace};
use yaak_templates::{parse_and_render, TemplateCallback};
-pub async fn render_template(template: &str, w: &Workspace, e: Option<&Environment>) -> String {
- let vars = &variables_from_environment(w, e).await;
- render(template, vars).await
+pub async fn render_template(
+ app_handle: &AppHandle,
+ template: &str,
+ w: &Workspace,
+ e: Option<&Environment>,
+) -> String {
+ let cb = &*app_handle.state::();
+ 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(
+ app_handle: &AppHandle,
+ r: &GrpcRequest,
+ w: &Workspace,
+ e: Option<&Environment>,
+) -> GrpcRequest {
+ let cb = &*app_handle.state::();
+ 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(
+ app_handle: &AppHandle,
r: &HttpRequest,
w: &Workspace,
e: Option<&Environment>,
) -> HttpRequest {
- let r = r.clone();
- let vars = &variables_from_environment(w, e).await;
+ let cb = &*app_handle.state::();
+ let vars = &variables_from_environment(w, e, cb).await;
let mut url_parameters = Vec::new();
- for p in r.url_parameters {
+ for p in r.url_parameters.clone() {
url_parameters.push(HttpUrlParameter {
enabled: p.enabled,
- name: render(p.name.as_str(), vars).await,
- value: render(p.value.as_str(), vars).await,
+ name: render(p.name.as_str(), vars, cb).await,
+ value: render(p.value.as_str(), vars, cb).await,
})
}
let mut headers = Vec::new();
- for p in r.headers {
+ for p in r.headers.clone() {
headers.push(HttpRequestHeader {
enabled: p.enabled,
- name: render(p.name.as_str(), vars).await,
- value: render(p.value.as_str(), vars).await,
+ name: render(p.name.as_str(), vars, cb).await,
+ value: render(p.value.as_str(), vars, cb).await,
})
}
let mut body = HashMap::new();
- for (k, v) in r.body {
+ for (k, v) in r.body.clone() {
let v = if v.is_string() {
- render(v.as_str().unwrap(), vars).await
+ render(v.as_str().unwrap(), vars, cb).await
} else {
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();
- for (k, v) in r.authentication {
+ for (k, v) in r.authentication.clone() {
let v = if v.is_string() {
- render(v.as_str().unwrap(), vars).await
+ render(v.as_str().unwrap(), vars, cb).await
} else {
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 {
- url: render(r.url.as_str(), vars).await,
+ url,
url_parameters,
headers,
body,
authentication,
- ..r
+ ..r.to_owned()
}
}
-pub async fn recursively_render_variables<'s>(
+pub async fn recursively_render_variables<'s, T: TemplateCallback>(
m: &HashMap,
render_count: usize,
+ cb: &T,
) -> HashMap {
let mut did_render = false;
let mut new_map = 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 {
did_render = true
}
@@ -82,15 +128,16 @@ pub async fn recursively_render_variables<'s>(
}
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
}
-pub async fn variables_from_environment(
+pub async fn variables_from_environment(
workspace: &Workspace,
environment: Option<&Environment>,
+ cb: &T,
) -> HashMap {
let mut variables = HashMap::new();
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);
}
- recursively_render_variables(&variables, 0).await
+ recursively_render_variables(&variables, 0, cb).await
}
-pub async fn render(template: &str, vars: &HashMap) -> String {
- parse_and_render(template, vars, &Box::new(PluginTemplateCallback::default())).await
-}
-
-#[derive(Default)]
-struct PluginTemplateCallback {}
-
-impl TemplateCallback for PluginTemplateCallback {
- async fn run(&self, fn_name: &str, args: HashMap) -> Result {
- match fn_name {
- "timestamp" => timestamp(args),
- _ => Err(format!("Unknown template function {fn_name}")),
- }
- }
+pub async fn render(
+ template: &str,
+ vars: &HashMap,
+ cb: &T,
+) -> String {
+ parse_and_render(template, vars, cb).await
}
fn add_variable_to_map(
diff --git a/src-tauri/src/template_callback.rs b/src-tauri/src/template_callback.rs
new file mode 100644
index 00000000..f9b174f2
--- /dev/null
+++ b/src-tauri/src/template_callback.rs
@@ -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) -> Result {
+ let plugin_manager = self.app_handle.state::();
+ let resp = plugin_manager
+ .call_template_function(fn_name, args)
+ .await
+ .map_err(|e| e.to_string())?;
+ Ok(resp.unwrap_or_default())
+ }
+}
diff --git a/src-tauri/src/template_fns.rs b/src-tauri/src/template_fns.rs
deleted file mode 100644
index 94b7434d..00000000
--- a/src-tauri/src/template_fns.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use chrono::{DateTime, Utc};
-use std::collections::HashMap;
-
-pub fn timestamp(args: HashMap) -> Result {
- 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 = 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()));
- }
-}
diff --git a/src-tauri/yaak_plugin_runtime/src/events.rs b/src-tauri/yaak_plugin_runtime/src/events.rs
index 66933771..0f834346 100644
--- a/src-tauri/yaak_plugin_runtime/src/events.rs
+++ b/src-tauri/yaak_plugin_runtime/src/events.rs
@@ -1,5 +1,5 @@
-use std::collections::HashMap;
use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
use ts_rs::TS;
use yaak_models::models::{
@@ -36,13 +36,14 @@ pub enum InternalEventPayload {
SendHttpRequestRequest(SendHttpRequestRequest),
SendHttpRequestResponse(SendHttpRequestResponse),
- GetHttpRequestActionsRequest,
+ GetHttpRequestActionsRequest(GetHttpRequestActionsRequest),
GetHttpRequestActionsResponse(GetHttpRequestActionsResponse),
CallHttpRequestActionRequest(CallHttpRequestActionRequest),
GetTemplateFunctionsRequest,
GetTemplateFunctionsResponse(GetTemplateFunctionsResponse),
CallTemplateFunctionRequest(CallTemplateFunctionRequest),
+ CallTemplateFunctionResponse(CallTemplateFunctionResponse),
CopyTextRequest(CopyTextRequest),
@@ -262,10 +263,16 @@ pub struct TemplateFunctionSelectOption {
#[ts(export)]
pub struct CallTemplateFunctionRequest {
pub name: String,
- pub plugin_ref_id: String,
pub args: CallTemplateFunctionArgs,
}
+#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
+#[serde(default, rename_all = "camelCase")]
+#[ts(export)]
+pub struct CallTemplateFunctionResponse {
+ pub value: Option,
+}
+
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
@@ -282,12 +289,17 @@ pub enum CallTemplateFunctionPurpose {
Preview,
}
-impl Default for CallTemplateFunctionPurpose{
+impl Default for CallTemplateFunctionPurpose {
fn default() -> Self {
CallTemplateFunctionPurpose::Preview
}
}
+#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
+#[serde(default)]
+#[ts(export)]
+pub struct GetHttpRequestActionsRequest {}
+
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
diff --git a/src-tauri/yaak_plugin_runtime/src/manager.rs b/src-tauri/yaak_plugin_runtime/src/manager.rs
index cfc04436..5245bbcf 100644
--- a/src-tauri/yaak_plugin_runtime/src/manager.rs
+++ b/src-tauri/yaak_plugin_runtime/src/manager.rs
@@ -1,5 +1,11 @@
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::nodejs::start_nodejs_plugin_runtime;
@@ -57,11 +63,13 @@ impl PluginManager {
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
.await
}
-
- pub async fn run_http_request_actions(&self) -> Result> {
+
+ pub async fn get_http_request_actions(&self) -> Result> {
let reply_events = self
.server
- .send_and_wait(&InternalEventPayload::GetHttpRequestActionsRequest)
+ .send_and_wait(&InternalEventPayload::GetHttpRequestActionsRequest(
+ GetHttpRequestActionsRequest {},
+ ))
.await?;
let mut all_actions = Vec::new();
@@ -74,7 +82,7 @@ impl PluginManager {
Ok(all_actions)
}
- pub async fn run_template_functions(&self) -> Result> {
+ pub async fn get_template_functions(&self) -> Result> {
let reply_events = self
.server
.send_and_wait(&InternalEventPayload::GetTemplateFunctionsRequest)
@@ -91,20 +99,47 @@ impl PluginManager {
}
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 event = plugin.build_event_to_send(&InternalEventPayload::CallHttpRequestActionRequest(req), None);
+ let plugin = self
+ .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?;
Ok(())
}
- pub async fn call_template_function(&self, req: CallTemplateFunctionRequest) -> Result<()> {
- let plugin = self.server.plugin_by_ref_id(req.plugin_ref_id.as_str()).await?;
- let event = plugin.build_event_to_send(&InternalEventPayload::CallTemplateFunctionRequest(req), None);
- plugin.send(&event).await?;
- Ok(())
+ pub async fn call_template_function(
+ &self,
+ fn_name: &str,
+ args: HashMap,
+ ) -> Result