Line data Source code
1 : /*
2 : * Copyright (C) 2025 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 95 : import React, { useState } from 'react';
7 :
8 : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
9 : import { ExclamationCircleIcon } from "@patternfly/react-icons";
10 : import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
11 : import { Icon } from '@patternfly/react-core/dist/esm/components/Icon/index.js';
12 :
13 95 : import cockpit from "cockpit";
14 : import { useEvent, useInit } from 'hooks';
15 :
16 78 : function countFailingDisks(proxies) {
17 78 : const sataFail = Object.keys(proxies.drives_ata).reduce((acc, drive) => {
18 78 : const smart = proxies.drives_ata[drive];
19 16 : if (smart.SmartFailing) {
20 16 : return acc + 1;
21 16 : } else {
22 78 : return acc;
23 78 : }
24 78 : }, 0);
25 :
26 0 : const nvmeFail = Object.keys(proxies.nvme_controller).reduce((acc, drive) => {
27 0 : const smart = proxies.nvme_controller[drive];
28 0 : if (smart.SmartCriticalWarning.length > 0) {
29 0 : return acc + 1;
30 0 : } else {
31 0 : return acc;
32 0 : }
33 0 : }, 0);
34 :
35 78 : return sataFail + nvmeFail;
36 78 : }
37 :
38 95 : const proxies = {
39 95 : drives_ata: null,
40 95 : nvme_controller: null,
41 95 : };
42 :
43 95 : export const SmartOverviewStatus = () => {
44 95 : useEvent(proxies.drives_ata, "changed");
45 95 : useEvent(proxies.nvme_controller, "changed");
46 95 : const [initDone, setInitDone] = useState(false);
47 :
48 95 : useInit(async () => {
49 95 : const udisksdbus = cockpit.dbus("org.freedesktop.UDisks2");
50 :
51 95 : const addProxy = (iface) => {
52 95 : return udisksdbus.proxies("org.freedesktop.UDisks2." + iface, "/org/freedesktop/UDisks2");
53 95 : };
54 :
55 95 : proxies.drives_ata = addProxy("Drive.Ata");
56 95 : proxies.nvme_controller = addProxy("NVMe.Controller");
57 95 : await Promise.all(Object.keys(proxies).map(proxy => proxies[proxy].wait()));
58 :
59 79 : setInitDone(true);
60 95 : });
61 :
62 79 : if (initDone === false || proxies.drives_ata === null || proxies.nvme_controller === null) {
63 95 : return null;
64 95 : }
65 :
66 79 : const failingDisks = countFailingDisks(proxies);
67 79 : if (failingDisks === 0) {
68 79 : return null;
69 79 : }
70 :
71 18 : return (
72 18 : <li id="smart-status">
73 18 : <Flex spaceItems={{ default: 'spaceItemsSm' }}>
74 18 : <Icon status="danger">
75 18 : <ExclamationCircleIcon />
76 18 : </Icon>
77 18 : <Button variant="link" component="a" isInline
78 1 : onClick={() => cockpit.jump("/storage")}
79 : >
80 18 : {cockpit.format(cockpit.ngettext("$0 disk is failing",
81 18 : "$0 disks are failing", failingDisks),
82 18 : failingDisks)}
83 18 : </Button>
84 18 : </Flex>
85 18 : </li>
86 : );
87 95 : };
|