From a140535f273f6dd8a0151518dd5e46b97385c6f1 Mon Sep 17 00:00:00 2001 From: Weixuan Fu Date: Wed, 21 Feb 2024 22:00:29 +0800 Subject: [PATCH 1/4] support 'open workflow in local comfyui' from cloud site --- ui/src/App.tsx | 3 - ui/src/db-tables/TableBase.ts | 7 ++ ui/src/db-tables/indexdb.ts | 7 +- .../hooks/useCloudEventListener.ts | 75 +++++++++++++++++++ ui/src/share/SharedTopbarButton.tsx | 4 +- 5 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 ui/src/model-manager/hooks/useCloudEventListener.ts diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 2dfc963..c4b12cd 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -32,7 +32,6 @@ import { openWorkflowInNewTab, } from "./utils"; import { Topbar } from "./topbar/Topbar"; -// import { authTokenListener, pullAuthTokenCloseIfExist } from "./auth/authUtils"; import { PanelPosition, Workflow } from "./types/dbTypes"; import { useDialog } from "./components/AlertDialogProvider"; import React from "react"; @@ -452,10 +451,8 @@ export default function App() { setIsDirty(res); }); }, 1000); - // pullAuthTokenCloseIfExist(); window.addEventListener("keydown", shortcutListener); - // window.addEventListener("message", authTokenListener); const fileInput = document.getElementById( "comfy-file-input", diff --git a/ui/src/db-tables/TableBase.ts b/ui/src/db-tables/TableBase.ts index ee9b2e5..8506718 100644 --- a/ui/src/db-tables/TableBase.ts +++ b/ui/src/db-tables/TableBase.ts @@ -92,4 +92,11 @@ export class TableBase { await indexdb[this.tableName].delete(id); await this.saveDiskDB(); } + public async listByIndex(index: keyof T, value: string): Promise { + const list = await indexdb[this.tableName] + .where(index as string) + .equals(value) + .toArray(); + return list as any[]; + } } diff --git a/ui/src/db-tables/indexdb.ts b/ui/src/db-tables/indexdb.ts index cb6569b..9886616 100644 --- a/ui/src/db-tables/indexdb.ts +++ b/ui/src/db-tables/indexdb.ts @@ -1,4 +1,3 @@ -// db.ts import Dexie, { Table } from "dexie"; import { Workflow, @@ -40,9 +39,9 @@ class ManagerDB extends Dexie { .upgrade((trans) => { // Here you can write logic to initialize or migrate data to the new 'media' table, if necessary }); - this.version(2) + this.version(3) .stores({ - workflows: "&id, name, parentFolderID", // Primary key and indexed props + workflows: "&id, name, parentFolderID, cloudID", // Primary key and indexed props changelogs: "&id, workflowID", media: "&id, workflowID", folders: "&id, name, parentFolderID", @@ -50,7 +49,7 @@ class ManagerDB extends Dexie { userSettings: "&id", models: "&id, fileName, fileHash", cache: "&id", - workflowVersions: "&id, name, workflowID", + workflowVersions: "&id, name, workflowID, cloudID", }) .upgrade((trans) => { // Here you can write logic to initialize or migrate data to the new 'media' table, if necessary diff --git a/ui/src/model-manager/hooks/useCloudEventListener.ts b/ui/src/model-manager/hooks/useCloudEventListener.ts new file mode 100644 index 0000000..bd3d643 --- /dev/null +++ b/ui/src/model-manager/hooks/useCloudEventListener.ts @@ -0,0 +1,75 @@ +import { + workflowVersionsTable, + workflowsTable, +} from "../../db-tables/WorkspaceDB"; + +export function useCloudEventListener() { + const cloudEventListener = async (event: MessageEvent) => { + const evt: CloudMessageEvent = event.data; + if (isCheckConnectionEvent(evt)) { + console.log(evt.detail.workflowID, evt.detail.versionID); + return; + } + if (isOpenWorkflowEvent(evt)) { + const { workflow, version } = evt.detail; + if (!workflow.id || !version.id) return; + const existingWorkflow = ( + await workflowsTable?.listByIndex("cloudID", workflow.id) + )?.at(0); + if (existingWorkflow) { + const existingVersion = ( + await workflowVersionsTable?.listByIndex("cloudID", version.id) + )?.at(0); + if (existingVersion) { + console.log("existingVersion", existingVersion); + return; + } else { + console.log("newVersion", version); + } + return; + } else { + console.log("newWorkflow", workflow); + } + } + }; + + window.addEventListener("message", cloudEventListener); +} + +interface CloudMessageEvent { + type: "check_connection" | "open_workflow"; + detail: any; +} + +interface OpenWorkflowEvent extends CloudMessageEvent { + type: "open_workflow"; + detail: { + workflow: { + id: string; + name: string; + }; + version: { + id: string; + name: string; + json: string; + }; + }; +} + +interface CheckConnectionEvent extends CloudMessageEvent { + type: "open_workflow"; + detail: { + workflowID: string; + versionID: string; + }; +} + +function isCheckConnectionEvent( + n: CloudMessageEvent, +): n is CheckConnectionEvent { + return n.type === "check_connection"; +} + +function isOpenWorkflowEvent(n: CloudMessageEvent): n is OpenWorkflowEvent { + return n.type === "open_workflow"; +} diff --git a/ui/src/share/SharedTopbarButton.tsx b/ui/src/share/SharedTopbarButton.tsx index f69db8d..c96e9e3 100644 --- a/ui/src/share/SharedTopbarButton.tsx +++ b/ui/src/share/SharedTopbarButton.tsx @@ -33,6 +33,8 @@ export function SharedTopbarButton({}) { { window.open(workflowsTable?.curWorkflow?.cloudURL); }} @@ -40,7 +42,7 @@ export function SharedTopbarButton({}) { size={"xs"} iconSpacing={"2px"} leftIcon={} - height={"26px"} + height={"27px"} px={1} > {privacy ? : "Shared"} From a92240c5c765ff2a596feac72fc754297128e85c Mon Sep 17 00:00:00 2001 From: Weixuan Fu Date: Thu, 22 Feb 2024 13:13:44 +0800 Subject: [PATCH 2/4] add server event listen scrip --- ui/src/App.tsx | 2 + .../hooks/ServerEventListener.ts | 118 ++++++++++++++++++ .../hooks/useCloudEventListener.ts | 75 ----------- 3 files changed, 120 insertions(+), 75 deletions(-) create mode 100644 ui/src/model-manager/hooks/ServerEventListener.ts delete mode 100644 ui/src/model-manager/hooks/useCloudEventListener.ts diff --git a/ui/src/App.tsx b/ui/src/App.tsx index c4b12cd..8f00a1d 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -42,6 +42,7 @@ const GalleryModal = React.lazy(() => import("./gallery/GalleryModal")); import { scanLocalNewFiles } from "./Api"; import { IconExternalLink } from "@tabler/icons-react"; import { DRAWER_Z_INDEX } from "./const"; +import ServerEventListener from "./model-manager/hooks/ServerEventListener"; const ModelManagerTopbar = React.lazy( () => import("./model-manager/topbar/ModelManagerTopbar"), @@ -585,6 +586,7 @@ export default function App() { setRoute("root")} /> )} + diff --git a/ui/src/model-manager/hooks/ServerEventListener.ts b/ui/src/model-manager/hooks/ServerEventListener.ts new file mode 100644 index 0000000..39e7d26 --- /dev/null +++ b/ui/src/model-manager/hooks/ServerEventListener.ts @@ -0,0 +1,118 @@ +import { useContext } from "react"; +import { useDialog } from "../../components/AlertDialogProvider"; +import { + workflowVersionsTable, + workflowsTable, +} from "../../db-tables/WorkspaceDB"; +import { WorkspaceContext } from "../../WorkspaceContext"; + +export default function ServerEventListener() { + const { showDialog } = useDialog(); + const { loadWorkflowID } = useContext(WorkspaceContext); + const openWorkflow = async (evt: OpenWorkflowEvent) => { + const { workflow, version } = evt.detail; + if (!workflow.id || !version.id) return; + const existingWorkflow = ( + await workflowsTable?.listByIndex("cloudID", workflow.id) + )?.at(0); + if (existingWorkflow) { + const existingVersion = ( + await workflowVersionsTable?.listByIndex("cloudID", version.id) + )?.at(0); + if (existingVersion) { + await loadWorkflowID(existingWorkflow.id); + console.log("existingVersion", existingVersion); + } else { + await workflowVersionsTable?.add({ + cloudID: version.id, + workflowID: existingWorkflow.id, + name: version.name, + json: version.json, + }); + console.log("newVersion", version); + } + } else { + const newWorkflow = await workflowsTable?.add({ + cloudID: workflow.id, + name: workflow.name, + json: version.json, + updateTime: Date.now(), + }); + if (!newWorkflow) { + alert("Failed to add workflow to local db"); + return; + } + await workflowVersionsTable?.add({ + cloudID: version.id, + workflowID: newWorkflow.id, + name: version.name, + json: version.json, + }); + await loadWorkflowID(newWorkflow.id); + console.log("newWorkflow", workflow); + } + }; + const cloudEventListener = async (event: MessageEvent) => { + const evt: CloudMessageEvent = event.data; + if (isCheckConnectionEvent(evt)) { + // TODO... + return; + } + if (isOpenWorkflowEvent(evt)) { + const origin = event.origin; + showDialog( + `Open workflow "${evt.detail.workflow.name}", version "${evt.detail.version.name}" from ${origin}`, + [ + { + label: "Open", + colorScheme: "teal", + onClick: () => { + openWorkflow(evt); + }, + }, + ], + ); + } + }; + + window.addEventListener("message", cloudEventListener); + return null; +} + +interface CloudMessageEvent { + type: "workspace_check_connection" | "workspace_open_workflow"; + detail: any; +} + +interface OpenWorkflowEvent extends CloudMessageEvent { + type: "workspace_open_workflow"; + detail: { + workflow: { + id: string; + name: string; + }; + version: { + id: string; + name: string; + json: string; + }; + }; +} + +interface CheckConnectionEvent extends CloudMessageEvent { + type: "workspace_check_connection"; + detail: { + workflowID: string; + versionID: string; + }; +} + +function isCheckConnectionEvent( + n: CloudMessageEvent, +): n is CheckConnectionEvent { + return n.type === "workspace_check_connection"; +} + +function isOpenWorkflowEvent(n: CloudMessageEvent): n is OpenWorkflowEvent { + return n.type === "workspace_open_workflow"; +} diff --git a/ui/src/model-manager/hooks/useCloudEventListener.ts b/ui/src/model-manager/hooks/useCloudEventListener.ts deleted file mode 100644 index bd3d643..0000000 --- a/ui/src/model-manager/hooks/useCloudEventListener.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { - workflowVersionsTable, - workflowsTable, -} from "../../db-tables/WorkspaceDB"; - -export function useCloudEventListener() { - const cloudEventListener = async (event: MessageEvent) => { - const evt: CloudMessageEvent = event.data; - if (isCheckConnectionEvent(evt)) { - console.log(evt.detail.workflowID, evt.detail.versionID); - return; - } - if (isOpenWorkflowEvent(evt)) { - const { workflow, version } = evt.detail; - if (!workflow.id || !version.id) return; - const existingWorkflow = ( - await workflowsTable?.listByIndex("cloudID", workflow.id) - )?.at(0); - if (existingWorkflow) { - const existingVersion = ( - await workflowVersionsTable?.listByIndex("cloudID", version.id) - )?.at(0); - if (existingVersion) { - console.log("existingVersion", existingVersion); - return; - } else { - console.log("newVersion", version); - } - return; - } else { - console.log("newWorkflow", workflow); - } - } - }; - - window.addEventListener("message", cloudEventListener); -} - -interface CloudMessageEvent { - type: "check_connection" | "open_workflow"; - detail: any; -} - -interface OpenWorkflowEvent extends CloudMessageEvent { - type: "open_workflow"; - detail: { - workflow: { - id: string; - name: string; - }; - version: { - id: string; - name: string; - json: string; - }; - }; -} - -interface CheckConnectionEvent extends CloudMessageEvent { - type: "open_workflow"; - detail: { - workflowID: string; - versionID: string; - }; -} - -function isCheckConnectionEvent( - n: CloudMessageEvent, -): n is CheckConnectionEvent { - return n.type === "check_connection"; -} - -function isOpenWorkflowEvent(n: CloudMessageEvent): n is OpenWorkflowEvent { - return n.type === "open_workflow"; -} From 13e01eb7e2c8255dd6b848df240e3049235ff7aa Mon Sep 17 00:00:00 2001 From: Weixuan Fu Date: Thu, 22 Feb 2024 17:06:21 +0800 Subject: [PATCH 3/4] opens a workflow version from cloud --- .../hooks/ServerEventListener.ts | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/ui/src/model-manager/hooks/ServerEventListener.ts b/ui/src/model-manager/hooks/ServerEventListener.ts index 39e7d26..4baf062 100644 --- a/ui/src/model-manager/hooks/ServerEventListener.ts +++ b/ui/src/model-manager/hooks/ServerEventListener.ts @@ -1,4 +1,4 @@ -import { useContext } from "react"; +import { useContext, useEffect } from "react"; import { useDialog } from "../../components/AlertDialogProvider"; import { workflowVersionsTable, @@ -20,18 +20,19 @@ export default function ServerEventListener() { await workflowVersionsTable?.listByIndex("cloudID", version.id) )?.at(0); if (existingVersion) { + // existing workflow and version await loadWorkflowID(existingWorkflow.id); - console.log("existingVersion", existingVersion); } else { + // existing workflow but new version await workflowVersionsTable?.add({ cloudID: version.id, workflowID: existingWorkflow.id, name: version.name, json: version.json, }); - console.log("newVersion", version); } } else { + // new workflow new version const newWorkflow = await workflowsTable?.add({ cloudID: workflow.id, name: workflow.name, @@ -49,15 +50,10 @@ export default function ServerEventListener() { json: version.json, }); await loadWorkflowID(newWorkflow.id); - console.log("newWorkflow", workflow); } }; const cloudEventListener = async (event: MessageEvent) => { const evt: CloudMessageEvent = event.data; - if (isCheckConnectionEvent(evt)) { - // TODO... - return; - } if (isOpenWorkflowEvent(evt)) { const origin = event.origin; showDialog( @@ -74,8 +70,12 @@ export default function ServerEventListener() { ); } }; - - window.addEventListener("message", cloudEventListener); + useEffect(() => { + if (window.opener) { + window.opener.postMessage("comfyui_workspace_manager_connected", "*"); + } + window.addEventListener("message", cloudEventListener); + }, []); return null; } @@ -99,20 +99,6 @@ interface OpenWorkflowEvent extends CloudMessageEvent { }; } -interface CheckConnectionEvent extends CloudMessageEvent { - type: "workspace_check_connection"; - detail: { - workflowID: string; - versionID: string; - }; -} - -function isCheckConnectionEvent( - n: CloudMessageEvent, -): n is CheckConnectionEvent { - return n.type === "workspace_check_connection"; -} - function isOpenWorkflowEvent(n: CloudMessageEvent): n is OpenWorkflowEvent { return n.type === "workspace_open_workflow"; } From 0fbc224d9fea74139dd309b9a1a8ece24c329e79 Mon Sep 17 00:00:00 2001 From: Weixuan Fu Date: Thu, 22 Feb 2024 17:09:04 +0800 Subject: [PATCH 4/4] keep indexdb version2 to avoid bug when the user for some reason revert back to earlier codebase version hence pulling earlier indexdb schema version --- ui/src/db-tables/indexdb.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ui/src/db-tables/indexdb.ts b/ui/src/db-tables/indexdb.ts index 9886616..ce7430d 100644 --- a/ui/src/db-tables/indexdb.ts +++ b/ui/src/db-tables/indexdb.ts @@ -36,9 +36,20 @@ class ManagerDB extends Dexie { models: "&id, fileName, fileHash", cache: "&id", }) - .upgrade((trans) => { - // Here you can write logic to initialize or migrate data to the new 'media' table, if necessary - }); + .upgrade((trans) => {}); + this.version(2) + .stores({ + workflows: "&id, name, parentFolderID", + changelogs: "&id, workflowID", + media: "&id, workflowID", + folders: "&id, name, parentFolderID", + tags: "&name", + userSettings: "&id", + models: "&id, fileName, fileHash", + cache: "&id", + workflowVersions: "&id, name, workflowID", + }) + .upgrade((trans) => {}); this.version(3) .stores({ workflows: "&id, name, parentFolderID, cloudID", // Primary key and indexed props @@ -51,9 +62,7 @@ class ManagerDB extends Dexie { cache: "&id", workflowVersions: "&id, name, workflowID, cloudID", }) - .upgrade((trans) => { - // Here you can write logic to initialize or migrate data to the new 'media' table, if necessary - }); + .upgrade((trans) => {}); } }