settings forms to prevent it from revert user changed

This commit is contained in:
Carter 2026-07-17 14:58:31 -06:00
parent 80750bd3e9
commit ddd0b5062b
3 changed files with 38 additions and 67 deletions

View file

@ -213,15 +213,13 @@ export default function ComponentSettings(props: Props) {
) )
); );
setFormComponent(initComponent); setFormComponent(initComponent);
setExcludedNodes(initComponent.settings.excludedNodes) setExcludedNodes(cloneDeep(initComponent.settings.excludedNodes));
}, [props.component, componentTypeOptions]); }, [props.component, componentTypeOptions]);
useEffect(() => { useEffect(() => {
if (isDialogOpen && prevIsDialogOpen) return; if (!isDialogOpen || prevIsDialogOpen) return;
if (props.component !== prevComponent || isDialogOpen !== prevIsDialogOpen) {
init(); init();
} }, [init, isDialogOpen, prevIsDialogOpen]);
}, [props.component, prevComponent, init, isDialogOpen, prevIsDialogOpen]);
const close = () => { const close = () => {
closeDialogCallback(); closeDialogCallback();

View file

@ -31,6 +31,7 @@ import LinearMutationBuilder from "common/LinearMutationBuilder";
import { makeStyles } from "@mui/styles"; import { makeStyles } from "@mui/styles";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import CancelSubmit from "common/CancelSubmit"; import CancelSubmit from "common/CancelSubmit";
import { cloneDeep } from "lodash";
interface TabPanelProps { interface TabPanelProps {
children?: React.ReactNode; children?: React.ReactNode;
@ -94,7 +95,6 @@ export default function DeviceSettings(props: Props) {
const { success, error } = useSnackbar(); const { success, error } = useSnackbar();
const deviceAPI = useDeviceAPI(); const deviceAPI = useDeviceAPI();
const { device, isDialogOpen, closeDialogCallback, canEdit, refreshCallback, components } = props; const { device, isDialogOpen, closeDialogCallback, canEdit, refreshCallback, components } = props;
const prevDevice = usePrevious(device);
const prevIsDialogOpen = usePrevious(isDialogOpen); const prevIsDialogOpen = usePrevious(isDialogOpen);
const [deviceForm, setDeviceForm] = useState<Device>(deviceFromForm(Device.clone(device))); const [deviceForm, setDeviceForm] = useState<Device>(deviceFromForm(Device.clone(device)));
const [isRemoveDeviceDialogOpen, setIsRemoveDeviceDialogOpen] = useState<boolean>(false); const [isRemoveDeviceDialogOpen, setIsRemoveDeviceDialogOpen] = useState<boolean>(false);
@ -103,7 +103,9 @@ export default function DeviceSettings(props: Props) {
const [compExtTwo, setCompExtTwo] = useState(""); const [compExtTwo, setCompExtTwo] = useState("");
const [compExtThree, setCompExtThree] = useState(""); const [compExtThree, setCompExtThree] = useState("");
const [currentTab, setCurrentTab] = useState(0); const [currentTab, setCurrentTab] = useState(0);
const [linearMutations, setLinearMutations] = useState<pond.LinearMutation[]>([]); const [linearMutations, setLinearMutations] = useState<pond.LinearMutation[]>(
cloneDeep(device.settings.mutations)
);
const [componentsByDevice, setComponentsByDevice] = useState<Map<string, Component[]>>( const [componentsByDevice, setComponentsByDevice] = useState<Map<string, Component[]>>(
new Map<string, Component[]>() new Map<string, Component[]>()
); );
@ -111,28 +113,22 @@ export default function DeviceSettings(props: Props) {
const [existingMutation, setExistingMutation] = useState<pond.LinearMutation>(); const [existingMutation, setExistingMutation] = useState<pond.LinearMutation>();
useEffect(() => { useEffect(() => {
if (isDialogOpen && prevIsDialogOpen) return; if (!isDialogOpen || prevIsDialogOpen) return;
if (prevDevice !== device || isDialogOpen !== prevIsDialogOpen) {
setDeviceForm(deviceFromForm(Device.clone(props.device))); const settingsForm = deviceFromForm(Device.clone(device));
if (device.settings.extensionComponents[0]) { setDeviceForm(settingsForm);
setCompExtOne(device.settings.extensionComponents[0]); setSleeps(settingsForm.settings.sleepDurationS > 0);
} setCompExtOne(settingsForm.settings.extensionComponents[0] ?? "");
if (device.settings.extensionComponents[1]) { setCompExtTwo(settingsForm.settings.extensionComponents[1] ?? "");
setCompExtTwo(device.settings.extensionComponents[1]); setCompExtThree(settingsForm.settings.extensionComponents[2] ?? "");
} setLinearMutations(cloneDeep(settingsForm.settings.mutations));
if (device.settings.extensionComponents[2]) {
setCompExtThree(device.settings.extensionComponents[2]);
}
if (device.settings.mutations) {
setLinearMutations(device.settings.mutations);
}
if (components) { if (components) {
let cbd = new Map<string, Component[]>(); let cbd = new Map<string, Component[]>();
cbd.set(device.id().toString(), components); cbd.set(settingsForm.id().toString(), components);
setComponentsByDevice(cbd); setComponentsByDevice(cbd);
} }
} }, [device, components, isDialogOpen, prevIsDialogOpen]);
}, [device, prevDevice, props.device, components, isDialogOpen, prevIsDialogOpen]);
const close = () => { const close = () => {
closeDialogCallback(); closeDialogCallback();
@ -147,7 +143,7 @@ export default function DeviceSettings(props: Props) {
const minCheckPeriodS = (): number => { const minCheckPeriodS = (): number => {
let defaultPeriod = 60; let defaultPeriod = 60;
switch (device.settings.platform) { switch (deviceForm.settings.platform) {
case pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON: case pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON:
return user.hasFeature("admin") ? defaultPeriod : 300; return user.hasFeature("admin") ? defaultPeriod : 300;
default: default:
@ -319,7 +315,7 @@ export default function DeviceSettings(props: Props) {
id="name" id="name"
name="name" name="name"
label="Name" label="Name"
defaultValue={deviceForm.settings.name} value={deviceForm.settings.name}
onChange={changeName} onChange={changeName}
margin="normal" margin="normal"
variant="outlined" variant="outlined"
@ -332,7 +328,7 @@ export default function DeviceSettings(props: Props) {
id="description" id="description"
name="description" name="description"
label="Description" label="Description"
defaultValue={deviceForm.settings.description} value={deviceForm.settings.description}
onChange={changeDescription} onChange={changeDescription}
multiline multiline
rows={2} rows={2}
@ -550,8 +546,8 @@ export default function DeviceSettings(props: Props) {
const mutationsContent = () => { const mutationsContent = () => {
let mutations: JSX.Element[] = []; let mutations: JSX.Element[] = [];
if (device.settings.mutations) { if (linearMutations) {
device.settings.mutations.forEach((mut, i) => { linearMutations.forEach((mut, i) => {
mutations.push( mutations.push(
<ListItem key={"mutation" + i}> <ListItem key={"mutation" + i}>
<Grid <Grid
@ -568,9 +564,7 @@ export default function DeviceSettings(props: Props) {
variant="contained" variant="contained"
style={{ backgroundColor: "red" }} style={{ backgroundColor: "red" }}
onClick={() => { onClick={() => {
let lm = linearMutations; setLinearMutations(linearMutations.filter((_, index) => index !== i));
lm.splice(i, 1);
setLinearMutations([...lm]);
}}> }}>
Remove Remove
</Button> </Button>
@ -696,9 +690,7 @@ export default function DeviceSettings(props: Props) {
setNewMutationDialog(false); setNewMutationDialog(false);
}} }}
onSubmit={newMutation => { onSubmit={newMutation => {
let lm = linearMutations; setLinearMutations([...linearMutations, newMutation]);
lm.push(newMutation);
setLinearMutations(lm);
}} }}
/> />
</React.Fragment> </React.Fragment>

View file

@ -32,7 +32,6 @@ import moment from "moment-timezone";
import { import {
componentIDToString, componentIDToString,
emptyComponentId, emptyComponentId,
getComponentIDString,
sameComponentID, sameComponentID,
stringToComponentId stringToComponentId
} from "pbHelpers/Component"; } from "pbHelpers/Component";
@ -130,9 +129,6 @@ export default function InteractionSettings(props: Props) {
} = props; } = props;
const theme = useTheme(); const theme = useTheme();
const { success, error } = useSnackbar(); const { success, error } = useSnackbar();
const prevInitialInteraction = usePrevious(initialInteraction);
const prevComponents = usePrevious(components);
const prevInitialComponent = usePrevious(initialComponent);
const prevIsDialogOpen = usePrevious(isDialogOpen); const prevIsDialogOpen = usePrevious(isDialogOpen);
const classes = useStyles(); const classes = useStyles();
const [{ user, as }] = useGlobalState(); const [{ user, as }] = useGlobalState();
@ -167,7 +163,7 @@ export default function InteractionSettings(props: Props) {
const setDefaultState = useCallback(() => { const setDefaultState = useCallback(() => {
let interaction = getDefaultInteraction(); let interaction = getDefaultInteraction();
if (initialInteraction && mode === "update") { if (initialInteraction && mode === "update") {
interaction = initialInteraction; interaction = Interaction.clone(initialInteraction);
if (interaction.settings.subtype === 0 || interaction.settings.subtype === 1) { if (interaction.settings.subtype === 0 || interaction.settings.subtype === 1) {
setSubtypeDropdown(interaction.settings.subtype); setSubtypeDropdown(interaction.settings.subtype);
} else { } else {
@ -223,7 +219,7 @@ export default function InteractionSettings(props: Props) {
setDutyCycle(interactionResult.dutyCycle.toString()); setDutyCycle(interactionResult.dutyCycle.toString());
setMappedComponents(mappedComponents); setMappedComponents(mappedComponents);
setInteraction(interaction); setInteraction(interaction);
}, [components, initialComponent, initialConditions, initialInteraction, mode, /*sensor*/]); }, [components, initialComponent, initialConditions, initialInteraction, mode, sensor, user]);
const availableSources = () => { const availableSources = () => {
return components.filter(component => isSource(component.settings.type)); return components.filter(component => isSource(component.settings.type));
@ -233,27 +229,12 @@ export default function InteractionSettings(props: Props) {
if (user && user.settings.timezone) { if (user && user.settings.timezone) {
setTimezone(user.settings.timezone); setTimezone(user.settings.timezone);
} }
if (isDialogOpen && prevIsDialogOpen) return; }, [user]);
if (
prevInitialInteraction !== initialInteraction || useEffect(() => {
(prevComponents && prevComponents.length !== components.length) || if (!isDialogOpen || prevIsDialogOpen) return;
getComponentIDString(prevInitialComponent) !== getComponentIDString(initialComponent) ||
isDialogOpen !== prevIsDialogOpen
) {
setDefaultState(); setDefaultState();
} }, [isDialogOpen, prevIsDialogOpen, setDefaultState]);
}, [
components.length,
initialComponent,
initialInteraction,
prevComponents,
prevInitialComponent,
prevInitialInteraction,
setDefaultState,
user,
isDialogOpen,
prevIsDialogOpen
]);
const getAvailableSinks = () => { const getAvailableSinks = () => {
let type = or(interaction.settings.result, pond.InteractionResult.create()).type; let type = or(interaction.settings.result, pond.InteractionResult.create()).type;