Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acaa2e4c35 | ||
|
|
99126eea03 | ||
|
|
fb5e3ae89e | ||
|
|
2f4d3c26a9 | ||
|
|
8456ea44bf | ||
|
|
7daf20238b | ||
|
|
2697daa7b8 | ||
|
|
c2780caad4 | ||
|
|
fb9f355c6a | ||
|
|
e751e0543a | ||
|
|
f62e1dc1a5 | ||
|
|
cb623b6e5f | ||
|
|
b1052d32b2 | ||
|
|
3b23b8aa91 | ||
|
|
c385393313 | ||
|
|
db9245b2ef | ||
|
|
87a1d96c2f | ||
|
|
8e1c6a47cb | ||
|
|
f68a5e994a | ||
|
|
3da2fcfa72 | ||
|
|
f3c8e8c98d | ||
|
|
3f02557170 | ||
|
|
d9c2015850 | ||
|
|
cf5ce2c3df | ||
|
|
9cf00a6de0 | ||
|
|
b36e2a472f |
+1
-1
@@ -11,7 +11,7 @@ pnpm-debug.log*
|
|||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
ui/node_modules
|
ui/node_modules
|
||||||
ui/src/utils/encryptUtils.ts
|
# ui/src/utils/encryptUtils.ts
|
||||||
db
|
db
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
|||||||
@@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
A ComfyUI workflow and model manager extension to **organize and manage all your workflows, models and generated images in one place**. Seamlessly switch between workflows, track version history and image generation history, 1 click install models from Civit ai, browse/update your installed models
|
A ComfyUI workflow and model manager extension to **organize and manage all your workflows, models and generated images in one place**. Seamlessly switch between workflows, track version history and image generation history, 1 click install models from Civit ai, browse/update your installed models
|
||||||
|
|
||||||
If you have questions or suggestions, please [join our Discord](https://discord.gg/HHvfEurv2Z)! I'm building a new platform that lets you quickly make a runnable web app from your comfyui workflow. www.nodecafe.co if you are interested to make your comfyui workflow into an app or colaborate with me, please DM me!
|
If you have questions or suggestions, please [join our Discord](https://discord.gg/HHvfEurv2Z)!
|
||||||
|
|
||||||
[6-21] tags are deprecated, please use folders to organize your workflows.
|
✨We have a new platform to turn your comfyui workflow to runnable web app: www.nodecafe.co please check it out! 🥳
|
||||||
|
|
||||||
|
[6-25] ⚠️ Please update workspace manager to latest version if it's not showing up for you after updating ComfyUI
|
||||||
|
|
||||||
[6-21] ‼️please upgrade to V2 and enable twoway sync if you haven't already. I will stop supporting V1 soon and will forcefully turn on twoway sync later. (twoway sync means that your workflow are twoway synced with your disk files /my_workflows directly)
|
[6-21] ‼️please upgrade to V2 and enable twoway sync if you haven't already. I will stop supporting V1 soon and will forcefully turn on twoway sync later. (twoway sync means that your workflow are twoway synced with your disk files /my_workflows directly)
|
||||||
|
|
||||||
[6-21] ‼️‼️Auto-save mode will be removed comopoletely from next version. Because there are reports that autosave mode sometimes overwrite workflows mistakenly. Therefore, please **manual save** your workflows always.
|
[6-21] ‼️ Auto-save mode will be removed comopoletely from next version. Because there are reports that autosave mode sometimes overwrite workflows mistakenly. Therefore, please **manual save** your workflows always.
|
||||||
|
|
||||||
[New!] We provide 👭**team workspace** now! If you need to **share workflows, backup workflow versions for enterprise and teams**, please contact me about our team/enterprise product at weixuanfu01@gmail.com or join discord and DM me @briefpeach
|
[New!] We provide 👭**team workspace** now! If you need to **share workflows, backup workflow versions for enterprise and teams**, please contact me about our team/enterprise product at weixuanfu01@gmail.com or join discord and DM me @briefpeach
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ Recommanded settings for V2 (Do not use these settings if you are on V1):
|
|||||||
|
|
||||||
- 🔁Switch between different workflows easily. 1click open workflow in multiple browser tabs.
|
- 🔁Switch between different workflows easily. 1click open workflow in multiple browser tabs.
|
||||||
- 🤏**Drag and drop** to insert subworkflows into current flow.
|
- 🤏**Drag and drop** to insert subworkflows into current flow.
|
||||||
- 🗂️Organize workflows with folders
|
- 🗂️Organize workflows with folders (tags are deprecated, please use folders to organize)
|
||||||
- 📂Save and sync all your workflows in a local folder (by default under `/ComfyUI/my_workflows` customize in Settings)
|
- 📂Save and sync all your workflows in a local folder (by default under `/ComfyUI/my_workflows` customize in Settings)
|
||||||
- **Save workflow by pressing the 💾 button, or ⌨Shift+S shortcut** (customize in Settings).
|
- **Save workflow by pressing the 💾 button, or ⌨Shift+S shortcut** (customize in Settings).
|
||||||
- Every time you save, it will create a new record in **Version History**. You can easily revert to any version.
|
- Every time you save, it will create a new record in **Version History**. You can easily revert to any version.
|
||||||
@@ -78,9 +80,6 @@ Recommend using Chrome browser for the best experience. Safari doesn't work well
|
|||||||
[中文版教程](https://www.uisdc.com/workspace-manager) [Roadmap](https://github.com/orgs/11cafe/projects/1/views/1)
|
[中文版教程](https://www.uisdc.com/workspace-manager) [Roadmap](https://github.com/orgs/11cafe/projects/1/views/1)
|
||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
**🦩v2.1 New gallery! Inspect image metadata**
|
|
||||||
|
|
||||||
<img width="400" alt="Screenshot 2024-03-23 at 12 58 38 AM" src="https://github.com/11cafe/comfyui-workspace-manager/assets/18367033/5bac9793-7491-4131-b850-037094d03823">
|
|
||||||
|
|
||||||
**🦄v2.0 Two-way sync with local folder, models manager support external models path like Automatic1111, cloud sync workflows**
|
**🦄v2.0 Two-way sync with local folder, models manager support external models path like Automatic1111, cloud sync workflows**
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,12 @@ def get_settings_endpoint(request):
|
|||||||
return web.json_response(text=json.dumps(settings), content_type='application/json')
|
return web.json_response(text=json.dumps(settings), content_type='application/json')
|
||||||
|
|
||||||
def get_settings():
|
def get_settings():
|
||||||
if os.path.exists(f'{db_dir_path}/settings.json'):
|
new_settings_path = os.path.join(db_dir_path, 'settings.json')
|
||||||
|
if os.path.exists(new_settings_path):
|
||||||
# to deprecate and remove legacy settings file
|
# to deprecate and remove legacy settings file
|
||||||
# if os.path.exists(f'{db_dir_path}/useSettings.json'):
|
# if os.path.exists(f'{db_dir_path}/useSettings.json'):
|
||||||
# os.remove(f'{db_dir_path}/useSettings.json')
|
# os.remove(f'{db_dir_path}/useSettings.json')
|
||||||
with open(f'{db_dir_path}/settings.json', 'r') as file:
|
with open(new_settings_path, 'r') as file:
|
||||||
return json.load(file)
|
return json.load(file)
|
||||||
data = read_table('userSettings')
|
data = read_table('userSettings')
|
||||||
if (data):
|
if (data):
|
||||||
|
|||||||
+1
-1
@@ -131,7 +131,7 @@ export default function App() {
|
|||||||
try {
|
try {
|
||||||
await loadDBs();
|
await loadDBs();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("error loading db", error);
|
console.error("🦄Workspace Manager - Error loading db", error);
|
||||||
}
|
}
|
||||||
setLoadingDB(false);
|
setLoadingDB(false);
|
||||||
|
|
||||||
|
|||||||
+38
-16
@@ -4,9 +4,8 @@ import { ColorModeScript, type StyleFunctionProps } from "@chakra-ui/react";
|
|||||||
import { ChakraProvider, extendTheme } from "@chakra-ui/react";
|
import { ChakraProvider, extendTheme } from "@chakra-ui/react";
|
||||||
import { AlertDialogProvider } from "./components/AlertDialogProvider.tsx";
|
import { AlertDialogProvider } from "./components/AlertDialogProvider.tsx";
|
||||||
import CSSReset from "./MyCSSReset.tsx";
|
import CSSReset from "./MyCSSReset.tsx";
|
||||||
|
import { waitForApp } from "./utils/comfyapp.ts";
|
||||||
|
|
||||||
const topbar = document.createElement("div");
|
|
||||||
document.body.append(topbar);
|
|
||||||
const App = React.lazy(() =>
|
const App = React.lazy(() =>
|
||||||
import("./App.tsx").then(({ default: App }) => ({
|
import("./App.tsx").then(({ default: App }) => ({
|
||||||
default: App,
|
default: App,
|
||||||
@@ -51,20 +50,6 @@ const theme = extendTheme({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
ReactDOM.createRoot(topbar).render(
|
|
||||||
<React.StrictMode>
|
|
||||||
<ChakraProvider resetCSS={false} disableGlobalStyle={true} theme={theme}>
|
|
||||||
<CSSReset scope=".workspace_manager" />
|
|
||||||
<ColorModeScript initialColorMode="dark" />
|
|
||||||
<AlertDialogProvider>
|
|
||||||
<Suspense>
|
|
||||||
<App />
|
|
||||||
</Suspense>
|
|
||||||
</AlertDialogProvider>
|
|
||||||
</ChakraProvider>
|
|
||||||
</React.StrictMode>,
|
|
||||||
);
|
|
||||||
|
|
||||||
// hacky fix for chakra add extra className (chakra-ui-light) into body
|
// hacky fix for chakra add extra className (chakra-ui-light) into body
|
||||||
// and resulted in user unable to copy new nodes into clipboard, because of this check: e.target.className === "litegraph"
|
// and resulted in user unable to copy new nodes into clipboard, because of this check: e.target.className === "litegraph"
|
||||||
// (https://github.com/comfyanonymous/ComfyUI/blob/57926635e8d84ae9eea4a0416cc75e363f5ede45/web/scripts/app.js#L861)
|
// (https://github.com/comfyanonymous/ComfyUI/blob/57926635e8d84ae9eea4a0416cc75e363f5ede45/web/scripts/app.js#L861)
|
||||||
@@ -96,3 +81,40 @@ const callback = function (
|
|||||||
};
|
};
|
||||||
const observer = new MutationObserver(callback);
|
const observer = new MutationObserver(callback);
|
||||||
observer.observe(targetNode, observerConfig);
|
observer.observe(targetNode, observerConfig);
|
||||||
|
|
||||||
|
function waitForDocumentBody() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (document.body) {
|
||||||
|
return resolve(document.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
resolve(document.body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for document.body to load so that the top menu is loaded and my react component has a place to mount
|
||||||
|
waitForDocumentBody()
|
||||||
|
.then(() => waitForApp())
|
||||||
|
.then(() => {
|
||||||
|
const topbar = document.createElement("div");
|
||||||
|
document.body.append(topbar);
|
||||||
|
ReactDOM.createRoot(topbar).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<ChakraProvider
|
||||||
|
resetCSS={false}
|
||||||
|
disableGlobalStyle={true}
|
||||||
|
theme={theme}
|
||||||
|
>
|
||||||
|
<CSSReset scope=".workspace_manager" />
|
||||||
|
<ColorModeScript initialColorMode="dark" />
|
||||||
|
<AlertDialogProvider>
|
||||||
|
<Suspense>
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
|
</AlertDialogProvider>
|
||||||
|
</ChakraProvider>
|
||||||
|
</React.StrictMode>,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -67,8 +67,13 @@ export default function AppIsDirtyEventListener() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const id = app.graph.extra?.[COMFYSPACE_TRACKING_FIELD_NAME]?.id;
|
const id = app.graph.extra?.[COMFYSPACE_TRACKING_FIELD_NAME]?.id;
|
||||||
|
console.log("🦄 Restoring workflow... id=", id);
|
||||||
if (id) {
|
if (id) {
|
||||||
const flow = await workflowsTable?.get(id);
|
const flow = await workflowsTable?.get(id);
|
||||||
|
console.log(
|
||||||
|
"🦄 Restored workflow",
|
||||||
|
flow?.parentFolderID + "/" + flow?.name,
|
||||||
|
);
|
||||||
flow && setCurFlowIDAndName(flow);
|
flow && setCurFlowIDAndName(flow);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ const api_base = location.pathname.split("/").slice(0, -1).join("/");
|
|||||||
|
|
||||||
export let api: any | null = null;
|
export let api: any | null = null;
|
||||||
|
|
||||||
import(api_base + "/scripts/api.js").then((apiJs) => {
|
export async function waitForApp() {
|
||||||
api = apiJs?.api;
|
await Promise.all([
|
||||||
});
|
import(api_base + "/scripts/api.js").then((apiJs) => {
|
||||||
|
api = apiJs?.api;
|
||||||
|
}),
|
||||||
|
|
||||||
import(api_base + "/scripts/app.js").then((appJs) => {
|
import(api_base + "/scripts/app.js").then((appJs) => {
|
||||||
app = appJs?.app;
|
app = appJs?.app;
|
||||||
});
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// utils/encryptUtils
|
||||||
|
const defaultSalt = import.meta.env.VITE_SHARE_KEY_ENCODE_KEY;
|
||||||
|
|
||||||
|
export function encodeKey(text: string, salt: string = defaultSalt): string {
|
||||||
|
const randomLength = Math.floor(Math.random() * 13) + 1; // Random length between 1 and 13
|
||||||
|
const randomPadding = Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.substring(2, 2 + randomLength);
|
||||||
|
const input = randomPadding + salt + text;
|
||||||
|
return btoa(encodeURIComponent(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeKey(encoded: string, salt: string = defaultSalt): string {
|
||||||
|
const decoded = decodeURIComponent(atob(encoded));
|
||||||
|
const saltIndex = decoded.indexOf(salt);
|
||||||
|
if (saltIndex === -1) throw new Error("Invalid encoded string or salt");
|
||||||
|
return decoded.slice(saltIndex + salt.length);
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ const rewriteImportPlugin = ({ isDev }) => {
|
|||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode }) => ({
|
export default defineConfig(({ mode }) => ({
|
||||||
|
base: "./",
|
||||||
envDir: ".",
|
envDir: ".",
|
||||||
build: {
|
build: {
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
Reference in New Issue
Block a user