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-06-17 06:28:00

            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 : };
        

Generated by: LCOV version 2.0-1