feat: add ctx.prompt.form() plugin API for multi-field form dialogs (#359)

This commit is contained in:
Gregory Schier
2026-01-10 08:55:43 -08:00
committed by GitHub
parent 6654d6c346
commit fe01796536
7 changed files with 72 additions and 2 deletions

View File

@@ -57,6 +57,10 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
let window = get_window_from_plugin_context(app_handle, &plugin_context)?;
Ok(call_frontend(&window, event).await)
}
InternalEventPayload::PromptFormRequest(_) => {
let window = get_window_from_plugin_context(app_handle, &plugin_context)?;
Ok(call_frontend(&window, event).await)
}
InternalEventPayload::FindHttpResponsesRequest(req) => {
let http_responses = app_handle
.db()

File diff suppressed because one or more lines are too long

View File

@@ -157,6 +157,9 @@ pub enum InternalEventPayload {
PromptTextRequest(PromptTextRequest),
PromptTextResponse(PromptTextResponse),
PromptFormRequest(PromptFormRequest),
PromptFormResponse(PromptFormResponse),
WindowInfoRequest(WindowInfoRequest),
WindowInfoResponse(WindowInfoResponse),
@@ -571,6 +574,28 @@ pub struct PromptTextResponse {
pub value: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "gen_events.ts")]
pub struct PromptFormRequest {
pub id: String,
pub title: String,
#[ts(optional)]
pub description: Option<String>,
pub inputs: Vec<FormInput>,
#[ts(optional)]
pub confirm_text: Option<String>,
#[ts(optional)]
pub cancel_text: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "gen_events.ts")]
pub struct PromptFormResponse {
pub values: Option<HashMap<String, JsonPrimitive>>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[serde(default, rename_all = "camelCase")]
#[ts(export, export_to = "gen_events.ts")]

File diff suppressed because one or more lines are too long

View File

@@ -11,6 +11,8 @@ import type {
ListHttpRequestsRequest,
ListHttpRequestsResponse,
OpenWindowRequest,
PromptFormRequest,
PromptFormResponse,
PromptTextRequest,
PromptTextResponse,
RenderGrpcRequestRequest,
@@ -37,6 +39,7 @@ export interface Context {
};
prompt: {
text(args: PromptTextRequest): Promise<PromptTextResponse['value']>;
form(args: PromptFormRequest): Promise<PromptFormResponse['values']>;
};
store: {
set<T>(key: string, value: T): Promise<void>;

View File

@@ -28,6 +28,7 @@ import type {
ListHttpRequestsResponse,
ListWorkspacesResponse,
PluginContext,
PromptFormResponse,
PromptTextResponse,
RenderGrpcRequestResponse,
RenderHttpRequestResponse,
@@ -661,6 +662,13 @@ export class PluginInstance {
});
return reply.value;
},
form: async (args) => {
const reply: PromptFormResponse = await this.#sendForReply(context, {
type: 'prompt_form_request',
...args,
});
return reply.values;
},
},
httpResponse: {
find: async (args) => {

View File

@@ -21,6 +21,7 @@ import { stringToColor } from './color';
import { generateId } from './generateId';
import { jotaiStore } from './jotai';
import { showPrompt } from './prompt';
import { showPromptForm } from './prompt-form';
import { invokeCmd } from './tauri';
import { showToast } from './toast';
@@ -47,6 +48,27 @@ export function initGlobalListeners() {
},
};
await emit(event.id, result);
} else if (event.payload.type === 'prompt_form_request') {
const values = await showPromptForm({
id: event.payload.id,
title: event.payload.title,
description: event.payload.description,
inputs: event.payload.inputs,
confirmText: event.payload.confirmText,
cancelText: event.payload.cancelText,
});
const result: InternalEvent = {
id: generateId(),
replyId: event.id,
pluginName: event.pluginName,
pluginRefId: event.pluginRefId,
context: event.context,
payload: {
type: 'prompt_form_response',
values,
},
};
await emit(event.id, result);
}
});