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

/*
 * Copyright (C) 2025 Red Hat, Inc.
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

import React, { useState } from 'react';

import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { ExclamationCircleIcon } from "@patternfly/react-icons";
import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { Icon } from '@patternfly/react-core/dist/esm/components/Icon/index.js';

import cockpit from "cockpit";
import { useEvent, useInit } from 'hooks';

function countFailingDisks(proxies) {
    const sataFail = Object.keys(proxies.drives_ata).reduce((acc, drive) => {
        const smart = proxies.drives_ata[drive];
        if (smart.SmartFailing) {
            return acc + 1;
        } else {
            return acc;
        }
    }, 0);

    const nvmeFail = Object.keys(proxies.nvme_controller).reduce((acc, drive) => {
        const smart = proxies.nvme_controller[drive];
        if (smart.SmartCriticalWarning.length > 0) {
            return acc + 1;
        } else {
            return acc;
        }
    }, 0);

    return sataFail + nvmeFail;
}

const proxies = {
    drives_ata: null,
    nvme_controller: null,
};

export const SmartOverviewStatus = () => {
    useEvent(proxies.drives_ata, "changed");
    useEvent(proxies.nvme_controller, "changed");
    const [initDone, setInitDone] = useState(false);

    useInit(async () => {
        const udisksdbus = cockpit.dbus("org.freedesktop.UDisks2");

        const addProxy = (iface) => {
            return udisksdbus.proxies("org.freedesktop.UDisks2." + iface, "/org/freedesktop/UDisks2");
        };

        proxies.drives_ata = addProxy("Drive.Ata");
        proxies.nvme_controller = addProxy("NVMe.Controller");
        await Promise.all(Object.keys(proxies).map(proxy => proxies[proxy].wait()));

        setInitDone(true);
    });

    if (initDone === false || proxies.drives_ata === null || proxies.nvme_controller === null) {
        return null;
    }

    const failingDisks = countFailingDisks(proxies);
    if (failingDisks === 0) {
        return null;
    }

    return (
        <li id="smart-status">
            <Flex spaceItems={{ default: 'spaceItemsSm' }}>
                <Icon status="danger">
                    <ExclamationCircleIcon />
                </Icon>
                <Button variant="link" component="a" isInline
                    onClick={() => cockpit.jump("/storage")}
                >
                    {cockpit.format(cockpit.ngettext("$0 disk is failing",
                                                     "$0 disks are failing", failingDisks),
                                    failingDisks)}
                </Button>
            </Flex>
        </li>
    );
};