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