292 lines
9.0 KiB
TypeScript
292 lines
9.0 KiB
TypeScript
import {
|
|
Button,
|
|
Dialog,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Grid,
|
|
Typography,
|
|
} from "@mui/material";
|
|
import { TimePicker } from "@mui/x-date-pickers";
|
|
import React from "react";
|
|
import { Device, DeviceRelay } from "../api/DeviceApi";
|
|
import { ServerApi } from "../api/ServerApi";
|
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
|
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
|
import { dayjsToTimeOfDay, timeOfDay } from "../utils/DateUtils";
|
|
import { lenValid } from "../utils/StringsUtils";
|
|
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
|
|
import { TextInput } from "../widgets/forms/TextInput";
|
|
import { MultipleSelectInput } from "../widgets/forms/MultipleSelectInput";
|
|
|
|
export function EditDeviceRelaysDialog(p: {
|
|
onClose: () => void;
|
|
relay?: DeviceRelay;
|
|
device: Device;
|
|
onUpdated: () => void;
|
|
}): React.ReactElement {
|
|
const loadingMessage = useLoadingMessage();
|
|
const alert = useAlert();
|
|
const snackbar = useSnackbar();
|
|
|
|
const [relay, setRelay] = React.useState<DeviceRelay>(
|
|
p.relay ?? {
|
|
id: "",
|
|
name: "relay",
|
|
enabled: false,
|
|
priority: 1,
|
|
consumption: 500,
|
|
minimal_downtime: 60 * 5,
|
|
minimal_uptime: 60 * 5,
|
|
depends_on: [],
|
|
conflicts_with: [],
|
|
}
|
|
);
|
|
|
|
const creating = !p.relay;
|
|
|
|
const onSubmit = async () => {
|
|
try {
|
|
loadingMessage.show(
|
|
`${creating ? "Creating" : "Updating"} relay information`
|
|
);
|
|
|
|
// TODO
|
|
|
|
snackbar(
|
|
`The relay have been successfully ${creating ? "created" : "updated"}!`
|
|
);
|
|
p.onUpdated();
|
|
} catch (e) {
|
|
console.error("Failed to update device relay information!" + e);
|
|
alert(`Failed to ${creating ? "create" : "update"} relay! ${e}`);
|
|
} finally {
|
|
loadingMessage.hide();
|
|
}
|
|
};
|
|
|
|
const canSubmit =
|
|
lenValid(relay.name, ServerApi.Config.constraints.relay_name_len) &&
|
|
relay.priority >= 0;
|
|
|
|
return (
|
|
<Dialog open>
|
|
<DialogTitle>Edit relay information</DialogTitle>
|
|
<DialogContent>
|
|
<DialogFormTitle>General info</DialogFormTitle>
|
|
<Grid container spacing={2}>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Relay name"
|
|
value={relay.name}
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
name: v ?? "",
|
|
};
|
|
})
|
|
}
|
|
size={ServerApi.Config.constraints.dev_name_len}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<CheckboxInput
|
|
editable
|
|
label="Enable relay"
|
|
checked={relay.enabled}
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
enabled: v,
|
|
};
|
|
})
|
|
}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Priority"
|
|
value={relay.priority.toString()}
|
|
type="number"
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
priority: Number(v) ?? 0,
|
|
};
|
|
})
|
|
}
|
|
size={ServerApi.Config.constraints.relay_priority}
|
|
helperText="Relay priority when selecting relays to turn on. 0 = lowest priority"
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Consumption"
|
|
value={relay.consumption.toString()}
|
|
type="number"
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
consumption: Number(v) ?? 0,
|
|
};
|
|
})
|
|
}
|
|
size={ServerApi.Config.constraints.relay_consumption}
|
|
helperText="Estimated consumption of device powered by relay"
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Minimal uptime"
|
|
value={relay.minimal_uptime.toString()}
|
|
type="number"
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
minimal_uptime: Number(v) ?? 0,
|
|
};
|
|
})
|
|
}
|
|
size={ServerApi.Config.constraints.relay_minimal_uptime}
|
|
helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Minimal downtime"
|
|
value={relay.minimal_downtime.toString()}
|
|
type="number"
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
minimal_downtime: Number(v) ?? 0,
|
|
};
|
|
})
|
|
}
|
|
size={ServerApi.Config.constraints.relay_minimal_downtime}
|
|
helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
<DialogFormTitle>Daily runtime</DialogFormTitle>
|
|
<Grid container spacing={2}>
|
|
<Grid item xs={6}>
|
|
<CheckboxInput
|
|
editable
|
|
label="Enable minimal runtime"
|
|
checked={!!relay.daily_runtime}
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
daily_runtime: v
|
|
? { reset_time: 0, min_runtime: 3600, catch_up_hours: [] }
|
|
: undefined,
|
|
};
|
|
})
|
|
}
|
|
/>
|
|
</Grid>
|
|
|
|
{!!relay.daily_runtime && (
|
|
<>
|
|
<Grid item xs={6}>
|
|
<TextInput
|
|
editable
|
|
label="Minimal daily runtime"
|
|
value={relay.daily_runtime!.min_runtime.toString()}
|
|
type="number"
|
|
onValueChange={(v) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
daily_runtime: {
|
|
...r.daily_runtime!,
|
|
min_runtime: Number(v),
|
|
},
|
|
};
|
|
})
|
|
}
|
|
size={
|
|
ServerApi.Config.constraints.relay_daily_minimal_runtime
|
|
}
|
|
helperText="Minimum time, in seconds, that this relay should run each day"
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<TimePicker
|
|
label="Reset time"
|
|
value={timeOfDay(relay.daily_runtime!.reset_time)}
|
|
onChange={(d) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
daily_runtime: {
|
|
...r.daily_runtime!,
|
|
reset_time: d ? dayjsToTimeOfDay(d) : 0,
|
|
},
|
|
};
|
|
})
|
|
}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<MultipleSelectInput
|
|
label="Catchup hours"
|
|
helperText="The hours during which the relay should be turned on to reach expected runtime"
|
|
values={Array.apply(null, Array(24)).map((_y, i) => {
|
|
return {
|
|
label: `${i.toString().padStart(2, "0")}:00`,
|
|
value: i,
|
|
};
|
|
})}
|
|
selected={relay.daily_runtime!.catch_up_hours}
|
|
onChange={(d) =>
|
|
setRelay((r) => {
|
|
return {
|
|
...r,
|
|
daily_runtime: {
|
|
...r.daily_runtime!,
|
|
catch_up_hours: d,
|
|
},
|
|
};
|
|
})
|
|
}
|
|
/>
|
|
</Grid>
|
|
</>
|
|
)}
|
|
</Grid>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={p.onClose}>Cancel</Button>
|
|
<Button onClick={onSubmit} autoFocus disabled={!canSubmit}>
|
|
Submit
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
function DialogFormTitle(p: React.PropsWithChildren): React.ReactElement {
|
|
return (
|
|
<>
|
|
<span style={{ height: "2px" }}></span>
|
|
<Typography variant="h6">{p.children}</Typography>
|
|
</>
|
|
);
|
|
}
|