🏡 index : quine-global-labs/mirror-cockpit-project-cockpit.git

/*
 * Copyright (C) 2022 Red Hat, Inc.
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */
import React, { useState, useEffect } from 'react';
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { PowerOffIcon, RedoIcon } from "@patternfly/react-icons";

import * as timeformat from "timeformat";

import cockpit from "cockpit";

import "./shutdownStatus.scss";

const _ = cockpit.gettext;

const getScheduledShutdown = (setShutdownTime: (t: number) => void, setShutdownType: (t: string) => void) => {
    const client = cockpit.dbus("org.freedesktop.login1");
    return client.call("/org/freedesktop/login1", "org.freedesktop.DBus.Properties", "Get",
                       ["org.freedesktop.login1.Manager", "ScheduledShutdown"], { type: "ss" })
            .then(([result]) => {
                const [type, time] = (result as cockpit.Variant).v as [string, number];
                setShutdownType(type);
                setShutdownTime(time);
            })
            .catch(err => console.warn("Failed to get ScheduledShutdown property", err.toString()));
};

const cancelShutdownAction = () => {
    const client = cockpit.dbus("org.freedesktop.login1", { superuser: "try" });
    return client.call("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "CancelScheduledShutdown")
            .then(([cancelled]) => {
                if (!cancelled) {
                    console.warn("Unable to cancel shutdown");
                }
            })
            .catch(err => console.warn("Failed to cancel shutdown", err.toString()));
};

export const ShutDownStatus = () => {
    const [shutdownType, setShutdownType] = useState<string | null>(null);
    const [shutdownTime, setShutdownTime] = useState<number | null>(0);

    useEffect(() => {
        getScheduledShutdown(setShutdownTime, setShutdownType);
        // logind does not have a propertieschanged mechanism https://github.com/systemd/systemd/issues/22244
        cockpit.file("/run/systemd/shutdown/scheduled").watch(() => {
            getScheduledShutdown(setShutdownTime, setShutdownType);
        });
    }, []);

    // We only care about these two types
    if (shutdownType !== "poweroff" && shutdownType !== "reboot") {
        // don't log undefined
        if (shutdownType !== null && shutdownType !== "") {
            console.log(`unsupported shutdown type ${shutdownType}`);
        }
        return null;
    }

    let displayDate = null;
    if (shutdownTime) {
        const date = new Date(shutdownTime / 1000);
        const now = new Date();
        if (date.getFullYear() === now.getFullYear()) {
            displayDate = timeformat.dateTimeNoYear(date);
        } else {
            displayDate = timeformat.dateTime(date);
        }
    }

    let text;
    let cancelText;
    let icon;
    if (shutdownType === "poweroff") {
        icon = <PowerOffIcon className="shutdown-status-poweroff-icon" />;
        text = _("Scheduled poweroff at $0");
        cancelText = _("Cancel poweroff");
    } else {
        icon = <RedoIcon className="reboot-status-poweroff-icon" />;
        text = _("Scheduled reboot at $0");
        cancelText = _("Cancel reboot");
    }

    return (
        <li id="system-health-shutdown-status">
            <Flex flexWrap={{ default: 'nowrap' }}>
                <FlexItem>{icon}</FlexItem>
                <Flex id="system-health-shutdown-status-text" spaceItems={{ default: 'spaceItemsNone' }} direction={{ default: 'column' }}>
                    {cockpit.format(text, displayDate)}
                    <FlexItem>
                        <Button variant="link" isInline
                                id="system-health-shutdown-status-cancel-btn"
                                className="pf-v6-u-font-size-sm"
                                onClick={cancelShutdownAction}>
                            {cancelText}
                        </Button>
                    </FlexItem>
                </Flex>
            </Flex>
        </li>);
};