feat: add build in progress modal when trying to exit (#3695)
* Changed store to stop the isBuilding state as well * Create Build In Progress modal * Use blocker to stop if its building as well
This commit is contained in:
parent
46a66a57c1
commit
a4dc5381b2
3 changed files with 80 additions and 23 deletions
26
src/frontend/src/modals/buildInProgressModal/index.tsx
Normal file
26
src/frontend/src/modals/buildInProgressModal/index.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import ConfirmationModal from "../confirmationModal";
|
||||||
|
|
||||||
|
export function BuildInProgressModal({
|
||||||
|
onStopBuild,
|
||||||
|
onCancel,
|
||||||
|
}: {
|
||||||
|
onStopBuild: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
open={true}
|
||||||
|
onClose={onCancel}
|
||||||
|
title="Build in Progress"
|
||||||
|
cancelText="Cancel"
|
||||||
|
confirmationText="Stop Build"
|
||||||
|
onConfirm={onStopBuild}
|
||||||
|
onCancel={onCancel}
|
||||||
|
size="x-small"
|
||||||
|
>
|
||||||
|
<ConfirmationModal.Content>
|
||||||
|
The flow is currently building. Do you want to stop the build and exit?
|
||||||
|
</ConfirmationModal.Content>
|
||||||
|
</ConfirmationModal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import { customStringify } from "@/utils/reactflowUtils";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useBlocker, useParams } from "react-router-dom";
|
import { useBlocker, useParams } from "react-router-dom";
|
||||||
import FlowToolbar from "../../components/chatComponent";
|
import FlowToolbar from "../../components/chatComponent";
|
||||||
|
import { BuildInProgressModal } from "../../modals/buildInProgressModal";
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
import useFlowStore from "../../stores/flowStore";
|
import useFlowStore from "../../stores/flowStore";
|
||||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
|
|
@ -23,7 +24,9 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
||||||
customStringify(currentFlow) !== customStringify(currentSavedFlow) &&
|
customStringify(currentFlow) !== customStringify(currentSavedFlow) &&
|
||||||
(currentFlow?.data?.nodes?.length ?? 0) > 0;
|
(currentFlow?.data?.nodes?.length ?? 0) > 0;
|
||||||
|
|
||||||
const blocker = useBlocker(changesNotSaved);
|
const isBuilding = useFlowStore((state) => state.isBuilding);
|
||||||
|
const blocker = useBlocker(changesNotSaved || isBuilding);
|
||||||
|
|
||||||
const version = useDarkStore((state) => state.version);
|
const version = useDarkStore((state) => state.version);
|
||||||
const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage);
|
const setOnFlowPage = useFlowStore((state) => state.setOnFlowPage);
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
@ -41,13 +44,30 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
||||||
|
|
||||||
const autoSaving = useFlowsManagerStore((state) => state.autoSaving);
|
const autoSaving = useFlowsManagerStore((state) => state.autoSaving);
|
||||||
|
|
||||||
|
const stopBuilding = useFlowStore((state) => state.stopBuilding);
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
saveFlow().then(() => (blocker.proceed ? blocker.proceed() : null));
|
saveFlow().then(() => (blocker.proceed ? blocker.proceed() : null));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleStopBuild = () => {
|
||||||
|
stopBuilding();
|
||||||
|
if (blocker.proceed) blocker.proceed();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExit = () => {
|
||||||
|
if (isBuilding) {
|
||||||
|
// Do nothing, let the blocker handle it
|
||||||
|
} else if (changesNotSaved) {
|
||||||
|
if (blocker.proceed) blocker.proceed();
|
||||||
|
} else {
|
||||||
|
navigate("/all");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||||
if (changesNotSaved) {
|
if (changesNotSaved || isBuilding) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.returnValue = ""; // Required for Chrome
|
event.returnValue = ""; // Required for Chrome
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +78,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||||
};
|
};
|
||||||
}, [changesNotSaved, navigate]);
|
}, [changesNotSaved, isBuilding]);
|
||||||
|
|
||||||
// Set flow tab id
|
// Set flow tab id
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -118,26 +138,36 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{blocker.state === "blocked" && currentSavedFlow && (
|
{blocker.state === "blocked" && (
|
||||||
<SaveChangesModal
|
<>
|
||||||
onSave={handleSave}
|
{isBuilding && (
|
||||||
onCancel={() => (blocker.reset ? blocker.reset() : null)}
|
<BuildInProgressModal
|
||||||
onProceed={() => (blocker.proceed ? blocker.proceed() : null)}
|
onStopBuild={handleStopBuild}
|
||||||
flowName={currentSavedFlow.name}
|
onCancel={() => blocker.reset?.()}
|
||||||
unsavedChanges={changesNotSaved}
|
/>
|
||||||
lastSaved={
|
)}
|
||||||
updatedAt
|
{!isBuilding && currentSavedFlow && (
|
||||||
? new Date(updatedAt).toLocaleString("en-US", {
|
<SaveChangesModal
|
||||||
hour: "numeric",
|
onSave={handleSave}
|
||||||
minute: "numeric",
|
onCancel={() => blocker.reset?.()}
|
||||||
second: "numeric",
|
onProceed={handleExit}
|
||||||
month: "numeric",
|
flowName={currentSavedFlow.name}
|
||||||
day: "numeric",
|
unsavedChanges={changesNotSaved}
|
||||||
})
|
lastSaved={
|
||||||
: undefined
|
updatedAt
|
||||||
}
|
? new Date(updatedAt).toLocaleString("en-US", {
|
||||||
autoSave={autoSaving}
|
hour: "numeric",
|
||||||
/>
|
minute: "numeric",
|
||||||
|
second: "numeric",
|
||||||
|
month: "numeric",
|
||||||
|
day: "numeric",
|
||||||
|
})
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
autoSave={autoSaving}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
||||||
isBuilding: false,
|
isBuilding: false,
|
||||||
stopBuilding: () => {
|
stopBuilding: () => {
|
||||||
get().buildController.abort();
|
get().buildController.abort();
|
||||||
|
set({ isBuilding: false });
|
||||||
},
|
},
|
||||||
isPending: true,
|
isPending: true,
|
||||||
setHasIO: (hasIO) => {
|
setHasIO: (hasIO) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue