/* * Copyright (C) 2021 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import cockpit from 'cockpit'; import React, { useState } from 'react'; import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js"; import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js"; import { DatePicker } from "@patternfly/react-core/dist/esm/components/DatePicker/index.js"; import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js"; import { Form, FormGroup, FormAlert } from "@patternfly/react-core/dist/esm/components/Form/index.js"; import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect/index.js"; import { InputGroup } from "@patternfly/react-core/dist/esm/components/InputGroup/index.js"; import { Modal, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core/dist/esm/components/Modal/index.js'; import { Radio } from "@patternfly/react-core/dist/esm/components/Radio/index.js"; import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput/index.js"; import { TimePicker } from "@patternfly/react-core/dist/esm/components/TimePicker/index.js"; import { MinusIcon, PlusIcon } from '@patternfly/react-icons'; import { FormHelper } from "cockpit-components-form-helper"; import { ModalError } from 'cockpit-components-inline-notification.jsx'; import { useDialogs } from "dialogs.jsx"; import { updateTime } from './services.jsx'; import { create_timer } from './timer-dialog-helpers.js'; import * as timeformat from "timeformat"; import "./timers.scss"; const _ = cockpit.gettext; export const CreateTimerDialogButton = ({ owner, isLoading }) => { const Dialogs = useDialogs(); return ( ); }; export const TimerDialog = ({ owner, timer }) => { const Dialogs = useDialogs(); const [command, setCommand] = useState(timer?.command || ''); const [delay, setDelay] = useState(timer?.delay || 'specific-time'); const [delayNumber, setDelayNumber] = useState(timer?.delayNumber || 0); const [delayUnit, setDelayUnit] = useState(timer?.delayUnit || 'sec'); const [description, setDescription] = useState(timer?.description || ''); const [dialogError, setDialogError] = useState(undefined); const [inProgress, setInProgress] = useState(false); const [name, setName] = useState(timer?.name || ''); const [repeat, setRepeat] = useState(timer?.repeat || 'no'); const [repeatPatterns, setRepeatPatterns] = useState(timer?.repeatPatterns || []); const [specificTime, setSpecificTime] = useState(timer?.specificTime || "00:00"); const [isSpecificTimeOpen, setSpecificTimeOpen] = useState(false); const [submitted, setSubmitted] = useState(false); const validationFailed = {}; if (!name.trim().length || !/^[a-zA-Z0-9:_.@-]+$/.test(name)) validationFailed.name = true; if (!description.trim().length) validationFailed.description = true; if (!command.trim().length) validationFailed.command = true; if (!/^[0-9]+$/.test(delayNumber)) validationFailed.delayNumber = true; const timePicker = (idx) => ( setRepeatPatterns(old => { const arr = [...old]; arr[idx].isOpen = isOpen; return arr; })} menuAppendTo={() => document.body} onChange={(_, time) => setRepeatPatterns(old => { const arr = [...old]; arr[idx].time = time; return arr; })} /> ); function onSubmit(event) { setSubmitted(true); if (event) event.preventDefault(); if (Object.keys(validationFailed).length) return false; create_timer({ name, description, command, delay, delayUnit, delayNumber, repeat, specificTime, repeatPatterns, owner }) .then(Dialogs.close, exc => { setDialogError(exc.message); setInProgress(false); }); return false; } return ( {dialogError && }
{timer && !timer.delay && } {timer && !timer.command && } setName(value)} readOnlyVariant={!!timer} /> setDescription(value)} /> { setCommand(str) }} /> setDelay("specific-time")} isChecked={delay === "specific-time"} label={_("At specific time")} /> setDelay("system-boot")} isChecked={delay === "system-boot"} label={_("After system boot")} /> { delay === "system-boot" && setDelayNumber(value)} /> setDelayUnit(val)} aria-label={_("Delay")}> } { delay === "specific-time" && <> { if (value === repeat) return; setRepeat(value); if (value === "minutely") setRepeatPatterns([{ key: 0, second: "0" }]); else if (value === "hourly") setRepeatPatterns([{ key: 0, minute: "0" }]); else if (value === "daily") setRepeatPatterns([{ key: 0, time: "00:00" }]); else if (value === "weekly") setRepeatPatterns([{ key: 0, day: "mon", time: "00:00" }]); else if (value === "monthly") setRepeatPatterns([{ key: 0, day: 1, time: "00:00" }]); else if (value === "yearly") setRepeatPatterns([{ key: 0, date: undefined, time: "00:00" }]); }} aria-label={_("Repeat")}> {repeat === "no" && document.body} time={specificTime} is24Hour onChange={(_, val) => setSpecificTime(val)} /> } {repeatPatterns.map((item, idx) => { let label; if (repeat === "minutely") label = _("At second"); else if (repeat === "hourly") label = _("At minute"); else if (repeat === "daily") label = _("Run at"); else if (repeat === "weekly" || repeat === "monthly" || repeat === "yearly") label = _("Run on"); let helperTextInvalid; const min = repeatPatterns[idx].minute; const validationFailedMinute = !(/^[0-9]+$/.test(min) && min <= 59 && min >= 0); if (submitted && repeat === 'hourly' && validationFailedMinute) { helperTextInvalid = _("Minute needs to be a number between 0-59"); } const sec = repeatPatterns[idx].second; const validationFailedSecond = !(/^[0-9]+$/.test(sec) && sec <= 59 && sec >= 0); if (submitted && repeat === 'minutely' && validationFailedSecond) { helperTextInvalid = _("Second needs to be a number between 0-59"); } return ( {repeat === "minutely" && setRepeatPatterns(old => { const arr = [...old]; arr[idx].second = second; return arr; })} validated={submitted && validationFailedSecond ? "error" : "default"} /> } {repeat === "hourly" && setRepeatPatterns(old => { const arr = [...old]; arr[idx].minute = minute; return arr; })} validated={submitted && validationFailedMinute ? "error" : "default"} /> } {repeat === "daily" && timePicker(idx)} {repeat === "weekly" && <> setRepeatPatterns(old => { const arr = [...old]; arr[idx].day = day; return arr; })} aria-label={_("Repeat weekly")}> {timePicker(idx)} } {repeat === "monthly" && <> setRepeatPatterns(old => { const arr = [...old]; arr[idx].day = day; return arr; })} aria-label={_("Repeat monthly")}> {[_("1st"), _("2nd"), _("3rd"), _("4th"), _("5th"), _("6th"), _("7th"), _("8th"), _("9th"), _("10th"), _("11th"), _("12th"), _("13th"), _("14th"), _("15th"), _("16th"), _("17th"), _("18th"), _("19th"), _("20th"), _("21th"), _("22th"), _("23th"), _("24th"), _("25th"), _("26th"), _("27th"), _("28th"), _("29th"), _("30th"), _("31st") ].map((day, index) => )} {timePicker(idx)} } {repeat === "yearly" && <> setRepeatPatterns(old => { const arr = [...old]; arr[idx].date = str; return arr; })} appendTo={() => document.body} value={repeatPatterns[idx].date || ""} /> {timePicker(idx)} } {repeat !== "no" &&
); };