@devtron-labs/devtron-fe-common-lib 0.0.58 → 0.0.59-beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/Common/Api.d.ts +9 -0
  2. package/dist/Common/Constants.d.ts +1 -0
  3. package/dist/Common/CustomInput/CustomInput.d.ts +1 -1
  4. package/dist/Common/CustomInput/Types.d.ts +2 -1
  5. package/dist/Common/SearchBar/types.d.ts +2 -2
  6. package/dist/Common/Types.d.ts +3 -2
  7. package/dist/Pages/GlobalConfigurations/BuildInfra/BuildInfraConfigForm.d.ts +4 -0
  8. package/dist/Pages/GlobalConfigurations/BuildInfra/BuildInfraDescriptionField.d.ts +4 -0
  9. package/dist/Pages/GlobalConfigurations/BuildInfra/BuildInfraFormAction.d.ts +7 -0
  10. package/dist/Pages/GlobalConfigurations/BuildInfra/BuildInfraFormItem.d.ts +4 -0
  11. package/dist/Pages/GlobalConfigurations/BuildInfra/BuildInfraProfileNameField.d.ts +4 -0
  12. package/dist/Pages/GlobalConfigurations/BuildInfra/Descriptor.d.ts +4 -0
  13. package/dist/Pages/GlobalConfigurations/BuildInfra/Footer.d.ts +4 -0
  14. package/dist/Pages/GlobalConfigurations/BuildInfra/constants.d.ts +52 -0
  15. package/dist/Pages/GlobalConfigurations/BuildInfra/index.d.ts +7 -0
  16. package/dist/Pages/GlobalConfigurations/BuildInfra/services.d.ts +6 -0
  17. package/dist/Pages/GlobalConfigurations/BuildInfra/types.d.ts +286 -0
  18. package/dist/Pages/GlobalConfigurations/BuildInfra/utils.d.ts +12 -0
  19. package/dist/Pages/GlobalConfigurations/index.d.ts +1 -0
  20. package/dist/Pages/index.d.ts +1 -0
  21. package/dist/Shared/Components/APIResponseHandler/APIResponseHandler.d.ts +4 -0
  22. package/dist/Shared/Components/APIResponseHandler/constants.d.ts +4 -0
  23. package/dist/Shared/Components/APIResponseHandler/index.d.ts +2 -0
  24. package/dist/Shared/Components/APIResponseHandler/types.d.ts +37 -0
  25. package/dist/Shared/Components/BulkSelection/BulkSelection.d.ts +4 -0
  26. package/dist/Shared/Components/BulkSelection/BulkSelectionDropdownItems.d.ts +4 -0
  27. package/dist/Shared/Components/BulkSelection/UseBulkSelection.d.ts +3 -0
  28. package/dist/Shared/Components/BulkSelection/constants.d.ts +8 -0
  29. package/dist/Shared/Components/BulkSelection/index.d.ts +4 -0
  30. package/dist/Shared/Components/BulkSelection/types.d.ts +50 -0
  31. package/dist/Shared/Components/ReactSelect/index.d.ts +1 -0
  32. package/dist/Shared/Components/ReactSelect/utils.d.ts +12 -0
  33. package/dist/Shared/Components/index.d.ts +3 -0
  34. package/dist/Shared/Helpers.d.ts +16 -0
  35. package/dist/Shared/index.d.ts +3 -0
  36. package/dist/Shared/validations.d.ts +7 -0
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.js +1342 -160
  39. package/package.json +1 -1
  40. package/src/Assets/Icon/ic-check-all.svg +5 -0
  41. package/src/Assets/Icon/ic-check-square.svg +4 -0
  42. package/src/Assets/Icon/ic-cpu.svg +4 -0
  43. package/src/Assets/Icon/ic-memory.svg +3 -0
  44. package/src/Assets/Icon/ic-timer.svg +3 -0
  45. package/src/Common/Api.ts +21 -0
  46. package/src/Common/BreadCrumb/Types.ts +0 -1
  47. package/src/Common/Checkbox.tsx +1 -0
  48. package/src/Common/Constants.ts +2 -1
  49. package/src/Common/CustomInput/CustomInput.tsx +6 -2
  50. package/src/Common/CustomInput/Types.ts +4 -3
  51. package/src/Common/DraggableWrapper/DraggableWrapper.tsx +3 -1
  52. package/src/Common/RJSF/utils.ts +2 -0
  53. package/src/Common/SearchBar/SearchBar.component.tsx +26 -15
  54. package/src/Common/SearchBar/searchBar.scss +1 -1
  55. package/src/Common/SearchBar/types.ts +1 -3
  56. package/src/Common/Types.ts +2 -1
  57. package/src/Pages/GlobalConfigurations/BuildInfra/BuildInfraConfigForm.tsx +128 -0
  58. package/src/Pages/GlobalConfigurations/BuildInfra/BuildInfraDescriptionField.tsx +44 -0
  59. package/src/Pages/GlobalConfigurations/BuildInfra/BuildInfraFormAction.tsx +106 -0
  60. package/src/Pages/GlobalConfigurations/BuildInfra/BuildInfraFormItem.tsx +55 -0
  61. package/src/Pages/GlobalConfigurations/BuildInfra/BuildInfraProfileNameField.tsx +32 -0
  62. package/src/Pages/GlobalConfigurations/BuildInfra/Descriptor.tsx +45 -0
  63. package/src/Pages/GlobalConfigurations/BuildInfra/Footer.tsx +55 -0
  64. package/src/Pages/GlobalConfigurations/BuildInfra/Readme.md +4 -0
  65. package/src/Pages/GlobalConfigurations/BuildInfra/constants.tsx +141 -0
  66. package/src/Pages/GlobalConfigurations/BuildInfra/index.ts +7 -0
  67. package/src/Pages/GlobalConfigurations/BuildInfra/services.tsx +167 -0
  68. package/src/Pages/GlobalConfigurations/BuildInfra/types.tsx +339 -0
  69. package/src/Pages/GlobalConfigurations/BuildInfra/utils.tsx +508 -0
  70. package/src/Pages/GlobalConfigurations/index.ts +1 -0
  71. package/src/Pages/index.ts +1 -0
  72. package/src/Shared/Components/APIResponseHandler/APIResponseHandler.tsx +41 -0
  73. package/src/Shared/Components/APIResponseHandler/constants.tsx +5 -0
  74. package/src/Shared/Components/APIResponseHandler/index.ts +2 -0
  75. package/src/Shared/Components/APIResponseHandler/types.tsx +39 -0
  76. package/src/Shared/Components/BulkSelection/BulkSelection.tsx +81 -0
  77. package/src/Shared/Components/BulkSelection/BulkSelectionDropdownItems.tsx +31 -0
  78. package/src/Shared/Components/BulkSelection/UseBulkSelection.tsx +99 -0
  79. package/src/Shared/Components/BulkSelection/constants.tsx +12 -0
  80. package/src/Shared/Components/BulkSelection/index.ts +4 -0
  81. package/src/Shared/Components/BulkSelection/types.tsx +58 -0
  82. package/src/Shared/Components/ReactSelect/index.ts +1 -0
  83. package/src/Shared/Components/ReactSelect/utils.tsx +97 -0
  84. package/src/Shared/Components/index.ts +3 -0
  85. package/src/Shared/Helpers.tsx +29 -0
  86. package/src/Shared/index.ts +3 -0
  87. package/src/Shared/validations.tsx +72 -0
  88. package/src/index.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.58",
3
+ "version": "0.0.59-beta-2",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -0,0 +1,5 @@
1
+ <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="2" y="2" width="11.2" height="11.2" rx="2" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M15.4667 5.86621V11.4662C15.4667 13.6754 13.6758 15.4662 11.4667 15.4662H5.8667" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M10.35 5.84961L6.85004 9.34945L5.10004 7.59961" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="2" y="2" width="12" height="12" rx="2" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M11.2083 5.95801L7.12498 10.0412L5.08331 7.99967" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
2
+ <path d="M12.5 5.625H7.5M12.5 8.125H7.5M15.625 3.125V16.875C15.625 17.2202 15.3452 17.5 15 17.5H5C4.65482 17.5 4.375 17.2202 4.375 16.875V3.125C4.375 2.77982 4.65482 2.5 5 2.5H15C15.3452 2.5 15.625 2.77982 15.625 3.125Z" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M10 15C10.5178 15 10.9375 14.5803 10.9375 14.0625C10.9375 13.5447 10.5178 13.125 10 13.125C9.48223 13.125 9.0625 13.5447 9.0625 14.0625C9.0625 14.5803 9.48223 15 10 15Z" fill="#596168"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
2
+ <path d="M16.25 8.125H18.125M16.25 11.875H18.125M1.875 8.125H3.75M1.875 11.875H3.75M11.875 16.25V18.125M8.125 16.25V18.125M11.875 1.875V3.75M8.125 1.875V3.75M7.8125 7.8125H12.1875V12.1875H7.8125V7.8125ZM4.375 3.75H15.625C15.9702 3.75 16.25 4.02982 16.25 4.375V15.625C16.25 15.9702 15.9702 16.25 15.625 16.25H4.375C4.02982 16.25 3.75 15.9702 3.75 15.625V4.375C3.75 4.02982 4.02982 3.75 4.375 3.75Z" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
2
+ <path d="M10 11.0415L13.0936 7.94791M8.125 1.6665H11.875M16.875 11.0415C16.875 14.8385 13.797 17.9165 10 17.9165C6.20304 17.9165 3.125 14.8385 3.125 11.0415C3.125 7.24455 6.20304 4.1665 10 4.1665C13.797 4.1665 16.875 7.24455 16.875 11.0415Z" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
package/src/Common/Api.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ServerErrors } from './ServerError'
2
2
  import { FALLBACK_REQUEST_TIMEOUT, Host, URLS } from './Constants'
3
3
  import { ResponseType, APIOptions } from './Types'
4
+ import { MutableRefObject } from 'react'
4
5
 
5
6
  const responseMessages = {
6
7
  100: 'Continue',
@@ -228,3 +229,23 @@ export const get = (url: string, options?: APIOptions): Promise<ResponseType> =>
228
229
  export const trash = (url: string, data?: object, options?: APIOptions): Promise<ResponseType> => {
229
230
  return fetchInTime(url, 'DELETE', data, options)
230
231
  }
232
+
233
+ /**
234
+ * Aborts the previous request before triggering next request
235
+ */
236
+ export const abortPreviousRequests = <T,>(
237
+ callback: () => Promise<T>,
238
+ abortControllerRef: MutableRefObject<AbortController>,
239
+ ): Promise<T> => {
240
+ abortControllerRef.current.abort()
241
+ // eslint-disable-next-line no-param-reassign
242
+ abortControllerRef.current = new AbortController()
243
+ return callback()
244
+ }
245
+
246
+ /**
247
+ * Returns true if the error is due to a aborted request
248
+ */
249
+ export const getIsRequestAborted = (error) =>
250
+ // The 0 code is common for aborted and blocked requests
251
+ error && error.code === 0 && error.message === 'The user aborted a request.'
@@ -1,4 +1,3 @@
1
-
2
1
  export interface Breadcrumb {
3
2
  to: string
4
3
  name: string
@@ -10,6 +10,7 @@ Valid States of Checkbox:
10
10
  5. disabled: false, checked: true, value: INTERMIDIATE
11
11
  6. disabled: false, checked: true, value: CHECKED
12
12
  */
13
+ // TODO: Associate label with input element
13
14
  export class Checkbox extends Component<CheckboxProps> {
14
15
  render() {
15
16
  let rootClassName = `${this.props.rootClassName ? this.props.rootClassName : ''}`
@@ -25,7 +25,8 @@ export const ROUTES = {
25
25
  USER_CHECK_ROLE: 'user/check/roles',
26
26
  IMAGE_TAGGING:'app/image-tagging',
27
27
  CD_MATERIAL_GET: 'app/cd-pipeline',
28
- DEPLOYMENT_TEMPLATE_LIST: 'app/template/list'
28
+ DEPLOYMENT_TEMPLATE_LIST: 'app/template/list',
29
+ INFRA_CONFIG_PROFILE: 'infra-config/profile',
29
30
  }
30
31
 
31
32
  export enum KEY_VALUE {
@@ -2,6 +2,7 @@ import { CustomInputProps } from './Types'
2
2
  import { ReactComponent as Info } from '../../Assets/Icon/ic-info-filled.svg'
3
3
  import { ReactComponent as ErrorIcon } from '../../Assets/Icon/ic-warning.svg'
4
4
 
5
+ // TODO: label association with input
5
6
  export function CustomInput({
6
7
  name,
7
8
  value,
@@ -13,7 +14,7 @@ export function CustomInput({
13
14
  disabled = false,
14
15
  labelClassName = '',
15
16
  placeholder = '',
16
- tabIndex = 1,
17
+ tabIndex = 0,
17
18
  dataTestid = '',
18
19
  isRequiredField = false,
19
20
  autoFocus = false,
@@ -30,6 +31,7 @@ export function CustomInput({
30
31
  required,
31
32
  additionalErrorInfo,
32
33
  inputWrapClassName = '',
34
+ inputProps = {},
33
35
  }: CustomInputProps) {
34
36
  function handleError(error: any): any[] {
35
37
  if (!Array.isArray(error)) {
@@ -93,7 +95,7 @@ export function CustomInput({
93
95
 
94
96
  return (
95
97
  <div className={`flex column left top ${inputWrapClassName}`}>
96
- {renderInputLabel()}
98
+ {renderInputLabel()}
97
99
  <input
98
100
  data-testid={dataTestid}
99
101
  type={type}
@@ -117,6 +119,8 @@ export function CustomInput({
117
119
  defaultValue={defaultValue}
118
120
  onKeyDown={onKeyDown}
119
121
  required={required}
122
+ // Will be passing other props like other data attributes etc from inputProps
123
+ {...inputProps}
120
124
  />
121
125
 
122
126
  {getInputError()}
@@ -1,4 +1,4 @@
1
- import React, { HTMLInputTypeAttribute } from 'react'
1
+ import React, { HTMLInputTypeAttribute, InputHTMLAttributes } from 'react'
2
2
 
3
3
  export interface CustomInputProps {
4
4
  name: string
@@ -6,7 +6,7 @@ export interface CustomInputProps {
6
6
  onChange: (e: any) => void
7
7
  onFocus?: (e: any) => void
8
8
  autoComplete?: string
9
- label?: string | React.ReactNode
9
+ label?: string | React.ReactNode
10
10
  labelClassName?: string
11
11
  type?: HTMLInputTypeAttribute
12
12
  disabled?: boolean
@@ -28,4 +28,5 @@ export interface CustomInputProps {
28
28
  required?: boolean
29
29
  additionalErrorInfo?: React.ReactNode
30
30
  inputWrapClassName?: string
31
- }
31
+ inputProps?: InputHTMLAttributes<HTMLInputElement>
32
+ }
@@ -94,8 +94,9 @@ export default function DraggableWrapper({
94
94
  }
95
95
 
96
96
  return (
97
+ // Since we are using position fixed so we need to disable click on the div so that it does not interfere with the click of other elements
97
98
  <div
98
- className="dc__position-fixed"
99
+ className="dc__position-fixed dc__disable-click"
99
100
  style={{
100
101
  zIndex,
101
102
  }}
@@ -106,6 +107,7 @@ export default function DraggableWrapper({
106
107
  {...childDivProps}
107
108
  style={{
108
109
  zIndex,
110
+ pointerEvents: 'auto',
109
111
  }}
110
112
  >
111
113
  {children}
@@ -19,6 +19,7 @@ export const getCommonSelectStyle = (styleOverrides = {}) => {
19
19
  ...base,
20
20
  paddingTop: 0,
21
21
  paddingBottom: 0,
22
+ cursor: 'pointer',
22
23
  }),
23
24
  control: (base, state) => ({
24
25
  ...base,
@@ -33,6 +34,7 @@ export const getCommonSelectStyle = (styleOverrides = {}) => {
33
34
  color: 'var(--N900)',
34
35
  backgroundColor: state.isFocused ? 'var(--N100)' : 'white',
35
36
  padding: '10px 12px',
37
+ cursor: 'pointer',
36
38
  }),
37
39
  dropdownIndicator: (base, state) => ({
38
40
  ...base,
@@ -1,4 +1,4 @@
1
- import { ChangeEvent, useCallback, useRef, useState, KeyboardEvent } from 'react'
1
+ import { ChangeEvent, useCallback, useRef, useState, KeyboardEvent, useEffect } from 'react'
2
2
  import { ReactComponent as Search } from '../../Assets/Icon/ic-search.svg'
3
3
  import { ReactComponent as Clear } from '../../Assets/Icon/ic-error-cross.svg'
4
4
  import { SearchBarProps } from './types'
@@ -55,9 +55,28 @@ const SearchBar = ({
55
55
  debounceTimeout,
56
56
  ])
57
57
 
58
+ // assuming initialSearchText will change if we are changing history otherwise will be constant and will not change
59
+ // since on changing history we expect to make api call using useAsync so not applying handleEnter
60
+ useEffect(() => {
61
+ inputRef.current.value = initialSearchText
62
+ setShowClearButton(!!initialSearchText)
63
+ }, [initialSearchText])
64
+
65
+ const _applySearch = (value: string) => {
66
+ handleSearchChange(value)
67
+ handleEnter(value)
68
+ }
69
+
70
+ const clearSearch = () => {
71
+ inputRef.current.value = ''
72
+ _applySearch('')
73
+ setShowClearButton(false)
74
+ }
75
+
58
76
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
59
77
  const { value } = e.target
60
78
  setShowClearButton(!!value)
79
+
61
80
  if (shouldDebounce) {
62
81
  debouncedSearchChange(value)
63
82
  } else {
@@ -65,43 +84,35 @@ const SearchBar = ({
65
84
  }
66
85
  }
67
86
 
68
- const _applySearch = (value: string) => {
69
- handleSearchChange(value)
70
- handleEnter(value)
71
- }
72
-
73
87
  const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
74
88
  const { key } = e
75
89
 
76
90
  if (key === 'Enter') {
91
+ e.preventDefault()
77
92
  const inputTarget = e.target as HTMLInputElement
78
93
  const value = inputTarget.value.trim()
79
94
  _applySearch(value)
80
95
  }
81
96
  }
82
97
 
83
- const clearSearch = () => {
84
- inputRef.current.value = ''
85
- _applySearch('')
86
- }
87
-
88
98
  return (
89
99
  <div className={containerClassName}>
90
- <div className="search-bar bcn-0 dc__block w-100 min-w-200 dc__position-rel en-2 bw-1 br-4 h-32">
91
- <Search className="search-bar__icon dc__position-abs icon-color-n6 icon-dim-18" />
100
+ <div className="search-bar bc-n50 focus-within-border-b5 dc__hover-border-n300 dc__block w-100 min-w-200 dc__position-rel en-2 bw-1 br-4 h-32">
101
+ <Search className="search-bar__icon dc__position-abs icon-color-n6 icon-dim-16" />
92
102
  <input
93
103
  placeholder="Search"
94
104
  data-testid="search-bar"
95
105
  type="text"
96
106
  {...inputProps}
97
107
  defaultValue={initialSearchText}
98
- className={`search-bar__input bcn-0 dc__position-abs w-100 h-100 br-4 dc__no-border pt-6 pr-10 pb-6 pl-30 fs-13 lh-20 fw-4 cn-9 placeholder-cn5 ${
108
+ className={`search-bar__input bc-n50 dc__position-abs w-100 h-100 br-4 dc__no-border pt-6 pr-10 pb-6 pl-30 fs-13 lh-20 fw-4 cn-9 placeholder-cn5 ${
99
109
  showClearButton ? 'pr-30' : 'pr-10'
100
110
  }`}
101
111
  onChange={handleChange}
102
112
  onKeyDown={handleKeyDown}
103
113
  ref={inputRef}
104
114
  />
115
+ {/* TODO: Sync with product since it should have ic-enter in case of not applied */}
105
116
  {showClearButton && (
106
117
  <button
107
118
  className="flex search-bar__clear-button dc__position-abs dc__transparent mt-0 mb-0 mr-5 ml-5"
@@ -109,7 +120,7 @@ const SearchBar = ({
109
120
  onClick={clearSearch}
110
121
  aria-label="Clear search"
111
122
  >
112
- <Clear className="icon-dim-18 icon-n4 dc__vertical-align-middle" />
123
+ <Clear className="icon-dim-16 icon-n4 dc__vertical-align-middle" />
113
124
  </button>
114
125
  )}
115
126
  </div>
@@ -3,7 +3,7 @@
3
3
  &:focus,
4
4
  &:focus-within {
5
5
  outline: none;
6
- border: solid 1px var(--B500);
6
+ border: solid 1px var(--B500) !important;
7
7
  }
8
8
 
9
9
  &__input {
@@ -1,5 +1,3 @@
1
- import { InputHTMLAttributes } from 'react'
2
-
3
1
  export interface SearchBarProps {
4
2
  /**
5
3
  * Initial search text
@@ -18,7 +16,7 @@ export interface SearchBarProps {
18
16
  /**
19
17
  * Input props for the search input
20
18
  */
21
- inputProps?: InputHTMLAttributes<HTMLInputElement>
19
+ inputProps?: React.InputHTMLAttributes<HTMLInputElement>
22
20
  /**
23
21
  * Class name for the container; can be used for handling width
24
22
  */
@@ -51,11 +51,12 @@ export interface Teams {
51
51
  export enum CHECKBOX_VALUE {
52
52
  CHECKED = 'CHECKED',
53
53
  INTERMEDIATE = 'INTERMEDIATE',
54
+ BULK_CHECKED = 'BULK_CHECKED',
54
55
  }
55
56
  export interface CheckboxProps {
56
57
  onChange: (event) => void
57
58
  isChecked: boolean
58
- value: 'CHECKED' | 'INTERMEDIATE'
59
+ value: 'CHECKED' | 'INTERMEDIATE' | 'BULK_CHECKED'
59
60
  disabled?: boolean
60
61
  tabIndex?: number
61
62
  rootClassName?: string
@@ -0,0 +1,128 @@
1
+ import { FunctionComponent } from 'react'
2
+ import { Progressing } from '../../../Common'
3
+ import BuildInfraFormAction from './BuildInfraFormAction'
4
+ import BuildInfraFormItem from './BuildInfraFormItem'
5
+ import BuildInfraProfileDescriptionField from './BuildInfraDescriptionField'
6
+ import BuildInfraProfileNameField from './BuildInfraProfileNameField'
7
+ import { BUILD_INFRA_FORM_FIELDS, BUILD_INFRA_TEXT } from './constants'
8
+ import { BuildInfraActionType, BuildInfraConfigFormProps, InheritingHeaderProps } from './types'
9
+
10
+ const InheritingHeader = ({
11
+ defaultHeading,
12
+ inheritingData,
13
+ isInheriting,
14
+ isDefaultProfile,
15
+ }: InheritingHeaderProps) => {
16
+ const inheritingDataString = inheritingData.map((data) => `${data.value} ${data.unit ?? ''}`).join(' - ')
17
+
18
+ if (isDefaultProfile || !isInheriting) {
19
+ // For typing issues
20
+ // eslint-disable-next-line react/jsx-no-useless-fragment
21
+ return <>{defaultHeading}</>
22
+ }
23
+
24
+ return (
25
+ <div className="flexbox dc__align-items-center dc__content-space w-100">
26
+ {defaultHeading}
27
+
28
+ <div className="flexbox dc__content-space w-100">
29
+ <span className="m-0 pt-0 pb-0 pl-4 pr-4 fs-13 lh-20 fw-4 cn-9 dc__ellipsis-right dc__word-break-all flex-grow-1">
30
+ {inheritingDataString}
31
+ </span>
32
+
33
+ {/* TODO: Add ellipsis */}
34
+ <p className="m-0 cn-7 fs-13 fw-4 lh-20 dc__no-shrink">
35
+ {BUILD_INFRA_TEXT.INHERITING_HEADING_DESCRIPTION}
36
+ </p>
37
+ </div>
38
+ </div>
39
+ )
40
+ }
41
+
42
+ const BuildInfraConfigForm: FunctionComponent<BuildInfraConfigFormProps> = ({
43
+ profileInput,
44
+ profileInputErrors,
45
+ handleProfileInputChange,
46
+ isDefaultProfile,
47
+ unitsMap,
48
+ configurationContainerLabel,
49
+ }) => {
50
+ const currentConfigurations = profileInput?.configurations
51
+
52
+ // will get the desired configuration from the currentConfigurations and then check if it is active or not
53
+ const isInheritingProfileValues = (actions: BuildInfraActionType[]) =>
54
+ actions.some((action) => !currentConfigurations[action.actionType].active)
55
+
56
+ // Had to show loader for an instance due to batching of state updates not working as expected :/
57
+ if (!currentConfigurations) {
58
+ return <Progressing pageLoader />
59
+ }
60
+
61
+ return (
62
+ <div className="flexbox-col dc__mxw-920 dc__gap-16">
63
+ {!isDefaultProfile && (
64
+ <div className="flexbox-col dc__gap-12">
65
+ <BuildInfraProfileNameField
66
+ handleProfileInputChange={handleProfileInputChange}
67
+ currentValue={profileInput.name}
68
+ error={profileInputErrors.name}
69
+ />
70
+
71
+ <BuildInfraProfileDescriptionField
72
+ handleProfileInputChange={handleProfileInputChange}
73
+ currentValue={profileInput.description}
74
+ error={profileInputErrors.description}
75
+ />
76
+ </div>
77
+ )}
78
+
79
+ <div className="flexbox-col dc__gap-12">
80
+ {configurationContainerLabel}
81
+
82
+ <div className="w-100 flexbox-col dc__gap-16 br-4 dc__border-n1 p-16">
83
+ {BUILD_INFRA_FORM_FIELDS.map((field, index) => (
84
+ <BuildInfraFormItem
85
+ key={field.locator}
86
+ marker={field.marker}
87
+ heading={
88
+ <InheritingHeader
89
+ defaultHeading={field.heading}
90
+ inheritingData={field.actions.map(
91
+ (action) => currentConfigurations[action.actionType],
92
+ )}
93
+ isInheriting={isInheritingProfileValues(field.actions)}
94
+ isDefaultProfile={isDefaultProfile}
95
+ />
96
+ }
97
+ showDivider={index !== BUILD_INFRA_FORM_FIELDS.length - 1}
98
+ isInheriting={isInheritingProfileValues(field.actions)}
99
+ handleProfileInputChange={handleProfileInputChange}
100
+ locator={field.locator}
101
+ isDefaultProfile={isDefaultProfile}
102
+ >
103
+ <div className="w-50 flexbox dc__gap-12 w-100 dc__align-start">
104
+ {field.actions.map((action) => (
105
+ <BuildInfraFormAction
106
+ key={action.actionType}
107
+ actionType={action.actionType}
108
+ label={action.label}
109
+ placeholder={action.placeholder}
110
+ error={profileInputErrors[action.actionType]}
111
+ // Assumption is for default profiles all input fields are required
112
+ isRequired
113
+ profileUnitsMap={unitsMap[action.actionType]}
114
+ handleProfileInputChange={handleProfileInputChange}
115
+ currentUnitName={currentConfigurations[action.actionType].unit}
116
+ currentValue={currentConfigurations[action.actionType].value}
117
+ />
118
+ ))}
119
+ </div>
120
+ </BuildInfraFormItem>
121
+ ))}
122
+ </div>
123
+ </div>
124
+ </div>
125
+ )
126
+ }
127
+
128
+ export default BuildInfraConfigForm
@@ -0,0 +1,44 @@
1
+ import { FormEvent, FunctionComponent } from 'react'
2
+ import { ReactComponent as ErrorIcon } from '../../../Assets/Icon/ic-warning.svg'
3
+ import { BuildInfraInputFieldComponentProps, BuildInfraMetaConfigTypes } from './types'
4
+ import { BUILD_INFRA_TEXT } from './constants'
5
+
6
+ const BuildInfraProfileDescriptionField: FunctionComponent<BuildInfraInputFieldComponentProps> = ({
7
+ handleProfileInputChange,
8
+ currentValue,
9
+ error,
10
+ }) => {
11
+ const handleChange = (e: FormEvent<HTMLTextAreaElement>) => {
12
+ handleProfileInputChange({
13
+ action: BuildInfraMetaConfigTypes.DESCRIPTION,
14
+ data: { value: e.currentTarget.value },
15
+ })
16
+ }
17
+
18
+ return (
19
+ <div className="flexbox-col dc__gap-4 w-100 dc__align-start">
20
+ <label htmlFor="build-infra-profile-description" className="m-0 fs-13 fw-4 lh-20 cn-7">
21
+ {BUILD_INFRA_TEXT.DESCRIPTION_LABEL}
22
+ </label>
23
+
24
+ <textarea
25
+ data-testid="build-infra-profile-description"
26
+ name="profile-description"
27
+ className="form__textarea mxh-140 dc__hover-border-n300"
28
+ id="build-infra-profile-description"
29
+ placeholder={BUILD_INFRA_TEXT.DESCRIPTION_PLACEHOLDER}
30
+ value={currentValue}
31
+ onChange={handleChange}
32
+ />
33
+
34
+ {error && (
35
+ <div className="form__error">
36
+ <ErrorIcon className="form__icon form__icon--error" />
37
+ {error}
38
+ </div>
39
+ )}
40
+ </div>
41
+ )
42
+ }
43
+
44
+ export default BuildInfraProfileDescriptionField
@@ -0,0 +1,106 @@
1
+ import { FormEvent, FunctionComponent, useMemo } from 'react'
2
+ import ReactSelect from 'react-select'
3
+ import { BuildInfraFormActionProps } from './types'
4
+ import { OptionType } from '../../../Common'
5
+ import { unitSelectorStyles } from './utils'
6
+ import { BUILD_INFRA_INPUT_CONSTRAINTS } from './constants'
7
+ import { ReactComponent as ErrorIcon } from '../../../Assets/Icon/ic-warning.svg'
8
+
9
+ /**
10
+ * In case need arise for variants break this CustomInput and Select as a separate component
11
+ */
12
+ const BuildInfraFormAction: FunctionComponent<BuildInfraFormActionProps> = ({
13
+ actionType,
14
+ label,
15
+ placeholder,
16
+ error,
17
+ isRequired,
18
+ profileUnitsMap,
19
+ handleProfileInputChange,
20
+ currentUnitName,
21
+ currentValue,
22
+ }) => {
23
+ const handleUnitChange = (selectedUnit: OptionType) => {
24
+ const data = {
25
+ unit: selectedUnit.label,
26
+ value: currentValue,
27
+ }
28
+ handleProfileInputChange({ action: actionType, data })
29
+ }
30
+
31
+ const handleInputChange = (e: FormEvent<HTMLInputElement>) => {
32
+ const data = {
33
+ unit: currentUnitName,
34
+ value: e.currentTarget.value,
35
+ }
36
+ handleProfileInputChange({ action: actionType, data })
37
+ }
38
+
39
+ const unitOptions = useMemo(() => {
40
+ const units =
41
+ Object.values(profileUnitsMap)?.map((unit) => ({
42
+ label: unit.name,
43
+ value: String(unit.conversionFactor),
44
+ })) ?? []
45
+ return units.sort((a, b) => Number(a.value) - Number(b.value))
46
+ }, [profileUnitsMap])
47
+
48
+ const currentUnit = useMemo(
49
+ () => unitOptions.find((unit) => unit.label === currentUnitName),
50
+ [unitOptions, currentUnitName],
51
+ )
52
+
53
+ return (
54
+ <div className="flexbox-col dc__gap-4 dc__mxw-420 w-100 dc__align-start">
55
+ <label
56
+ htmlFor={`${actionType}-input`}
57
+ className={`fs-13 fw-4 lh-20 cn-7 ${isRequired ? 'dc__required-field' : ''}`}
58
+ >
59
+ {label}
60
+ </label>
61
+ <div className="w-100 flexbox dc__align-items-center">
62
+ <div className="flex-grow-1">
63
+ <input
64
+ data-testid={`${actionType}-input-field`}
65
+ name={actionType}
66
+ type="number"
67
+ step={BUILD_INFRA_INPUT_CONSTRAINTS.STEP}
68
+ min={BUILD_INFRA_INPUT_CONSTRAINTS.MIN}
69
+ className="form__input dc__no-right-border dc__no-right-radius"
70
+ placeholder={placeholder}
71
+ value={currentValue}
72
+ onChange={handleInputChange}
73
+ required={isRequired}
74
+ autoComplete="off"
75
+ id={`${actionType}-input`}
76
+ />
77
+ </div>
78
+
79
+ {profileUnitsMap && (
80
+ <ReactSelect
81
+ name={`${actionType}-unit`}
82
+ className="bcn-0 dc__mxw-120"
83
+ options={unitOptions}
84
+ value={currentUnit}
85
+ onChange={handleUnitChange}
86
+ isSearchable={false}
87
+ components={{
88
+ IndicatorSeparator: null,
89
+ ClearIndicator: null,
90
+ }}
91
+ styles={unitSelectorStyles()}
92
+ />
93
+ )}
94
+ </div>
95
+
96
+ {error && (
97
+ <div className="form__error">
98
+ <ErrorIcon className="form__icon form__icon--error" />
99
+ {error}
100
+ </div>
101
+ )}
102
+ </div>
103
+ )
104
+ }
105
+
106
+ export default BuildInfraFormAction
@@ -0,0 +1,55 @@
1
+ import { FormEvent, FunctionComponent } from 'react'
2
+ import { BuildInfraFormItemProps, BuildInfraInheritActions } from './types'
3
+ import { CHECKBOX_VALUE, Checkbox } from '../../../Common'
4
+
5
+ const BuildInfraFormItem: FunctionComponent<BuildInfraFormItemProps> = ({
6
+ heading,
7
+ marker: Marker,
8
+ children,
9
+ isInheriting,
10
+ showDivider,
11
+ handleProfileInputChange,
12
+ locator,
13
+ isDefaultProfile,
14
+ }) => {
15
+ const handleActivationChange = (e: FormEvent<HTMLInputElement>) => {
16
+ const { checked } = e.currentTarget
17
+ const action = (checked ? `activate_${locator}` : `de_activate_${locator}`) as BuildInfraInheritActions
18
+ handleProfileInputChange({ action })
19
+ }
20
+
21
+ const renderMarker = () => {
22
+ if (isDefaultProfile) {
23
+ return <Marker className="icon-dim-20 dc__no-shrink" />
24
+ }
25
+
26
+ return (
27
+ <Checkbox
28
+ onChange={handleActivationChange}
29
+ isChecked={!isInheriting}
30
+ value={CHECKBOX_VALUE.CHECKED}
31
+ dataTestId={`${locator}_marker`}
32
+ />
33
+ )
34
+ }
35
+
36
+ // If in configuration active is false, means it is inheriting values from other profile
37
+ return (
38
+ <>
39
+ <div className="flexbox-col dc__gap-8 w-100">
40
+ <div className="flexbox dc__gap-12 dc__align-start w-100">
41
+ {renderMarker()}
42
+
43
+ <div className="flexbox-col dc__gap-8 w-100">
44
+ {heading}
45
+ {!isInheriting && children}
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ {showDivider && <div className="w-100 dc__border-bottom-n1" />}
51
+ </>
52
+ )
53
+ }
54
+
55
+ export default BuildInfraFormItem