All files / modules/75-cf/components/PipelineSteps/FlagConfigurationStep/FlagChanges/subSections ItemVariationDialog.tsx

100% Statements 30/30
87.5% Branches 14/16
100% Functions 15/15
100% Lines 26/26

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 151 152 153 154 155 156 157 158 159 160              7x 7x                       7x   7x                                                     7x                       28x 28x   28x 25x       28x 51x       28x 51x       28x 1x 5x 1x   1x     28x 2x     28x                                                       84x           84x         34x   34x                                                   7x  
/*
 * 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, { FC, ReactNode, useMemo, useRef } from 'react'
import {
  Button,
  ButtonVariation,
  Container,
  Dialog,
  Formik,
  FormikForm,
  FormInput,
  Layout,
  MultiSelectOption,
  SelectOption
} from '@wings-software/uicore'
import * as Yup from 'yup'
import type { FormikProps } from 'formik'
import { useStrings } from 'framework/strings'
import type { Variation } from 'services/cf'
 
interface ItemVariationDialogFormValues {
  variation: Variation['identifier']
  items: SelectOption[]
}
 
interface Item {
  identifier: string
  name: string
  [key: string]: any
}
 
export interface ItemVariationDialogProps {
  title: ReactNode
  itemPlaceholder: string
  itemLabel: string
  isOpen: boolean
  closeDialog: () => void
  selectedItems: Item[]
  selectedVariation?: Variation
  items: Item[]
  variations: Variation[]
  onChange: (selectedItems: Item[], selectedVariation: Variation) => void
}
 
const ItemVariationDialog: FC<ItemVariationDialogProps> = ({
  title,
  itemPlaceholder,
  itemLabel,
  isOpen,
  closeDialog,
  selectedItems,
  selectedVariation,
  items,
  variations,
  onChange
}) => {
  const { getString } = useStrings()
  const formRef = useRef<FormikProps<ItemVariationDialogFormValues>>()
 
  const initialItems = useMemo<ItemVariationDialogFormValues['items']>(
    () => selectedItems.map(({ name, identifier }) => ({ label: name, value: identifier })),
    [selectedItems]
  )
 
  const itemOptions = useMemo<MultiSelectOption[]>(
    () => items.map<MultiSelectOption>(({ name, identifier }) => ({ label: name, value: identifier })),
    [items]
  )
 
  const variationOptions = useMemo<SelectOption[]>(
    () => variations.map<SelectOption>(({ name, identifier }) => ({ label: name || identifier, value: identifier })),
    [variations]
  )
 
  const handleSubmit = (values: ItemVariationDialogFormValues): void => {
    onChange(
      items.filter(({ identifier }) => !!values.items.find(({ value }) => value === identifier)),
      variations.find(({ identifier }) => values.variation === identifier) as Variation
    )
    closeDialog()
  }
 
  const handleSubmitButtonClicked = (): void => {
    formRef.current?.submitForm()
  }
 
  return (
    <Dialog
      enforceFocus={false}
      isOpen={isOpen}
      title={title}
      onClose={closeDialog}
      style={{ paddingBottom: 'var(--spacing-13)' }} // 😭 can't do this via a class
      footer={
        <Layout.Horizontal spacing="small">
          <Button
            variation={ButtonVariation.PRIMARY}
            text={getString('done')}
            onClick={handleSubmitButtonClicked}
            disabled={!!formRef.current?.isValid}
          />
          <Button variation={ButtonVariation.SECONDARY} text={getString('cancel')} onClick={closeDialog} />
        </Layout.Horizontal>
      }
    >
      <Formik<ItemVariationDialogFormValues>
        formName="ItemVariation"
        initialValues={{ items: initialItems, variation: selectedVariation?.identifier || '' }}
        enableReinitialize={true}
        onSubmit={handleSubmit}
        validationSchema={Yup.object().shape({
          items: Yup.array()
            .of(
              Yup.object().shape({
                value: Yup.string().oneOf(itemOptions.map(({ value }) => value as string)),
                label: Yup.string()
              })
            )
            .required(),
          variation: Yup.string()
            .oneOf(variations.map(({ identifier }) => identifier))
            .required()
        })}
      >
        {formikProps => {
          formRef.current = formikProps
 
          return (
            <FormikForm>
              <Container height={250}>
                <FormInput.MultiSelect
                  placeholder={itemPlaceholder}
                  name="items"
                  items={itemOptions}
                  multiSelectProps={{ allowCreatingNewItems: false }}
                  label={itemLabel}
                />
                <FormInput.Select
                  placeholder={getString('cf.pipeline.flagConfiguration.selectVariation')}
                  usePortal={true}
                  name="variation"
                  items={variationOptions}
                  label={getString('cf.pipeline.flagConfiguration.variationServed')}
                />
              </Container>
            </FormikForm>
          )
        }}
      </Formik>
    </Dialog>
  )
}
 
export default ItemVariationDialog