All files / modules/10-common/components/MultiTypeList MultiTypeList.tsx

95.83% Statements 23/24
77.27% Branches 17/22
85.71% Functions 6/7
95.65% Lines 22/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150              124x 124x 124x 124x             124x 124x 124x 124x 124x     124x                                           124x                     107x   107x   107x 199x     107x   107x                                           92x     72x                               1x                     4x                                                         124x  
/*
 * Copyright 2021 Harness Inc. All rights reserved.
 * Use of this source code is governed by the PolyForm Shield 1.0.0 license
 * that can be found in the licenses directory at the root of this repository, also available at
 * https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt.
 */
 
import React from 'react'
import { v4 as nameSpace, v5 as uuid } from 'uuid'
import cx from 'classnames'
import {
  FormInput,
  Button,
  getMultiTypeFromValue,
  MultiTypeInputType,
  MultiTextInputProps
} from '@wings-software/uicore'
import { FieldArray, connect, FormikContext } from 'formik'
import { get } from 'lodash-es'
import { ConfigureOptions, ConfigureOptionsProps } from '@common/components/ConfigureOptions/ConfigureOptions'
import { useStrings } from 'framework/strings'
import MultiTypeFieldSelector, {
  MultiTypeFieldSelectorProps
} from '@common/components/MultiTypeFieldSelector/MultiTypeFieldSelector'
import css from './MultiTypeList.module.scss'
 
export type ListValue = { id: string; value: string }[]
export type MultiTypeListType = ListValue | string
 
interface MultiTypeListConfigureOptionsProps
  extends Omit<ConfigureOptionsProps, 'value' | 'type' | 'variableName' | 'onChange'> {
  variableName?: ConfigureOptionsProps['variableName']
}
 
export interface MultiTypeListProps {
  name: string
  placeholder?: string
  multiTypeFieldSelectorProps: Omit<MultiTypeFieldSelectorProps, 'name' | 'defaultValueToReset' | 'children'>
  multiTextInputProps?: Omit<MultiTextInputProps, 'name'>
  enableConfigureOptions?: boolean
  configureOptionsProps?: MultiTypeListConfigureOptionsProps
  formik?: FormikContext<any>
  style?: React.CSSProperties
  disabled?: boolean
}
 
export const MultiTypeList = (props: MultiTypeListProps): React.ReactElement => {
  const {
    name,
    placeholder,
    multiTypeFieldSelectorProps,
    multiTextInputProps = {},
    enableConfigureOptions = true,
    configureOptionsProps,
    formik,
    disabled,
    ...restProps
  } = props
 
  const { getString } = useStrings()
 
  const getDefaultResetValue = () => {
    return [{ id: uuid('', nameSpace()), value: '' }]
  }
 
  const value = get(formik?.values, name, getDefaultResetValue()) as MultiTypeListType
 
  return (
    <div className={cx(css.group, css.withoutSpacing)} {...restProps}>
      {typeof value === 'string' && getMultiTypeFromValue(value) === MultiTypeInputType.RUNTIME ? (
        <FormInput.MultiTextInput
          style={{ flexGrow: 1, marginBottom: 0 }}
          name={name}
          multiTextInputProps={{
            allowableTypes: [MultiTypeInputType.FIXED, MultiTypeInputType.RUNTIME]
          }}
          {...multiTypeFieldSelectorProps}
        />
      ) : (
        <MultiTypeFieldSelector
          name={name}
          defaultValueToReset={getDefaultResetValue()}
          style={{ flexGrow: 1, marginBottom: 0 }}
          {...multiTypeFieldSelectorProps}
          disableTypeSelection={multiTypeFieldSelectorProps.disableTypeSelection || disabled}
        >
          <FieldArray
            name={name}
            render={({ push, remove }) => (
              <>
                {Array.isArray(value) &&
                  value.map(({ id }, index: number) => (
                    <div className={cx(css.group, css.withoutAligning)} key={id}>
                      <FormInput.MultiTextInput
                        label=""
                        name={`${name}[${index}].value`}
                        placeholder={placeholder}
                        multiTextInputProps={{
                          allowableTypes: [MultiTypeInputType.FIXED, MultiTypeInputType.EXPRESSION],
                          ...multiTextInputProps
                        }}
                        style={{ flexGrow: 1 }}
                        disabled={disabled}
                      />
                      <Button
                        icon="main-trash"
                        iconProps={{ size: 20 }}
                        minimal
                        onClick={() => remove(index)}
                        data-testid={`remove-${name}-[${index}]`}
                        disabled={disabled}
                      />
                    </div>
                  ))}
                <Button
                  intent="primary"
                  minimal
                  text={getString('plusAdd')}
                  data-testid={`add-${name}`}
                  onClick={() => push({ id: uuid('', nameSpace()), value: '' })}
                  disabled={disabled}
                  style={{ padding: 0 }}
                />
              </>
            )}
          />
        </MultiTypeFieldSelector>
      )}
      {enableConfigureOptions &&
        typeof value === 'string' &&
        getMultiTypeFromValue(value) === MultiTypeInputType.RUNTIME && (
          <ConfigureOptions
            style={{ marginTop: 11 }}
            value={value}
            type={getString('list')}
            variableName={name}
            showRequiredField={false}
            showDefaultField={false}
            showAdvanced={true}
            onChange={val => formik?.setFieldValue(name, val)}
            {...configureOptionsProps}
            isReadonly={props.disabled}
          />
        )}
    </div>
  )
}
 
export default connect(MultiTypeList)