UNPKG

@iobroker/adapter-react-v5

Version:

React components to develop ioBroker interfaces with react.

401 lines 16.3 kB
import React, { Component } from 'react'; import { Checkbox, Button, MenuItem, Select, FormControlLabel, AppBar, Tabs, Tab, TextField } from '@mui/material'; import { I18n } from '../i18n'; import { convertCronToText } from './SimpleCron/cronText'; const styles = { mainDiv: { width: '100%', height: '100%', }, periodSelect: { // margin: '0 10px 60px 10px', display: 'block', width: 250, }, slider: { marginTop: 20, display: 'block', width: '100%', }, tabContent: { padding: 20, height: 'calc(100% - 240px)', overflow: 'auto', }, numberButton: { padding: 4, minWidth: 40, margin: 5, }, numberButtonBreak: { display: 'block', }, appBar: { color: 'white', }, warning: { marginLeft: 16, color: 'red', fontSize: 12, }, }; const WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; // 5-7,9-11 => [5,6,7,9,10,11] function convertMinusIntoArray(value, max) { const result = []; if (value === '*') { if (max === 24 || max === 60 || max === 7) { for (let i = 0; i < max; i++) { result.push(i); } } else { for (let i = 1; i <= max; i++) { result.push(i); } } return result; // array with entries max } const parts = (value || '').toString().split(','); for (let p = 0; p < parts.length; p++) { if (!parts[p].trim().length) { continue; } const items = parts[p].trim().split('-'); if (items.length > 1) { const iMax = parseInt(items[1], 10); for (let i = parseInt(items[0], 10); i <= iMax; i++) { result.push(i); } } else { result.push(parseInt(parts[p], 10)); } } result.sort(); // remove double entries for (let p = result.length - 1; p >= 0; p--) { if (result[p] === result[p + 1]) { result.splice(p + 1, 1); } } return result; } // [5,6,7,9,10,11] => 5-7,9-11 function convertArrayIntoMinus(value, max) { if (typeof value !== 'object') { value = [value]; } if (value.length === max) { return '*'; } const newParts = []; if (!value.length) { return '-'; } value = value.map(a => parseInt(a, 10)); value.sort((a, b) => a - b); let start = value[0]; let end = value[0]; for (let p = 1; p < value.length; p++) { if (value[p] - 1 !== parseInt(value[p - 1], 10)) { if (start === end) { newParts.push(start); } else if (end - 1 === start) { newParts.push(`${start},${end}`); } else { newParts.push(`${start}-${end}`); } start = value[p]; } end = value[p]; } if (start === end) { newParts.push(start); } else if (end - 1 === start) { newParts.push(`${start},${end}`); } else { newParts.push(`${start}-${end}`); } return newParts.join(','); } export class ComplexCron extends Component { constructor(props) { super(props); let cron = typeof this.props.cronExpression === 'string' ? this.props.cronExpression.replace(/^["']/, '').replace(/["']\n?$/, '') : ''; if (cron[0] === '{') { cron = ''; } const state = ComplexCron.cron2state(cron || '* * * * *'); this.state = { extended: false, tab: state.seconds !== false ? 1 : 0, cron: ComplexCron.state2cron(state), modes: { seconds: null, minutes: null, hours: null, dates: null, months: null, dow: null, }, }; Object.assign(this.state, state); if (this.state.cron !== this.props.cronExpression) { setTimeout(() => this.props.onChange && this.props.onChange(this.state.cron), 100); } } static cron2state(cron) { cron = cron.replace(/['"]/g, '').trim(); const cronParts = cron.split(' ').map(p => p.trim()); let options; if (cronParts.length === 6) { options = { seconds: cronParts[0] || '*', minutes: cronParts[1] || '*', hours: cronParts[2] || '*', dates: cronParts[3] || '*', months: cronParts[4] || '*', dow: cronParts[5] || '*', }; } else { options = { seconds: false, minutes: cronParts[0] || '*', hours: cronParts[1] || '*', dates: cronParts[2] || '*', months: cronParts[3] || '*', dow: cronParts[4] || '*', }; } return options; } static state2cron(state) { let text = `${state.minutes} ${state.hours} ${state.dates} ${state.months} ${state.dow}`; if (state.seconds !== false) { text = `${state.seconds} ${text}`; } return text; } recalcCron() { const cron = ComplexCron.state2cron(this.state); if (cron !== this.state.cron) { this.setState({ cron }, () => this.props.onChange && this.props.onChange(this.state.cron)); } } onToggle(i, type, max) { if (i === true) { this.setCronAttr(type, '*'); } else if (i === false) { if (max === 60 || max === 24) { this.setCronAttr(type, '0'); } else { this.setCronAttr(type, '1'); } } else { const nums = convertMinusIntoArray(this.state[type], max); const pos = nums.indexOf(i); if (pos !== -1) { nums.splice(pos, 1); } else { nums.push(i); nums.sort(); } this.setCronAttr(type, convertArrayIntoMinus(nums, max)); } } getDigitsSelector(type, max) { let values = []; if (max === 7) { values = [1, 2, 3, 4, 5, 6, 0]; } else if (max === 60 || max === 24) { for (let i = 0; i < max; i++) { values.push(i); } } else { for (let i = 1; i <= max; i++) { values.push(i); } } const parts = convertMinusIntoArray(this.state[type], max); return [ React.createElement(Button, { key: "removeall", variant: "outlined", style: styles.numberButton, // style={{paddingBottom: 20}} color: "primary", onClick: () => this.onToggle(false, type, max) }, I18n.t('ra_Deselect all')), React.createElement(Button, { key: "addall", variant: "contained", // style={{paddingBottom: 20}} style: styles.numberButton, color: "secondary", onClick: () => this.onToggle(true, type, max) }, I18n.t('ra_Select all')), React.createElement("div", { key: "all" }, values.map(i => [ (max === 7 && i === 4) || (max === 12 && i === 7) || (max === 31 && !((i - 1) % 10)) || (max === 60 && i && !(i % 10)) || (max === 24 && i && !(i % 6)) ? (React.createElement("div", { key: `allInner${i}`, style: { width: '100%' } })) : null, React.createElement(Button, { key: `_${i}`, variant: parts.indexOf(i) !== -1 ? 'contained' : 'outlined', style: styles.numberButton, color: parts.indexOf(i) !== -1 ? 'secondary' : 'primary', onClick: () => this.onToggle(i, type, max) }, max === 7 ? I18n.t(WEEKDAYS[i]) : max === 12 ? MONTHS[i - 1] : i), ])), ]; } getPeriodsTab(type, max) { const value = this.state[type]; let every = value === '*'; let everyN = value === undefined || value === null ? false : value.toString().includes('/'); let select; if (this.state.modes[type] === null) { select = every ? 'every' : everyN ? 'everyN' : 'specific'; const modes = JSON.parse(JSON.stringify(this.state.modes)); modes[type] = select; setTimeout(() => this.setState({ modes }, () => this.recalcCron()), 100); return null; } every = this.state.modes[type] === 'every'; everyN = this.state.modes[type] === 'everyN'; select = this.state.modes[type]; let valueNumber = 1; if (everyN && value) { valueNumber = parseInt(value.replace('*/', ''), 10) || 1; } return (React.createElement("div", null, React.createElement(Select, { variant: "standard", style: { ...styles.periodSelect, verticalAlign: 'bottom' }, value: select, onChange: e => { const modes = JSON.parse(JSON.stringify(this.state.modes)); modes[type] = e.target.value; if (e.target.value === 'every') { this.setCronAttr(type, '*', modes); } else if (e.target.value === 'everyN') { const num = parseInt((this.state[type] || '').toString().replace('*/', ''), 10) || 1; this.setCronAttr(type, `*/${num}`, modes); } else if (e.target.value === 'specific') { let num = parseInt((this.state[type] || '').toString().split(',')[0], 10) || 0; if (!num && (type === 'months' || type === 'dates')) { num = 1; } this.setCronAttr(type, convertArrayIntoMinus(num, max), modes); } } }, React.createElement(MenuItem, { key: "every", value: "every" }, I18n.t(`sc_every_${type}`)), React.createElement(MenuItem, { key: "everyN", value: "everyN" }, I18n.t(`sc_everyN_${type}`)), React.createElement(MenuItem, { key: "specific", value: "specific" }, I18n.t(`sc_specific_${type}`))), everyN && (React.createElement(TextField, { variant: "standard", key: "interval", label: I18n.t(`sc_${type}`), value: valueNumber, slotProps: { htmlInput: { min: 1, max, }, inputLabel: { shrink: true, }, }, onChange: e => { // @ts-expect-error is allowed this.setState({ [type]: `*/${e.target.value}` }, () => this.recalcCron()); }, type: "number", margin: "normal" })), !every && !everyN && this.getDigitsSelector(type, max))); } static convertCronToText(cron, lang) { if (cron.split(' ').includes('-')) { return I18n.t('ra_Invalid CRON'); } return convertCronToText(cron, lang); } setCronAttr(attr, value, modes) { if (modes) { if (attr === 'seconds') { this.setState({ seconds: value, modes }, () => this.recalcCron()); } else if (attr === 'minutes') { this.setState({ minutes: value, modes }, () => this.recalcCron()); } else if (attr === 'hours') { this.setState({ hours: value, modes }, () => this.recalcCron()); } else if (attr === 'dates') { this.setState({ dates: value, modes }, () => this.recalcCron()); } else if (attr === 'months') { this.setState({ months: value, modes }, () => this.recalcCron()); } else if (attr === 'dow') { this.setState({ dow: value, modes }, () => this.recalcCron()); } else { this.setState({ modes }, () => this.recalcCron()); } } else if (attr === 'seconds') { this.setState({ seconds: value }, () => this.recalcCron()); } else if (attr === 'minutes') { this.setState({ minutes: value }, () => this.recalcCron()); } else if (attr === 'hours') { this.setState({ hours: value }, () => this.recalcCron()); } else if (attr === 'dates') { this.setState({ dates: value }, () => this.recalcCron()); } else if (attr === 'months') { this.setState({ months: value }, () => this.recalcCron()); } else if (attr === 'dow') { this.setState({ dow: value }, () => this.recalcCron()); } } render() { const tab = this.state.seconds !== false ? this.state.tab : this.state.tab + 1; // Detect if every minute or every second is activated const everyMinute = this.state.minutes === '*' || this.state.minutes === '*/1'; const everySecond = this.state.seconds === '*' || this.state.seconds === '*/1'; return (React.createElement("div", { style: styles.mainDiv }, React.createElement("div", { style: { paddingLeft: 8, width: 'calc(100% - px)' } }, React.createElement(TextField, { variant: "standard", style: { width: '100%' }, value: this.state.cron, disabled: true })), React.createElement("div", { style: { paddingLeft: 8, width: 'calc(100% - px)', height: 60 } }, ComplexCron.convertCronToText(this.state.cron, this.props.language || 'en'), React.createElement("span", { style: styles.warning }, everySecond ? I18n.t('ra_warning_every_second') : everyMinute ? I18n.t('ra_warning_every_minute') : '')), React.createElement(FormControlLabel, { control: React.createElement(Checkbox, { checked: !!this.state.seconds, onChange: e => this.setState({ seconds: e.target.checked ? '*' : false }, () => this.recalcCron()) }), label: I18n.t('ra_use seconds') }), React.createElement(AppBar, { position: "static", sx: { '&.MuiAppBar-root': styles.appBar }, color: "secondary" }, React.createElement(Tabs, { value: this.state.tab, style: styles.appBar, color: "secondary", onChange: (_active, _tab) => this.setState({ tab: _tab }) }, this.state.seconds !== false && (React.createElement(Tab, { id: "sc_seconds", label: I18n.t('sc_seconds') })), React.createElement(Tab, { id: "minutes", label: I18n.t('sc_minutes') }), React.createElement(Tab, { id: "hours", label: I18n.t('sc_hours') }), React.createElement(Tab, { id: "dates", label: I18n.t('sc_dates') }), React.createElement(Tab, { id: "months", label: I18n.t('sc_months') }), React.createElement(Tab, { id: "dow", label: I18n.t('sc_dows') }))), tab === 0 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('seconds', 60)), tab === 1 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('minutes', 60)), tab === 2 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('hours', 24)), tab === 3 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('dates', 31)), tab === 4 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('months', 12)), tab === 5 && React.createElement("div", { style: styles.tabContent }, this.getPeriodsTab('dow', 7)))); } } //# sourceMappingURL=ComplexCron.js.map