All files / modules/70-pipeline/context StageErrorContext.tsx

20.63% Statements 13/63
0% Branches 0/32
22.22% Functions 4/18
22.81% Lines 13/57

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              124x   124x                                       124x         51x 46x 3x               124x 1x 1x                       1x                         1x                               1x                                           1x            
/*
 * 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, { useState } from 'react'
import type { FormikProps, FormikErrors } from 'formik'
import { clone, merge } from 'lodash-es'
 
interface DeployStageErrorState {
  errors: FormikErrors<unknown>
  forms: { [key: string]: React.MutableRefObject<FormikProps<unknown> | null>[] }
}
 
interface FormProps {
  tab: string
  form: React.MutableRefObject<FormikProps<unknown> | null>
}
 
export interface StageErrorContextInterface {
  state: DeployStageErrorState
  subscribeForm: (formData: FormProps) => void
  unSubscribeForm: (formData: FormProps) => void
  submitFormsForTab: (tab: string) => void
  checkErrorsForTab: (tab: string) => Promise<void>
}
 
export const StageErrorContext = React.createContext<StageErrorContextInterface>({
  state: {
    errors: {},
    forms: {}
  },
  subscribeForm: () => undefined,
  unSubscribeForm: () => undefined,
  submitFormsForTab: () => undefined,
  checkErrorsForTab: () => new Promise<void>(() => undefined)
})
 
export interface DeployStageErrorProviderProps {
  children: React.ReactNode
}
 
export function DeployStageErrorProvider(props: DeployStageErrorProviderProps): React.ReactElement {
  const [state, setState] = useState<DeployStageErrorState>({ errors: {}, forms: {} })
  const subscribeForm = React.useCallback((formData: FormProps): void => {
    setState(prevState => {
      const forms = clone(prevState).forms
      const existingForms = forms[formData.tab]
      if (existingForms) {
        existingForms.push(formData.form)
      } else {
        forms[formData.tab] = [formData.form]
      }
      return { ...prevState, forms }
    })
  }, [])
  const unSubscribeForm = React.useCallback((formData: FormProps) => {
    setState(prevState => {
      const forms = clone(prevState).forms
      const existingForms = forms[formData.tab]
      if (existingForms) {
        const index = existingForms.findIndex(form => form === formData.form)
        existingForms.splice(index, 1)
        if (existingForms.length === 0) delete forms[formData.tab]
        return { ...prevState, forms }
      }
      return { ...prevState }
    })
  }, [])
  const submitFormsForTab = (tab: string) => {
    const forms = state.forms[tab]
    if (!forms) return
    const promises = []
    for (const form of forms) {
      form.current?.submitForm()
      promises.push(form.current?.validateForm())
    }
    Promise.all(promises).then(values => {
      let errors = {}
      values.forEach(value => {
        errors = merge(errors, value)
      })
      setState({ ...state, errors })
    })
  }
  const checkErrorsForTab = (tab: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      const forms = state.forms[tab]
      if (!forms) resolve()
      const promises = []
      for (const form of forms) {
        form.current?.submitForm()
        promises.push(form.current?.validateForm())
      }
      Promise.all(promises).then(values => {
        let errors = {}
        let errorsCount = 0
        values.forEach(value => {
          errorsCount += Object.keys(value ?? {}).length
          errors = merge(errors, value)
        })
        setState({ ...state, errors })
        if (errorsCount === 0) resolve()
        reject()
      })
    })
  }
  return (
    <StageErrorContext.Provider value={{ state, subscribeForm, unSubscribeForm, checkErrorsForTab, submitFormsForTab }}>
      {props.children}
    </StageErrorContext.Provider>
  )
}