mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
@@ -25,9 +25,9 @@
|
|||||||
"@mui/icons-material": "^5.11.11",
|
"@mui/icons-material": "^5.11.11",
|
||||||
"@mui/material": "^5.11.11",
|
"@mui/material": "^5.11.11",
|
||||||
"@remix-run/router": "^1.3.3",
|
"@remix-run/router": "^1.3.3",
|
||||||
"@table-library/react-table-library": "4.0.28",
|
"@table-library/react-table-library": "4.0.29",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"@types/node": "^18.14.2",
|
"@types/node": "^18.14.4",
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import { ScheduleItem, ScheduleFlag } from './types';
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
export const APIURL = window.location.origin + '/api/';
|
|
||||||
|
|
||||||
const SettingsScheduler: FC = () => {
|
const SettingsScheduler: FC = () => {
|
||||||
const { LL, locale } = useI18nContext();
|
const { LL, locale } = useI18nContext();
|
||||||
@@ -69,7 +68,8 @@ const SettingsScheduler: FC = () => {
|
|||||||
time: '12:00',
|
time: '12:00',
|
||||||
cmd: '',
|
cmd: '',
|
||||||
value: '',
|
value: '',
|
||||||
description: ''
|
description: '',
|
||||||
|
o_id: ''
|
||||||
};
|
};
|
||||||
const [schedule, setSchedule] = useState<ScheduleItem[]>([emptySchedule]);
|
const [schedule, setSchedule] = useState<ScheduleItem[]>([emptySchedule]);
|
||||||
const [scheduleItem, setScheduleItem] = useState<ScheduleItem>();
|
const [scheduleItem, setScheduleItem] = useState<ScheduleItem>();
|
||||||
@@ -97,7 +97,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
|
|
||||||
const schedule_theme = useTheme({
|
const schedule_theme = useTheme({
|
||||||
Table: `
|
Table: `
|
||||||
--data-table-library_grid-template-columns: 140px 48px 324px 72px 240px repeat(1, minmax(100px, 1fr));
|
--data-table-library_grid-template-columns: 152px 36px 324px 72px 240px repeat(1, minmax(100px, 1fr));
|
||||||
`,
|
`,
|
||||||
BaseRow: `
|
BaseRow: `
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -106,22 +106,18 @@ const SettingsScheduler: FC = () => {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
BaseCell: `
|
BaseCell: `
|
||||||
|
&:nth-of-type(1) {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
&:nth-of-type(2) {
|
&:nth-of-type(2) {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
},
|
}
|
||||||
&:nth-of-type(3) {
|
|
||||||
text-align: center;
|
|
||||||
},
|
|
||||||
&:nth-of-type(4) {
|
|
||||||
text-align: center;
|
|
||||||
},
|
|
||||||
`,
|
`,
|
||||||
HeaderRow: `
|
HeaderRow: `
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
color: #90CAF9;
|
color: #90CAF9;
|
||||||
.th {
|
.th {
|
||||||
padding: 8px;
|
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
@@ -132,7 +128,6 @@ const SettingsScheduler: FC = () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.td {
|
.td {
|
||||||
padding: 8px;
|
|
||||||
border-top: 1px solid #565656;
|
border-top: 1px solid #565656;
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
}
|
}
|
||||||
@@ -325,13 +320,8 @@ const SettingsScheduler: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateScheduleItem = () => {
|
const updateScheduleItem = () => {
|
||||||
if (scheduleItem) {
|
setSchedule([...schedule.filter((si) => creating || si.o_id !== scheduleItem.o_id), scheduleItem]);
|
||||||
const new_schedule = [...schedule.filter((si) => si.id !== scheduleItem.id), scheduleItem].sort((a, b) =>
|
setScheduleItem(undefined);
|
||||||
a.time.localeCompare(b.time)
|
|
||||||
);
|
|
||||||
setSchedule(new_schedule);
|
|
||||||
setScheduleItem(undefined);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderSchedule = () => {
|
const renderSchedule = () => {
|
||||||
@@ -340,7 +330,11 @@ const SettingsScheduler: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table data={{ nodes: schedule.filter((si) => !si.deleted) }} theme={schedule_theme} layout={{ custom: true }}>
|
<Table
|
||||||
|
data={{ nodes: schedule.filter((si) => !si.deleted).sort((a, b) => a.time.localeCompare(b.time)) }}
|
||||||
|
theme={schedule_theme}
|
||||||
|
layout={{ custom: true }}
|
||||||
|
>
|
||||||
{(tableList: any) => (
|
{(tableList: any) => (
|
||||||
<>
|
<>
|
||||||
<Header>
|
<Header>
|
||||||
@@ -414,7 +408,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
if (scheduleItem) {
|
if (scheduleItem) {
|
||||||
try {
|
try {
|
||||||
setFieldErrors(undefined);
|
setFieldErrors(undefined);
|
||||||
await validate(schedulerItemValidation(schedule, creating), scheduleItem);
|
await validate(schedulerItemValidation(schedule, scheduleItem.o_id), scheduleItem);
|
||||||
updateScheduleItem();
|
updateScheduleItem();
|
||||||
} catch (errors: any) {
|
} catch (errors: any) {
|
||||||
setFieldErrors(errors);
|
setFieldErrors(errors);
|
||||||
@@ -422,44 +416,47 @@ const SettingsScheduler: FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeDialog = () => {
|
||||||
|
setScheduleItem(undefined);
|
||||||
|
setFieldErrors();
|
||||||
|
};
|
||||||
|
|
||||||
const renderEditSchedule = () => {
|
const renderEditSchedule = () => {
|
||||||
if (scheduleItem) {
|
if (scheduleItem) {
|
||||||
return (
|
return (
|
||||||
<Dialog open={!!scheduleItem} onClose={() => setScheduleItem(undefined)}>
|
<Dialog open={!!scheduleItem} onClose={() => closeDialog()}>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{creating ? LL.ADD(0) + ' ' + LL.NEW() + ' ' + LL.SCHEDULE() : LL.EDIT() + " '" + scheduleItem.id + "'"}
|
{creating ? LL.ADD(0) + ' ' + LL.NEW() + ' ' + LL.SCHEDULE() : LL.EDIT() + " '" + scheduleItem.id + "'"}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="id"
|
||||||
|
label={LL.NAME()}
|
||||||
|
value={scheduleItem.id}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
sx={{ width: '60ch' }}
|
||||||
|
onChange={updateValue(setScheduleItem)}
|
||||||
|
/>
|
||||||
{creating ? (
|
{creating ? (
|
||||||
<>
|
<RadioGroup
|
||||||
<ValidatedTextField
|
row
|
||||||
fieldErrors={fieldErrors}
|
name="schedule-type"
|
||||||
name="id"
|
onChange={(event) => {
|
||||||
label={LL.NAME()}
|
if ((event.target as HTMLInputElement).value === 't') {
|
||||||
value={scheduleItem.id}
|
scheduleItem.flags = ScheduleFlag.SCHEDULE_TIMER;
|
||||||
fullWidth
|
scheduleItem.time = '01:00';
|
||||||
margin="normal"
|
} else {
|
||||||
sx={{ width: '60ch' }}
|
scheduleItem.flags = 0;
|
||||||
onChange={updateValue(setScheduleItem)}
|
}
|
||||||
/>
|
updateValue(setScheduleItem);
|
||||||
<RadioGroup
|
setFlags(['']); // refresh screen
|
||||||
row
|
}}
|
||||||
name="schedule-type"
|
>
|
||||||
onChange={(event) => {
|
<FormControlLabel value="w" control={<Radio />} label={LL.WEEKLY()} />
|
||||||
if ((event.target as HTMLInputElement).value === 't') {
|
<FormControlLabel value="t" control={<Radio />} label={LL.TIMER()} />
|
||||||
scheduleItem.flags = ScheduleFlag.SCHEDULE_TIMER;
|
</RadioGroup>
|
||||||
scheduleItem.time = '01:00';
|
|
||||||
} else {
|
|
||||||
scheduleItem.flags = 0;
|
|
||||||
}
|
|
||||||
updateValue(setScheduleItem);
|
|
||||||
setFlags(['']); // refresh screen
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormControlLabel value="w" control={<Radio />} label={LL.WEEKLY()} />
|
|
||||||
<FormControlLabel value="t" control={<Radio />} label={LL.TIMER()} />
|
|
||||||
</RadioGroup>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<Typography variant="h6" color="primary" sx={{ pb: 1 }}>
|
<Typography variant="h6" color="primary" sx={{ pb: 1 }}>
|
||||||
{LL.TYPE()}: {scheduleItem.flags & ScheduleFlag.SCHEDULE_TIMER ? LL.TIMER() : LL.WEEKLY()}
|
{LL.TYPE()}: {scheduleItem.flags & ScheduleFlag.SCHEDULE_TIMER ? LL.TIMER() : LL.WEEKLY()}
|
||||||
@@ -536,16 +533,11 @@ const SettingsScheduler: FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button startIcon={<CancelIcon />} variant="outlined" onClick={() => closeDialog()} color="secondary">
|
||||||
startIcon={<CancelIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => setScheduleItem(undefined)}
|
|
||||||
color="secondary"
|
|
||||||
>
|
|
||||||
{LL.CANCEL()}
|
{LL.CANCEL()}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<DoneIcon />}
|
startIcon={creating ? <AddIcon /> : <DoneIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => validateScheduleItem()}
|
onClick={() => validateScheduleItem()}
|
||||||
|
|||||||
@@ -85,26 +85,26 @@ export const createSettingsValidator = (settings: Settings) =>
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schedulerItemValidation = (schedule: ScheduleItem[], creating: boolean) =>
|
export const schedulerItemValidation = (schedule: ScheduleItem[], o_id: string) =>
|
||||||
new Schema({
|
new Schema({
|
||||||
id: [
|
id: [
|
||||||
{ required: true, message: 'Name is required' },
|
{ required: true, message: 'Name is required' },
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
pattern: /^[a-zA-Z0-9_\\.]{1,24}$/,
|
pattern: /^[a-zA-Z0-9_\\.]{1,15}$/,
|
||||||
message: "Must be 1-24 characters: alpha numeric, '_' or '.'"
|
message: "Must be 1-15 characters: alpha numeric, '_' or '.'"
|
||||||
},
|
},
|
||||||
...(creating ? [uniqueIDValidator(schedule)] : [])
|
...[uniqueIDValidator(schedule, o_id)]
|
||||||
],
|
],
|
||||||
cmd: [
|
cmd: [
|
||||||
{ required: true, message: 'Command is required' },
|
{ required: true, message: 'Command is required' },
|
||||||
{ type: 'string', min: 1, max: 32, message: 'Command must be 1-32 characters' }
|
{ type: 'string', min: 1, max: 64, message: 'Command must be 1-64 characters' }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
export const uniqueIDValidator = (schedule: ScheduleItem[]) => ({
|
export const uniqueIDValidator = (schedule: ScheduleItem[], o_id: string) => ({
|
||||||
validator(rule: InternalRuleItem, id: string, callback: (error?: string) => void) {
|
validator(rule: InternalRuleItem, id: string, callback: (error?: string) => void) {
|
||||||
if (id && schedule.find((si) => si.id === id)) {
|
if (id && o_id !== id && schedule.find((si) => si.id === id)) {
|
||||||
callback('Name already in use');
|
callback('Name already in use');
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
|
|||||||
@@ -1165,9 +1165,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@table-library/react-table-library@npm:4.0.28":
|
"@table-library/react-table-library@npm:4.0.29":
|
||||||
version: 4.0.28
|
version: 4.0.29
|
||||||
resolution: "@table-library/react-table-library@npm:4.0.28"
|
resolution: "@table-library/react-table-library@npm:4.0.29"
|
||||||
dependencies:
|
dependencies:
|
||||||
clsx: 1.1.1
|
clsx: 1.1.1
|
||||||
react-virtualized-auto-sizer: 1.0.7
|
react-virtualized-auto-sizer: 1.0.7
|
||||||
@@ -1176,7 +1176,7 @@ __metadata:
|
|||||||
"@emotion/react": ">= 11"
|
"@emotion/react": ">= 11"
|
||||||
react: ">=16.8.0"
|
react: ">=16.8.0"
|
||||||
react-dom: ">=16.8.0"
|
react-dom: ">=16.8.0"
|
||||||
checksum: de4e429d5659e22b101cfef8aafb430fcad20a20af803982e50ed0ba070968c0bd5a3ef02e64c34eb1b40fb7415f417cf3c30b483b0b1bbad9099f15d6489a8d
|
checksum: f0daace88cc8fe20d23a7f0430c293cd737ae9d0f5deb8ef17eec238917ae0fd1d196453e2a8549cdd6e92533c4e2469dc0aeb6333555502b8b1e5df4ab2bdf4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1238,10 +1238,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:^18.14.2":
|
"@types/node@npm:^18.14.4":
|
||||||
version: 18.14.2
|
version: 18.14.4
|
||||||
resolution: "@types/node@npm:18.14.2"
|
resolution: "@types/node@npm:18.14.4"
|
||||||
checksum: 53c07e721f6ae33de71306f6a0b75dae6066a4f55bd5484c93bd59ff25f0c5f004ceafeef509a4d0cb9e24a247efc34d50489bcc1b05a53ecc68e2fc088e65cb
|
checksum: 3f2f625777747b9f87e793eea5a8bbf1ac2c828846bda5811d07a457d55cfe6762239779759de61e7b7e917632b9ceee3f7ffd2a024117e7ec364dc1b4eb8d55
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1485,10 +1485,10 @@ __metadata:
|
|||||||
"@mui/icons-material": ^5.11.11
|
"@mui/icons-material": ^5.11.11
|
||||||
"@mui/material": ^5.11.11
|
"@mui/material": ^5.11.11
|
||||||
"@remix-run/router": ^1.3.3
|
"@remix-run/router": ^1.3.3
|
||||||
"@table-library/react-table-library": 4.0.28
|
"@table-library/react-table-library": 4.0.29
|
||||||
"@types/lodash-es": ^4.17.6
|
"@types/lodash-es": ^4.17.6
|
||||||
"@types/mime-types": ^2
|
"@types/mime-types": ^2
|
||||||
"@types/node": ^18.14.2
|
"@types/node": ^18.14.4
|
||||||
"@types/react": ^18.0.28
|
"@types/react": ^18.0.28
|
||||||
"@types/react-dom": ^18.0.11
|
"@types/react-dom": ^18.0.11
|
||||||
"@types/react-router-dom": ^5.3.3
|
"@types/react-router-dom": ^5.3.3
|
||||||
|
|||||||
Reference in New Issue
Block a user