@iobroker/adapter-react-v5
Version:
React components to develop ioBroker interfaces with react.
698 lines • 29.4 kB
JavaScript
import React from 'react';
import { InputLabel, MenuItem, Select, TextField, FormControl, FormControlLabel, Checkbox, } from '@mui/material';
import { convertCronToText } from './cronText';
import { I18n } from '../../i18n';
const styles = {
mainDiv: {
width: '100%',
height: '100%',
overflow: 'auto',
},
formControl: {
margin: 0,
minWidth: 120,
},
formControlMarginRight: {
marginRight: 5,
},
formControlPaddingTop: {
paddingTop: 6.2,
},
};
const PERIODIC = {
once: 'once',
interval: 'interval',
intervalBetween: 'intervalBetween',
specific: 'specific',
};
const PERIODIC_TYPES = {
seconds: 'seconds',
minutes: 'minutes',
// hours: 'hours',
};
const WEEKDAYS = [
'ra_Sunday',
'ra_Monday',
'ra_Tuesday',
'ra_Wednesday',
'ra_Thursday',
'ra_Friday',
'ra_Saturday',
'ra_Sunday',
];
function padding(num) {
if (num < 10) {
return `0${num}`;
}
return `${num}`;
}
const DEFAULT_STATE = {
mode: 'interval',
interval: {
period: 1,
unit: PERIODIC_TYPES.minutes,
},
};
function text2weekdays(text) {
if (text === '*') {
return [0, 1, 2, 3, 4, 5, 6];
}
const parts = text.split(',');
const list = [];
parts.forEach(part => {
const _parts = part.split('-');
if (_parts.length === 2) {
const start = parseInt(_parts[0], 10);
const end = parseInt(_parts[1], 10);
for (let day = start; day <= end; day++) {
if (!list.includes(day === 7 ? 0 : day)) {
list.push(day === 7 ? 0 : day);
}
}
}
else {
if (part === '7') {
part = '0';
}
const numPart = parseInt(part, 10);
if (!list.includes(numPart)) {
list.push(numPart);
}
}
});
list.sort();
return list;
}
export function cron2state(cron, force) {
cron = cron.replace(/['"]/g, '').trim();
const cronParts = cron.split(' ');
let options;
let state = null;
if (cronParts.length === 6) {
options = {
seconds: cronParts[0] || '*',
minutes: cronParts[1] || '*',
hours: cronParts[2] || '*',
date: cronParts[3] || '*',
months: cronParts[4] || '*',
dow: cronParts[5] || '*',
};
}
else {
options = {
seconds: null,
minutes: cronParts[0] || '*',
hours: cronParts[1] || '*',
date: cronParts[2] || '*',
months: cronParts[3] || '*',
dow: cronParts[4] || '*',
};
}
// * * * * *
if (options.seconds === null &&
options.minutes === '*' &&
options.hours === '*' &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
state = {
mode: 'interval',
interval: {
period: 1,
unit: PERIODIC_TYPES.minutes,
},
};
} // * * * * * *
if (options.seconds === '*' &&
options.minutes === '*' &&
options.hours === '*' &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
state = {
mode: 'interval',
interval: {
period: 1,
unit: PERIODIC_TYPES.seconds,
},
};
}
else if (options.seconds === null &&
options.minutes.includes('/') &&
options.hours === '*' &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
// */n * * * *
state = {
mode: 'interval',
interval: {
period: parseInt(options.minutes.split('/')[1], 10),
unit: PERIODIC_TYPES.minutes,
},
};
}
else if (options.seconds !== null &&
options.seconds.includes('/') &&
options.minutes === '*' &&
options.hours === '*' &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
// */n * * * * *
state = {
mode: 'interval',
interval: {
period: parseInt(options.seconds.split('/')[1], 10),
unit: PERIODIC_TYPES.seconds,
},
};
}
else if (options.seconds !== null &&
options.seconds.includes('/') &&
options.minutes === '*' &&
options.hours.includes('-') &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
// */n * 0-23 * * 1-7 or */n * 0-23 * * *
state = {
mode: 'intervalBetween',
intervalBetween: {
period: parseInt(options.seconds.split('/')[1], 10),
unit: PERIODIC_TYPES.seconds,
timeFrom: parseInt(options.hours.split('-')[0], 10),
timeTo: parseInt(options.hours.split('-')[1], 10),
weekdays: text2weekdays(options.dow),
},
};
}
else if (options.seconds === null &&
options.minutes.includes('/') &&
options.hours.includes('-') &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
// */n 0-23 * * 1-7 or */n 0-23 * * *
state = {
mode: 'intervalBetween',
intervalBetween: {
period: parseInt(options.minutes.split('/')[1], 10),
unit: PERIODIC_TYPES.minutes,
timeFrom: parseInt(options.hours.split('-')[0], 10),
timeTo: parseInt(options.hours.split('-')[1], 10),
weekdays: text2weekdays(options.dow),
},
};
}
else if (options.seconds === null &&
parseInt(options.minutes, 10).toString() === options.minutes &&
parseInt(options.hours, 10).toString() === options.hours &&
options.date === '*' &&
options.months === '*' &&
(options.dow === '*' || force)) {
// m h * * 1-7 or m h * * *
state = {
mode: 'specific',
specific: {
time: `${padding(parseInt(options.hours, 10))}:${padding(parseInt(options.minutes, 10))}`,
weekdays: text2weekdays(options.dow),
},
};
}
else if (options.seconds === null &&
parseInt(options.minutes, 10).toString() === options.minutes &&
parseInt(options.hours, 10).toString() === options.hours &&
parseInt(options.date, 10).toString() === options.date &&
parseInt(options.months, 10).toString() === options.months &&
(options.dow === '*' || force)) {
// m h d M *
state = {
mode: 'once',
once: {
time: `${padding(parseInt(options.hours, 10))}:${padding(parseInt(options.minutes, 10))}`,
date: `${padding(parseInt(options.date, 10))}.${padding(parseInt(options.months, 10))}`,
},
};
}
return state;
}
export class SimpleCron extends React.Component {
constructor(props) {
super(props);
let cron = typeof props.cronExpression === 'string'
? props.cronExpression.replace(/^["']/, '').replace(/["']\n?$/, '')
: '';
if (cron[0] === '{') {
cron = '';
}
const state = cron2state(cron || '* * * * *', true) || DEFAULT_STATE;
this.state = {
extended: false,
cron: SimpleCron.state2cron(state),
mode: 'interval',
once: {
time: '00:00',
date: '',
},
interval: {
period: 1,
unit: PERIODIC_TYPES.minutes,
},
intervalBetween: {
period: 1,
unit: PERIODIC_TYPES.minutes,
timeFrom: 0,
timeTo: 23,
weekdays: [0, 1, 2, 3, 4, 5, 6],
},
specific: {
time: '00:00',
weekdays: [0, 1, 2, 3, 4, 5, 6],
},
};
Object.assign(this.state, state);
if (this.state.cron !== props.cronExpression) {
setTimeout(() => props.onChange && props.onChange(this.state.cron), 100);
}
}
static periodArray2text(list, max = 7) {
max = max || 7;
if (list.length === max) {
return '*';
}
const text = [];
let start = null;
let end = null;
if (!list.length) {
return '_';
}
for (let i = 0; i < list.length; i++) {
if (start === null) {
start = list[i];
end = list[i];
}
else if (list[i - 1] + 1 === list[i]) {
end = list[i];
}
else {
if (start !== end) {
text.push(`${start}-${end}`);
}
else {
text.push(start);
}
start = list[i];
end = list[i];
}
}
if (start !== end) {
text.push(`${start}-${end}`);
}
else {
text.push(start);
}
return text.join(',');
}
static text2weekdays(text) {
return text2weekdays(text);
}
static state2cron(state) {
let cron = '* * * * *';
if (state.mode === 'interval') {
const settings = state.interval || {
period: 1,
unit: PERIODIC_TYPES.minutes,
};
if (settings.period !== undefined && settings.period > 60) {
settings.period = 60;
}
if (settings.period !== undefined && settings.period < 1) {
settings.period = 1;
}
if (settings.minutes !== undefined && settings.minutes !== null && settings.minutes > 60) {
settings.minutes = 60;
}
if (settings.minutes !== undefined && settings.minutes !== null && settings.minutes < 1) {
settings.minutes = 1;
}
if (settings.hours !== undefined && settings.hours !== null && settings.hours > 24) {
settings.hours = 24;
}
if (settings.hours !== undefined && settings.hours !== null && settings.hours < 1) {
settings.hours = 1;
}
if (state.extended) {
cron = `${settings.minutes !== undefined && settings.minutes !== null && settings.minutes > 1 ? `*/${settings.minutes}` : '*'} ${settings.hours !== undefined && settings.hours !== null && settings.hours > 1 ? `*/${settings.hours}` : '*'} * * *`;
}
else {
switch (settings.unit) {
case PERIODIC_TYPES.seconds:
cron = `${settings.period > 1 ? `*/${settings.period}` : '*'} * * * * *`;
break;
case PERIODIC_TYPES.minutes:
cron = `${settings.period > 1 ? `*/${settings.period}` : '*'} * * * *`;
break;
default:
break;
}
}
}
else if (state.mode === 'intervalBetween') {
const settings = state.intervalBetween || {
period: 1,
unit: PERIODIC_TYPES.minutes,
timeFrom: 0,
timeTo: 24,
weekdays: [0, 1, 2, 3, 4, 5, 6],
};
let hours;
settings.timeFrom = settings.timeFrom || 0;
settings.timeTo = settings.timeTo === undefined ? 24 : settings.timeTo;
if (settings.timeFrom !== 0 && settings.timeTo === 24) {
settings.timeTo = 23;
}
if (settings.timeFrom === 0 && settings.timeTo === 24) {
hours = '*';
}
else {
hours = settings.timeFrom !== settings.timeTo ? `${settings.timeFrom}-${settings.timeTo}` : '*';
}
if (settings.period > 60) {
settings.period = 60;
}
if (settings.period < 1) {
settings.period = 1;
}
settings.unit = settings.unit || PERIODIC_TYPES.minutes;
switch (settings.unit) {
case PERIODIC_TYPES.seconds:
cron = `${settings.period > 1 ? `*/${settings.period}` : '*'} * ${hours} * * ${this.periodArray2text(settings.weekdays)}`;
break;
case PERIODIC_TYPES.minutes:
cron = `${settings.period > 1 ? `*/${settings.period}` : '*'} ${hours} * * ${this.periodArray2text(settings.weekdays)}`;
break;
default:
break;
}
}
else if (state.mode === 'specific') {
const settings = state.specific || {
time: '00:00',
weekdays: [0, 1, 2, 3, 4, 5, 6],
};
const parts = (settings.time || '00:00').split(':');
let minutes = parseInt(parts[1], 10) || 0;
if (minutes > 59) {
minutes = 59;
}
if (minutes < 0) {
minutes = 0;
}
let hours = parseInt(parts[0], 10) || 0;
if (hours > 23) {
hours = 59;
}
if (hours < 0) {
hours = 0;
}
cron = `${minutes} ${hours} * * ${this.periodArray2text(settings.weekdays || [])}`;
}
else if (state.mode === 'once') {
const settings = state.once || {
time: '00:00',
date: '',
};
if (!settings.date) {
settings.date = `${new Date().getDate()}.${padding(new Date().getMonth() + 1)}`;
}
const parts = (settings.time || '00:00').split(':');
const partsDate = settings.date.split('.');
let minutes = parseInt(parts[1], 10) || 0;
if (minutes > 59) {
minutes = 59;
}
if (minutes < 0) {
minutes = 0;
}
let hours = parseInt(parts[0], 10) || 0;
if (hours > 23) {
hours = 59;
}
if (hours < 0) {
hours = 0;
}
let date = parseInt(partsDate[0], 10) || 1;
if (date > 31) {
date = 31;
}
if (date < 1) {
hours = 1;
}
let month = parseInt(partsDate[1], 10) || 1;
if (month > 12) {
month = 12;
}
if (month < 1) {
month = 1;
}
cron = `${minutes} ${hours} ${date} ${month} *`;
}
return cron;
}
recalcCron() {
this.onChange(SimpleCron.state2cron(this.state));
}
getControlsWeekdaysElements(type) {
const settings = type === 'intervalBetween' ? this.state.intervalBetween : this.state.specific;
return (React.createElement("div", { key: "weekdays", style: { paddingLeft: 8, width: 'calc(100% - 8px)', maxWidth: 600 } },
React.createElement("h5", null, I18n.t('ra_On weekdays')),
[1, 2, 3, 4, 5, 6, 0].map(day => (React.createElement(FormControlLabel, { key: WEEKDAYS[day], control: React.createElement(Checkbox, { checked: settings.weekdays.includes(day), onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
const pos = _settings.weekdays.indexOf(day);
if (e.target.checked) {
if (pos === -1) {
_settings.weekdays.push(day);
}
}
else {
if (pos !== -1) {
_settings.weekdays.splice(pos, 1);
}
}
_settings.weekdays.sort();
if (type === 'intervalBetween') {
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
}
else {
this.setState({ specific: _settings }, () => this.recalcCron());
}
}, value: day.toString() }), label: I18n.t(WEEKDAYS[day]) })))));
}
getControlsPeriodElements(type) {
const settings = type === 'interval' ? this.state.interval : this.state.intervalBetween;
if (this.state.extended) {
return (React.createElement("div", { key: "period", style: { paddingLeft: 8, display: 'inline-block' } },
React.createElement("h5", { style: { marginBottom: 5 } }, I18n.t('sc_period')),
React.createElement(TextField, { variant: "standard", style: { marginTop: 0, marginBottom: 0, verticalAlign: 'bottom' }, key: "value", label: I18n.t('sc_minutes'), value: settings.minutes, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
_settings.minutes = parseInt(e.target.value, 10);
if (_settings.minutes < 1) {
_settings.minutes = 1;
}
if (type === 'interval') {
this.setState({ interval: _settings }, () => this.recalcCron());
}
else {
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
}
}, slotProps: {
htmlInput: {
min: 1,
max: 60,
},
inputLabel: {
shrink: true,
},
}, type: "number", margin: "normal" }),
React.createElement(TextField, { variant: "standard", style: { marginTop: 0, marginBottom: 0, verticalAlign: 'bottom' }, key: "value", label: I18n.t('sc_hours'), value: settings.hours, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
_settings.hours = parseInt(e.target.value, 10);
if (_settings.hours < 1) {
_settings.hours = 1;
}
if (type === 'interval') {
this.setState({ interval: _settings }, () => this.recalcCron());
}
else {
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
}
}, slotProps: {
htmlInput: {
min: 1,
max: 24,
},
inputLabel: {
shrink: true,
},
}, type: "number", margin: "normal" })));
}
return (React.createElement("div", { key: "period", style: { paddingLeft: 8, display: 'inline-block' } },
React.createElement("h5", { style: { marginBottom: 5 } }, I18n.t('sc_period')),
React.createElement(TextField, { variant: "standard", style: { marginTop: 0, marginBottom: 0, verticalAlign: 'bottom' }, key: "value", label: I18n.t('sc_every'), value: settings.period, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
_settings.period = parseInt(e.target.value, 10);
if (_settings.period < 1) {
_settings.period = 1;
}
if (type === 'interval') {
this.setState({ interval: _settings }, () => this.recalcCron());
}
else {
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
}
}, slotProps: {
htmlInput: {
min: 1,
max: 60,
},
inputLabel: {
shrink: true,
},
}, type: "number", margin: "normal" }),
React.createElement(Select, { variant: "standard", style: { verticalAlign: 'bottom' }, value: settings.unit, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
_settings.unit = e.target.value;
if (type === 'interval') {
this.setState({ interval: _settings }, () => this.recalcCron());
}
else {
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
}
} },
React.createElement(MenuItem, { value: "seconds" }, I18n.t('sc_seconds')),
")",
React.createElement(MenuItem, { value: "minutes" }, I18n.t('sc_minutes')),
")")));
}
getControlsTime(type) {
const settings = type === 'once' ? this.state.once : this.state.specific;
return (React.createElement(FormControl, { variant: "standard", sx: {
...styles.formControl,
'&.MuiFormControl-root': styles.formControlMarginRight,
} },
React.createElement(TextField, { variant: "standard", key: "at", label: I18n.t('sc_time'), value: settings.time, type: "time", sx: (theme) => ({
'& input[type="time"]::-webkit-calendar-picker-indicator': {
filter: theme.palette.mode === 'dark' ? 'invert(80%)' : undefined,
},
}), onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state[type]));
_settings.time = e.target.value;
if (type === 'once') {
this.setState({ once: _settings }, () => this.recalcCron());
}
else {
this.setState({ specific: _settings }, () => this.recalcCron());
}
}, slotProps: {
inputLabel: {
shrink: true,
},
}, margin: "normal" })));
}
getControlsDate() {
const settings = this.state.once;
if (!settings.date) {
const d = new Date();
settings.date = `${d.getDate()}.${padding(d.getMonth() + 1)}`;
}
// <InputLabel htmlFor="formatted-text-mask-input">{I18n.t('sc_at')}</InputLabel>
return (React.createElement(FormControl, { variant: "standard", style: styles.formControl },
React.createElement(TextField, { variant: "standard", key: "date", label: I18n.t('sc_date'), value: settings.date, type: "text", slotProps: {
htmlInput: {
style: styles.formControlPaddingTop,
},
inputLabel: {
shrink: true,
},
}, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state.once));
_settings.date = e.target.value;
this.setState({ once: _settings }, () => this.recalcCron());
}, margin: "normal" })));
}
getOnceElements() {
return (React.createElement("div", { style: { marginLeft: 8 } },
this.getControlsTime('once'),
this.getControlsDate()));
}
getIntervalElements() {
return this.getControlsPeriodElements('interval');
}
getIntervalBetweenElements() {
const settings = this.state.intervalBetween;
return [
this.getControlsPeriodElements('intervalBetween'),
React.createElement("div", { key: "between", style: { paddingLeft: 8, display: 'inline-block', verticalAlign: 'top' } },
React.createElement("h5", { style: { marginBottom: 5 } }, I18n.t('sc_hours')),
React.createElement(FormControl, { variant: "standard", style: styles.formControl },
React.createElement(InputLabel, { shrink: true, htmlFor: "age-label-placeholder" }, I18n.t('sc_from')),
React.createElement(Select, { variant: "standard", style: { width: 100 }, value: settings.timeFrom, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state.intervalBetween));
_settings.timeFrom = parseInt(e.target.value, 10);
if (_settings.timeTo === 24) {
_settings.timeTo = 23;
}
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
} }, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].map(hour => (React.createElement(MenuItem, { key: `B_${hour}`, value: hour }, `${padding(hour)}:00`))))),
React.createElement(FormControl, { variant: "standard", style: styles.formControl },
React.createElement(InputLabel, { shrink: true, htmlFor: "age-label-placeholder" }, I18n.t('sc_to')),
React.createElement(Select, { variant: "standard", style: { width: 100 }, value: settings.timeTo, onChange: e => {
const _settings = JSON.parse(JSON.stringify(this.state.intervalBetween));
_settings.timeTo = parseInt(e.target.value, 10);
this.setState({ intervalBetween: _settings }, () => this.recalcCron());
} },
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].map(hour => (React.createElement(MenuItem, { key: `A_${hour}`, value: hour }, `${padding(hour)}:00`))),
!settings.timeFrom && React.createElement(MenuItem, { value: 24 }, "00:00")))),
this.getControlsWeekdaysElements('intervalBetween'),
];
}
getSpecificTimeElements() {
return [
React.createElement("div", { key: "time", style: { marginLeft: 8 } }, this.getControlsTime('specific')),
this.getControlsWeekdaysElements('specific'),
];
}
onModeChange(mode) {
if (mode !== this.state.mode) {
this.setState({ mode }, () => this.recalcCron());
}
}
onChange(cron) {
if (cron !== this.state.cron) {
this.setState({ cron });
this.props.onChange && this.props.onChange(cron);
}
}
render() {
return (React.createElement("div", { style: styles.mainDiv },
React.createElement("div", { style: { paddingLeft: 8, width: 'calc(100% - 8px)' } },
React.createElement(TextField, { variant: "standard", style: { width: '100%' }, value: this.state.cron, disabled: true, error: this.state.cron.includes('_') })),
React.createElement("div", { style: { paddingLeft: 8, width: 'calc(100% - 8px)', height: 60 } }, this.state.cron.includes('_')
? I18n.t('sc_invalid_cron')
: convertCronToText(this.state.cron, this.props.language || 'en')),
React.createElement("div", null,
React.createElement(FormControl, { variant: "standard", style: { ...styles.formControl, marginLeft: 8, marginTop: 8 } },
React.createElement(InputLabel, null, I18n.t('ra_Repeat')),
React.createElement(Select, { variant: "standard", value: this.state.mode, onChange: e => this.onModeChange(e.target.value), inputProps: { name: 'mode', id: 'mode' } },
React.createElement(MenuItem, { value: "once" }, I18n.t('sc_once')),
React.createElement(MenuItem, { value: "interval" }, I18n.t('sc_interval')),
React.createElement(MenuItem, { value: "intervalBetween" }, I18n.t('sc_intervalBetween')),
React.createElement(MenuItem, { value: "specific" }, I18n.t('sc_specific'))))),
this.state.mode === PERIODIC.once && this.getOnceElements(),
this.state.mode === 'interval' && this.getIntervalElements(),
this.state.mode === 'intervalBetween' && this.getIntervalBetweenElements(),
this.state.mode === 'specific' && this.getSpecificTimeElements()));
}
}
//# sourceMappingURL=index.js.map