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