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 93 : const getScheduledShutdown = (setShutdownTime: (t: number) => void, setShutdownType: (t: string) => void) => {
19 93 : const client = cockpit.dbus("org.freedesktop.login1");
20 93 : return client.call("/org/freedesktop/login1", "org.freedesktop.DBus.Properties", "Get",
21 93 : ["org.freedesktop.login1.Manager", "ScheduledShutdown"], { type: "ss" })
22 84 : .then(([result]) => {
23 84 : const [type, time] = (result as cockpit.Variant).v as [string, number];
24 84 : setShutdownType(type);
25 84 : setShutdownTime(time);
26 84 : })
27 0 : .catch(err => console.warn("Failed to get ScheduledShutdown property", err.toString()));
28 93 : };
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 93 : export const ShutDownStatus = () => {
42 93 : const [shutdownType, setShutdownType] = useState<string | null>(null);
43 93 : const [shutdownTime, setShutdownTime] = useState<number | null>(0);
44 :
45 93 : useEffect(() => {
46 93 : 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 93 : }, []);
52 :
53 : // We only care about these two types
54 93 : if (shutdownType !== "poweroff" && shutdownType !== "reboot") {
55 : // don't log undefined
56 17 : if (shutdownType !== null && shutdownType !== "") {
57 17 : console.log(`unsupported shutdown type ${shutdownType}`);
58 17 : }
59 93 : return null;
60 93 : }
61 :
62 19 : let displayDate = null;
63 19 : if (shutdownTime) {
64 19 : const date = new Date(shutdownTime / 1000);
65 19 : const now = new Date();
66 19 : if (date.getFullYear() == now.getFullYear()) {
67 19 : displayDate = timeformat.dateTimeNoYear(date);
68 17 : } else {
69 17 : displayDate = timeformat.dateTime(date);
70 17 : }
71 19 : }
72 :
73 19 : let text;
74 19 : let cancelText;
75 19 : let icon;
76 18 : if (shutdownType === "poweroff") {
77 18 : icon = <PowerOffIcon className="shutdown-status-poweroff-icon" />;
78 18 : text = _("Scheduled poweroff at $0");
79 18 : cancelText = _("Cancel poweroff");
80 17 : } else {
81 18 : icon = <RedoIcon className="reboot-status-poweroff-icon" />;
82 18 : text = _("Scheduled reboot at $0");
83 18 : cancelText = _("Cancel reboot");
84 18 : }
85 :
86 19 : return (
87 19 : <li id="system-health-shutdown-status">
88 19 : <Flex flexWrap={{ default: 'nowrap' }}>
89 19 : <FlexItem>{icon}</FlexItem>
90 19 : <Flex id="system-health-shutdown-status-text" spaceItems={{ default: 'spaceItemsNone' }} direction={{ default: 'column' }}>
91 19 : {cockpit.format(text, displayDate)}
92 19 : <FlexItem>
93 19 : <Button variant="link" isInline
94 19 : id="system-health-shutdown-status-cancel-btn"
95 19 : className="pf-v6-u-font-size-sm"
96 19 : onClick={cancelShutdownAction}>
97 19 : {cancelText}
98 19 : </Button>
99 19 : </FlexItem>
100 19 : </Flex>
101 19 : </Flex>
102 19 : </li>);
103 93 : };
|