LCOV - code coverage report
Current view: top level - pkg/systemd/overview-cards - uncleanShutdownStatus.jsx Coverage Total Hit
Test: cockpit Lines: 90.5 % 63 57
Test Date: 2026-07-17 07:33:01

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 Red Hat, Inc.
       3              :  * SPDX-License-Identifier: LGPL-2.1-or-later
       4              :  */
       5              : 
       6           92 : import React, { useState } from 'react';
       7              : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
       8              : import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
       9              : import { Icon } from "@patternfly/react-core/dist/esm/components/Icon/index.js";
      10              : import { ExclamationTriangleIcon } from "@patternfly/react-icons";
      11              : 
      12           92 : import cockpit from "cockpit";
      13              : 
      14              : import { useInit } from 'hooks';
      15              : 
      16           92 : const _ = cockpit.gettext;
      17              : 
      18           92 : export const UncleanShutdownStatus = () => {
      19           92 :     const [uncleanShutdownId, setUncleanShutdownId] = useState(null);
      20           92 :     const [uncleanShutdownStatusVisible, setUncleanShutdownStatusVisible] = useState(false);
      21              : 
      22           92 :     useInit(() => {
      23           92 :         cockpit.spawn(
      24           92 :             ["last", "--system", "--limit=2", "--time-format=iso", "shutdown", "reboot"],
      25           92 :             { environ: ["LC_ALL=C"], err: "message", }
      26           85 :         ).then((data) => {
      27           85 :             const previous_boot = data.split("\n")[1];
      28           85 :             if (previous_boot === undefined)
      29           85 :                 return;
      30              : 
      31              :             // "crash" on wtmpdb, "still running" on util-linux
      32           85 :             if (!previous_boot.includes("crash") && !previous_boot.includes("still running"))
      33           85 :                 return;
      34              : 
      35           16 :             const lines = previous_boot.split(/ +/);
      36           16 :             const started = new Date(lines[4]);
      37           16 :             if (isNaN(started)) {
      38           16 :                 console.warn("cannot parse start date of last line", previous_boot);
      39           16 :             } else {
      40           16 :                 const epoch = started.getTime().toString();
      41           16 :                 setUncleanShutdownId(epoch);
      42           16 :                 setUncleanShutdownStatusVisible(epoch != cockpit.sessionStorage.getItem("dismissed-unclean-shutdown-id"));
      43           16 :             }
      44           85 :         });
      45           92 :     });
      46              : 
      47           16 :     if (!uncleanShutdownId || !uncleanShutdownStatusVisible) {
      48           92 :         return null;
      49           92 :     }
      50              : 
      51            0 :     function hideAlert() {
      52            0 :         setUncleanShutdownStatusVisible(false);
      53            0 :         cockpit.sessionStorage.setItem('dismissed-unclean-shutdown-id', uncleanShutdownId);
      54            0 :     }
      55              : 
      56           16 :     return (
      57           16 :         <li id="unclean-shutdown-status">
      58           16 :             <Flex flexWrap={{ default: 'nowrap' }}>
      59           16 :                 <FlexItem>
      60           16 :                     <Icon status="danger">
      61           16 :                         <ExclamationTriangleIcon />
      62           16 :                     </Icon>
      63           16 :                 </FlexItem>
      64           16 :                 <div>
      65           16 :                     <div className="pf-v6-u-text-break-word pf-v6-u-text-color-status-danger">
      66           16 :                         {_("Unclean shutdown")}
      67           16 :                     </div>
      68           16 :                     <Flex>
      69           16 :                         <Button variant="link" isInline
      70           16 :                                     className="pf-v6-u-font-size-sm"
      71            0 :                                     onClick={() => cockpit.jump("/system/logs#/?boot=-1")}>
      72           16 :                             {_("View logs")}
      73           16 :                         </Button>
      74           16 :                         <Button variant="link" isInline
      75           16 :                                     className="pf-v6-u-font-size-sm"
      76            0 :                                     onClick={() => hideAlert()}
      77           16 :                                     id="unclean-shutdown-status-dismiss">
      78           16 :                             {_("Dismiss")}
      79           16 :                         </Button>
      80           16 :                     </Flex>
      81           16 :                 </div>
      82           16 :             </Flex>
      83           16 :         </li>
      84              :     );
      85           92 : };
        

Generated by: LCOV version 2.0-1