LCOV - code coverage report
Current view: top level - src - PublishPort.jsx Coverage Total Hit
Test: cockpit-podman Lines: 98.3 % 115 113
Test Date: 2025-05-21 17:35:03

            Line data    Source code
       1           43 : import React from 'react';
       2              : 
       3              : import { Button } from "@patternfly/react-core/dist/esm/components/Button";
       4              : import { FormGroup } from "@patternfly/react-core/dist/esm/components/Form";
       5              : import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect";
       6              : import { Popover } from "@patternfly/react-core/dist/esm/components/Popover";
       7              : import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput";
       8              : import { Grid } from "@patternfly/react-core/dist/esm/layouts/Grid";
       9              : import { OutlinedQuestionCircleIcon, TrashIcon } from '@patternfly/react-icons';
      10              : import { FormHelper } from "cockpit-components-form-helper.jsx";
      11           43 : import ipaddr from "ipaddr.js";
      12              : 
      13              : import cockpit from 'cockpit';
      14              : 
      15              : import * as utils from './util.js';
      16              : 
      17           43 : const _ = cockpit.gettext;
      18              : 
      19           43 : const MAX_PORT = 65535;
      20              : 
      21            5 : export function validatePublishPort(value, key) {
      22            5 :     switch (key) {
      23            5 :     case "IP":
      24            5 :         if (value && !ipaddr.isValid(value))
      25            1 :             return _("Must be a valid IP address");
      26            5 :         break;
      27            5 :     case "hostPort": {
      28            5 :         if (value) {
      29            5 :             const hostPort = parseInt(value);
      30            5 :             if (hostPort < 1 || hostPort > MAX_PORT)
      31            1 :                 return _("1 to 65535");
      32            5 :         }
      33              : 
      34            5 :         break;
      35            5 :     }
      36            5 :     case "containerPort": {
      37            5 :         if (!value)
      38            1 :             return _("Container port must not be empty");
      39              : 
      40            5 :         const containerPort = parseInt(value);
      41            5 :         if (containerPort < 1 || containerPort > MAX_PORT)
      42            3 :             return _("1 to 65535");
      43              : 
      44            5 :         break;
      45            5 :     }
      46            0 :     default:
      47            0 :         console.error(`Unknown key "${key}"`); // not-covered: unreachable assertion
      48            5 :     }
      49            5 : }
      50              : 
      51            5 : export const PublishPort = ({ id, item, onChange, idx, removeitem, _itemCount, validationFailed, onValidationChange }) =>
      52              :     (
      53            5 :         <Grid hasGutter id={id}>
      54            5 :             <FormGroup className="pf-m-5-col-on-md"
      55            5 :                 id={id + "-ip-address-group"}
      56            5 :                 label={_("IP address")}
      57            5 :                 fieldId={id + "-ip-address"}
      58            5 :                 labelHelp={
      59            5 :                     <Popover aria-label={_("IP address help")}
      60            5 :                         enableFlip
      61            5 :                         bodyContent={_("If host IP is set to 0.0.0.0 or not set at all, the port will be bound on all IPs on the host.")}>
      62            5 :                         <Button variant="plain" hasNoPadding aria-label="More info" icon={<OutlinedQuestionCircleIcon />} />
      63            5 :                     </Popover>
      64              :                 }>
      65            5 :                 <TextInput id={id + "-ip-address"}
      66            5 :                         value={item.IP || ''}
      67            1 :                         validated={validationFailed?.IP ? "error" : "default"}
      68            5 :                         onChange={(_event, value) => {
      69            5 :                             utils.validationClear(validationFailed, "IP", onValidationChange);
      70            1 :                             utils.validationDebounce(() => onValidationChange({ ...validationFailed, IP: validatePublishPort(value, "IP") }));
      71            5 :                             onChange(idx, 'IP', value);
      72            5 :                         }} />
      73            5 :                 <FormHelper helperTextInvalid={validationFailed?.IP} />
      74            5 :             </FormGroup>
      75            5 :             <FormGroup className="pf-m-2-col-on-md"
      76            5 :                     id={id + "-host-port-group"}
      77            5 :                     label={_("Host port")}
      78            5 :                     fieldId={id + "-host-port"}
      79            5 :                     labelHelp={
      80            5 :                         <Popover aria-label={_("Host port help")}
      81            5 :                             enableFlip
      82            5 :                             bodyContent={_("If the host port is not set the container port will be randomly assigned a port on the host.")}>
      83            5 :                             <Button variant="plain" hasNoPadding aria-label="More info" icon={<OutlinedQuestionCircleIcon />} />
      84            5 :                         </Popover>
      85              :                     }>
      86            5 :                 <TextInput id={id + "-host-port"}
      87            5 :                             type='number'
      88            5 :                             step={1}
      89            5 :                             min={1}
      90            5 :                             max={MAX_PORT}
      91            5 :                             value={item.hostPort || ''}
      92            1 :                             validated={validationFailed?.hostPort ? "error" : "default"}
      93            5 :                             onChange={(_event, value) => {
      94            5 :                                 utils.validationClear(validationFailed, "hostPort", onValidationChange);
      95            1 :                                 utils.validationDebounce(() => onValidationChange({ ...validationFailed, hostPort: validatePublishPort(value, "hostPort") }));
      96            5 :                                 onChange(idx, 'hostPort', value);
      97            5 :                             }} />
      98            5 :                 <FormHelper helperTextInvalid={validationFailed?.hostPort} />
      99            5 :             </FormGroup>
     100            5 :             <FormGroup className="pf-m-3-col-on-md"
     101            5 :                         id={id + "-container-port-group"}
     102            5 :                         label={_("Container port")}
     103            5 :                         fieldId={id + "-container-port"} isRequired>
     104            5 :                 <TextInput id={id + "-container-port"}
     105            5 :                             type='number'
     106            5 :                             step={1}
     107            5 :                             min={1}
     108            5 :                             max={MAX_PORT}
     109            3 :                             validated={validationFailed?.containerPort ? "error" : "default"}
     110            5 :                             value={item.containerPort || ''}
     111            5 :                             onChange={(_event, value) => {
     112            5 :                                 utils.validationClear(validationFailed, "containerPort", onValidationChange);
     113            1 :                                 utils.validationDebounce(() => onValidationChange({ ...validationFailed, containerPort: validatePublishPort(value, "containerPort") }));
     114            5 :                                 onChange(idx, 'containerPort', value);
     115            5 :                             }} />
     116            5 :                 <FormHelper helperTextInvalid={validationFailed?.containerPort} />
     117            5 :             </FormGroup>
     118            5 :             <FormGroup className="pf-m-2-col-on-md"
     119            5 :                         label={_("Protocol")}
     120            5 :                         fieldId={id + "-protocol"}>
     121            5 :                 <FormSelect className='pf-v6-c-form-control container-port-protocol'
     122            5 :                             id={id + "-protocol"}
     123            5 :                             value={item.protocol}
     124            4 :                             onChange={(_event, value) => onChange(idx, 'protocol', value)}>
     125            5 :                     <FormSelectOption value='tcp' key='tcp' label={_("TCP")} />
     126            5 :                     <FormSelectOption value='udp' key='udp' label={_("UDP")} />
     127            5 :                 </FormSelect>
     128            5 :             </FormGroup>
     129            5 :             <FormGroup className="pf-m-1-col-on-md remove-button-group">
     130            5 :                 <Button variant='plain'
     131            5 :                             className="btn-close"
     132            5 :                             id={id + "-btn-close"}
     133            5 :                             size="sm"
     134            5 :                             aria-label={_("Remove item")}
     135            5 :                             icon={<TrashIcon />}
     136            4 :                             onClick={() => removeitem(idx)} />
     137            5 :             </FormGroup>
     138            5 :         </Grid>
     139              :     );
        

Generated by: LCOV version 2.0-1