mirror of
https://github.com/penpot/penpot-mcp.git
synced 2026-04-25 11:18:37 +00:00
Refactor task handling (introducing abstraction TaskHandler)
This commit is contained in:
parent
23d2270df0
commit
8275735999
55
penpot-plugin/src/TaskHandler.ts
Normal file
55
penpot-plugin/src/TaskHandler.ts
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
/**
|
||||
* Abstract base class for task handlers in the Penpot MCP plugin.
|
||||
*
|
||||
* @template TParams - The type of parameters this handler expects
|
||||
*/
|
||||
export abstract class TaskHandler<TParams = any> {
|
||||
/** The task identifier this handler is responsible for */
|
||||
abstract readonly task: string;
|
||||
|
||||
/**
|
||||
* Checks if this handler can process the given task.
|
||||
*
|
||||
* @param task - The task identifier to check
|
||||
* @returns True if this handler applies to the given task
|
||||
*/
|
||||
applies(task: string): boolean {
|
||||
return this.task === task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a task response back to the MCP server.
|
||||
*/
|
||||
public static sendTaskResponse(taskId: string, success: boolean, data: any = undefined, error: any = undefined): void {
|
||||
const response = {
|
||||
type: "task-response",
|
||||
response: {
|
||||
id: taskId,
|
||||
success: success,
|
||||
data: data,
|
||||
error: error,
|
||||
},
|
||||
};
|
||||
|
||||
// Send to main.ts which will forward to MCP server via WebSocket
|
||||
penpot.ui.sendMessage(response);
|
||||
console.log("Sent task response:", response);
|
||||
}
|
||||
|
||||
public static sendTaskSuccess(taskId: string, data: any = undefined): void {
|
||||
this.sendTaskResponse(taskId, true, data);
|
||||
}
|
||||
|
||||
public static sendTaskError(taskId: string, error: string): void {
|
||||
this.sendTaskResponse(taskId, false, undefined, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the task with the provided parameters.
|
||||
*
|
||||
* @param taskId - The unique ID of the task request
|
||||
* @param params - The parameters for the task
|
||||
*/
|
||||
abstract handle(taskId: string, params: TParams): void;
|
||||
}
|
||||
@ -1,3 +1,13 @@
|
||||
import {PrintTextTaskHandler} from "./task-handlers/PrintTextTaskHandler";
|
||||
import {TaskHandler} from "./TaskHandler";
|
||||
|
||||
/**
|
||||
* Registry of all available task handlers.
|
||||
*/
|
||||
const taskHandlers: TaskHandler[] = [
|
||||
new PrintTextTaskHandler(),
|
||||
];
|
||||
|
||||
penpot.ui.open("Penpot MCP Plugin", `?theme=${penpot.theme}`);
|
||||
|
||||
// Handle both legacy string messages and new request-based messages
|
||||
@ -31,80 +41,24 @@ penpot.ui.onMessage<string | { id: string; task: string; params: any }>((message
|
||||
function handlePluginTaskRequest(request: { id: string; task: string; params: any }): void {
|
||||
console.log("Executing plugin task:", request.task, request.params);
|
||||
|
||||
switch (request.task) {
|
||||
case "printText":
|
||||
handlePrintTextTask(request.id, request.params);
|
||||
break;
|
||||
// Find the appropriate handler
|
||||
const handler = taskHandlers.find(h => h.applies(request.task));
|
||||
|
||||
default:
|
||||
console.warn("Unknown plugin task:", request.task);
|
||||
sendTaskError(request.id, `Unknown task type: ${request.task}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the printText task by creating text in Penpot.
|
||||
*
|
||||
* @param taskId - The unique ID of the task request
|
||||
* @param params - The parameters containing the text to create
|
||||
*/
|
||||
function handlePrintTextTask(taskId: string, params: { text: string }): void {
|
||||
if (!params.text) {
|
||||
console.error("printText task requires 'text' parameter");
|
||||
sendTaskError(taskId, "printText task requires 'text' parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const text = penpot.createText(params.text);
|
||||
|
||||
if (text) {
|
||||
// Center the text in the viewport
|
||||
text.x = penpot.viewport.center.x;
|
||||
text.y = penpot.viewport.center.y;
|
||||
|
||||
// Select the newly created text
|
||||
penpot.selection = [text];
|
||||
|
||||
console.log("Successfully created text:", params.text);
|
||||
sendTaskSuccess(taskId, { textId: text.id });
|
||||
} else {
|
||||
console.error("Failed to create text element");
|
||||
sendTaskError(taskId, "Failed to create text element");
|
||||
if (handler) {
|
||||
try {
|
||||
// Cast the params to the expected type and handle the task
|
||||
handler.handle(request.id, request.params);
|
||||
} catch (error) {
|
||||
console.error(`Error handling task '${request.task}':`, error);
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||
TaskHandler.sendTaskError(request.id, `Error handling task: ${errorMessage}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating text:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||
sendTaskError(taskId, `Error creating text: ${errorMessage}`);
|
||||
} else {
|
||||
console.warn("Unknown plugin task:", request.task);
|
||||
TaskHandler.sendTaskError(request.id, `Unknown task type: ${request.task}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a task response back to the MCP server.
|
||||
*/
|
||||
function sendTaskResponse(taskId: string, success: boolean, data: any = undefined, error: any = undefined): void {
|
||||
const response = {
|
||||
type: "task-response",
|
||||
response: {
|
||||
id: taskId,
|
||||
success: success,
|
||||
data: data,
|
||||
error: error,
|
||||
},
|
||||
};
|
||||
|
||||
// Send to main.ts which will forward to MCP server via WebSocket
|
||||
penpot.ui.sendMessage(response);
|
||||
console.log("Sent task response:", response);
|
||||
}
|
||||
|
||||
function sendTaskSuccess(taskId: string, data: any = undefined): void {
|
||||
sendTaskResponse(taskId, true, data);
|
||||
}
|
||||
|
||||
function sendTaskError(taskId: string, error: string): void {
|
||||
sendTaskResponse(taskId, false, undefined, error);
|
||||
}
|
||||
|
||||
// Update the theme in the iframe
|
||||
penpot.on("themechange", (theme) => {
|
||||
|
||||
46
penpot-plugin/src/task-handlers/PrintTextTaskHandler.ts
Normal file
46
penpot-plugin/src/task-handlers/PrintTextTaskHandler.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {TaskHandler} from "../TaskHandler";
|
||||
import {PrintTextTaskParams} from "../../../common/src";
|
||||
|
||||
/**
|
||||
* Task handler for printing text to Penpot.
|
||||
*/
|
||||
export class PrintTextTaskHandler extends TaskHandler<PrintTextTaskParams> {
|
||||
readonly task = "printText";
|
||||
|
||||
/**
|
||||
* Handles the printText task by creating text in Penpot.
|
||||
*
|
||||
* @param taskId - The unique ID of the task request
|
||||
* @param params - The parameters containing the text to create
|
||||
*/
|
||||
handle(taskId: string, params: PrintTextTaskParams): void {
|
||||
if (!params.text) {
|
||||
console.error("printText task requires 'text' parameter");
|
||||
TaskHandler.sendTaskError(taskId, "printText task requires 'text' parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const text = penpot.createText(params.text);
|
||||
|
||||
if (text) {
|
||||
// Center the text in the viewport
|
||||
text.x = penpot.viewport.center.x;
|
||||
text.y = penpot.viewport.center.y;
|
||||
|
||||
// Select the newly created text
|
||||
penpot.selection = [text];
|
||||
|
||||
console.log("Successfully created text:", params.text);
|
||||
TaskHandler.sendTaskSuccess(taskId, { textId: text.id });
|
||||
} else {
|
||||
console.error("Failed to create text element");
|
||||
TaskHandler.sendTaskError(taskId, "Failed to create text element");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating text:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||
TaskHandler.sendTaskError(taskId, `Error creating text: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user