@devtron-labs/devtron-fe-common-lib 0.0.39 → 0.0.40-beta-1

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 (63) hide show
  1. package/dist/Common/Common.service.d.ts +2 -2
  2. package/dist/Common/Constants.d.ts +1 -0
  3. package/dist/Common/RJSF/Form.d.ts +4 -0
  4. package/dist/Common/RJSF/common/FieldRow.d.ts +3 -0
  5. package/dist/Common/RJSF/common/types.d.ts +8 -0
  6. package/dist/Common/RJSF/config.d.ts +4 -0
  7. package/dist/Common/RJSF/constants.d.ts +5 -0
  8. package/dist/Common/RJSF/index.d.ts +2 -0
  9. package/dist/Common/RJSF/templates/ArrayFieldItemTemplate.d.ts +3 -0
  10. package/dist/Common/RJSF/templates/ArrayFieldTemplate.d.ts +3 -0
  11. package/dist/Common/RJSF/templates/BaseInput.d.ts +3 -0
  12. package/dist/Common/RJSF/templates/ButtonTemplates/AddButton.d.ts +3 -0
  13. package/dist/Common/RJSF/templates/ButtonTemplates/RemoveButton.d.ts +3 -0
  14. package/dist/Common/RJSF/templates/ButtonTemplates/SubmitButton.d.ts +3 -0
  15. package/dist/Common/RJSF/templates/ButtonTemplates/index.d.ts +3 -0
  16. package/dist/Common/RJSF/templates/Description.d.ts +3 -0
  17. package/dist/Common/RJSF/templates/Field.d.ts +3 -0
  18. package/dist/Common/RJSF/templates/FieldErrorTemplate.d.ts +3 -0
  19. package/dist/Common/RJSF/templates/ObjectFieldTemplate.d.ts +3 -0
  20. package/dist/Common/RJSF/templates/TitleField.d.ts +3 -0
  21. package/dist/Common/RJSF/templates/WrapIfAdditionalTemplate.d.ts +3 -0
  22. package/dist/Common/RJSF/templates/index.d.ts +10 -0
  23. package/dist/Common/RJSF/types.d.ts +3 -0
  24. package/dist/Common/RJSF/utils.d.ts +14 -0
  25. package/dist/Common/RJSF/widgets/Checkbox.d.ts +3 -0
  26. package/dist/Common/RJSF/widgets/Select.d.ts +3 -0
  27. package/dist/Common/RJSF/widgets/index.d.ts +2 -0
  28. package/dist/Common/Types.d.ts +36 -2
  29. package/dist/Common/index.d.ts +1 -0
  30. package/dist/index.js +567 -222
  31. package/package.json +4 -1
  32. package/src/Assets/Icon/ic-chevron-down.svg +5 -0
  33. package/src/Common/Common.service.ts +223 -76
  34. package/src/Common/Constants.ts +1 -0
  35. package/src/Common/ImageTags.tsx +11 -2
  36. package/src/Common/RJSF/Form.tsx +29 -0
  37. package/src/Common/RJSF/common/FieldRow.tsx +31 -0
  38. package/src/Common/RJSF/common/types.ts +9 -0
  39. package/src/Common/RJSF/config.ts +37 -0
  40. package/src/Common/RJSF/constants.ts +5 -0
  41. package/src/Common/RJSF/index.ts +2 -0
  42. package/src/Common/RJSF/rjsfForm.scss +17 -0
  43. package/src/Common/RJSF/templates/ArrayFieldItemTemplate.tsx +33 -0
  44. package/src/Common/RJSF/templates/ArrayFieldTemplate.tsx +77 -0
  45. package/src/Common/RJSF/templates/BaseInput.tsx +16 -0
  46. package/src/Common/RJSF/templates/ButtonTemplates/AddButton.tsx +18 -0
  47. package/src/Common/RJSF/templates/ButtonTemplates/RemoveButton.tsx +10 -0
  48. package/src/Common/RJSF/templates/ButtonTemplates/SubmitButton.tsx +18 -0
  49. package/src/Common/RJSF/templates/ButtonTemplates/index.ts +3 -0
  50. package/src/Common/RJSF/templates/Description.tsx +12 -0
  51. package/src/Common/RJSF/templates/Field.tsx +30 -0
  52. package/src/Common/RJSF/templates/FieldErrorTemplate.tsx +25 -0
  53. package/src/Common/RJSF/templates/ObjectFieldTemplate.tsx +96 -0
  54. package/src/Common/RJSF/templates/TitleField.tsx +9 -0
  55. package/src/Common/RJSF/templates/WrapIfAdditionalTemplate.tsx +51 -0
  56. package/src/Common/RJSF/templates/index.ts +10 -0
  57. package/src/Common/RJSF/types.ts +4 -0
  58. package/src/Common/RJSF/utils.ts +59 -0
  59. package/src/Common/RJSF/widgets/Checkbox.tsx +44 -0
  60. package/src/Common/RJSF/widgets/Select.tsx +76 -0
  61. package/src/Common/RJSF/widgets/index.ts +2 -0
  62. package/src/Common/Types.ts +44 -2
  63. package/src/Common/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.39",
3
+ "version": "0.0.40-beta-1",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -41,6 +41,9 @@
41
41
  "@sentry/browser": "^7.31.1"
42
42
  },
43
43
  "peerDependencies": {
44
+ "@rjsf/core": "^5.13.3",
45
+ "@rjsf/utils": "^5.13.3",
46
+ "@rjsf/validator-ajv8": "^5.13.3",
44
47
  "react": "^17.0.2",
45
48
  "react-dom": "^17.0.2",
46
49
  "react-router": "^5.3.0",
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <path fill="#999" class="fill-color" fill-rule="nonzero" d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/>
4
+ </g>
5
+ </svg>
@@ -2,7 +2,19 @@ import moment from 'moment';
2
2
  import {get, post} from './Api';
3
3
  import { ROUTES } from './Constants'
4
4
  import { sortCallback } from './Helper';
5
- import { TeamList ,ResponseType, DeploymentNodeType, CDModalTab, FilterStates } from './Types';
5
+ import {
6
+ TeamList,
7
+ ResponseType,
8
+ DeploymentNodeType,
9
+ CDModalTab,
10
+ FilterStates,
11
+ CDMaterialServiceEnum,
12
+ CDMaterialServiceQueryParams,
13
+ CDMaterialResponseType,
14
+ CDMaterialsMetaInfo,
15
+ CDMaterialsApprovalInfo,
16
+ CDMaterialFilterQuery,
17
+ } from './Types'
6
18
 
7
19
  export const getTeamListMin = (): Promise<TeamList> => {
8
20
  // ignore active field
@@ -30,7 +42,7 @@ interface UserRole extends ResponseType {
30
42
  }
31
43
  }
32
44
 
33
- let stageMap = {
45
+ const stageMap = {
34
46
  PRECD: 'PRE',
35
47
  CD: 'DEPLOY',
36
48
  POSTCD: 'POST',
@@ -51,83 +63,218 @@ export function setImageTags(request, pipelineId: number, artifactId: number){
51
63
  return post(`${ROUTES.IMAGE_TAGGING}/${pipelineId}/${artifactId}`,request )
52
64
  }
53
65
 
54
- // FIXME: This is only returning materials to cater the case of search in approval but it should be a common function service coming from dashboard.
55
- export const getCDMaterials = (
56
- cdMaterialId,
57
- stageType: DeploymentNodeType,
58
- abortSignal: AbortSignal,
59
- isApprovalNode?: boolean,
60
- imageTag?: string): Promise<any> => {
61
- const URL = (!imageTag) ? `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}` : `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}&search=${imageTag}`
62
-
63
- return get(URL, {
64
- signal: abortSignal,
65
- }).then((response) => {
66
- let artifacts = response.result.ci_artifacts ?? []
67
- if (!response.result) {
68
- return {
69
- materials: [],
66
+ const processURL = (url: string, params: object) => {
67
+ const validParams = Object.keys(params).filter((key) => {
68
+ return params[key] != null
69
+ })
70
+
71
+ if (!validParams.length) {
72
+ return url
73
+ }
74
+
75
+ const queryString = validParams
76
+ .map((key) => {
77
+ if (Array.isArray(params[key])) {
78
+ return `${key}=${params[key].join(',')}`
70
79
  }
80
+ return `${key}=${params[key]}`
81
+ })
82
+ .join('&')
83
+
84
+ return `${url}?${queryString}`
85
+ }
86
+
87
+ const cdMaterialListModal = (artifacts: any[], offset: number, artifactId?: number, artifactStatus?: string) => {
88
+ if (!artifacts || !artifacts.length) return []
89
+
90
+ const markFirstSelected = offset === 0
91
+ const startIndex = offset
92
+ let isImageMarked = false
93
+
94
+ const materials = artifacts.map((material, index) => {
95
+ let artifactStatusValue = ''
96
+ const filterState = material.filterState ?? FilterStates.ALLOWED
97
+
98
+ if (artifactId && artifactStatus && material.id === artifactId) {
99
+ artifactStatusValue = artifactStatus
71
100
  }
72
- else {
73
- const materials = artifacts.map((material, index) => {
74
- let artifactStatusValue = ''
75
- const filterState = material.filterState ?? FilterStates.ALLOWED
76
-
77
- return {
78
- index,
79
- id: material.id,
80
- deployedTime: material.deployed_time
81
- ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
82
- : 'Not Deployed',
83
- deployedBy: material.deployedBy,
84
- wfrId: material.wfrId,
85
- image: extractImage(material.image),
86
- showChanges: false,
87
- vulnerabilities: [],
88
- buildTime: material.build_time || '',
89
- tab: CDModalTab.Changes,
90
- showSourceInfo: false,
91
- deployed: material.deployed || false,
92
- latest: material.latest || false,
93
- vulnerabilitiesLoading: true,
94
- scanned: material.scanned,
95
- scanEnabled: material.scanEnabled,
96
- isSelected: !material.vulnerable && filterState === FilterStates.ALLOWED && index === 0,
97
- vulnerable: material.vulnerable,
98
- runningOnParentCd: material.runningOnParentCd,
99
- artifactStatus: artifactStatusValue,
100
- userApprovalMetadata: material.userApprovalMetadata,
101
- triggeredBy: material.triggeredBy,
102
- isVirtualEnvironment: material.isVirtualEnvironment,
103
- imageComment: material.imageComment,
104
- imageReleaseTags: material.imageReleaseTags,
105
- materialInfo: material.material_info
106
- ? material.material_info.map((mat) => {
107
- return {
108
- modifiedTime: mat.modifiedTime ? moment(mat.modifiedTime).format("ddd, DD MMM YYYY, hh:mm A") : '',
109
- commitLink: createGitCommitUrl(mat.url, mat.revision),
110
- author: mat.author || '',
111
- message: mat.message || '',
112
- revision: mat.revision || '',
113
- tag: mat.tag || '',
114
- webhookData: mat.webhookData || '',
115
- url: mat.url || '',
116
- branch:
117
- (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
118
- ? material.ciConfigureSourceValue
119
- : mat.branch) || '',
120
- type: material.ciConfigureSourceType || '',
121
- }
122
- })
123
- : [],
124
- filterState,
125
- }
126
- })
127
- return {
128
- materials: materials
129
- }
101
+
102
+ const selectImage =
103
+ !isImageMarked && markFirstSelected && filterState === FilterStates.ALLOWED ? !material.vulnerable : false
104
+ if (selectImage) {
105
+ isImageMarked = true
106
+ }
107
+
108
+ return {
109
+ index: startIndex + index,
110
+ id: material.id,
111
+ deployedTime: material.deployed_time
112
+ ? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
113
+ : 'Not Deployed',
114
+ deployedBy: material.deployedBy,
115
+ wfrId: material.wfrId,
116
+ tab: CDModalTab.Changes,
117
+ image: extractImage(material.image),
118
+ showChanges: false,
119
+ vulnerabilities: [],
120
+ buildTime: material.build_time || '',
121
+ isSelected: selectImage,
122
+ showSourceInfo: false,
123
+ deployed: material.deployed || false,
124
+ latest: material.latest || false,
125
+ vulnerabilitiesLoading: true,
126
+ scanned: material.scanned,
127
+ scanEnabled: material.scanEnabled,
128
+ vulnerable: material.vulnerable,
129
+ runningOnParentCd: material.runningOnParentCd,
130
+ artifactStatus: artifactStatusValue,
131
+ userApprovalMetadata: material.userApprovalMetadata,
132
+ triggeredBy: material.triggeredBy,
133
+ isVirtualEnvironment: material.isVirtualEnvironment,
134
+ imageComment: material.imageComment,
135
+ imageReleaseTags: material.imageReleaseTags,
136
+ // It is going to be null but required in type so can't remove
137
+ lastExecution: material.lastExecution,
138
+ materialInfo: material.material_info
139
+ ? material.material_info.map((mat) => {
140
+ return {
141
+ modifiedTime: mat.modifiedTime
142
+ ? moment(mat.modifiedTime).format('ddd, DD MMM YYYY, hh:mm A')
143
+ : '',
144
+ commitLink: createGitCommitUrl(mat.url, mat.revision),
145
+ author: mat.author || '',
146
+ message: mat.message || '',
147
+ revision: mat.revision || '',
148
+ tag: mat.tag || '',
149
+ webhookData: mat.webhookData || '',
150
+ url: mat.url || '',
151
+ branch:
152
+ (material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
153
+ ? material.ciConfigureSourceValue
154
+ : mat.branch) || '',
155
+ type: material.ciConfigureSourceType || '',
156
+ }
157
+ })
158
+ : [],
159
+ filterState,
160
+ appliedFiltersTimestamp: material.appliedFiltersTimestamp ?? '',
161
+ appliedFilters: material.appliedFilters ?? [],
162
+ appliedFiltersState: material.appliedFiltersState ?? FilterStates.ALLOWED,
163
+ createdTime: material.createdTime ?? '',
164
+ dataSource: material.data_source ?? '',
165
+ }
166
+ })
167
+ return materials
168
+ }
169
+
170
+ const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResult): CDMaterialsApprovalInfo => {
171
+ if (!enableApproval) {
172
+ return {
173
+ approvalUsers: [],
174
+ userApprovalConfig: null,
175
+ requestedUserId: 0,
176
+ }
177
+ }
178
+
179
+ return {
180
+ approvalUsers: cdMaterialsResult.approvalUsers,
181
+ userApprovalConfig: cdMaterialsResult.userApprovalConfig,
182
+ requestedUserId: cdMaterialsResult.requestedUserId,
183
+ }
184
+ }
185
+
186
+ const processCDMaterialsMetaInfo = (cdMaterialsResult): CDMaterialsMetaInfo => {
187
+ if (!cdMaterialsResult) {
188
+ return {
189
+ tagsEditable: false,
190
+ appReleaseTagNames: [],
191
+ hideImageTaggingHardDelete: false,
192
+ resourceFilters: [],
193
+ totalCount: 0,
194
+ canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
130
195
  }
196
+ }
197
+
198
+ return {
199
+ appReleaseTagNames: cdMaterialsResult.appReleaseTagNames,
200
+ tagsEditable: cdMaterialsResult.tagsEditable,
201
+ hideImageTaggingHardDelete: cdMaterialsResult.hideImageTaggingHardDelete,
202
+ resourceFilters: cdMaterialsResult.resourceFilters ?? [],
203
+ totalCount: cdMaterialsResult.totalCount ?? 0,
204
+ canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
205
+ }
206
+ }
207
+
208
+ const processCDMaterialServiceResponse = (
209
+ cdMaterialsResult,
210
+ stage: DeploymentNodeType,
211
+ offset: number,
212
+ filter: CDMaterialFilterQuery,
213
+ ): CDMaterialResponseType => {
214
+ if (!cdMaterialsResult) {
215
+ return {
216
+ materials: [],
217
+ ...processCDMaterialsMetaInfo(cdMaterialsResult),
218
+ ...processCDMaterialsApprovalInfo(false, cdMaterialsResult),
219
+ }
220
+ }
221
+
222
+ const materials = cdMaterialListModal(
223
+ cdMaterialsResult.ci_artifacts,
224
+ offset ?? 0,
225
+ cdMaterialsResult.latest_wf_artifact_id,
226
+ cdMaterialsResult.latest_wf_artifact_status,
227
+ )
228
+ const approvalInfo = processCDMaterialsApprovalInfo(
229
+ stage === DeploymentNodeType.CD || stage === DeploymentNodeType.APPROVAL,
230
+ cdMaterialsResult,
231
+ )
232
+ const metaInfo = processCDMaterialsMetaInfo(cdMaterialsResult)
233
+
234
+ // TODO: On update of service would remove from here
235
+ const filteredMaterials =
236
+ filter && filter === CDMaterialFilterQuery.RESOURCE
237
+ ? materials.filter((material) => {
238
+ return material.filterState === FilterStates.ALLOWED
239
+ })
240
+ : materials
241
+
242
+ return {
243
+ materials: filteredMaterials,
244
+ ...approvalInfo,
245
+ ...metaInfo,
246
+ }
247
+ }
248
+
249
+ const getSanitizedQueryParams = (queryParams: CDMaterialServiceQueryParams): CDMaterialServiceQueryParams => {
250
+ const { filter, ...rest } = queryParams
251
+ return rest
252
+ }
253
+
254
+ export const genericCDMaterialsService = (
255
+ serviceType: CDMaterialServiceEnum,
256
+ cdMaterialID: number,
257
+ stage: DeploymentNodeType,
258
+ signal: AbortSignal,
259
+ queryParams: CDMaterialServiceQueryParams = {},
260
+ ): Promise<CDMaterialResponseType> => {
261
+ // TODO: On update of service would remove from here
262
+ const manipulatedParams = getSanitizedQueryParams(queryParams)
263
+
264
+ let URL
265
+ switch (serviceType) {
266
+ case CDMaterialServiceEnum.ROLLBACK:
267
+ URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material/rollback`, manipulatedParams)
268
+ break
269
+
270
+ // Meant for handling getCDMaterialList
271
+ default:
272
+ URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material`, { ...manipulatedParams, stage: stageMap[stage] })
273
+ break
274
+ }
275
+
276
+ return get(URL, { signal }).then((response) => {
277
+ return processCDMaterialServiceResponse(response.result, stage, queryParams.offset, queryParams.filter)
131
278
  })
132
279
  }
133
280
 
@@ -24,6 +24,7 @@ export const ROUTES = {
24
24
  PROJECT_LIST_MIN: 'team/autocomplete',
25
25
  USER_CHECK_ROLE: 'user/check/roles',
26
26
  IMAGE_TAGGING:'app/image-tagging',
27
+ CD_MATERIAL_GET: 'app/cd-pipeline'
27
28
  }
28
29
 
29
30
  export enum KEY_VALUE {
@@ -18,8 +18,10 @@ import { showError, stopPropagation } from './Helper'
18
18
  import { TippyCustomized } from './TippyCustomized'
19
19
  import { setImageTags } from './Common.service'
20
20
  import Tippy from '@tippyjs/react'
21
+ import { Progressing } from './Progressing'
21
22
 
22
23
  export const ImageTagsContainer = ({
24
+ // Setting it to zero in case of external pipeline
23
25
  ciPipelineId,
24
26
  artifactId,
25
27
  imageComment,
@@ -47,6 +49,7 @@ export const ImageTagsContainer = ({
47
49
  const [hardDeleteTags, setHardDeleteTags] = useState<ReleaseTag[]>([])
48
50
  const [descriptionValidationMessage, setDescriptionValidationMessage] = useState<string>('')
49
51
  const [textInput, setTextInput] = useState<string>('')
52
+ const [loading, setLoading] = useState<boolean>(false)
50
53
 
51
54
 
52
55
  useEffect(() => {
@@ -213,7 +216,8 @@ export const ImageTagsContainer = ({
213
216
  }
214
217
 
215
218
  // set loading state true
216
- setImageTags(payload, ciPipelineId, artifactId)
219
+ setLoading(true)
220
+ setImageTags(payload, ciPipelineId ?? 0, artifactId)
217
221
  .then((res) => {
218
222
  const tags = res.result?.imageReleaseTags?.map((tag) => ({
219
223
  id: tag.id,
@@ -249,6 +253,9 @@ export const ImageTagsContainer = ({
249
253
  showError(err)
250
254
  }
251
255
  })
256
+ .finally(()=>{
257
+ setLoading(false)
258
+ })
252
259
  }
253
260
 
254
261
  const renderInfoCard = (): JSX.Element => {
@@ -425,6 +432,7 @@ export const ImageTagsContainer = ({
425
432
  stopPropagation(e)
426
433
  handleCancel()
427
434
  }}
435
+ disabled={loading}
428
436
  >
429
437
  Cancel
430
438
  </button>
@@ -436,8 +444,9 @@ export const ImageTagsContainer = ({
436
444
  stopPropagation(e)
437
445
  onClickSave()
438
446
  }}
447
+ disabled={loading}
439
448
  >
440
- Save
449
+ {loading ? <Progressing /> : 'Save'}
441
450
  </button>
442
451
  </div>
443
452
  </div>
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import RJSF from '@rjsf/core'
3
+ import RJSFValidator from '@rjsf/validator-ajv8'
4
+
5
+ import { templates, widgets } from './config'
6
+ import { FormProps } from './types'
7
+ import { translateString } from './utils'
8
+ import './rjsfForm.scss'
9
+
10
+ // Need to use this way because the default import was not working as expected
11
+ // The default import resolves to an object intead of a function
12
+ const Form = (RJSF as any).default as typeof RJSF
13
+ const validator = (RJSFValidator as any).default as typeof RJSFValidator
14
+
15
+ export const RJSFForm = (props: FormProps) => (
16
+ <Form
17
+ noHtml5Validate
18
+ showErrorList={false}
19
+ autoComplete="off"
20
+ {...props}
21
+ validator={validator}
22
+ templates={{
23
+ ...templates,
24
+ ...props.templates,
25
+ }}
26
+ widgets={{ ...widgets, ...props.widgets }}
27
+ translateString={translateString}
28
+ />
29
+ )
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { FieldRowProps } from './types'
3
+
4
+ export const FieldRowWithLabel = ({
5
+ showLabel,
6
+ label,
7
+ required,
8
+ children,
9
+ id,
10
+ shouldAlignCenter = true,
11
+ }: FieldRowProps) => (
12
+ <div
13
+ className={
14
+ showLabel
15
+ ? `display-grid dc__gap-12 rjsf-form-template__field ${shouldAlignCenter ? 'flex-align-center' : ''}`
16
+ : ''
17
+ }
18
+ >
19
+ {showLabel && (
20
+ <label className="cn-7 fs-13 lh-32 fw-4 flexbox mb-0" htmlFor={id}>
21
+ {!!label && (
22
+ <>
23
+ <span className="dc__ellipsis-right">{label}</span>
24
+ {required && <span className="cr-5">&nbsp;*</span>}
25
+ </>
26
+ )}
27
+ </label>
28
+ )}
29
+ {children}
30
+ </div>
31
+ )
@@ -0,0 +1,9 @@
1
+ import { FieldTemplateProps } from '@rjsf/utils'
2
+
3
+ export interface FieldRowProps extends Pick<FieldTemplateProps, 'children' | 'label' | 'required' | 'id'> {
4
+ showLabel?: boolean
5
+ /**
6
+ * @default true
7
+ */
8
+ shouldAlignCenter?: boolean
9
+ }
@@ -0,0 +1,37 @@
1
+ import React from 'react'
2
+ import { RegistryWidgetsType } from '@rjsf/utils'
3
+
4
+ import {
5
+ AddButton,
6
+ ArrayFieldItemTemplate,
7
+ ArrayFieldTemplate,
8
+ BaseInputTemplate,
9
+ DescriptionFieldTemplate,
10
+ FieldTemplate,
11
+ FieldErrorTemplate,
12
+ ObjectFieldTemplate,
13
+ RemoveButton,
14
+ SubmitButton,
15
+ TitleFieldTemplate,
16
+ WrapIfAdditionalTemplate,
17
+ } from './templates'
18
+ import { CheckboxWidget, SelectWidget } from './widgets'
19
+ import { FormProps } from './types'
20
+
21
+ export const widgets: RegistryWidgetsType = {
22
+ CheckboxWidget,
23
+ SelectWidget,
24
+ }
25
+
26
+ export const templates: FormProps['templates'] = {
27
+ ArrayFieldItemTemplate,
28
+ ArrayFieldTemplate,
29
+ BaseInputTemplate,
30
+ ButtonTemplates: { AddButton, RemoveButton, SubmitButton },
31
+ DescriptionFieldTemplate,
32
+ FieldTemplate,
33
+ FieldErrorTemplate,
34
+ ObjectFieldTemplate,
35
+ TitleFieldTemplate,
36
+ WrapIfAdditionalTemplate,
37
+ }
@@ -0,0 +1,5 @@
1
+ export const PLACEHOLDERS = {
2
+ SELECT: 'Please select an option',
3
+ INPUT: 'Please enter an input',
4
+ OBJECT_KEY: 'Please enter a value for the key',
5
+ }
@@ -0,0 +1,2 @@
1
+ export { RJSFForm } from './Form'
2
+ export * from './types'
@@ -0,0 +1,17 @@
1
+ .rjsf-form-template {
2
+ &__field {
3
+ grid-template-columns: 250px 1fr;
4
+ }
5
+
6
+ &__additional-fields {
7
+ grid-template-columns: 1fr 1fr minmax(20px, auto);
8
+ }
9
+
10
+ &__array-field-item {
11
+ grid-template-columns: 1fr auto;
12
+
13
+ & :first-child {
14
+ margin: 0;
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ import React, { CSSProperties } from 'react'
2
+ import { ArrayFieldTemplateItemType } from '@rjsf/utils'
3
+
4
+ export const ArrayFieldItemTemplate = ({
5
+ children,
6
+ className,
7
+ disabled,
8
+ hasToolbar,
9
+ hasRemove,
10
+ index,
11
+ onDropIndexClick,
12
+ readonly,
13
+ registry,
14
+ uiSchema,
15
+ }: ArrayFieldTemplateItemType) => {
16
+ const { RemoveButton } = registry.templates.ButtonTemplates
17
+
18
+ return (
19
+ <div className="display-grid rjsf-form-template__array-field-item flex-align-center dc__gap-8 mb-12">
20
+ {children}
21
+ {hasToolbar && hasRemove && (
22
+ <div>
23
+ <RemoveButton
24
+ disabled={disabled || readonly}
25
+ onClick={onDropIndexClick(index)}
26
+ uiSchema={uiSchema}
27
+ registry={registry}
28
+ />
29
+ </div>
30
+ )}
31
+ </div>
32
+ )
33
+ }
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import { getTemplate, getUiOptions, ArrayFieldTemplateProps, ArrayFieldTemplateItemType } from '@rjsf/utils'
3
+ import { FieldRowWithLabel } from '../common/FieldRow'
4
+
5
+ const ActionButton = ({ canAdd, onAddClick, disabled, readonly, uiSchema, registry }) => {
6
+ const {
7
+ ButtonTemplates: { AddButton },
8
+ } = registry.templates
9
+
10
+ return (
11
+ canAdd && (
12
+ <AddButton onClick={onAddClick} disabled={disabled || readonly} uiSchema={uiSchema} registry={registry} />
13
+ )
14
+ )
15
+ }
16
+
17
+ export const ArrayFieldTemplate = ({
18
+ canAdd,
19
+ className,
20
+ disabled,
21
+ idSchema,
22
+ uiSchema,
23
+ items,
24
+ onAddClick,
25
+ readonly,
26
+ registry,
27
+ required,
28
+ title,
29
+ }: ArrayFieldTemplateProps) => {
30
+ const uiOptions = getUiOptions(uiSchema)
31
+ const ArrayFieldItemTemplate = getTemplate<'ArrayFieldItemTemplate'>('ArrayFieldItemTemplate', registry, uiOptions)
32
+ const label = uiOptions.title || title
33
+
34
+ return (
35
+ <fieldset className={className} id={idSchema.$id}>
36
+ {/* Show the label here in case there are no items, otherwise handled by Field Template */}
37
+ {items.length ? (
38
+ <>
39
+ {items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType, index) => {
40
+ // Show the title as the label for the first field
41
+ const children = {
42
+ ...itemProps.children,
43
+ props: {
44
+ ...itemProps.children.props,
45
+ name: index === 0 ? label : '',
46
+ },
47
+ }
48
+ return (
49
+ <ArrayFieldItemTemplate key={key} {...itemProps}>
50
+ {children}
51
+ </ArrayFieldItemTemplate>
52
+ )
53
+ })}
54
+ <ActionButton
55
+ canAdd={canAdd}
56
+ onAddClick={onAddClick}
57
+ disabled={disabled}
58
+ readonly={readonly}
59
+ uiSchema={uiSchema}
60
+ registry={registry}
61
+ />
62
+ </>
63
+ ) : (
64
+ <FieldRowWithLabel label={label} required={required} showLabel id={idSchema.$id}>
65
+ <ActionButton
66
+ canAdd={canAdd}
67
+ onAddClick={onAddClick}
68
+ disabled={disabled}
69
+ readonly={readonly}
70
+ uiSchema={uiSchema}
71
+ registry={registry}
72
+ />
73
+ </FieldRowWithLabel>
74
+ )}
75
+ </fieldset>
76
+ )
77
+ }