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