Line data Source code
1 : /*
2 : * Copyright (C) 2025 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 92 : 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 92 : import cockpit from "cockpit";
14 : import { useEvent, useInit } from 'hooks';
15 :
16 76 : function countFailingDisks(proxies) {
17 76 : const sataFail = Object.keys(proxies.drives_ata).reduce((acc, drive) => {
18 76 : const smart = proxies.drives_ata[drive];
19 15 : if (smart.SmartFailing) {
20 15 : return acc + 1;
21 15 : } else {
22 76 : return acc;
23 76 : }
24 76 : }, 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 76 : return sataFail + nvmeFail;
36 76 : }
37 :
38 92 : const proxies = {
39 92 : drives_ata: null,
40 92 : nvme_controller: null,
41 92 : };
42 :
43 92 : export const SmartOverviewStatus = () => {
44 92 : useEvent(proxies.drives_ata, "changed");
45 92 : useEvent(proxies.nvme_controller, "changed");
46 92 : const [initDone, setInitDone] = useState(false);
47 :
48 92 : useInit(async () => {
49 92 : const udisksdbus = cockpit.dbus("org.freedesktop.UDisks2");
50 :
51 92 : const addProxy = (iface) => {
52 92 : return udisksdbus.proxies("org.freedesktop.UDisks2." + iface, "/org/freedesktop/UDisks2");
53 92 : };
54 :
55 92 : proxies.drives_ata = addProxy("Drive.Ata");
56 92 : proxies.nvme_controller = addProxy("NVMe.Controller");
57 92 : await Promise.all(Object.keys(proxies).map(proxy => proxies[proxy].wait()));
58 :
59 78 : setInitDone(true);
60 92 : });
61 :
62 78 : if (initDone === false || proxies.drives_ata === null || proxies.nvme_controller === null) {
63 92 : return null;
64 92 : }
65 :
66 78 : const failingDisks = countFailingDisks(proxies);
67 78 : if (failingDisks === 0) {
68 78 : return null;
69 78 : }
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 92 : };
|