LCOV - code coverage report
Current view: top level - pkg/lib - cockpit-components-checkbox-select.tsx Coverage Total Hit
Test: cockpit Lines: 96.9 % 64 62
Test Date: 2026-07-03 14:25:32

            Line data    Source code
       1              : /*
       2              : SPDX-License-Identifier: MIT
       3              : 
       4              : Copyright (c) 2019 Red Hat, Inc.
       5              : */
       6              : 
       7              : /* This is a copy of MultiTypeaheadSelect.tsx from
       8              : 
       9              :        https://github.com/patternfly/patternfly-react/blob/v5/packages/react-templates/src/components/Select/CheckboxSelect.tsx
      10              : 
      11              :    We don't use it directly from the @patternfly/react-templates node
      12              :    module since we want to add features to it, and also to isolate us
      13              :    from gratuitous upstream changes.
      14              : 
      15              :    Our changes:
      16              : 
      17              :    - The selection is controlled from the outside and not maintained
      18              :      as internal state. This is how things should work with React.
      19              : 
      20              :    - The selected value can be any JavaScript value, not just a string
      21              :      or number. Normally, the (stringified) value is used as a React
      22              :      key. If your values are not suitable for this because they are
      23              :      neither strings nor numbers, you need to provide an explicit key.
      24              : 
      25              :      { key: 12, value: { param: "filestate", value: "enabled" }, content: _("Enabled") }
      26              : 
      27              :    - The badge is always maintained by this component, in a way that
      28              :      avoids layout flicker.
      29              : 
      30              : */
      31              : 
      32              : /* eslint-disable */
      33              : 
      34           44 : import React from 'react';
      35              : import { Badge } from "@patternfly/react-core/dist/esm/components/Badge/index.js";
      36              : import { Select, SelectList, SelectOption, SelectOptionProps, SelectProps } from "@patternfly/react-core/dist/esm/components/Select/index.js";
      37              : import { MenuToggle, MenuToggleElement, MenuToggleProps } from "@patternfly/react-core/dist/esm/components/MenuToggle/index.js";
      38              : 
      39              : export interface CheckboxSelectOption<T> extends Omit<SelectOptionProps, 'content'> {
      40              :   /** Content of the select option. */
      41              :   content: React.ReactNode;
      42              :   /** Value of the select option. */
      43              :   value: T;
      44              : }
      45              : 
      46              : export interface CheckboxSelectProps<T> extends Omit<SelectProps, 'toggle' | 'onSelect'> {
      47              :   /** Options of the select. */
      48              :   options?: CheckboxSelectOption<T>[];
      49              :   /** Currently checked options */
      50              :   selected: T[];
      51              :   /** Callback triggered when checking or unchecking an option. */
      52              :   onSelect: (value: T, checked: boolean) => void;
      53              :   /** Callback triggered when the select opens or closes. */
      54              :   onToggle?: (nextIsOpen: boolean) => void;
      55              :   /** Flag indicating the select should be disabled. */
      56              :   isDisabled?: boolean;
      57              :   /** Content of the toggle. */
      58              :   toggleContent: React.ReactNode;
      59              :   /** Width of the toggle. */
      60              :   toggleWidth?: string;
      61              :   /** Additional props passed to the toggle. */
      62              :   toggleProps?: MenuToggleProps;
      63              :   /** Is there a badge with the selected options count? */
      64              :   noBadge?: boolean,
      65              : }
      66              : 
      67           37 : export function CheckboxSelect<T>({
      68           37 :   options,
      69           37 :   selected,
      70           37 :   isDisabled = false,
      71           37 :   onSelect,
      72           37 :   onToggle,
      73           37 :   toggleContent,
      74           37 :   toggleWidth,
      75           37 :   toggleProps,
      76           37 :   noBadge = false,
      77           37 :   ...props
      78           37 : }: CheckboxSelectProps<T>) {
      79           37 :   const [isOpen, setIsOpen] = React.useState(false);
      80              : 
      81           37 :   const checkboxSelectOptions = options?.map((option) => {
      82           37 :     const { content, value, key, ...props } = option;
      83           37 :     const isSelected = selected.includes(value);
      84           37 :     return (
      85            3 :       <SelectOption value={value} key={key !== undefined ? key : `${value}`}
      86           37 :                     hasCheckbox isSelected={isSelected} {...props}>
      87           37 :         {content}
      88           37 :       </SelectOption>
      89              :     );
      90           37 :   });
      91              : 
      92            2 :   const onToggleClick = () => {
      93            0 :     onToggle && onToggle(!isOpen);
      94            2 :     setIsOpen(!isOpen);
      95            2 :   };
      96              : 
      97            2 :   const _onSelect = (event: React.MouseEvent<Element, MouseEvent> | undefined, value: T | undefined) => {
      98            2 :     if (value && event) {
      99            2 :       onSelect(value, (event.target as HTMLInputElement).checked);
     100            2 :     }
     101            2 :   };
     102              : 
     103           37 :   const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
     104           37 :     <MenuToggle
     105           37 :       ref={toggleRef}
     106           37 :       onClick={onToggleClick}
     107           37 :       isExpanded={isOpen}
     108           37 :       isDisabled={isDisabled}
     109           37 :       style={
     110           37 :         {
     111           37 :           width: toggleWidth
     112           37 :         } as React.CSSProperties
     113              :       }
     114           37 :       {...toggleProps}
     115              :     >
     116           37 :       {toggleContent}
     117           37 :       {!noBadge &&
     118            4 :        <Badge style={{ visibility: selected.length > 0 ? "visible" : "hidden" }} isRead>
     119           27 :          {selected.length}
     120           27 :        </Badge>}
     121           37 :     </MenuToggle>
     122              :   );
     123              : 
     124           37 :   return (
     125           37 :     <Select
     126           37 :       isOpen={isOpen}
     127           37 :       selected={selected}
     128           37 :       onSelect={_onSelect}
     129            1 :       onOpenChange={(isOpen) => {
     130            0 :         onToggle && onToggle(isOpen);
     131            1 :         setIsOpen(isOpen);
     132            1 :       }}
     133           37 :       toggle={toggle}
     134           37 :       role="menu"
     135           37 :       {...props}
     136              :     >
     137           37 :       <SelectList>{checkboxSelectOptions}</SelectList>
     138           37 :     </Select>
     139              :   );
     140           37 : };
        

Generated by: LCOV version 2.0-1