Request actions (#65)

This commit is contained in:
Gregory Schier
2024-08-14 15:31:52 -07:00
committed by GitHub
parent 12f4c2c668
commit b95fa25898
29 changed files with 392 additions and 116 deletions

View File

@@ -21,6 +21,7 @@ use tauri::TitleBarStyle;
use tauri::{AppHandle, Emitter, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
use tauri::{Listener, Runtime};
use tauri::{Manager, WindowEvent};
use tauri_plugin_clipboard_manager::ClipboardExt;
use tauri_plugin_log::{fern, Target, TargetKind};
use tauri_plugin_shell::ShellExt;
use tokio::sync::{watch, Mutex};
@@ -55,7 +56,8 @@ use yaak_models::queries::{
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
};
use yaak_plugin_runtime::events::{
FilterResponse, GetHttpRequestByIdResponse, InternalEvent, InternalEventPayload,
CallHttpRequestActionRequest, FilterResponse, GetHttpRequestActionsResponse,
GetHttpRequestByIdResponse, InternalEvent, InternalEventPayload, RenderHttpRequestResponse,
SendHttpRequestResponse,
};
@@ -870,29 +872,24 @@ async fn cmd_import_data(
}
#[tauri::command]
async fn cmd_request_to_curl(
app: AppHandle,
request_id: &str,
async fn cmd_http_request_actions(
plugin_manager: State<'_, PluginManager>,
environment_id: Option<&str>,
) -> Result<String, String> {
let request = get_http_request(&app, request_id)
) -> Result<Vec<GetHttpRequestActionsResponse>, String> {
plugin_manager
.run_http_request_actions()
.await
.map_err(|e| e.to_string())?;
let environment = match environment_id {
Some(id) => Some(get_environment(&app, id).await.map_err(|e| e.to_string())?),
None => None,
};
let workspace = get_workspace(&app, &request.workspace_id)
.await
.map_err(|e| e.to_string())?;
let rendered = render_request(&request, &workspace, environment.as_ref());
.map_err(|e| e.to_string())
}
let import_response = plugin_manager
.run_export_curl(&rendered)
#[tauri::command]
async fn cmd_call_http_request_action(
req: CallHttpRequestActionRequest,
plugin_manager: State<'_, PluginManager>,
) -> Result<(), String> {
plugin_manager
.call_http_request_action(req)
.await
.map_err(|e| e.to_string())?;
Ok(import_response.content)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1624,6 +1621,7 @@ pub fn run() {
Ok(())
})
.invoke_handler(tauri::generate_handler![
cmd_call_http_request_action,
cmd_check_for_updates,
cmd_create_cookie_jar,
cmd_create_environment,
@@ -1642,6 +1640,7 @@ pub fn run() {
cmd_delete_http_request,
cmd_delete_http_response,
cmd_delete_workspace,
cmd_dismiss_notification,
cmd_duplicate_grpc_request,
cmd_duplicate_http_request,
cmd_export_data,
@@ -1656,6 +1655,7 @@ pub fn run() {
cmd_get_workspace,
cmd_grpc_go,
cmd_grpc_reflect,
cmd_http_request_actions,
cmd_import_data,
cmd_list_cookie_jars,
cmd_list_environments,
@@ -1669,8 +1669,6 @@ pub fn run() {
cmd_metadata,
cmd_new_nested_window,
cmd_new_window,
cmd_request_to_curl,
cmd_dismiss_notification,
cmd_save_response,
cmd_send_ephemeral_request,
cmd_send_http_request,
@@ -1915,9 +1913,49 @@ async fn handle_plugin_event<R: Runtime>(
let event = match event.clone().payload {
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
let http_request = get_http_request(app_handle, req.id.as_str()).await.ok();
InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse {
http_request,
})
Some(InternalEventPayload::GetHttpRequestByIdResponse(
GetHttpRequestByIdResponse { http_request },
))
}
InternalEventPayload::CopyTextRequest(req) => {
app_handle
.clipboard()
.write_text(req.text.as_str())
.expect("Failed to write text to clipboard");
None
}
InternalEventPayload::ShowToastRequest(req) => {
app_handle
.emit("show_toast", req)
.expect("Failed to emit show_toast");
None
}
InternalEventPayload::RenderHttpRequestRequest(req) => {
let webview_windows = app_handle.get_focused_window()?.webview_windows();
let w = match webview_windows.iter().next() {
None => return None,
Some((_, w)) => w,
};
let workspace = get_workspace(app_handle, req.http_request.workspace_id.as_str())
.await
.expect("Failed to get workspace for request");
let url = w.url().unwrap();
let mut query_pairs = url.query_pairs();
let environment_id = query_pairs
.find(|(k, _v)| k == "environment_id")
.map(|(_k, v)| v.to_string());
let environment = match environment_id {
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());
Some(InternalEventPayload::RenderHttpRequestResponse(
RenderHttpRequestResponse {
http_request: rendered_http_request,
},
))
}
InternalEventPayload::SendHttpRequestRequest(req) => {
let webview_windows = app_handle.get_focused_window()?.webview_windows();
@@ -1964,10 +2002,12 @@ async fn handle_plugin_event<R: Runtime>(
Err(_e) => return None,
};
InternalEventPayload::SendHttpRequestResponse(SendHttpRequestResponse { http_response })
Some(InternalEventPayload::SendHttpRequestResponse(
SendHttpRequestResponse { http_response },
))
}
_ => return None,
_ => None,
};
Some(event)
event
}

View File

@@ -32,13 +32,24 @@ pub enum InternalEventPayload {
ExportHttpRequestRequest(ExportHttpRequestRequest),
ExportHttpRequestResponse(ExportHttpRequestResponse),
SendHttpRequestRequest(SendHttpRequestRequest),
SendHttpRequestResponse(SendHttpRequestResponse),
GetHttpRequestActionsRequest,
GetHttpRequestActionsResponse(GetHttpRequestActionsResponse),
CallHttpRequestActionRequest(CallHttpRequestActionRequest),
CopyTextRequest(CopyTextRequest),
RenderHttpRequestRequest(RenderHttpRequestRequest),
RenderHttpRequestResponse(RenderHttpRequestResponse),
ShowToastRequest(ShowToastRequest),
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
/// Returned when a plugin doesn't get run, just so the server
/// has something to listen for
EmptyResponse(EmptyResponse),
@@ -122,6 +133,86 @@ pub struct SendHttpRequestResponse {
pub http_response: HttpResponse,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct CopyTextRequest {
pub text: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct RenderHttpRequestRequest {
pub http_request: HttpRequest,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct RenderHttpRequestResponse {
pub http_request: HttpRequest,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct ShowToastRequest {
pub message: String,
pub variant: ToastVariant,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub enum ToastVariant {
Custom,
Copied,
Success,
Info,
Warning,
Error,
}
impl Default for ToastVariant {
fn default() -> Self {
ToastVariant::Info
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct GetHttpRequestActionsResponse {
pub actions: Vec<HttpRequestAction>,
pub plugin_ref_id: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct HttpRequestAction {
pub key: String,
pub label: String,
pub icon: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct CallHttpRequestActionRequest {
pub key: String,
pub plugin_ref_id: String,
pub args: CallHttpRequestActionArgs,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]
pub struct CallHttpRequestActionArgs {
pub http_request: HttpRequest,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export)]

View File

@@ -1,8 +1,5 @@
use crate::error::Result;
use crate::events::{
ExportHttpRequestRequest, ExportHttpRequestResponse, FilterRequest, FilterResponse
, ImportRequest, ImportResponse, InternalEvent, InternalEventPayload,
};
use crate::events::{CallHttpRequestActionRequest, FilterRequest, FilterResponse, GetHttpRequestActionsResponse, ImportRequest, ImportResponse, InternalEvent, InternalEventPayload};
use crate::error::Error::PluginErr;
use crate::nodejs::start_nodejs_plugin_runtime;
@@ -12,7 +9,6 @@ use std::time::Duration;
use tauri::{AppHandle, Runtime};
use tokio::sync::mpsc;
use tokio::sync::watch::Sender;
use yaak_models::models::HttpRequest;
pub struct PluginManager {
kill_tx: Sender<bool>,
@@ -61,6 +57,29 @@ impl PluginManager {
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
.await
}
pub async fn run_http_request_actions(&self) -> Result<Vec<GetHttpRequestActionsResponse>> {
let reply_events = self
.server
.send_and_wait(&InternalEventPayload::GetHttpRequestActionsRequest)
.await?;
let mut all_actions = Vec::new();
for event in reply_events {
if let InternalEventPayload::GetHttpRequestActionsResponse(resp) = event.payload {
all_actions.push(resp.clone());
}
}
Ok(all_actions)
}
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);
plugin.send(&event).await?;
Ok(())
}
pub async fn run_import(&self, content: &str) -> Result<(ImportResponse, String)> {
let reply_events = self
@@ -72,43 +91,17 @@ impl PluginManager {
// TODO: Don't just return the first valid response
for event in reply_events {
match event.payload {
InternalEventPayload::ImportResponse(resp) => {
let ref_id = event.plugin_ref_id.as_str();
let plugin = self.server.plugin_by_ref_id(ref_id).await?;
let plugin_name = plugin.name().await;
return Ok((resp, plugin_name));
}
_ => {}
if let InternalEventPayload::ImportResponse(resp) = event.payload {
let ref_id = event.plugin_ref_id.as_str();
let plugin = self.server.plugin_by_ref_id(ref_id).await?;
let plugin_name = plugin.name().await;
return Ok((resp, plugin_name));
}
}
Err(PluginErr("No import responses found".to_string()))
}
pub async fn run_export_curl(
&self,
request: &HttpRequest,
) -> Result<ExportHttpRequestResponse> {
let event = self
.server
.send_to_plugin_and_wait(
"exporter-curl",
&InternalEventPayload::ExportHttpRequestRequest(ExportHttpRequestRequest {
http_request: request.to_owned(),
}),
)
.await?;
match event.payload {
InternalEventPayload::ExportHttpRequestResponse(resp) => Ok(resp),
InternalEventPayload::EmptyResponse(_) => {
Err(PluginErr("Export returned empty".to_string()))
}
e => Err(PluginErr(format!("Export returned invalid event {:?}", e))),
}
}
pub async fn run_filter(
&self,
filter: &str,