LCOV - code coverage report
Current view: top level - pkg/systemd/overview-cards - smart-status.jsx Coverage Total Hit
Test: cockpit Lines: 85.2 % 61 52
Test Date: 2026-07-02 14:11:36

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

Generated by: LCOV version 2.0-1