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

Generated by: LCOV version 2.0-1