remove auto save timer, cleanup code
This commit is contained in:
+13
-118
@@ -20,17 +20,16 @@ import {
|
||||
workflowVersionsTable,
|
||||
} from "./db-tables/WorkspaceDB";
|
||||
import { defaultGraph } from "./defaultGraph";
|
||||
import { JsonDiff, WorkspaceContext } from "./WorkspaceContext";
|
||||
import { WorkspaceContext } from "./WorkspaceContext";
|
||||
import {
|
||||
getFileUrl,
|
||||
matchShortcut,
|
||||
getWorkflowIdInUrlHash,
|
||||
generateUrlHashWithFlowId,
|
||||
openWorkflowInNewTab,
|
||||
validateOrSaveAllJsonFileMyWorkflows,
|
||||
} from "./utils";
|
||||
import { Topbar } from "./topbar/Topbar";
|
||||
import { EShortcutKeys, Workflow, WorkflowVersion } from "./types/dbTypes";
|
||||
import { Workflow, WorkflowVersion } from "./types/dbTypes";
|
||||
import { useDialog } from "./components/AlertDialogProvider";
|
||||
import React from "react";
|
||||
const RecentFilesDrawer = React.lazy(
|
||||
@@ -46,7 +45,7 @@ import { useStateRef } from "./customHooks/useStateRef";
|
||||
import { indexdb } from "./db-tables/indexdb";
|
||||
import EnableTwowaySyncConfirm from "./settings/EnableTwowaySyncConfirm";
|
||||
import { deepJsonDiffCheck } from "./utils/deepJsonDiffCheck";
|
||||
|
||||
const AppEventListener = React.lazy(() => import("./topbar/AppEventListener"));
|
||||
const ModelManagerTopbar = React.lazy(
|
||||
() => import("./model-manager/topbar/ModelManagerTopbar"),
|
||||
);
|
||||
@@ -70,12 +69,8 @@ export default function App() {
|
||||
const { showDialog } = useDialog();
|
||||
const [loadChild, setLoadChild] = useState(false);
|
||||
const developmentEnvLoadFirst = useRef(false);
|
||||
const autoSaveTimer = useRef(0);
|
||||
const toast = useToast();
|
||||
const workflowOverwriteNoticeStateRef = useRef("hide"); // disabled/hide/show;
|
||||
const [jsonDiff, setJsonDiff] = useState<JsonDiff>(null);
|
||||
const [curVersion, setCurVersion, curVersionRef] =
|
||||
useStateRef<WorkflowVersion | null>(null);
|
||||
const [curVersion, setCurVersion] = useStateRef<WorkflowVersion | null>(null);
|
||||
const saveCurWorkflow = useCallback(async () => {
|
||||
if (curFlowID.current) {
|
||||
if (workflowsTable?.curWorkflow?.saveLock) {
|
||||
@@ -120,6 +115,10 @@ export default function App() {
|
||||
};
|
||||
|
||||
const discardUnsavedChanges = async () => {
|
||||
if (userSettingsTable?.autoSave) {
|
||||
alert("You cannot discard unsaved changes when auto save is enabled");
|
||||
return;
|
||||
}
|
||||
const userInput = confirm(
|
||||
"Are you sure you want to discard unsaved changes? This will revert current workflow to your last saved version. You will lose all changes made since your last save.",
|
||||
);
|
||||
@@ -128,19 +127,14 @@ export default function App() {
|
||||
// User clicked OK
|
||||
const curID = workflowsTable?.curWorkflow?.id;
|
||||
if (curID == null) return;
|
||||
let lastSavedJson;
|
||||
if (userSettingsTable?.autoSave) {
|
||||
lastSavedJson = (await changelogsTable?.getLastestByWorkflowID(curID))
|
||||
?.json;
|
||||
} else {
|
||||
lastSavedJson = (await workflowsTable?.get(curID))?.json;
|
||||
}
|
||||
const lastSavedJson = (await workflowsTable?.get(curID))?.json;
|
||||
if (lastSavedJson) {
|
||||
workflowsTable?.updateCurWorkflow({
|
||||
...workflowsTable.curWorkflow!,
|
||||
json: lastSavedJson,
|
||||
});
|
||||
await app.loadGraphData(JSON.parse(lastSavedJson));
|
||||
setIsDirty(false);
|
||||
} else {
|
||||
alert("Error: No last saved version found");
|
||||
}
|
||||
@@ -189,24 +183,6 @@ export default function App() {
|
||||
if (latestWfID) {
|
||||
loadWorkflowIDImpl(latestWfID);
|
||||
}
|
||||
// console.log("jjjj😂j", app.graph);
|
||||
document.addEventListener("click", (e) => {
|
||||
console.log("app.canvas.", app.canvas);
|
||||
if (
|
||||
app.canvas.node_over != null ||
|
||||
app.canvas.node_capturing_input != null ||
|
||||
app.canvas.node_widget != null
|
||||
) {
|
||||
console.log("🙀on change node click!!");
|
||||
}
|
||||
});
|
||||
// console.log("jjjj😂j LGrpaoh", LGraph.prototype);
|
||||
document.addEventListener("keyup", function (event) {
|
||||
console.log("keyyyyyy app.canvas", app.canvas);
|
||||
if (event.target?.matches("input, textarea")) {
|
||||
console.log("🎹🎹on change keyboard click!!");
|
||||
}
|
||||
});
|
||||
await validateOrSaveAllJsonFileMyWorkflows();
|
||||
|
||||
indexdb.cache.get(UPGRADE_TO_2WAY_SYNC_KEY).then(async (value) => {
|
||||
@@ -275,10 +251,8 @@ export default function App() {
|
||||
|
||||
const loadWorkflowIDImpl = async (id: string, versionID?: string | null) => {
|
||||
if (app.graph == null) {
|
||||
console.error("app.graph is null cannot load workflow");
|
||||
return;
|
||||
}
|
||||
|
||||
const flow = await workflowsTable?.get(id);
|
||||
// If the currently loaded flow does not exist, you need to clear the URL hash and localStorage to avoid popping up another prompt that the flow does not exist when refreshing the page.
|
||||
if (flow == null) {
|
||||
@@ -304,20 +278,9 @@ export default function App() {
|
||||
app.loadGraphData(JSON.parse(flow.json));
|
||||
}
|
||||
setRoute("root");
|
||||
/**
|
||||
* By an unlocked flow with isDirty true and unsaved,
|
||||
* When switching to a locked flow, isDirty is still true, and checkIsDirty() is not executed in autoSaveTimer.
|
||||
* causes * to be displayed in front of the topbar flow name,
|
||||
* So add this logic and reset isDirty every time you open a new process
|
||||
* In fact, it is reasonable to reset isDirty every time you open a new flow.
|
||||
*/
|
||||
isDirty && setIsDirty(false);
|
||||
};
|
||||
|
||||
const compareJsonDiff = (diff: { old: Object; new: Object } | null) => {
|
||||
setJsonDiff(diff);
|
||||
};
|
||||
|
||||
const loadWorkflowID = async (
|
||||
id: string | null,
|
||||
versionID?: string | null,
|
||||
@@ -464,72 +427,6 @@ export default function App() {
|
||||
}
|
||||
graphAppSetup();
|
||||
setLoadChild(true);
|
||||
autoSaveTimer.current = setInterval(async () => {
|
||||
const autoSaveEnabled = userSettingsTable?.autoSave;
|
||||
if (workflowsTable?.curWorkflow?.saveLock) return;
|
||||
const isDirty = checkIsDirty();
|
||||
setIsDirty(!!isDirty);
|
||||
if (!isDirty) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
curVersionRef.current != null &&
|
||||
curVersionRef.current.json !== JSON.stringify(app.graph.serialize())
|
||||
) {
|
||||
setCurVersion(null);
|
||||
}
|
||||
if (curFlowID.current != null && autoSaveEnabled) {
|
||||
const isLatest = await workflowsTable?.latestVersionCheck();
|
||||
if (
|
||||
workflowOverwriteNoticeStateRef.current !== "disabled" &&
|
||||
!isLatest
|
||||
) {
|
||||
workflowOverwriteNoticeStateRef.current = "show";
|
||||
showDialog(
|
||||
`This notification is to inform you that it appears you've opened the same workflow in multiple tabs. If all tabs are set to auto-save, this may lead to conflicts and potential data loss.\n\nYou might want to consider disabling auto-save to prevent this. We will remind you to save changes if you leave a page with unsaved work.`,
|
||||
[
|
||||
{
|
||||
label: "Do Not Remind Again",
|
||||
onClick: () => {
|
||||
workflowOverwriteNoticeStateRef.current = "disabled";
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Disable Auto-Save",
|
||||
colorScheme: "teal",
|
||||
onClick: () => {
|
||||
userSettingsTable?.upsert({ autoSave: false });
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
} else {
|
||||
// autosave workflow if enabled
|
||||
const graphJson = JSON.stringify(app.graph.serialize());
|
||||
graphJson != null &&
|
||||
(await workflowsTable?.updateFlow(curFlowID.current!, {
|
||||
json: graphJson,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
const shortcutListener = async (event: KeyboardEvent) => {
|
||||
if (document.visibilityState === "hidden") return;
|
||||
|
||||
const matchResult = await matchShortcut(event);
|
||||
|
||||
switch (matchResult) {
|
||||
case EShortcutKeys.SAVE:
|
||||
saveCurWorkflow();
|
||||
break;
|
||||
case EShortcutKeys.SAVE_AS:
|
||||
setRoute("saveAsModal");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", shortcutListener);
|
||||
|
||||
const fileInput = document.getElementById(
|
||||
"comfy-file-input",
|
||||
@@ -605,13 +502,10 @@ export default function App() {
|
||||
app.canvasEl.addEventListener("drop", handleDrop);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", shortcutListener);
|
||||
window.removeEventListener("change", fileInputListener);
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
window.removeEventListener("executed", handleExecuted);
|
||||
app.canvasEl.removeEventListener("drop", handleDrop);
|
||||
|
||||
clearInterval(autoSaveTimer.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -628,13 +522,13 @@ export default function App() {
|
||||
discardUnsavedChanges: discardUnsavedChanges,
|
||||
saveCurWorkflow: saveCurWorkflow,
|
||||
isDirty: isDirty,
|
||||
setIsDirty: setIsDirty,
|
||||
loadNewWorkflow: loadNewWorkflow,
|
||||
loadFilePath: loadFilePath,
|
||||
setRoute: setRoute,
|
||||
route: route,
|
||||
jsonDiff: jsonDiff,
|
||||
compareJson: compareJsonDiff,
|
||||
curVersion: curVersion,
|
||||
setCurVersion: setCurVersion,
|
||||
}}
|
||||
>
|
||||
<div ref={workspaceContainerRef} className="workspace_manager">
|
||||
@@ -673,6 +567,7 @@ export default function App() {
|
||||
)}
|
||||
</Box>
|
||||
<ServerEventListener />
|
||||
<AppEventListener />
|
||||
</Portal>
|
||||
</div>
|
||||
</WorkspaceContext.Provider>
|
||||
|
||||
@@ -14,6 +14,7 @@ export const WorkspaceContext = createContext<{
|
||||
versionID?: string | null,
|
||||
forceLoad?: boolean,
|
||||
) => void;
|
||||
setIsDirty: (dirty: boolean) => void;
|
||||
saveCurWorkflow: () => void;
|
||||
discardUnsavedChanges: () => Promise<void>;
|
||||
isDirty: boolean;
|
||||
@@ -21,9 +22,8 @@ export const WorkspaceContext = createContext<{
|
||||
loadFilePath: (path: string, overwriteCurrent?: boolean) => void;
|
||||
setRoute: (route: WorkspaceRoute) => void;
|
||||
route: WorkspaceRoute;
|
||||
jsonDiff: JsonDiff;
|
||||
compareJson: (jsonDiff: JsonDiff) => void;
|
||||
curVersion: WorkflowVersion | null;
|
||||
setCurVersion: (version: WorkflowVersion | null) => void;
|
||||
}>({
|
||||
curFlowID: null,
|
||||
loadWorkflowID: () => {},
|
||||
@@ -34,9 +34,9 @@ export const WorkspaceContext = createContext<{
|
||||
loadFilePath: () => {},
|
||||
setRoute: () => {},
|
||||
route: "root",
|
||||
jsonDiff: null,
|
||||
compareJson: () => {},
|
||||
curVersion: null,
|
||||
setIsDirty: () => {},
|
||||
setCurVersion: () => {},
|
||||
});
|
||||
|
||||
export const RecentFilesContext = createContext<{
|
||||
|
||||
@@ -45,7 +45,6 @@ import HoverMenu from "./HoverMenu";
|
||||
const ShareDialog = lazy(() => import("../share/ShareDialog"));
|
||||
// @ts-ignore
|
||||
import { app } from "/scripts/app.js";
|
||||
import JsonDiffCompareModal from "./JsonDiffCompareModal";
|
||||
|
||||
export default function DropdownTitle() {
|
||||
const {
|
||||
@@ -211,9 +210,6 @@ export default function DropdownTitle() {
|
||||
{route == "versionHistory" && (
|
||||
<VersionHistoryDrawer onClose={() => setRoute("root")} />
|
||||
)}
|
||||
|
||||
<JsonDiffCompareModal />
|
||||
|
||||
{route === "saveAsModal" && (
|
||||
<Modal isOpen={true} onClose={handleOnCloseModal}>
|
||||
<ModalOverlay />
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Box, Modal, ModalContent } from "@chakra-ui/react";
|
||||
import { useContext } from "react";
|
||||
import { WorkspaceContext } from "../WorkspaceContext";
|
||||
|
||||
export default function JsonDiffCompareModal() {
|
||||
const { jsonDiff, compareJson } = useContext(WorkspaceContext);
|
||||
|
||||
if (jsonDiff == null) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
isOpen={true}
|
||||
onClose={() => {
|
||||
compareJson(null);
|
||||
}}
|
||||
>
|
||||
<ModalContent>
|
||||
<Box height={"80vh"} width={"90%"} overflow={"scroll"}>
|
||||
{/* TODO: add json comparison ui view */}
|
||||
</Box>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export function SharedTopbarButton({}) {
|
||||
<a href={cloudURL} style={{ textDecoration: "none" }} target="_blank">
|
||||
<DarkMode>
|
||||
<Tag>
|
||||
{privacy ? <PrivacyLabel privacy={privacy} showEmoji /> : "Shared"}
|
||||
{privacy === "PUBLIC" ? "🌐" : privacy === "UNLISTED" ? "🔗" : "🔒"}
|
||||
</Tag>
|
||||
</DarkMode>
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useContext, useEffect } from "react";
|
||||
// @ts-expect-error
|
||||
import { app } from "/scripts/app.js";
|
||||
import { WorkspaceContext } from "../WorkspaceContext";
|
||||
import { userSettingsTable, workflowsTable } from "../db-tables/WorkspaceDB";
|
||||
import { useToast } from "@chakra-ui/react";
|
||||
import { matchShortcut } from "../utils";
|
||||
import { EShortcutKeys } from "../types/dbTypes";
|
||||
|
||||
export default function AppEventListener() {
|
||||
const { setIsDirty, setRoute, saveCurWorkflow } =
|
||||
useContext(WorkspaceContext);
|
||||
const toast = useToast();
|
||||
useEffect(() => {
|
||||
const shortcutListener = async (matchResult: string) => {
|
||||
switch (matchResult) {
|
||||
case EShortcutKeys.SAVE:
|
||||
saveCurWorkflow();
|
||||
break;
|
||||
case EShortcutKeys.SAVE_AS:
|
||||
setRoute("saveAsModal");
|
||||
break;
|
||||
}
|
||||
};
|
||||
document.addEventListener("click", (e) => {
|
||||
if (
|
||||
app.canvas.node_over != null ||
|
||||
app.canvas.node_capturing_input != null ||
|
||||
app.canvas.node_widget != null
|
||||
) {
|
||||
onIsDirty();
|
||||
}
|
||||
});
|
||||
document.addEventListener("keydown", async function (event) {
|
||||
if (document.visibilityState === "hidden") return;
|
||||
|
||||
const matchResult = await matchShortcut(event);
|
||||
if (matchResult) {
|
||||
shortcutListener(matchResult);
|
||||
// @ts-expect-error
|
||||
} else if (event.target?.matches("input, textarea")) {
|
||||
onIsDirty();
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const onIsDirty = async () => {
|
||||
if (workflowsTable?.curWorkflow?.saveLock) return;
|
||||
const autoSaveEnabled = await userSettingsTable?.getSetting("autoSave");
|
||||
if (!autoSaveEnabled) {
|
||||
setIsDirty(true);
|
||||
}
|
||||
if (workflowsTable?.curWorkflow?.id && autoSaveEnabled) {
|
||||
const isLatest = await workflowsTable?.latestVersionCheck();
|
||||
if (!isLatest) {
|
||||
toast({
|
||||
title: "You are working on an outdated version",
|
||||
description:
|
||||
"This workflow is changed by another tab. Please close the page and reopen to get the latest version.",
|
||||
status: "warning",
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
});
|
||||
} else {
|
||||
// autosave workflow if enabled
|
||||
const graphJson = JSON.stringify(app.graph.serialize());
|
||||
graphJson != null &&
|
||||
(await workflowsTable?.updateFlow(workflowsTable.curWorkflow.id, {
|
||||
json: graphJson,
|
||||
}));
|
||||
setIsDirty(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
return null;
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Button, ButtonGroup, Flex, IconButton } from "@chakra-ui/react";
|
||||
import { IconPlus, IconTriangleInvertedFilled } from "@tabler/icons-react";
|
||||
import { useContext } from "react";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { WorkspaceContext } from "../WorkspaceContext";
|
||||
|
||||
export default function VersionNameTopbar(
|
||||
{
|
||||
// onClick,
|
||||
}: {
|
||||
// onClick: () => void;
|
||||
},
|
||||
) {
|
||||
const { route, setRoute, curVersion } = useContext(WorkspaceContext);
|
||||
export default function VersionNameTopbar({}: {}) {
|
||||
const { setRoute, curVersion, isDirty, setCurVersion } =
|
||||
useContext(WorkspaceContext);
|
||||
useEffect(() => {
|
||||
if (isDirty) {
|
||||
curVersion &&
|
||||
setCurVersion?.({ ...curVersion, name: curVersion.name + "*" });
|
||||
}
|
||||
}, [isDirty]);
|
||||
if (!curVersion) {
|
||||
return null;
|
||||
}
|
||||
@@ -22,7 +23,7 @@ export default function VersionNameTopbar(
|
||||
rightIcon={<IconTriangleInvertedFilled size={10} />}
|
||||
onClick={() => setRoute("versionHistory")}
|
||||
>
|
||||
{curVersion?.name ?? "latest*"}
|
||||
{curVersion.name}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
|
||||
Reference in New Issue
Block a user