LCOV - code coverage report
Current view: top level - pkg/storaged/overview - overview.jsx Coverage Total Hit
Test: cockpit Lines: 95.5 % 132 126
Test Date: 2026-07-03 07:31:16

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2023 Red Hat, Inc.
       3              :  * SPDX-License-Identifier: LGPL-2.1-or-later
       4              :  */
       5              : 
       6          113 : import cockpit from "cockpit";
       7          113 : import React from "react";
       8              : import client from "../client";
       9              : 
      10              : import { install_dialog } from "cockpit-components-install-dialog.jsx";
      11              : 
      12              : import { Card, CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";
      13              : import { Stack, StackItem } from "@patternfly/react-core/dist/esm/layouts/Stack/index.js";
      14              : import { DropdownGroup, DropdownList } from '@patternfly/react-core/dist/esm/components/Dropdown/index.js';
      15              : 
      16              : import { StoragePlots } from "../plot.jsx";
      17              : import { StorageMenuItem, StorageBarMenu } from "../storage-controls.jsx";
      18              : import { dialog_open } from "../dialog.jsx";
      19              : import { StorageLogsPanel } from "../logs-panel.jsx";
      20              : 
      21              : import { create_mdraid } from "../mdraid/create-dialog.jsx";
      22              : import { create_vgroup } from "../lvm2/create-dialog.jsx";
      23              : import { create_stratis_pool } from "../stratis/create-dialog.jsx";
      24              : import { iscsi_change_name, iscsi_discover } from "../iscsi/create-dialog.jsx";
      25              : import { get_other_devices } from "../utils.js";
      26              : 
      27              : import { new_page, new_card, StorageCard, ChildrenTable } from "../pages.jsx";
      28              : import { make_drive_page } from "../drive/drive.jsx";
      29              : import { make_lvm2_volume_group_page } from "../lvm2/volume-group.jsx";
      30              : import { make_mdraid_page } from "../mdraid/mdraid.jsx";
      31              : import { make_stratis_pool_page } from "../stratis/pool.jsx";
      32              : import { make_stratis_stopped_pool_page } from "../stratis/stopped-pool.jsx";
      33              : import { make_nfs_page, nfs_fstab_dialog } from "../nfs/nfs.jsx";
      34              : import { make_iscsi_session_page } from "../iscsi/session.jsx";
      35              : import { make_other_page } from "../block/other.jsx";
      36              : import { make_btrfs_volume_page } from "../btrfs/volume.jsx";
      37              : 
      38          113 : const _ = cockpit.gettext;
      39              : 
      40          112 : export function make_overview_page() {
      41          112 :     const overview_card = new_card({
      42          112 :         title: _("Storage"),
      43          112 :         page_location: [],
      44          112 :         page_name: _("Storage"),
      45          112 :         component: OverviewCard
      46          112 :     });
      47              : 
      48          112 :     const overview_page = new_page(null, overview_card);
      49              : 
      50            1 :     Object.keys(client.iscsi_sessions).forEach(p => make_iscsi_session_page(overview_page, client.iscsi_sessions[p]));
      51          112 :     Object.keys(client.drives).forEach(p => {
      52          112 :         if (!client.drives_iscsi_session[p])
      53          112 :             make_drive_page(overview_page, client.drives[p]);
      54          112 :     });
      55           25 :     Object.keys(client.vgroups).forEach(p => make_lvm2_volume_group_page(overview_page, client.vgroups[p]));
      56            7 :     Object.keys(client.mdraids).forEach(p => make_mdraid_page(overview_page, client.mdraids[p]));
      57           18 :     Object.keys(client.stratis_pools).map(p => make_stratis_pool_page(overview_page, client.stratis_pools[p]));
      58           11 :     Object.keys(client.stratis_manager.StoppedPools).map(uuid => make_stratis_stopped_pool_page(overview_page, uuid));
      59            3 :     client.nfs.entries.forEach(e => make_nfs_page(overview_page, e));
      60           54 :     get_other_devices(client).map(p => make_other_page(overview_page, client.blocks[p]));
      61          112 :     Object.keys(client.uuids_btrfs_volume).forEach(uuid => make_btrfs_volume_page(overview_page, uuid));
      62          112 : }
      63              : 
      64          104 : const OverviewCard = ({ card, plot_state }) => {
      65          104 :     function menu_item(feature, title, action) {
      66          104 :         const feature_enabled = !feature || feature.is_enabled();
      67          104 :         const required_package = feature && feature.package;
      68              : 
      69           23 :         if (!feature_enabled && !(required_package && client.features.packagekit))
      70            6 :             return null;
      71              : 
      72           32 :         function install_then_action() {
      73            2 :             if (!feature_enabled) {
      74            2 :                 install_dialog(required_package, feature.dialog_options).then(
      75            2 :                     () => {
      76            2 :                         feature.enable()
      77            2 :                                 .then(action)
      78            0 :                                 .catch(error => {
      79            0 :                                     dialog_open({
      80            0 :                                         Title: _("Error"),
      81            0 :                                         Body: error.toString()
      82            0 :                                     });
      83            0 :                                 });
      84            2 :                     },
      85            1 :                     () => null /* ignore cancel */);
      86            1 :             } else {
      87           31 :                 action();
      88           31 :             }
      89           32 :         }
      90              : 
      91          104 :         return <StorageMenuItem key={title} onClick={install_then_action}>{title}</StorageMenuItem>;
      92          104 :     }
      93              : 
      94          104 :     const lvm2_feature = {
      95          104 :         is_enabled: () => client.features.lvm2
      96          104 :     };
      97              : 
      98          104 :     const stratis_feature = {
      99          104 :         is_enabled: () => client.features.stratis,
     100          104 :         package: client.get_config("stratis_package", false),
     101            1 :         enable: () => {
     102            1 :             return cockpit.spawn(["systemctl", "start", "stratisd"], { superuser: "require" })
     103            1 :                     .then(() => client.stratis_start());
     104            1 :         },
     105              : 
     106          104 :         dialog_options: {
     107          104 :             title: _("Install Stratis support"),
     108          104 :             text: _("The $0 package must be installed to create Stratis pools.")
     109          104 :         }
     110          104 :     };
     111              : 
     112          104 :     const nfs_feature = {
     113           93 :         is_enabled: () => client.features.nfs,
     114          104 :         package: client.get_config("nfs_client_package", false),
     115            1 :         enable: () => {
     116            1 :             client.features.nfs = true;
     117            1 :             client.nfs.start();
     118            1 :             return Promise.resolve();
     119            1 :         },
     120              : 
     121          104 :         dialog_options: {
     122          104 :             title: _("Install NFS support")
     123          104 :         }
     124          104 :     };
     125              : 
     126          104 :     const iscsi_feature = {
     127          104 :         is_enabled: () => client.features.iscsi,
     128          104 :     };
     129              : 
     130          104 :     const local_menu_items = [
     131            5 :         menu_item(null, _("Create MDRAID device"), () => create_mdraid()),
     132           12 :         menu_item(lvm2_feature, _("Create LVM2 volume group"), () => create_vgroup()),
     133            9 :         menu_item(stratis_feature, _("Create Stratis pool"), () => create_stratis_pool()),
     134          104 :     ].filter(item => !!item);
     135              : 
     136          104 :     const net_menu_items = [
     137            5 :         !client.in_anaconda_mode() && menu_item(nfs_feature, _("New NFS mount"), () => nfs_fstab_dialog(null, null)),
     138            1 :         menu_item(iscsi_feature, _("Change iSCSI initiator name"), () => iscsi_change_name()),
     139            1 :         menu_item(iscsi_feature, _("Add iSCSI portal"), () => iscsi_discover()),
     140          104 :     ].filter(item => !!item);
     141              : 
     142          104 :     const groups = [];
     143              : 
     144          104 :     if (local_menu_items.length > 0)
     145          104 :         groups.push(
     146          104 :             <DropdownGroup key="local" label={_("Local storage")}>
     147          104 :                 <DropdownList>
     148          104 :                     {local_menu_items}
     149          104 :                 </DropdownList>
     150          104 :             </DropdownGroup>);
     151              : 
     152          104 :     if (net_menu_items.length > 0)
     153          104 :         groups.push(
     154          104 :             <DropdownGroup key="net" label={_("Networked storage")}>
     155          104 :                 <DropdownList>
     156          104 :                     {net_menu_items}
     157          104 :                 </DropdownList>
     158          104 :             </DropdownGroup>);
     159              : 
     160          104 :     const actions = <StorageBarMenu label={_("Create storage device")} menuItems={groups} />;
     161              : 
     162          104 :     return (
     163          104 :         <Stack hasGutter>
     164          104 :             { !client.in_anaconda_mode() &&
     165           94 :             <StackItem>
     166           94 :                 <Card isPlain>
     167           94 :                     <CardBody>
     168           94 :                         <StoragePlots plot_state={plot_state} />
     169           94 :                     </CardBody>
     170           94 :                 </Card>
     171           94 :             </StackItem>
     172              :             }
     173          104 :             <StackItem>
     174          104 :                 <StorageCard card={card} actions={actions}>
     175          104 :                     <ChildrenTable
     176          104 :                         emptyCaption={_("No storage found")}
     177          104 :                         aria-label={_("Storage")}
     178          104 :                         show_icons
     179          104 :                         page={card.page}
     180          104 :                     />
     181          104 :                 </StorageCard>
     182          104 :             </StackItem>
     183          104 :             { !client.in_anaconda_mode() &&
     184           94 :             <StackItem>
     185           94 :                 <StorageLogsPanel />
     186           94 :             </StackItem>
     187              :             }
     188          104 :         </Stack>);
     189          104 : };
        

Generated by: LCOV version 2.0-1