LCOV - code coverage report
Current view: top level - src - PruneUnusedImagesModal.jsx Coverage Total Hit
Test: cockpit-podman Lines: 85.7 % 84 72
Test Date: 2025-05-21 17:35:03

            Line data    Source code
       1           43 : import React, { useState } from 'react';
       2              : 
       3              : import { Button } from "@patternfly/react-core/dist/esm/components/Button";
       4              : import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox";
       5              : import { List, ListItem } from "@patternfly/react-core/dist/esm/components/List";
       6              : import {
       7              :     Modal
       8              : } from '@patternfly/react-core/dist/esm/deprecated/components/Modal';
       9              : import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex";
      10              : 
      11              : import cockpit from 'cockpit';
      12              : 
      13              : import * as client from './client.js';
      14              : import * as utils from './util.js';
      15              : 
      16              : import "@patternfly/patternfly/utilities/Spacing/spacing.css";
      17              : 
      18           43 : const _ = cockpit.gettext;
      19              : 
      20            4 : function ImageOptions({ images, checked, user, handleChange, name, showCheckbox }) {
      21            4 :     const [isExpanded, onToggle] = useState(false);
      22            4 :     let shownImages = images;
      23            4 :     if (!isExpanded) {
      24            4 :         shownImages = shownImages.slice(0, 5);
      25            4 :     }
      26              : 
      27            0 :     if (shownImages.length === 0) {
      28            0 :         return null;
      29            0 :     }
      30            4 :     const listNameId = "list-" + name;
      31              : 
      32            4 :     return (
      33            4 :         <Flex flex={{ default: 'column' }}>
      34            4 :             {showCheckbox &&
      35            2 :                 <Checkbox
      36            2 :                   label={user.uid === 0
      37            2 :                       ? _("Delete unused system images:")
      38            2 :                       : cockpit.format(_("Delete unused images of user $0:"), user.name)}
      39            2 :                   isChecked={checked}
      40            2 :                   id={name}
      41            2 :                   name={name}
      42            1 :                   onChange={(_, val) => handleChange(val)}
      43            2 :                   aria-owns={listNameId}
      44            2 :                 />
      45              :             }
      46            4 :             <List id={listNameId}>
      47            4 :                 {shownImages.map((image, index) =>
      48            4 :                     <ListItem className="pf-v6-u-ml-md" key={index}>
      49            4 :                         {utils.image_name(image)}
      50            4 :                     </ListItem>
      51            4 :                 )}
      52            4 :                 {!isExpanded && images.length > 5 &&
      53            0 :                 <Button onClick={onToggle} variant="link" isInline>
      54            0 :                     {_("Show more")}
      55            0 :                 </Button>
      56              :                 }
      57            4 :             </List>
      58            4 :         </Flex>
      59              :     );
      60            4 : }
      61              : 
      62            4 : const PruneUnusedImagesModal = ({ close, unusedImages, onAddNotification, users }) => {
      63            4 :     const unusedOwners = users.filter(user => unusedImages.some(image => image.uid === user.uid));
      64            4 :     const [isPruning, setPruning] = useState(false);
      65            4 :     const [deleteOwners, setDeleteOwners] = useState(unusedOwners);
      66              : 
      67            4 :     const handlePruneUnusedImages = () => {
      68            4 :         setPruning(true);
      69              : 
      70            4 :         const actions = deleteOwners.map(owner => client.pruneUnusedImages(owner.con));
      71            4 :         Promise.all(actions).then(close)
      72            0 :                 .catch(ex => {
      73            0 :                     const error = _("Failed to prune unused images");
      74            0 :                     onAddNotification({ type: 'danger', error, errorDetail: ex.message });
      75            0 :                     close();
      76            0 :                 });
      77            4 :     };
      78              : 
      79            4 :     const showCheckboxes = unusedOwners.length > 1;
      80              : 
      81            1 :     const onCheckChange = (user, checked) => setDeleteOwners(prevState => {
      82            1 :         return checked ? prevState.concat([user]) : prevState.filter(u => u !== user);
      83            1 :     });
      84              : 
      85            4 :     return (
      86            4 :         <Modal isOpen
      87            4 :                onClose={close}
      88            4 :                position="top" variant="medium"
      89            4 :                title={cockpit.format(_("Prune unused images"))}
      90            4 :                footer={<>
      91            4 :                    <Button id="btn-img-delete" variant="danger"
      92            4 :                            spinnerAriaValueText={isPruning ? _("Pruning images") : undefined}
      93            4 :                            isLoading={isPruning}
      94            4 :                            isDisabled={deleteOwners.length === 0}
      95            4 :                            onClick={handlePruneUnusedImages}>
      96            4 :                        {isPruning ? _("Pruning images") : _("Prune")}
      97            4 :                    </Button>
      98            0 :                    <Button variant="link" onClick={() => close()}>{_("Cancel")}</Button>
      99            4 :                </>}
     100              :         >
     101            4 :             <Flex flex={{ default: 'column' }}>
     102            4 :                 {unusedOwners.map(user => (
     103            4 :                     <ImageOptions key={user.name}
     104            4 :                                   images={unusedImages.filter(image => image.uid === user.uid)}
     105            4 :                                   name={"deleteImages-" + user.name}
     106            4 :                                   checked={deleteOwners.some(u => u.uid === user.uid)}
     107            1 :                                   handleChange={checked => onCheckChange(user, checked)}
     108            4 :                                   showCheckbox={showCheckboxes}
     109            4 :                                   user={user} />))
     110              :                 }
     111            4 :             </Flex>
     112            4 :         </Modal>
     113              :     );
     114            4 : };
     115              : 
     116           43 : export default PruneUnusedImagesModal;
        

Generated by: LCOV version 2.0-1