diff --git a/pkgs/webview-ui/app/src/api.ts b/pkgs/webview-ui/app/src/api.ts index a3c342863..ac919b440 100644 --- a/pkgs/webview-ui/app/src/api.ts +++ b/pkgs/webview-ui/app/src/api.ts @@ -1,5 +1,6 @@ import { FromSchema } from "json-schema-to-ts"; import { schema } from "@/api"; +import { nanoid } from "nanoid"; export type API = FromSchema; @@ -41,47 +42,44 @@ const operations = schema.properties; const operationNames = Object.keys(operations) as OperationNames[]; type ObserverRegistry = { - [K in OperationNames]: ((response: OperationResponse) => void)[]; + [K in OperationNames]: Record< + string, + (response: OperationResponse) => void + >; }; -const obs: ObserverRegistry = operationNames.reduce( +const registry: ObserverRegistry = operationNames.reduce( (acc, opName) => ({ ...acc, - [opName]: [], + [opName]: {}, }), {} as ObserverRegistry ); -interface ReceiveOptions { - /** - * Calls only the registered function that has the same key as used with dispatch - * - */ - fnKey: string; -} function createFunctions( operationName: K ): { dispatch: (args: OperationArgs) => void; - receive: (fn: (response: OperationResponse) => void) => void; + receive: (fn: (response: OperationResponse) => void, id: string) => void; } { return { dispatch: (args: OperationArgs) => { - // console.log( - // `Operation: ${String(operationName)}, Arguments: ${JSON.stringify(args)}` - // ); // Send the data to the gtk app window.webkit.messageHandlers.gtk.postMessage({ method: operationName, data: args, }); }, - receive: ( - fn: (response: OperationResponse) => void - // options?: ReceiveOptions - ) => { - obs[operationName].push(fn); + receive: (fn: (response: OperationResponse) => void, id: string) => { + // @ts-expect-error: This should work although typescript doesn't let us write + registry[operationName][id] = fn; + window.clan[operationName] = (s: string) => { - obs[operationName].forEach((f) => deserialize(f)(s)); + const f = (response: OperationResponse) => { + if (response.op_key === id) { + registry[operationName][id](response); + } + }; + deserialize(f)(s); }; }, }; @@ -90,7 +88,7 @@ function createFunctions( type PyApi = { [K in OperationNames]: { dispatch: (args: OperationArgs) => void; - receive: (fn: (response: OperationResponse) => void) => void; + receive: (fn: (response: OperationResponse) => void, id: string) => void; }; }; @@ -110,6 +108,23 @@ function download(filename: string, text: string) { document.body.removeChild(element); } +export const callApi = ( + method: K, + args: OperationArgs +) => { + return new Promise>((resolve, reject) => { + const id = nanoid(); + pyApi[method].receive((response) => { + if (response.status === "error") { + reject(response); + } + resolve(response); + }, id); + + pyApi[method].dispatch({ ...args, op_key: id }); + }); +}; + const deserialize = (fn: (response: T) => void) => (str: string) => {