LCOV - code coverage report
Current view: top level - pkg/systemd/overview-cards - smart-status.jsx Coverage Total Hit
Test: cockpit Lines: 86.9 % 61 53
Test Date: 2026-07-17 14:32:59

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 Red Hat, Inc.
       3              :  * SPDX-License-Identifier: LGPL-2.1-or-later
       4              :  */
       5              : 
       6           94 : 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           94 : import cockpit from "cockpit";
      14              : import { useEvent, useInit } from 'hooks';
      15              : 
      16           77 : function countFailingDisks(proxies) {
      17           77 :     const sataFail = Object.keys(proxies.drives_ata).reduce((acc, drive) => {
      18           77 :         const smart = proxies.drives_ata[drive];
      19           16 :         if (smart.SmartFailing) {
      20           16 :             return acc + 1;
      21           16 :         } else {
      22           77 :             return acc;
      23           77 :         }
      24           77 :     }, 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           77 :     return sataFail + nvmeFail;
      36           77 : }
      37              : 
      38           94 : const proxies = {
      39           94 :     drives_ata: null,
      40           94 :     nvme_controller: null,
      41           94 : };
      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           78 :         setInitDone(true);
      60           93 :     });
      61              : 
      62           78 :     if (initDone === false || proxies.drives_ata === null || proxies.nvme_controller === null) {
      63           93 :         return null;
      64           93 :     }
      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           93 : };
        

Generated by: LCOV version 2.0-1