Line data Source code
1 : /*
2 : * Copyright (C) 2022 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 93 : 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 93 : import cockpit from "cockpit";
13 :
14 : import "./shutdownStatus.scss";
15 :
16 93 : 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 82 : .then(([result]) => {
23 82 : const [type, time] = (result as cockpit.Variant).v as [string, number];
24 82 : setShutdownType(type);
25 82 : setShutdownTime(time);
26 82 : })
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 92 : cockpit.file("/run/systemd/shutdown/scheduled").watch(() => {
49 92 : getScheduledShutdown(setShutdownTime, setShutdownType);
50 92 : });
51 93 : }, []);
52 :
53 : // We only care about these two types
54 93 : 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 93 : return null;
60 93 : }
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 93 : };
|