Make prompt() to return null on cancel

This commit is contained in:
Gregory Schier
2024-10-02 05:54:44 -07:00
parent 89ff25cd54
commit 4160e5b1c4
26 changed files with 436 additions and 108 deletions

View File

@@ -45,6 +45,7 @@ pub async fn send_http_request<R: Runtime>(
&WindowContext::from_window(window),
RenderPurpose::Send,
);
let rendered_request =
render_http_request(&request, &workspace, environment.as_ref(), &cb).await;

View File

@@ -63,7 +63,7 @@ use yaak_plugin_runtime::events::{
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, Icon,
InternalEvent, InternalEventPayload, RenderHttpRequestResponse, RenderPurpose,
SendHttpRequestResponse, ShowPromptResponse, ShowToastRequest, TemplateRenderResponse,
SendHttpRequestResponse, PromptTextResponse, ShowToastRequest, TemplateRenderResponse,
WindowContext,
};
use yaak_plugin_runtime::plugin_handle::PluginHandle;
@@ -1081,6 +1081,18 @@ async fn cmd_send_http_request(
// that has not yet been saved in the DB.
request: HttpRequest,
) -> Result<HttpResponse, String> {
let response = create_default_http_response(&window, &request.id)
.await
.map_err(|e| e.to_string())?;
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
window.listen_any(
format!("cancel_http_response_{}", response.id),
move |_event| {
let _ = cancel_tx.send(true);
},
);
let environment = match environment_id {
Some(id) => match get_environment(&window, id).await {
Ok(env) => Some(env),
@@ -1101,18 +1113,6 @@ async fn cmd_send_http_request(
None => None,
};
let response = create_default_http_response(&window, &request.id)
.await
.map_err(|e| e.to_string())?;
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
window.listen_any(
format!("cancel_http_response_{}", response.id),
move |_event| {
let _ = cancel_tx.send(true);
},
);
send_http_request(
&window,
&request,
@@ -2171,18 +2171,18 @@ async fn call_frontend<T: Serialize + Clone, R: Runtime>(
window: WebviewWindow<R>,
event_name: &str,
args: T,
) -> ShowPromptResponse {
) -> PromptTextResponse {
let reply_id = format!("{event_name}_reply");
let payload = FrontendCall {
args,
reply_id: reply_id.clone(),
};
window.emit_to(window.label(), event_name, payload).unwrap();
let (tx, mut rx) = tokio::sync::watch::channel(ShowPromptResponse::default());
let (tx, mut rx) = tokio::sync::watch::channel(PromptTextResponse::default());
let event_id = window.clone().listen(reply_id, move |ev| {
println!("GOT REPLY {ev:?}");
let resp: ShowPromptResponse = serde_json::from_str(ev.payload()).unwrap();
let resp: PromptTextResponse = serde_json::from_str(ev.payload()).unwrap();
_ = tx.send(resp);
});
@@ -2220,11 +2220,11 @@ async fn handle_plugin_event<R: Runtime>(
};
None
}
InternalEventPayload::ShowPromptRequest(req) => {
InternalEventPayload::PromptTextRequest(req) => {
let window = get_window_from_window_context(app_handle, &window_context)
.expect("Failed to find window for render");
let resp = call_frontend(window, "show_prompt", req).await;
Some(InternalEventPayload::ShowPromptResponse(resp))
Some(InternalEventPayload::PromptTextResponse(resp))
}
InternalEventPayload::FindHttpResponsesRequest(req) => {
let http_responses = list_http_responses(

View File

@@ -59,21 +59,15 @@ export type ImportResponse = { resources: ImportResources, };
export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, };
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } | { "type": "reload_response" } | { "type": "terminate_request" } | { "type": "terminate_response" } | { "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": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "show_prompt_request" } & ShowPromptRequest | { "type": "show_prompt_response" } & ShowPromptResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" };
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } | { "type": "reload_response" } | { "type": "terminate_request" } | { "type": "terminate_response" } | { "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": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" };
export type OpenFileFilter = { name: string, extensions: Array<string>, };
export type OpenFileFilter = { name: string,
/**
* File extensions to require
*/
extensions: Array<string>, };
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };
export type RenderHttpRequestResponse = { httpRequest: HttpRequest, };
export type RenderPurpose = "send" | "preview";
export type SendHttpRequestRequest = { httpRequest: HttpRequest, };
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
export type ShowPromptRequest = { id: string, title: string, label: string, description?: string, defaultValue?: string, placeholder?: string,
export type PromptTextRequest = { id: string, title: string, label: string, description?: string, defaultValue?: string, placeholder?: string,
/**
* Text to add to the confirmation button
*/
@@ -87,7 +81,17 @@ cancelText?: string,
*/
require?: boolean, };
export type ShowPromptResponse = { value: string, };
export type PromptTextResponse = { value: string | null, };
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };
export type RenderHttpRequestResponse = { httpRequest: HttpRequest, };
export type RenderPurpose = "send" | "preview";
export type SendHttpRequestRequest = { httpRequest: HttpRequest, };
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
export type ShowToastRequest = { message: string, color?: Color, icon?: Icon, };
@@ -95,19 +99,131 @@ export type TemplateFunction = { name: string, aliases?: Array<string>, args: Ar
export type TemplateFunctionArg = { "type": "text" } & TemplateFunctionTextArg | { "type": "select" } & TemplateFunctionSelectArg | { "type": "checkbox" } & TemplateFunctionCheckboxArg | { "type": "http_request" } & TemplateFunctionHttpRequestArg | { "type": "file" } & TemplateFunctionFileArg;
export type TemplateFunctionBaseArg = { name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionBaseArg = {
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateFunctionCheckboxArg = { name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionCheckboxArg = {
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateFunctionFileArg = { title: string, multiple?: boolean, directory?: boolean, defaultPath?: string, filters?: Array<OpenFileFilter>, name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionFileArg = {
/**
* The title of the file selection window
*/
title: string,
/**
* Allow selecting multiple files
*/
multiple?: boolean, directory?: boolean, defaultPath?: string, filters?: Array<OpenFileFilter>,
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateFunctionHttpRequestArg = { name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionHttpRequestArg = {
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateFunctionSelectArg = { options: Array<TemplateFunctionSelectOption>, name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionSelectArg = {
/**
* The options that will be available in the select input
*/
options: Array<TemplateFunctionSelectOption>,
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateFunctionSelectOption = { name: string, value: string, };
export type TemplateFunctionSelectOption = { label: string, value: string, };
export type TemplateFunctionTextArg = { placeholder?: string, name: string, optional?: boolean, label?: string, defaultValue?: string, };
export type TemplateFunctionTextArg = {
/**
* Placeholder for the text input
*/
placeholder?: string,
/**
* The name of the argument. Should be `camelCase` format
*/
name: string,
/**
* Whether the user must fill in the argument
*/
optional?: boolean,
/**
* The label of the input
*/
label?: string,
/**
* The default value
*/
defaultValue?: string, };
export type TemplateRenderRequest = { data: JsonValue, purpose: RenderPurpose, };

View File

@@ -76,8 +76,8 @@ pub enum InternalEventPayload {
ShowToastRequest(ShowToastRequest),
ShowPromptRequest(ShowPromptRequest),
ShowPromptResponse(ShowPromptResponse),
PromptTextRequest(PromptTextRequest),
PromptTextResponse(PromptTextResponse),
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
@@ -215,7 +215,7 @@ pub struct ShowToastRequest {
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "events.ts")]
pub struct ShowPromptRequest {
pub struct PromptTextRequest {
// A unique ID to identify the prompt (eg. "enter-password")
pub id: String,
// Title to show on the prompt dialog
@@ -242,8 +242,8 @@ pub struct ShowPromptRequest {
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "events.ts")]
pub struct ShowPromptResponse {
pub value: String,
pub struct PromptTextResponse {
pub value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
@@ -294,6 +294,9 @@ pub struct GetTemplateFunctionsResponse {
#[ts(export, export_to = "events.ts")]
pub struct TemplateFunction {
pub name: String,
/// Also support alternative names. This is useful for not breaking existing
/// tags when changing the `name` property
#[ts(optional)]
pub aliases: Option<Vec<String>>,
pub args: Vec<TemplateFunctionArg>,
@@ -314,11 +317,18 @@ pub enum TemplateFunctionArg {
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "events.ts")]
pub struct TemplateFunctionBaseArg {
/// The name of the argument. Should be `camelCase` format
pub name: String,
/// Whether the user must fill in the argument
#[ts(optional)]
pub optional: Option<bool>,
/// The label of the input
#[ts(optional)]
pub label: Option<String>,
/// The default value
#[ts(optional)]
pub default_value: Option<String>,
}
@@ -329,6 +339,8 @@ pub struct TemplateFunctionBaseArg {
pub struct TemplateFunctionTextArg {
#[serde(flatten)]
pub base: TemplateFunctionBaseArg,
/// Placeholder for the text input
#[ts(optional)]
pub placeholder: Option<String>,
}
@@ -347,13 +359,23 @@ pub struct TemplateFunctionHttpRequestArg {
pub struct TemplateFunctionFileArg {
#[serde(flatten)]
pub base: TemplateFunctionBaseArg,
/// The title of the file selection window
pub title: String,
/// Allow selecting multiple files
#[ts(optional)]
pub multiple: Option<bool>,
// Select a directory, not a file
#[ts(optional)]
pub directory: Option<bool>,
// Default file path for selection dialog
#[ts(optional)]
pub default_path: Option<String>,
// Specify to only allow selection of certain file extensions
#[ts(optional)]
pub filters: Option<Vec<OpenFileFilter>>,
}
@@ -363,6 +385,7 @@ pub struct TemplateFunctionFileArg {
#[ts(export, export_to = "events.ts")]
pub struct OpenFileFilter {
pub name: String,
/// File extensions to require
pub extensions: Vec<String>,
}
@@ -372,6 +395,8 @@ pub struct OpenFileFilter {
pub struct TemplateFunctionSelectArg {
#[serde(flatten)]
pub base: TemplateFunctionBaseArg,
/// The options that will be available in the select input
pub options: Vec<TemplateFunctionSelectOption>,
}
@@ -387,7 +412,7 @@ pub struct TemplateFunctionCheckboxArg {
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "events.ts")]
pub struct TemplateFunctionSelectOption {
pub name: String,
pub label: String,
pub value: String,
}