Merge branch 'dev' into beta
This commit is contained in:
+3
-3
@@ -92,6 +92,7 @@ export default function App() {
|
||||
changelogsTable?.create({
|
||||
workflowID: curFlowID.current,
|
||||
json: graphJson,
|
||||
isAutoSave: false,
|
||||
}),
|
||||
]);
|
||||
userSettingsTable?.autoSave &&
|
||||
@@ -445,6 +446,7 @@ export default function App() {
|
||||
};
|
||||
setCurFlowIDAndName(newFlow);
|
||||
await workflowsTable?.createFlow(newFlow);
|
||||
setIsDirty(true);
|
||||
}
|
||||
};
|
||||
fileInput?.addEventListener("change", fileInputListener);
|
||||
@@ -501,6 +503,7 @@ export default function App() {
|
||||
setCurFlowIDAndName(newFlow);
|
||||
await workflowsTable?.createFlow(newFlow);
|
||||
}
|
||||
setIsDirty(true);
|
||||
};
|
||||
app.canvasEl.addEventListener("drop", handleDrop);
|
||||
|
||||
@@ -563,9 +566,6 @@ export default function App() {
|
||||
<GalleryModal onclose={() => setRoute("root")} />
|
||||
</Suspense>
|
||||
)}
|
||||
{route === "modelList" && (
|
||||
<ModelsListDrawer onClose={() => setRoute("root")} />
|
||||
)}
|
||||
</Box>
|
||||
<ServerEventListener />
|
||||
<AppIsDirtyEventListener />
|
||||
|
||||
@@ -14,6 +14,7 @@ import FolderOnTopSettings from "../settings/FolderOnTopSettings";
|
||||
import TwoWaySyncSettings from "../settings/TwoWaySyncSettings";
|
||||
import CommonCheckboxSettings from "../settings/CommonCheckboxSettings";
|
||||
import SelectMyWorkflowsDir from "../settings/SelectMyWorkflowsDir";
|
||||
import { MaximumChangelog } from "../settings/MaximumChangelogSettings";
|
||||
|
||||
export default function WorkspaceSettingsModal({
|
||||
onClose,
|
||||
@@ -47,6 +48,7 @@ export default function WorkspaceSettingsModal({
|
||||
settingKey="overwriteCurWorkflowWhenDroppingFileToCanvas"
|
||||
text="Overwrite current workflow when drag and drop workflow file to canvas"
|
||||
/>
|
||||
<MaximumChangelog />
|
||||
</VStack>
|
||||
</HStack>
|
||||
</ModalBody>
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function DropdownTitle() {
|
||||
height={TOPBAR_BUTTON_HEIGHT + "px"}
|
||||
aria-label="menu"
|
||||
size={"sm"}
|
||||
// backgroundColor={"gray.700"}
|
||||
// backgroundColor={"#4a4d6b"}
|
||||
backgroundColor={"teal.600"}
|
||||
>
|
||||
File
|
||||
|
||||
@@ -34,7 +34,8 @@ import DeleteConfirm from "./DeleteConfirm";
|
||||
|
||||
export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
const toast = useToast();
|
||||
const { curFlowID, isDirty, loadWorkflowID } = useContext(WorkspaceContext);
|
||||
const { curFlowID, isDirty, loadWorkflowID, curVersion } =
|
||||
useContext(WorkspaceContext);
|
||||
const [active, setActive] = useState(0); // 0: version、1: changelog
|
||||
const [selectedVersion, setSelectedVersion] = useState<string | null>(null);
|
||||
const [changelogs, setChangelogs] = useState<Changelog[]>([]);
|
||||
@@ -55,11 +56,6 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
const vers =
|
||||
(await workflowVersionsTable?.listByWorkflowID(curFlowID!)) ?? [];
|
||||
setVersions(vers);
|
||||
|
||||
const graphJson = JSON.stringify(app.graph.serialize());
|
||||
const selectedVer = vers?.filter((c) => c.json === graphJson);
|
||||
const selectedVerID = selectedVer?.[0]?.id;
|
||||
selectedVerID && setSelectedVersion(selectedVerID);
|
||||
};
|
||||
|
||||
const onDelete = (id: string) => {
|
||||
@@ -88,7 +84,7 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
|
||||
return (
|
||||
<Card
|
||||
width={400}
|
||||
width={430}
|
||||
height={"100vh"}
|
||||
gap={0}
|
||||
position={"fixed"}
|
||||
@@ -130,7 +126,7 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
mb={1}
|
||||
justify={"space-between"}
|
||||
backgroundColor={
|
||||
version.id === selectedVersion ? "teal.300" : undefined
|
||||
version.id === curVersion?.id ? "teal.300" : undefined
|
||||
}
|
||||
borderRadius={4}
|
||||
>
|
||||
@@ -154,12 +150,6 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
}
|
||||
app.loadGraphData(JSON.parse(version.json));
|
||||
loadWorkflowID(curFlowID!, version.id);
|
||||
// toast({
|
||||
// title: `Switched to version "${version.name}"`,
|
||||
// status: "success",
|
||||
// duration: 3000,
|
||||
// isClosable: true,
|
||||
// });
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
@@ -182,7 +172,7 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
<Stack divider={<StackDivider />} spacing={2}>
|
||||
{changelogs?.map((c) => {
|
||||
return (
|
||||
<HStack key={c.id}>
|
||||
<HStack key={c.id} justifyContent={"space-between"}>
|
||||
<Button
|
||||
key={c.id}
|
||||
size={"sm"}
|
||||
@@ -202,10 +192,12 @@ export function VersionHistoryDrawer({ onClose }: { onClose: () => void }) {
|
||||
}}
|
||||
isActive={c.id === selectedVersion}
|
||||
>
|
||||
Saved at {formatTimestamp(c.createTime, true)}
|
||||
Saved at {new Date(c.createTime).toLocaleString()}
|
||||
</Button>
|
||||
{c.isAutoSave ? (
|
||||
<Tag colorScheme="teal">Auto save</Tag>
|
||||
<Tag colorScheme="teal" size={"sm"}>
|
||||
Auto save
|
||||
</Tag>
|
||||
) : null}
|
||||
</HStack>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Table } from "./WorkspaceDB";
|
||||
import { Table, userSettingsTable } from "./WorkspaceDB";
|
||||
import { Changelog } from "../types/dbTypes";
|
||||
import { TableBase } from "./TableBase";
|
||||
import { indexdb } from "./indexdb";
|
||||
@@ -29,6 +29,7 @@ export class ChangelogsTable extends TableBase<Changelog> {
|
||||
public async create(input: {
|
||||
json: string;
|
||||
workflowID: string;
|
||||
isAutoSave: boolean;
|
||||
}): Promise<Changelog | null> {
|
||||
const latest = await this.getLastestByWorkflowID(input.workflowID);
|
||||
// only create when there is a change
|
||||
@@ -41,29 +42,23 @@ export class ChangelogsTable extends TableBase<Changelog> {
|
||||
json: input.json,
|
||||
workflowID: input.workflowID,
|
||||
createTime: Date.now(),
|
||||
isAutoSave: input.isAutoSave,
|
||||
};
|
||||
this.deleteLogsExceedLimit(input.workflowID);
|
||||
await indexdb.changelogs.add(change);
|
||||
await this.saveDiskDB();
|
||||
return change;
|
||||
}
|
||||
async deleteLogsExceedLimit(workflowID: string, limit: number = LIMIT) {
|
||||
async deleteLogsExceedLimit(workflowID: string) {
|
||||
const all = await indexdb.changelogs
|
||||
.where("workflowID")
|
||||
.equals(workflowID)
|
||||
.reverse()
|
||||
.sortBy("createTime");
|
||||
const autoSaved = all.filter((c) => c.isAutoSave === true);
|
||||
const manualSaved = all.filter(
|
||||
(c) => c.isAutoSave == null || c.isAutoSave == false,
|
||||
);
|
||||
|
||||
if (autoSaved.length > limit) {
|
||||
const toDelete = autoSaved.slice(limit);
|
||||
await indexdb.changelogs.bulkDelete(toDelete.map((c) => c.id));
|
||||
await this.saveDiskDB();
|
||||
}
|
||||
if (manualSaved.length > limit) {
|
||||
const toDelete = manualSaved.slice(limit);
|
||||
const limit =
|
||||
(await userSettingsTable?.getSetting("maximumChangelogNumber")) ?? LIMIT;
|
||||
if (all.length > limit) {
|
||||
const toDelete = all.slice(limit);
|
||||
await indexdb.changelogs.bulkDelete(toDelete.map((c) => c.id));
|
||||
await this.saveDiskDB();
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ export class UserSettingsTable extends TableBase<UserSettings> {
|
||||
foldersOnTop: false,
|
||||
cloudHost: "https://www.comfyspace.art",
|
||||
overwriteCurWorkflowWhenDroppingFileToCanvas: false,
|
||||
maximumChangelogNumber: 200,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -152,9 +152,17 @@ export function ModelItem({ data }: Props) {
|
||||
fontSize={14}
|
||||
></Text>
|
||||
</Box>
|
||||
<Tooltip label={data.date.toLocaleDateString()}>
|
||||
<Tooltip
|
||||
label={
|
||||
<span>
|
||||
{data.model_name + data.model_extension}
|
||||
<br />
|
||||
{data.date.toLocaleDateString()}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Text textAlign="center" p="1" fontSize={14} noOfLines={2}>
|
||||
{model?.modelName ?? data.model_name}
|
||||
{model?.modelName ?? data.model_name + data.model_extension}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function InstallMissingModelsButton({}: Props) {
|
||||
const [showMyModels, setShowMyModels] = useState(false);
|
||||
const [missingModels, setMissingModels] = useState<MissingModel[]>([]);
|
||||
useEffect(() => {
|
||||
// temporary disable missing model check
|
||||
// diable until it is working
|
||||
return;
|
||||
// monkey patch queue prompt api to catch errors
|
||||
const queuePrompt = app.queuePrompt as Function;
|
||||
@@ -43,7 +43,7 @@ export default function InstallMissingModelsButton({}: Props) {
|
||||
setMissingModels(
|
||||
Object.values(nodeErrors).flatMap((nodeError) =>
|
||||
nodeError.errors
|
||||
.filter((error) => error.type === "value_not_in_list")
|
||||
?.filter((error) => error?.type === "value_not_in_list")
|
||||
.map((error) => {
|
||||
const { input_name, received_value } = error.extra_info;
|
||||
return {
|
||||
@@ -79,6 +79,7 @@ export default function InstallMissingModelsButton({}: Props) {
|
||||
aria-label="missing models"
|
||||
px={2}
|
||||
onClick={() => setShowMyModels(true)}
|
||||
colorScheme="teal"
|
||||
>
|
||||
Install Missing ({missingModels.length})
|
||||
</Button>
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import { Button, HStack } from "@chakra-ui/react";
|
||||
import { lazy, useEffect, useState, DragEvent } from "react";
|
||||
import { Button, Stack } from "@chakra-ui/react";
|
||||
import { lazy, useEffect, DragEvent, useContext } from "react";
|
||||
import ModelsListDrawer from "../models-list-drawer/ModelsListDrawer";
|
||||
import { IconGripVertical } from "@tabler/icons-react";
|
||||
import Draggable from "../../components/Draggable";
|
||||
|
||||
// @ts-ignore
|
||||
import { app } from "/scripts/app.js";
|
||||
import "./index.css";
|
||||
import { userSettingsTable } from "../../db-tables/WorkspaceDB";
|
||||
import { ModelManagerPosition } from "../../types/dbTypes";
|
||||
import { WorkspaceContext } from "../../WorkspaceContext";
|
||||
|
||||
const AddMissingModelsButton = lazy(
|
||||
() => import("./InstallMissingModelsButton"),
|
||||
);
|
||||
|
||||
export default function ModelManagerTopbar() {
|
||||
const [showMyModels, setShowMyModels] = useState(false);
|
||||
const [positionStyle, setPositionStyle] = useState<ModelManagerPosition>();
|
||||
|
||||
const { setRoute, route } = useContext(WorkspaceContext);
|
||||
const handleModelDrop = async (
|
||||
e: DragEvent<HTMLCanvasElement> & { canvasX: number; canvasY: number },
|
||||
) => {
|
||||
@@ -35,85 +30,29 @@ export default function ModelManagerTopbar() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
userSettingsTable?.getSetting("modelManagerTopBarStyle").then((res) => {
|
||||
updatePosition(res, false);
|
||||
});
|
||||
app.canvasEl.addEventListener("drop", handleModelDrop);
|
||||
return () => {
|
||||
app.canvasEl.removeEventListener("drop", handleModelDrop);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const updatePosition = (
|
||||
position?: ModelManagerPosition,
|
||||
needUpdateDB: boolean = false,
|
||||
) => {
|
||||
const { top: curTop = 0, right: curRight = 0 } = positionStyle || {};
|
||||
const { top = 0, right = 0 } = position ?? {};
|
||||
let newTop = curTop + top;
|
||||
let newRight = positionStyle === undefined ? right : curRight - right;
|
||||
const clientWidth = document.documentElement.clientWidth;
|
||||
const clientHeight = document.documentElement.clientHeight;
|
||||
const panelElement = document.getElementById("modelManagerTopBar");
|
||||
const offsetWidth = panelElement?.offsetWidth || 224;
|
||||
|
||||
if (newTop + 32 > clientHeight) newTop = clientHeight - 38;
|
||||
if (newRight + offsetWidth > clientWidth)
|
||||
newRight = clientWidth - offsetWidth - 4;
|
||||
|
||||
setPositionStyle({
|
||||
top: Math.max(4, newTop),
|
||||
right: Math.max(4, newRight),
|
||||
});
|
||||
|
||||
needUpdateDB &&
|
||||
userSettingsTable?.upsert({
|
||||
modelManagerTopBarStyle: { top: newTop, right: newRight },
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Draggable
|
||||
onDragEnd={(position: { x: number; y: number }) => {
|
||||
updatePosition({ top: position.y, right: position.x }, true);
|
||||
}}
|
||||
dragIconId="dragModelManagerTopBarIcon"
|
||||
>
|
||||
{positionStyle ? (
|
||||
<HStack
|
||||
style={{
|
||||
position: "fixed",
|
||||
...positionStyle,
|
||||
}}
|
||||
gap={2}
|
||||
draggable={false}
|
||||
id="modelManagerTopBar"
|
||||
className="model-manager-top-bar"
|
||||
>
|
||||
<IconGripVertical
|
||||
id="dragModelManagerTopBarIcon"
|
||||
className="drag-model-manager-top-bar-icon"
|
||||
cursor="move"
|
||||
size={15}
|
||||
color="#FFF"
|
||||
/>
|
||||
<AddMissingModelsButton />
|
||||
<Button
|
||||
size={"sm"}
|
||||
colorScheme="blue"
|
||||
aria-label="My models"
|
||||
onClick={() => setShowMyModels(true)}
|
||||
px={1}
|
||||
>
|
||||
Models
|
||||
</Button>
|
||||
{showMyModels && (
|
||||
<ModelsListDrawer onClose={() => setShowMyModels(false)} />
|
||||
)}
|
||||
</HStack>
|
||||
) : (
|
||||
""
|
||||
<Stack style={{ position: "relative" }}>
|
||||
<Button
|
||||
size={"sm"}
|
||||
colorScheme="blue"
|
||||
aria-label="My models"
|
||||
onClick={() => setRoute("modelList")}
|
||||
px={1}
|
||||
>
|
||||
Models
|
||||
</Button>
|
||||
<div style={{ position: "absolute", top: "38px", left: "0px" }}>
|
||||
<AddMissingModelsButton />
|
||||
</div>
|
||||
{route === "modelList" && (
|
||||
<ModelsListDrawer onClose={() => setRoute("root")} />
|
||||
)}
|
||||
</Draggable>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Stack, Text, NumberInput, NumberInputField } from "@chakra-ui/react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { userSettingsTable } from "../db-tables/WorkspaceDB";
|
||||
|
||||
export function MaximumChangelog() {
|
||||
const [changelogNumber, setChangelogNumber] = useState<number>(200);
|
||||
|
||||
const onInputChange = (newValue: string) => {
|
||||
if (!newValue.length) {
|
||||
setChangelogNumber(0);
|
||||
return;
|
||||
}
|
||||
setChangelogNumber(parseInt(newValue));
|
||||
};
|
||||
|
||||
const onBlur = async () => {
|
||||
if (changelogNumber < 0) {
|
||||
setChangelogNumber(0);
|
||||
}
|
||||
await userSettingsTable?.upsert({
|
||||
maximumChangelogNumber: Number(changelogNumber),
|
||||
});
|
||||
};
|
||||
const getMaximumChangelogNumber = () => {
|
||||
userSettingsTable?.getSetting("maximumChangelogNumber").then((res) => {
|
||||
setChangelogNumber(res);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getMaximumChangelogNumber();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Text>
|
||||
Maximum number of save change history to store. This does not include
|
||||
versions that you created by "Create Version", which are always stored
|
||||
and has no limit.
|
||||
</Text>
|
||||
|
||||
<NumberInput
|
||||
defaultValue={200}
|
||||
min={0}
|
||||
keepWithinRange={true}
|
||||
placeholder="Enter a number"
|
||||
maxWidth={"300px"}
|
||||
value={changelogNumber}
|
||||
onChange={(e) => onInputChange(e)}
|
||||
onBlur={() => {
|
||||
onBlur();
|
||||
}}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
onBlur();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<NumberInputField />
|
||||
</NumberInput>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -2,8 +2,12 @@ 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 {
|
||||
changelogsTable,
|
||||
userSettingsTable,
|
||||
workflowsTable,
|
||||
} from "../db-tables/WorkspaceDB";
|
||||
import { Box, useToast } from "@chakra-ui/react";
|
||||
import { matchShortcut } from "../utils";
|
||||
import { EShortcutKeys } from "../types/dbTypes";
|
||||
import useDebounceFn from "../customHooks/useDebounceFn";
|
||||
@@ -43,24 +47,43 @@ export default function AppIsDirtyEventListener() {
|
||||
});
|
||||
document.addEventListener("keydown", async function (event) {
|
||||
if (document.visibilityState === "hidden") return;
|
||||
|
||||
const matchResult = await matchShortcut(event);
|
||||
if (matchResult) {
|
||||
shortcutListener(matchResult);
|
||||
} else if (
|
||||
// @ts-expect-error
|
||||
} else if (event.target?.matches("input, textarea")) {
|
||||
event.target?.matches("input, textarea") &&
|
||||
Object.keys(app.canvas.selected_nodes ?? {}).length
|
||||
) {
|
||||
onIsDirty();
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const autoSaveWorkflow = async () => {
|
||||
// autosave workflow if enabled
|
||||
if (!workflowsTable?.curWorkflow?.id) {
|
||||
return;
|
||||
}
|
||||
const graphJson = JSON.stringify(app.graph.serialize());
|
||||
graphJson != null &&
|
||||
(await workflowsTable?.updateFlow(workflowsTable.curWorkflow!.id, {
|
||||
(await workflowsTable?.updateFlow(workflowsTable.curWorkflow.id, {
|
||||
json: graphJson,
|
||||
}));
|
||||
changelogsTable?.create({
|
||||
workflowID: workflowsTable.curWorkflow.id,
|
||||
isAutoSave: true,
|
||||
json: graphJson,
|
||||
});
|
||||
setIsDirty(false);
|
||||
toast({
|
||||
position: "bottom-left",
|
||||
duration: 1000,
|
||||
render: () => (
|
||||
<Box color="white" p={3}>
|
||||
Auto saved
|
||||
</Box>
|
||||
),
|
||||
});
|
||||
};
|
||||
const [debounceAutoSaveWorkflow, _cancelDebounceAutoSaveWorkflow] =
|
||||
useDebounceFn(autoSaveWorkflow, 1000);
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
IconLock,
|
||||
} from "@tabler/icons-react";
|
||||
import DropdownTitle from "../components/DropdownTitle";
|
||||
import { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { lazy, useCallback, useContext, useEffect, useState } from "react";
|
||||
import EditFlowName from "../components/EditFlowName";
|
||||
import { WorkspaceContext } from "../WorkspaceContext";
|
||||
import { PanelPosition } from "../types/dbTypes";
|
||||
@@ -19,6 +19,9 @@ import { SharedTopbarButton } from "../share/SharedTopbarButton";
|
||||
import VersionNameTopbar from "./VersionNameTopbar";
|
||||
import { userSettingsTable, workflowsTable } from "../db-tables/WorkspaceDB";
|
||||
import { TOPBAR_BUTTON_HEIGHT } from "../const";
|
||||
const ModelManagerTopbar = lazy(
|
||||
() => import("../model-manager/topbar/ModelManagerTopbar"),
|
||||
);
|
||||
|
||||
interface Props {
|
||||
curFlowName: string | null;
|
||||
@@ -85,6 +88,7 @@ export function Topbar({ curFlowName, setCurFlowName }: Props) {
|
||||
<Button
|
||||
size={"sm"}
|
||||
aria-label="workspace folder"
|
||||
// backgroundColor={colorMode === "dark" ? "#333547" : undefined}
|
||||
onClick={() => setRoute("recentFlows")}
|
||||
px={2}
|
||||
>
|
||||
@@ -93,16 +97,7 @@ export function Topbar({ curFlowName, setCurFlowName }: Props) {
|
||||
<IconTriangleInvertedFilled size={8} />
|
||||
</HStack>
|
||||
</Button>
|
||||
<Button
|
||||
size={"sm"}
|
||||
colorScheme="blue"
|
||||
height={TOPBAR_BUTTON_HEIGHT + "px"}
|
||||
aria-label="My models"
|
||||
onClick={() => setRoute("modelList")}
|
||||
px={1}
|
||||
>
|
||||
Models
|
||||
</Button>
|
||||
<ModelManagerTopbar />
|
||||
<Tooltip label="New workflow">
|
||||
<Button
|
||||
size={"sm"}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button, ButtonGroup, Flex, IconButton } from "@chakra-ui/react";
|
||||
import { IconPlus, IconTriangleInvertedFilled } from "@tabler/icons-react";
|
||||
import { Button, ButtonGroup, Flex } from "@chakra-ui/react";
|
||||
import { IconTriangleInvertedFilled } from "@tabler/icons-react";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { WorkspaceContext } from "../WorkspaceContext";
|
||||
|
||||
@@ -7,9 +7,8 @@ export default function VersionNameTopbar({}: {}) {
|
||||
const { setRoute, curVersion, isDirty, setCurVersion } =
|
||||
useContext(WorkspaceContext);
|
||||
useEffect(() => {
|
||||
if (isDirty) {
|
||||
curVersion &&
|
||||
setCurVersion?.({ ...curVersion, name: curVersion.name + "*" });
|
||||
if (isDirty && curVersion && curVersion?.name.endsWith("*") === false) {
|
||||
setCurVersion?.({ ...curVersion, name: curVersion.name + "*" });
|
||||
}
|
||||
}, [isDirty]);
|
||||
if (!curVersion) {
|
||||
|
||||
@@ -88,6 +88,7 @@ export type UserSettings = {
|
||||
cloudHost: string;
|
||||
overwriteCurWorkflowWhenDroppingFileToCanvas: boolean;
|
||||
defaultFolders: Record<MODEL_TYPE, string>;
|
||||
maximumChangelogNumber: number;
|
||||
};
|
||||
|
||||
export interface PanelPosition {
|
||||
|
||||
Reference in New Issue
Block a user