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