Line data Source code
1 : /*
2 : * Copyright (C) 2022 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 94 : import React, { useState, useEffect } from 'react';
6 : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
7 : import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
8 : import { PowerOffIcon, RedoIcon } from "@patternfly/react-icons";
9 :
10 : import * as timeformat from "timeformat";
11 :
12 94 : import cockpit from "cockpit";
13 :
14 : import "./shutdownStatus.scss";
15 :
16 94 : const _ = cockpit.gettext;
17 :
18 94 : const getScheduledShutdown = (setShutdownTime: (t: number) => void, setShutdownType: (t: string) => void) => {
19 94 : const client = cockpit.dbus("org.freedesktop.login1");
20 94 : return client.call("/org/freedesktop/login1", "org.freedesktop.DBus.Properties", "Get",
21 94 : ["org.freedesktop.login1.Manager", "ScheduledShutdown"], { type: "ss" })
22 86 : .then(([result]) => {
23 86 : const [type, time] = (result as cockpit.Variant).v as [string, number];
24 86 : setShutdownType(type);
25 86 : setShutdownTime(time);
26 86 : })
27 0 : .catch(err => console.warn("Failed to get ScheduledShutdown property", err.toString()));
28 94 : };
29 :
30 2 : const cancelShutdownAction = () => {
31 2 : const client = cockpit.dbus("org.freedesktop.login1", { superuser: "try" });
32 2 : return client.call("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "CancelScheduledShutdown")
33 2 : .then(([cancelled]) => {
34 0 : if (!cancelled) {
35 0 : console.warn("Unable to cancel shutdown");
36 0 : }
37 2 : })
38 0 : .catch(err => console.warn("Failed to cancel shutdown", err.toString()));
39 2 : };
40 :
41 94 : export const ShutDownStatus = () => {
42 94 : const [shutdownType, setShutdownType] = useState<string | null>(null);
43 94 : const [shutdownTime, setShutdownTime] = useState<number | null>(0);
44 :
45 94 : useEffect(() => {
46 94 : getScheduledShutdown(setShutdownTime, setShutdownType);
47 : // logind does not have a propertieschanged mechanism https://github.com/systemd/systemd/issues/22244
48 93 : cockpit.file("/run/systemd/shutdown/scheduled").watch(() => {
49 93 : getScheduledShutdown(setShutdownTime, setShutdownType);
50 93 : });
51 94 : }, []);
52 :
53 : // We only care about these two types
54 94 : if (shutdownType !== "poweroff" && shutdownType !== "reboot") {
55 : // don't log undefined
56 16 : if (shutdownType !== null && shutdownType !== "") {
57 16 : console.log(`unsupported shutdown type ${shutdownType}`);
58 16 : }
59 94 : return null;
60 94 : }
61 :
62 18 : let displayDate = null;
63 18 : if (shutdownTime) {
64 18 : const date = new Date(shutdownTime / 1000);
65 18 : const now = new Date();
66 18 : if (date.getFullYear() == now.getFullYear()) {
67 18 : displayDate = timeformat.dateTimeNoYear(date);
68 16 : } else {
69 16 : displayDate = timeformat.dateTime(date);
70 16 : }
71 18 : }
72 :
73 18 : let text;
74 18 : let cancelText;
75 18 : let icon;
76 17 : if (shutdownType === "poweroff") {
77 17 : icon = <PowerOffIcon className="shutdown-status-poweroff-icon" />;
78 17 : text = _("Scheduled poweroff at $0");
79 17 : cancelText = _("Cancel poweroff");
80 16 : } else {
81 17 : icon = <RedoIcon className="reboot-status-poweroff-icon" />;
82 17 : text = _("Scheduled reboot at $0");
83 17 : cancelText = _("Cancel reboot");
84 17 : }
85 :
86 18 : return (
87 18 : <li id="system-health-shutdown-status">
88 18 : <Flex flexWrap={{ default: 'nowrap' }}>
89 18 : <FlexItem>{icon}</FlexItem>
90 18 : <Flex id="system-health-shutdown-status-text" spaceItems={{ default: 'spaceItemsNone' }} direction={{ default: 'column' }}>
91 18 : {cockpit.format(text, displayDate)}
92 18 : <FlexItem>
93 18 : <Button variant="link" isInline
94 18 : id="system-health-shutdown-status-cancel-btn"
95 18 : className="pf-v6-u-font-size-sm"
96 18 : onClick={cancelShutdownAction}>
97 18 : {cancelText}
98 18 : </Button>
99 18 : </FlexItem>
100 18 : </Flex>
101 18 : </Flex>
102 18 : </li>);
103 94 : };
|