Merge branch 'werk' into dev_environment

This commit is contained in:
Carter 2026-07-20 16:11:23 -06:00
commit 48a4750510
5 changed files with 53 additions and 71 deletions

View file

@ -503,10 +503,14 @@ export default function ComponentForm(props: Props) {
};
const isOffsetValid = (min?: number, max?: number) => {
let minimum = min ?? modeDictionaryValue(compMode?.mode.dictionaryB, "min") ?? 0;
let maximum = max ?? modeDictionaryValue(compMode?.mode.dictionaryB, "max") ?? 100;
const minimum = min ?? modeDictionaryValue(compMode?.mode.dictionaryB, "min") ?? 0;
const maximum = max ?? modeDictionaryValue(compMode?.mode.dictionaryB, "max") ?? 100;
if (compMode && form.component.settings.calibrate) {
return Number(form.offset) <= maximum && Number(form.offset) >= minimum;
const offset = Number(form.offset);
const meetsMinimum = compMode.mode.exclusiveMinimumB
? offset > minimum
: offset >= minimum;
return !isNaN(offset) && offset <= maximum && meetsMinimum;
}
return !isNaN(Number(form.offset));
};
@ -850,6 +854,11 @@ export default function ComponentForm(props: Props) {
onFocus={selectText}
margin="normal"
fullWidth
inputProps={
compMode.mode.stepB !== undefined
? { step: compMode.mode.stepB }
: undefined
}
type={compMode.mode.entryB}
variant="outlined">
{compMode.mode.entryB === "select" &&

View file

@ -121,10 +121,12 @@
],
"labelB": "To Node Id",
"entryB": "number",
"exclusiveMinimumB": true,
"stepB": "any",
"dictionaryB": [
{
"key": "min",
"value": 1,
"value": 0,
"restricted": false
},
{

View file

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

View file

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

View file

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