mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
web: add redo
This commit is contained in:
@@ -44,11 +44,13 @@ const CaseBuilder = () => {
|
|||||||
return processedScenario!!;
|
return processedScenario!!;
|
||||||
});
|
});
|
||||||
const [undoStack, setUndoStack] = useState<UnitCommitmentScenario[]>([]);
|
const [undoStack, setUndoStack] = useState<UnitCommitmentScenario[]>([]);
|
||||||
|
const [redoStack, setRedoStack] = useState<UnitCommitmentScenario[]>([]);
|
||||||
const [toastMessage, setToastMessage] = useState<string>("");
|
const [toastMessage, setToastMessage] = useState<string>("");
|
||||||
|
|
||||||
const setAndSaveScenario = (
|
const setAndSaveScenario = (
|
||||||
newScenario: UnitCommitmentScenario,
|
newScenario: UnitCommitmentScenario,
|
||||||
updateUndoStack = true,
|
updateUndoStack = true,
|
||||||
|
clearRedoStack = true,
|
||||||
) => {
|
) => {
|
||||||
if (updateUndoStack) {
|
if (updateUndoStack) {
|
||||||
const newUndoStack = [...undoStack, scenario];
|
const newUndoStack = [...undoStack, scenario];
|
||||||
@@ -57,6 +59,9 @@ const CaseBuilder = () => {
|
|||||||
}
|
}
|
||||||
setUndoStack(newUndoStack);
|
setUndoStack(newUndoStack);
|
||||||
}
|
}
|
||||||
|
if (clearRedoStack) {
|
||||||
|
setRedoStack([]);
|
||||||
|
}
|
||||||
setScenario(newScenario);
|
setScenario(newScenario);
|
||||||
localStorage.setItem("scenario", JSON.stringify(newScenario));
|
localStorage.setItem("scenario", JSON.stringify(newScenario));
|
||||||
};
|
};
|
||||||
@@ -90,8 +95,19 @@ const CaseBuilder = () => {
|
|||||||
|
|
||||||
const onUndo = () => {
|
const onUndo = () => {
|
||||||
if (undoStack.length === 0) return;
|
if (undoStack.length === 0) return;
|
||||||
|
const newRedoStack = [...redoStack, scenario];
|
||||||
|
if (newRedoStack.length > 25) {
|
||||||
|
newRedoStack.splice(0, newRedoStack.length - 25);
|
||||||
|
}
|
||||||
|
setRedoStack(newRedoStack);
|
||||||
setUndoStack(undoStack.slice(0, -1));
|
setUndoStack(undoStack.slice(0, -1));
|
||||||
setAndSaveScenario(undoStack[undoStack.length - 1]!, false);
|
setAndSaveScenario(undoStack[undoStack.length - 1]!, false, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRedo = () => {
|
||||||
|
if (redoStack.length === 0) return;
|
||||||
|
setRedoStack(redoStack.slice(0, -1));
|
||||||
|
setAndSaveScenario(redoStack[redoStack.length - 1]!, true, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSolve = async () => {
|
const onSolve = async () => {
|
||||||
@@ -128,7 +144,10 @@ const CaseBuilder = () => {
|
|||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
onUndo={onUndo}
|
onUndo={onUndo}
|
||||||
|
onRedo={onRedo}
|
||||||
onSolve={onSolve}
|
onSolve={onSolve}
|
||||||
|
canUndo={undoStack.length > 0}
|
||||||
|
canRedo={redoStack.length > 0}
|
||||||
/>
|
/>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<Parameters
|
<Parameters
|
||||||
|
|||||||
@@ -9,14 +9,17 @@ import SiteHeaderButton from "../Common/Buttons/SiteHeaderButton";
|
|||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import FileUploadElement from "../Common/Buttons/FileUploadElement";
|
import FileUploadElement from "../Common/Buttons/FileUploadElement";
|
||||||
import { UnitCommitmentScenario } from "../../core/Data/types";
|
import { UnitCommitmentScenario } from "../../core/Data/types";
|
||||||
import { faDownload, faGear, faRotateLeft, faTrash, faUpload } from "@fortawesome/free-solid-svg-icons";
|
import { faDownload, faGear, faRotateLeft, faRotateRight, faTrash, faUpload } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
onClear: () => void;
|
onClear: () => void;
|
||||||
onSave: () => void;
|
onSave: () => void;
|
||||||
onUndo: () => void;
|
onUndo: () => void;
|
||||||
|
onRedo: () => void;
|
||||||
onLoad: (data: UnitCommitmentScenario) => void;
|
onLoad: (data: UnitCommitmentScenario) => void;
|
||||||
onSolve: () => void;
|
onSolve: () => void;
|
||||||
|
canUndo: boolean;
|
||||||
|
canRedo: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Header(props: HeaderProps) {
|
function Header(props: HeaderProps) {
|
||||||
@@ -44,6 +47,13 @@ function Header(props: HeaderProps) {
|
|||||||
title="Undo"
|
title="Undo"
|
||||||
icon={faRotateLeft}
|
icon={faRotateLeft}
|
||||||
onClick={props.onUndo}
|
onClick={props.onUndo}
|
||||||
|
disabled={!props.canUndo}
|
||||||
|
/>
|
||||||
|
<SiteHeaderButton
|
||||||
|
title="Redo"
|
||||||
|
icon={faRotateRight}
|
||||||
|
onClick={props.onRedo}
|
||||||
|
disabled={!props.canRedo}
|
||||||
/>
|
/>
|
||||||
<SiteHeaderButton
|
<SiteHeaderButton
|
||||||
title="Clear"
|
title="Clear"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.SiteHeaderButton {
|
.SiteHeaderButton {
|
||||||
padding: 6px 20px;
|
padding: 6px 16px;
|
||||||
margin: 0 0 0 0px;
|
margin: 0 0 0 0;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
border: var(--box-border);
|
border: var(--box-border);
|
||||||
box-shadow: var(--box-shadow);
|
box-shadow: var(--box-shadow);
|
||||||
@@ -59,3 +59,9 @@
|
|||||||
.primary:active {
|
.primary:active {
|
||||||
background: color-mix(in hsl, #000, var(--primary) 90%);
|
background: color-mix(in hsl, #000, var(--primary) 90%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
color: var(--contrast-20);
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,19 +13,23 @@ function SiteHeaderButton({
|
|||||||
icon,
|
icon,
|
||||||
onClick,
|
onClick,
|
||||||
variant = "light",
|
variant = "light",
|
||||||
|
disabled = false,
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
icon: IconDefinition;
|
icon: IconDefinition;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
variant?: "light" | "primary";
|
variant?: "light" | "primary";
|
||||||
|
disabled?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const variantClass = variant === "primary" ? styles.primary : styles.light;
|
const variantClass = variant === "primary" ? styles.primary : styles.light;
|
||||||
|
const disabledClass = disabled ? styles.disabled : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={`${styles.SiteHeaderButton} ${variantClass}`}
|
className={`${styles.SiteHeaderButton} ${variantClass} ${disabledClass}`}
|
||||||
title={title}
|
title={title}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={icon} />
|
<FontAwesomeIcon icon={icon} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user