@digi-frontend/dgate-api-documentation 1.0.28 → 1.0.31

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 (103) hide show
  1. package/.editorconfig +12 -12
  2. package/.prettierignore +7 -7
  3. package/.prettierrc +15 -15
  4. package/dist/{a7568b270e175038.svg → 070dc6ecd197bc80.svg} +8 -8
  5. package/dist/{43595976d1fdccbf.svg → 2e10bbdb265df50e.svg} +4 -4
  6. package/dist/{b82c7612e73342f3.svg → 7f54eeb0bb2d1150.svg} +3 -3
  7. package/dist/{56dc416b683db280.svg → 8789eb84283ea95b.svg} +5 -5
  8. package/dist/{af16a554be8c4d69.svg → 9bdff13f8d8fa48a.svg} +3 -3
  9. package/dist/_virtual/index4.js +1 -1
  10. package/dist/_virtual/index5.js +1 -1
  11. package/dist/_virtual/index6.js +1 -1
  12. package/dist/{64efc2716808c4a4.svg → bb8b87cace25e052.svg} +3 -3
  13. package/dist/{72db3b05a96dd600.svg → d32ce84bbd78babd.svg} +3 -3
  14. package/dist/{844eba3f2e42a9eb.svg → d501922060662842.svg} +3 -3
  15. package/dist/node_modules/toposort/index.js +1 -1
  16. package/dist/node_modules/yup/index.esm.js +1 -1
  17. package/dist/src/assets/icons/AddRow.svg.js +1 -1
  18. package/dist/src/assets/icons/AddRow.svg.js.map +1 -1
  19. package/dist/src/assets/icons/CheckMarkSquare.svg.js +1 -1
  20. package/dist/src/assets/icons/CheckMarkSquare.svg.js.map +1 -1
  21. package/dist/src/assets/icons/CloseIcon.svg.js +1 -1
  22. package/dist/src/assets/icons/CloseIcon.svg.js.map +1 -1
  23. package/dist/src/assets/icons/DeleteIcon.svg.js +1 -1
  24. package/dist/src/assets/icons/DeleteIcon.svg.js.map +1 -1
  25. package/dist/src/assets/icons/DownArrow.svg.js +1 -1
  26. package/dist/src/assets/icons/DownArrow.svg.js.map +1 -1
  27. package/dist/src/assets/icons/EditIcon.svg.js +1 -1
  28. package/dist/src/assets/icons/EditIcon.svg.js.map +1 -1
  29. package/dist/src/assets/icons/UpArrow.svg.js +1 -1
  30. package/dist/src/assets/icons/UpArrow.svg.js.map +1 -1
  31. package/dist/src/assets/icons/deleteOutlinedIcon.svg.js +1 -1
  32. package/dist/src/assets/icons/deleteOutlinedIcon.svg.js.map +1 -1
  33. package/dist/src/components/Chips/Chips.js.map +1 -1
  34. package/dist/src/components/InfoForm/InfoForm.js.map +1 -1
  35. package/dist/src/components/JsonInput/JsonInput.js.map +1 -1
  36. package/dist/src/components/LivePreview/LivePreview.js.map +1 -1
  37. package/dist/src/components/MethodAccordion/MethodAccordion.js +1 -1
  38. package/dist/src/components/MethodAccordion/MethodAccordion.js.map +1 -1
  39. package/dist/src/components/SVGLoader/SVGLoader.js.map +1 -1
  40. package/dist/src/components/SectionHead/SectionHead.js.map +1 -1
  41. package/dist/src/components/SimpleLabelValue/SimpleLabelValue.js.map +1 -1
  42. package/dist/src/components/Tooltip/Tooltip.js.map +1 -1
  43. package/dist/src/components/dialog/index.js.map +1 -1
  44. package/dist/src/components/table/table.js +1 -1
  45. package/dist/src/components/table/table.js.map +1 -1
  46. package/dist/src/components/table/tags-table.js +1 -1
  47. package/dist/src/components/table/tags-table.js.map +1 -1
  48. package/dist/src/constants/index.js.map +1 -1
  49. package/dist/src/constants/regex.js.map +1 -1
  50. package/dist/src/helpers/layout.helper.js.map +1 -1
  51. package/dist/src/helpers/methodAccordion.helper.js.map +1 -1
  52. package/dist/src/layout/layout.js.map +1 -1
  53. package/dist/src/validator/form.scheme.js.map +1 -1
  54. package/dist/styles.css +212 -212
  55. package/package.json +43 -43
  56. package/rollup.config.js +35 -35
  57. package/src/assets/icons/AddRow.svg +3 -3
  58. package/src/assets/icons/CheckMarkSquare.svg +5 -5
  59. package/src/assets/icons/CloseIcon.svg +4 -4
  60. package/src/assets/icons/DeleteIcon.svg +3 -3
  61. package/src/assets/icons/DownArrow.svg +3 -3
  62. package/src/assets/icons/EditIcon.svg +3 -3
  63. package/src/assets/icons/UpArrow.svg +3 -3
  64. package/src/assets/icons/deleteOutlinedIcon.svg +8 -8
  65. package/src/assets/icons/index.ts +8 -8
  66. package/src/components/Chips/Chips.tsx +87 -87
  67. package/src/components/Chips/style.scss +147 -147
  68. package/src/components/InfoForm/InfoForm.module.scss +165 -165
  69. package/src/components/InfoForm/InfoForm.tsx +426 -426
  70. package/src/components/JsonInput/JsonInput.tsx +149 -149
  71. package/src/components/JsonInput/style.module.scss +133 -133
  72. package/src/components/LivePreview/LivePreview.module.scss +24 -24
  73. package/src/components/LivePreview/LivePreview.tsx +184 -184
  74. package/src/components/MethodAccordion/MethodAccordion.module.scss +338 -338
  75. package/src/components/MethodAccordion/MethodAccordion.tsx +515 -514
  76. package/src/components/SVGLoader/SVGLoader.tsx +94 -94
  77. package/src/components/SectionHead/SectionHead.scss +29 -29
  78. package/src/components/SectionHead/SectionHead.tsx +22 -22
  79. package/src/components/SimpleLabelValue/SimpleLabelValue.tsx +31 -31
  80. package/src/components/SimpleLabelValue/index.ts +1 -1
  81. package/src/components/SimpleLabelValue/style.scss +30 -30
  82. package/src/components/Tooltip/Tooltip.scss +133 -133
  83. package/src/components/Tooltip/Tooltip.tsx +85 -85
  84. package/src/components/_global.scss +337 -337
  85. package/src/components/dialog/dialog.ts +54 -54
  86. package/src/components/dialog/index.tsx +85 -85
  87. package/src/components/dialog/style.scss +104 -104
  88. package/src/components/table/style.scss +190 -190
  89. package/src/components/table/table.tsx +327 -322
  90. package/src/components/table/tags-table.tsx +348 -341
  91. package/src/constants/index.ts +93 -93
  92. package/src/constants/regex.ts +7 -7
  93. package/src/global.d.ts +13 -13
  94. package/src/helpers/layout.helper.ts +162 -162
  95. package/src/helpers/methodAccordion.helper.ts +19 -19
  96. package/src/index.ts +1 -1
  97. package/src/layout/layout.module.css +61 -61
  98. package/src/layout/layout.tsx +150 -150
  99. package/src/types/layout.type.ts +30 -30
  100. package/src/types/openApi.ts +108 -108
  101. package/src/types/transformedOpenApi.ts +52 -52
  102. package/src/validator/form.scheme.ts +70 -70
  103. package/tsconfig.json +33 -33
@@ -1,514 +1,515 @@
1
- import { useEffect, useState } from 'react'
2
- import { Accordion, Button, SelectGroup, SelectGroupV2, Switch, TextArea } from 'digitinary-ui'
3
- import SVGLoader from '../../components/SVGLoader/SVGLoader'
4
- import { DeleteIcon, DownArrowIcon, EditIcon, deleteOutlinedIcon } from '../../assets/icons'
5
- import { httpStatusCodes, methodColorMapping, paramsTableHeaders } from '../../constants/index'
6
- import Tooltip from '../../components/Tooltip/Tooltip'
7
- import { TransformedMethod } from '../../types/layout.type'
8
- import SimpleLabelValue from '../../components/SimpleLabelValue'
9
- import { capitalize, handleStatusColor } from '../../helpers/methodAccordion.helper'
10
- import ParamterTable from '../table/table'
11
- import CommonDialog from '../../components/dialog'
12
- import JsonInput from '../../components/JsonInput/JsonInput'
13
- import styles from './MethodAccordion.module.scss'
14
- import { Tags } from '@entities/openApi'
15
- import regex from '../../constants/regex'
16
-
17
- const httpStatusCodeOptions = httpStatusCodes.map((code) => ({
18
- label: (
19
- <div className={styles.statusCodeOptionContainer}>
20
- <div
21
- className={styles.statusCodeOptionCircle}
22
- style={{ backgroundColor: handleStatusColor(code) }}
23
- ></div>
24
- <span>{code}</span>
25
- </div>
26
- ),
27
- value: code,
28
- }))
29
-
30
- const MethodsAccordion = ({
31
- method,
32
- path,
33
- setFieldValue,
34
- readOnly,
35
- tags,
36
- isOpen,
37
- setIsOpen,
38
- }: {
39
- method: TransformedMethod
40
- path: string
41
- setFieldValue?: (key: string, value: string | string[]) => void
42
- readOnly?: boolean
43
- tags: Tags[]
44
- isOpen: boolean
45
- setIsOpen: (open: boolean) => void
46
- }) => {
47
- const [isExpanded, setIsExpanded] = useState({
48
- request: false,
49
- response: false,
50
- method: false,
51
- })
52
- const [isFormOpen, setIsFormOpen] = useState(false)
53
- const [tooltipRefs, setTooltipRefs] = useState<{ [key: number]: any }>({})
54
- const [tableData, setTableData] = useState([])
55
- const [openDeleteDialog, setOpenDeleteDialog] = useState(false)
56
- const [selectedParamIndex, setSelectedParamIndex] = useState<number | null>(null)
57
- const [selectedParamName, setSelectedParamName] = useState<string | null>(null)
58
- const [tableRecords, setTableRecords] = useState()
59
- const [selectionTags, setSelectionTags] = useState([])
60
- const [selectedStatusCode, setSelectedStatusCode] = useState(httpStatusCodeOptions[4])
61
- const currentResponse =
62
- method.responses.find((res) => Number(res.code) === selectedStatusCode.value) || '{}'
63
-
64
- const onTableChange = (key, value, index) => {
65
- const newTableData = tableData.map((item, tIndex) => {
66
- if (tIndex === index) {
67
- return { ...item, [key]: value }
68
- } else {
69
- return item
70
- }
71
- })
72
-
73
- setTableData(newTableData)
74
- }
75
-
76
- const generateTableData = (items) => {
77
- return items.map((item, index) => {
78
- return {
79
- id: index,
80
- paramName: item.name,
81
- paramType: capitalize(item.in),
82
- schemaType: capitalize(item.schema?.type) || '',
83
- required: (
84
- <>
85
- {readOnly ? (
86
- item.required ? (
87
- 'True'
88
- ) : (
89
- 'False'
90
- )
91
- ) : (
92
- <Switch
93
- checked={item.required}
94
- onClick={() => {
95
- if (readOnly) {
96
- return null
97
- }
98
- onTableChange('required', !item.required, index)
99
- setFieldValue(`parameters[${index}][required]`, !item.required)
100
- }}
101
- />
102
- )}
103
- </>
104
- ),
105
- description: (
106
- <div className={styles.paramDescContainer}>
107
- <Tooltip
108
- key={`${index}-description`}
109
- allowHTML
110
- disabled={method.parameters[index].description?.length <= 12}
111
- content={
112
- <div style={{ padding: '0.625rem' }}>{method.parameters[index].description}</div>
113
- }
114
- arrowWithBorder
115
- placement="bottom-end"
116
- type="function"
117
- delay={[0, 0]}
118
- onShow={() => tooltipRefs[index]?.hide()}
119
- >
120
- <p style={{ alignSelf: 'center' }}>
121
- {method.parameters[index].description
122
- ? method.parameters[index].description.substring(0, 12)
123
- : readOnly && '-'}
124
- {method.parameters[index].description &&
125
- method.parameters[index].description.length > 12
126
- ? '...'
127
- : ''}
128
- </p>
129
- </Tooltip>
130
- {!readOnly && (
131
- <Tooltip
132
- key={`${index}-add-edit-description`}
133
- allowHTML
134
- arrowWithBorder
135
- placement="bottom-end"
136
- type="function"
137
- trigger="click"
138
- delay={[0, 0]}
139
- onCreate={(instance) =>
140
- setTooltipRefs((prev) => ({
141
- ...prev,
142
- [index]: instance,
143
- }))
144
- }
145
- content={
146
- <div className={styles.editDescTooltipContent}>
147
- <p className={styles.editDescTooltipContent_header}>Description</p>
148
- <TextArea
149
- placeholder="Describe parameter..."
150
- value={item.description}
151
- disabled={readOnly}
152
- maxLength={120}
153
- onChange={(value) => {
154
- if (value === '' || regex.ASCII.test(value))
155
- onTableChange('description', value, index)
156
- }}
157
- />
158
- {!readOnly && (
159
- <Button
160
- className={styles.editDescTooltipContent_btn}
161
- variant="outlined"
162
- size="small"
163
- onClick={() => {
164
- setFieldValue(
165
- `parameters[${index}].description`,
166
- item.description?.trim()
167
- )
168
- tooltipRefs[index]?.hide()
169
- }}
170
- disabled={!item.description?.trim()}
171
- >
172
- Apply
173
- </Button>
174
- )}
175
- </div>
176
- }
177
- >
178
- {readOnly || method.parameters[index].description?.length > 0 ? (
179
- <Button
180
- className={styles.editDescBtn}
181
- variant="link"
182
- color="action"
183
- endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
184
- ></Button>
185
- ) : (
186
- <Button
187
- className={styles.editDescBtn}
188
- variant="link"
189
- color="action"
190
- endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
191
- >
192
- {readOnly ? 'View ' : 'Add '} Description
193
- </Button>
194
- )}
195
- </Tooltip>
196
- )}
197
-
198
- {!readOnly && <div className={styles.paramDescContainer_separator}></div>}
199
-
200
- {!readOnly && (
201
- <Button
202
- className={styles.deleteParamBtn}
203
- variant="link"
204
- color="error"
205
- endIcon={<SVGLoader src={DeleteIcon} width="1.125rem" height="1.125rem" />}
206
- onClick={() => handleDeleteClick(index, item.name)}
207
- ></Button>
208
- )}
209
- </div>
210
- ),
211
- }
212
- })
213
- }
214
-
215
- const confirmDeleteParameter = () => {
216
- if (selectedParamIndex !== null) {
217
- setTableData((prev) => prev.filter((_, i) => i !== selectedParamIndex))
218
- setFieldValue(
219
- `parameters`,
220
- method?.parameters?.filter((_, i) => i !== selectedParamIndex)
221
- )
222
- }
223
- setOpenDeleteDialog(false)
224
- setSelectedParamIndex(null)
225
- }
226
-
227
- const handleDeleteClick = (id: number, name: string) => {
228
- setSelectedParamIndex(id)
229
- setSelectedParamName(name)
230
-
231
- setOpenDeleteDialog(true)
232
- }
233
-
234
- const saveNewRow = (values) => {
235
- setTableData([...tableData, values])
236
- setFieldValue(`parameters`, [...method.parameters, values])
237
- }
238
-
239
- useEffect(() => {
240
- setTableRecords(generateTableData(tableData))
241
- }, [tableData])
242
-
243
- useEffect(() => {
244
- if (method?.parameters) {
245
- setTableData(method.parameters)
246
- }
247
- }, [method, path])
248
-
249
- useEffect(() => {
250
- // prepare tags selection list
251
- if (method?.tags.length || tags?.length) {
252
- const convertedStringArray = (method?.tags || [])?.map((item) => ({
253
- label: capitalize(item),
254
- value: item,
255
- }))
256
- const mergedArray = [
257
- ...convertedStringArray,
258
- ...(tags || []).map((item) => ({ label: capitalize(item.name), value: item.name })),
259
- ]
260
-
261
- const filteredArray = mergedArray.filter(
262
- (value, index, self) => index === self.findIndex((t) => t.value === value.value)
263
- )
264
-
265
- setSelectionTags(filteredArray)
266
- }
267
- }, [tags, method])
268
-
269
- return (
270
- <div>
271
- <Accordion
272
- expanded={isOpen}
273
- onChange={() => setIsOpen(!isOpen)}
274
- className={`${styles.methodAccordion} ${readOnly ? styles.readOnly : ''}`}
275
- summary={
276
- <div className={styles.methodSummaryContainer}>
277
- <div className={styles.methodSummary}>
278
- <span
279
- style={{
280
- backgroundColor: methodColorMapping?.[method?.type]?.color || '#3A6CD1',
281
- }}
282
- className={styles.methodLabel}
283
- >
284
- {methodColorMapping?.[method?.type]?.label || method?.type}
285
- </span>
286
- <span className={styles.methodPath}>{path}</span>
287
- </div>
288
- <div
289
- className={`${styles.methodExpandArrowContainer} ${isOpen ? styles.expanded : ''}`}
290
- >
291
- <SVGLoader src={DownArrowIcon} width="2rem" height="2rem" />
292
- </div>
293
- </div>
294
- }
295
- children={
296
- <div className={styles.methodAccordionContent}>
297
- <SelectGroup
298
- className={styles.methodDesc}
299
- disabled={readOnly}
300
- placeholder="Select Tags"
301
- label="Tags"
302
- value={method.tags?.map((t) => ({
303
- label: capitalize(t),
304
- value: t,
305
- }))}
306
- onChange={(item) => {
307
- setFieldValue(
308
- 'tags',
309
- item.map((i) => i.value)
310
- )
311
- }}
312
- options={[
313
- {
314
- list: selectionTags,
315
- },
316
- ]}
317
- isMultiple={true}
318
- withSearch={false}
319
- clearable={false}
320
- />
321
- {!readOnly ? (
322
- <TextArea
323
- className={styles.methodDesc}
324
- label="Description"
325
- placeholder="Describe the method's purpose and functionality..."
326
- maxLength={120}
327
- value={method?.description}
328
- onChange={(value) => {
329
- if (value === '' || regex.ASCII.test(value)) setFieldValue('description', value)
330
- }}
331
- />
332
- ) : (
333
- <SimpleLabelValue
334
- key={'description'}
335
- label={'Description: '}
336
- value={method?.description || '-'}
337
- />
338
- )}
339
- <div className={styles.paramsTable}>
340
- <ParamterTable
341
- id="paramter-table"
342
- data={tableRecords}
343
- headCells={paramsTableHeaders}
344
- isFormOpen={isFormOpen}
345
- setIsFormOpen={setIsFormOpen}
346
- saveNewRow={saveNewRow}
347
- readOnly={readOnly}
348
- />
349
- </div>
350
- {method?.type !== 'get' && (
351
- <Accordion
352
- expanded={isExpanded.request}
353
- onChange={() => null}
354
- className={styles.requestAccordion}
355
- summary={
356
- <span className={styles.requestAccordionSummary}>
357
- <div
358
- className={styles.requestAccordionSummary_title}
359
- onClick={() =>
360
- setIsExpanded((prev) => ({
361
- ...prev,
362
- request: !prev.request,
363
- }))
364
- }
365
- >
366
- <SVGLoader
367
- className={isExpanded.request ? styles.expanded : ''}
368
- src={DownArrowIcon}
369
- width="2rem"
370
- height="2rem"
371
- />
372
- Request
373
- {method?.type !== 'delete' && <span style={{ color: 'red' }}>*</span>}
374
- </div>
375
- </span>
376
- }
377
- children={
378
- <JsonInput
379
- acceptType="JSON"
380
- withFooter={!readOnly}
381
- className={'jsonField'}
382
- placeholder="Enter your request body as a JSON object...."
383
- fieldIsDisabled={readOnly}
384
- value={method?.requestBody?.content?.schema?.properties || '{}'}
385
- onChange={(value: string) => {
386
- setFieldValue('requestBody.content.schema.properties', value)
387
- }}
388
- onValidation={() => null}
389
- />
390
- }
391
- />
392
- )}
393
- <Accordion
394
- expanded={isExpanded.response}
395
- onChange={() => null}
396
- className={styles.responseAccordion}
397
- summary={
398
- <span className={styles.responseAccordionSummary}>
399
- <div
400
- className={styles.responseAccordionSummary_title}
401
- onClick={() =>
402
- setIsExpanded((prev) => ({
403
- ...prev,
404
- response: !prev.response,
405
- }))
406
- }
407
- >
408
- <SVGLoader
409
- className={isExpanded.response ? styles.expanded : ''}
410
- src={DownArrowIcon}
411
- width="2rem"
412
- height="2rem"
413
- />
414
- Response<span style={{ color: 'red' }}>*</span>
415
- </div>
416
-
417
- <SelectGroup
418
- withSearch={false}
419
- isMultiple={false}
420
- clearable={false}
421
- placeholder="200"
422
- options={[
423
- {
424
- list: httpStatusCodeOptions,
425
- },
426
- ]}
427
- value={selectedStatusCode}
428
- onChange={(value) => {
429
- setSelectedStatusCode(value)
430
- }}
431
- />
432
- </span>
433
- }
434
- children={
435
- <JsonInput
436
- acceptType="JSON"
437
- withFooter={!readOnly}
438
- className={'jsonField'}
439
- placeholder="Enter your response as a JSON object..."
440
- fieldIsDisabled={readOnly}
441
- value={currentResponse?.content?.schema?.properties || '{}'}
442
- onChange={(value) => {
443
- const currentResIndex = method.responses.findIndex(
444
- (res) => res.code === currentResponse.code
445
- )
446
-
447
- if (currentResIndex !== -1) {
448
- setFieldValue(
449
- `responses[${currentResIndex}].content.schema.properties`,
450
- value
451
- )
452
- } else {
453
- const clonedResponses = structuredClone(method.responses)
454
-
455
- clonedResponses.push({
456
- code: selectedStatusCode.value.toString(),
457
- content: {
458
- contentType: 'application/json',
459
- schema: {
460
- type: 'object',
461
- properties: value,
462
- },
463
- },
464
- })
465
-
466
- setFieldValue('responses', clonedResponses)
467
- }
468
- }}
469
- onValidation={() => null}
470
- />
471
- }
472
- />
473
- </div>
474
- }
475
- />
476
- <CommonDialog
477
- status="error"
478
- content={
479
- <p
480
- style={{
481
- textAlign: 'center',
482
- fontWeight: 400,
483
- fontSize: '1rem',
484
- lineHeight: '1.4375rem',
485
- }}
486
- className="delete-msg-container"
487
- >
488
- Are you sure you want to delete
489
- <span className="plan-name">
490
- Parameter <strong>{selectedParamName}</strong>
491
- </span>
492
- ?
493
- </p>
494
- }
495
- onSubmit={{
496
- onClick: confirmDeleteParameter,
497
- text: 'Delete',
498
- color: 'error',
499
- fullWidth: true,
500
- }}
501
- onCancel={{
502
- text: 'Cancel',
503
- color: 'normal',
504
- fullWidth: true,
505
- }}
506
- onClose={() => setOpenDeleteDialog(false)}
507
- open={openDeleteDialog}
508
- icon={<SVGLoader src={deleteOutlinedIcon} width="4.0625rem" height="4.0625rem" />}
509
- />
510
- </div>
511
- )
512
- }
513
-
514
- export default MethodsAccordion
1
+ import { useEffect, useState } from 'react'
2
+ import { Accordion, Button, SelectGroup, SelectGroupV2, Switch, TextArea } from 'digitinary-ui'
3
+ import SVGLoader from '../../components/SVGLoader/SVGLoader'
4
+ import { DeleteIcon, DownArrowIcon, EditIcon, deleteOutlinedIcon } from '../../assets/icons'
5
+ import { httpStatusCodes, methodColorMapping, paramsTableHeaders } from '../../constants/index'
6
+ import Tooltip from '../../components/Tooltip/Tooltip'
7
+ import { TransformedMethod } from '../../types/layout.type'
8
+ import SimpleLabelValue from '../../components/SimpleLabelValue'
9
+ import { capitalize, handleStatusColor } from '../../helpers/methodAccordion.helper'
10
+ import ParamterTable from '../table/table'
11
+ import CommonDialog from '../../components/dialog'
12
+ import JsonInput from '../../components/JsonInput/JsonInput'
13
+ import styles from './MethodAccordion.module.scss'
14
+ import { Tags } from '@entities/openApi'
15
+ import regex from '../../constants/regex'
16
+
17
+ const httpStatusCodeOptions = httpStatusCodes.map((code) => ({
18
+ label: (
19
+ <div className={styles.statusCodeOptionContainer}>
20
+ <div
21
+ className={styles.statusCodeOptionCircle}
22
+ style={{ backgroundColor: handleStatusColor(code) }}
23
+ ></div>
24
+ <span>{code}</span>
25
+ </div>
26
+ ),
27
+ value: code,
28
+ }))
29
+
30
+ const MethodsAccordion = ({
31
+ method,
32
+ path,
33
+ setFieldValue,
34
+ readOnly,
35
+ tags,
36
+ isOpen,
37
+ setIsOpen,
38
+ }: {
39
+ method: TransformedMethod
40
+ path: string
41
+ setFieldValue?: (key: string, value: string | string[]) => void
42
+ readOnly?: boolean
43
+ tags: Tags[]
44
+ isOpen: boolean
45
+ setIsOpen: (open: boolean) => void
46
+ }) => {
47
+ const [isExpanded, setIsExpanded] = useState({
48
+ request: false,
49
+ response: false,
50
+ method: false,
51
+ })
52
+ const [isFormOpen, setIsFormOpen] = useState(false)
53
+ const [tooltipRefs, setTooltipRefs] = useState<{ [key: number]: any }>({})
54
+ const [tableData, setTableData] = useState([])
55
+ const [openDeleteDialog, setOpenDeleteDialog] = useState(false)
56
+ const [selectedParamIndex, setSelectedParamIndex] = useState<number | null>(null)
57
+ const [selectedParamName, setSelectedParamName] = useState<string | null>(null)
58
+ const [tableRecords, setTableRecords] = useState()
59
+ const [selectionTags, setSelectionTags] = useState([])
60
+ const [selectedStatusCode, setSelectedStatusCode] = useState(httpStatusCodeOptions[4])
61
+ const currentResponse =
62
+ method.responses.find((res) => Number(res.code) === selectedStatusCode.value) || '{}'
63
+
64
+ const onTableChange = (key, value, index) => {
65
+ const newTableData = tableData.map((item, tIndex) => {
66
+ if (tIndex === index) {
67
+ return { ...item, [key]: value }
68
+ } else {
69
+ return item
70
+ }
71
+ })
72
+
73
+ setTableData(newTableData)
74
+ }
75
+
76
+ const generateTableData = (items) => {
77
+ return items.map((item, index) => {
78
+ return {
79
+ id: index,
80
+ paramName: item.name,
81
+ paramType: capitalize(item.in),
82
+ schemaType: capitalize(item.schema?.type) || '',
83
+ required: (
84
+ <>
85
+ {readOnly ? (
86
+ item.required ? (
87
+ 'True'
88
+ ) : (
89
+ 'False'
90
+ )
91
+ ) : (
92
+ <Switch
93
+ checked={item.required}
94
+ onClick={() => {
95
+ if (readOnly) {
96
+ return null
97
+ }
98
+ onTableChange('required', !item.required, index)
99
+ setFieldValue(`parameters[${index}][required]`, !item.required)
100
+ }}
101
+ />
102
+ )}
103
+ </>
104
+ ),
105
+ description: (
106
+ <div className={styles.paramDescContainer}>
107
+ <Tooltip
108
+ key={`${index}-description`}
109
+ allowHTML
110
+ disabled={method.parameters[index].description?.length <= 12}
111
+ content={
112
+ <div style={{ padding: '0.625rem' }}>{method.parameters[index].description}</div>
113
+ }
114
+ arrowWithBorder
115
+ placement="bottom-end"
116
+ type="function"
117
+ delay={[0, 0]}
118
+ onShow={() => tooltipRefs[index]?.hide()}
119
+ >
120
+ <p style={{ alignSelf: 'center' }}>
121
+ {method.parameters[index].description
122
+ ? method.parameters[index].description.substring(0, 12)
123
+ : readOnly && '-'}
124
+ {method.parameters[index].description &&
125
+ method.parameters[index].description.length > 12
126
+ ? '...'
127
+ : ''}
128
+ </p>
129
+ </Tooltip>
130
+ {!readOnly && (
131
+ <Tooltip
132
+ key={`${index}-add-edit-description`}
133
+ allowHTML
134
+ arrowWithBorder
135
+ placement="bottom-end"
136
+ type="function"
137
+ trigger="click"
138
+ delay={[0, 0]}
139
+ onCreate={(instance) =>
140
+ setTooltipRefs((prev) => ({
141
+ ...prev,
142
+ [index]: instance,
143
+ }))
144
+ }
145
+ content={
146
+ <div className={styles.editDescTooltipContent}>
147
+ <p className={styles.editDescTooltipContent_header}>Description</p>
148
+ <TextArea
149
+ placeholder="Describe parameter..."
150
+ value={item.description}
151
+ disabled={readOnly}
152
+ maxLength={120}
153
+ onChange={(value) => {
154
+ if (value === '' || regex.ASCII.test(value))
155
+ onTableChange('description', value, index)
156
+ }}
157
+ />
158
+ {!readOnly && (
159
+ <Button
160
+ className={styles.editDescTooltipContent_btn}
161
+ variant="outlined"
162
+ size="small"
163
+ onClick={() => {
164
+ setFieldValue(
165
+ `parameters[${index}].description`,
166
+ item.description?.trim()
167
+ )
168
+ tooltipRefs[index]?.hide()
169
+ }}
170
+ disabled={!item.description?.trim()}
171
+ >
172
+ Apply
173
+ </Button>
174
+ )}
175
+ </div>
176
+ }
177
+ >
178
+ {readOnly || method.parameters[index].description?.length > 0 ? (
179
+ <Button
180
+ className={styles.editDescBtn}
181
+ variant="link"
182
+ color="action"
183
+ endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
184
+ ></Button>
185
+ ) : (
186
+ <Button
187
+ className={styles.editDescBtn}
188
+ variant="link"
189
+ color="action"
190
+ endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
191
+ >
192
+ {readOnly ? 'View ' : 'Add '} Description
193
+ </Button>
194
+ )}
195
+ </Tooltip>
196
+ )}
197
+
198
+ {!readOnly && <div className={styles.paramDescContainer_separator}></div>}
199
+
200
+ {!readOnly && (
201
+ <Button
202
+ className={styles.deleteParamBtn}
203
+ variant="link"
204
+ color="error"
205
+ endIcon={<SVGLoader src={DeleteIcon} width="1.125rem" height="1.125rem" />}
206
+ onClick={() => handleDeleteClick(index, item.name)}
207
+ ></Button>
208
+ )}
209
+ </div>
210
+ ),
211
+ }
212
+ })
213
+ }
214
+
215
+ const confirmDeleteParameter = () => {
216
+ if (selectedParamIndex !== null) {
217
+ setTableData((prev) => prev.filter((_, i) => i !== selectedParamIndex))
218
+ setFieldValue(
219
+ `parameters`,
220
+ method?.parameters?.filter((_, i) => i !== selectedParamIndex)
221
+ )
222
+ }
223
+ setOpenDeleteDialog(false)
224
+ setSelectedParamIndex(null)
225
+ }
226
+
227
+ const handleDeleteClick = (id: number, name: string) => {
228
+ setSelectedParamIndex(id)
229
+ setSelectedParamName(name)
230
+
231
+ setOpenDeleteDialog(true)
232
+ }
233
+
234
+ const saveNewRow = (values) => {
235
+ setTableData([...tableData, values])
236
+ setFieldValue(`parameters`, [...method.parameters, values])
237
+ }
238
+
239
+ useEffect(() => {
240
+ setTableRecords(generateTableData(tableData))
241
+ }, [tableData])
242
+
243
+ useEffect(() => {
244
+ if (method?.parameters) {
245
+ setTableData(method.parameters)
246
+ }
247
+ }, [method, path])
248
+
249
+ useEffect(() => {
250
+ // prepare tags selection list
251
+ if (method?.tags.length || tags?.length) {
252
+ const convertedStringArray = (method?.tags || [])?.map((item) => ({
253
+ label: capitalize(item),
254
+ value: item,
255
+ }))
256
+ const mergedArray = [
257
+ ...convertedStringArray,
258
+ ...(tags || []).map((item) => ({ label: capitalize(item.name), value: item.name })),
259
+ ]
260
+
261
+ const filteredArray = mergedArray.filter(
262
+ (value, index, self) => index === self.findIndex((t) => t.value === value.value)
263
+ )
264
+
265
+ setSelectionTags(filteredArray)
266
+ }
267
+ }, [tags, method])
268
+
269
+ return (
270
+ <div>
271
+ <Accordion
272
+ expanded={isOpen}
273
+ onChange={() => setIsOpen(!isOpen)}
274
+ className={`${styles.methodAccordion} ${readOnly ? styles.readOnly : ''}`}
275
+ summary={
276
+ <div className={styles.methodSummaryContainer}>
277
+ <div className={styles.methodSummary}>
278
+ <span
279
+ style={{
280
+ backgroundColor: methodColorMapping?.[method?.type]?.color || '#3A6CD1',
281
+ }}
282
+ className={styles.methodLabel}
283
+ >
284
+ {methodColorMapping?.[method?.type]?.label || method?.type}
285
+ </span>
286
+ <span className={styles.methodPath}>{path}</span>
287
+ </div>
288
+ <div
289
+ className={`${styles.methodExpandArrowContainer} ${isOpen ? styles.expanded : ''}`}
290
+ >
291
+ <SVGLoader src={DownArrowIcon} width="2rem" height="2rem" />
292
+ </div>
293
+ </div>
294
+ }
295
+ children={
296
+ <div className={styles.methodAccordionContent}>
297
+ <SelectGroup
298
+ className={styles.methodDesc}
299
+ disabled={readOnly}
300
+ placeholder="Select Tags"
301
+ label="Tags"
302
+ value={method.tags?.map((t) => ({
303
+ label: capitalize(t),
304
+ value: t,
305
+ }))}
306
+ onChange={(item) => {
307
+ setFieldValue(
308
+ 'tags',
309
+ item.map((i) => i.value)
310
+ )
311
+ }}
312
+ options={[
313
+ {
314
+ list: selectionTags,
315
+ },
316
+ ]}
317
+ isMultiple={true}
318
+ withSearch={false}
319
+ clearable={false}
320
+ />
321
+ {!readOnly ? (
322
+ <TextArea
323
+ className={styles.methodDesc}
324
+ label="Description"
325
+ placeholder="Describe the method's purpose and functionality..."
326
+ maxLength={120}
327
+ value={method?.description}
328
+ onChange={(value) => {
329
+ if (value === '' || regex.ASCII.test(value)) setFieldValue('description', value)
330
+ }}
331
+ />
332
+ ) : (
333
+ <SimpleLabelValue
334
+ key={'description'}
335
+ label={'Description: '}
336
+ value={method?.description || '-'}
337
+ />
338
+ )}
339
+ <div className={styles.paramsTable}>
340
+ <ParamterTable
341
+ id="paramter-table"
342
+ data={tableRecords}
343
+ headCells={paramsTableHeaders}
344
+ isFormOpen={isFormOpen}
345
+ setIsFormOpen={setIsFormOpen}
346
+ saveNewRow={saveNewRow}
347
+ readOnly={readOnly}
348
+ />
349
+ </div>
350
+ {method?.type !== 'get' && (
351
+ <Accordion
352
+ expanded={isExpanded.request}
353
+ onChange={() => null}
354
+ className={styles.requestAccordion}
355
+ summary={
356
+ <span className={styles.requestAccordionSummary}>
357
+ <div
358
+ className={styles.requestAccordionSummary_title}
359
+ onClick={() =>
360
+ setIsExpanded((prev) => ({
361
+ ...prev,
362
+ request: !prev.request,
363
+ }))
364
+ }
365
+ >
366
+ <SVGLoader
367
+ className={isExpanded.request ? styles.expanded : ''}
368
+ src={DownArrowIcon}
369
+ width="2rem"
370
+ height="2rem"
371
+ />
372
+ Request
373
+ {method?.type !== 'delete' && <span style={{ color: 'red' }}>*</span>}
374
+ </div>
375
+ </span>
376
+ }
377
+ children={
378
+ <JsonInput
379
+ acceptType="JSON"
380
+ withFooter={!readOnly}
381
+ className={'jsonField'}
382
+ placeholder="Enter your request body as a JSON object...."
383
+ fieldIsDisabled={readOnly}
384
+ value={method?.requestBody?.content?.schema?.properties || '{}'}
385
+ onChange={(value: string) => {
386
+ setFieldValue('requestBody.content.schema.properties', value)
387
+ }}
388
+ onValidation={() => null}
389
+ />
390
+ }
391
+ />
392
+ )}
393
+ <Accordion
394
+ expanded={isExpanded.response}
395
+ onChange={() => null}
396
+ className={styles.responseAccordion}
397
+ summary={
398
+ <span className={styles.responseAccordionSummary}>
399
+ <div
400
+ className={styles.responseAccordionSummary_title}
401
+ onClick={() =>
402
+ setIsExpanded((prev) => ({
403
+ ...prev,
404
+ response: !prev.response,
405
+ }))
406
+ }
407
+ >
408
+ <SVGLoader
409
+ className={isExpanded.response ? styles.expanded : ''}
410
+ src={DownArrowIcon}
411
+ width="2rem"
412
+ height="2rem"
413
+ />
414
+ Response<span style={{ color: 'red' }}>*</span>
415
+ </div>
416
+
417
+ <SelectGroup
418
+ withSearch={false}
419
+ isMultiple={false}
420
+ clearable={false}
421
+ placeholder="200"
422
+ options={[
423
+ {
424
+ list: httpStatusCodeOptions,
425
+ },
426
+ ]}
427
+ value={selectedStatusCode}
428
+ onChange={(value) => {
429
+ setSelectedStatusCode(value)
430
+ }}
431
+ />
432
+ </span>
433
+ }
434
+ children={
435
+ <JsonInput
436
+ acceptType="JSON"
437
+ withFooter={!readOnly}
438
+ className={'jsonField'}
439
+ placeholder="Enter your response as a JSON object..."
440
+ fieldIsDisabled={readOnly}
441
+ value={currentResponse?.content?.schema?.properties || '{}'}
442
+ onChange={(value) => {
443
+ const currentResIndex = method.responses.findIndex(
444
+ (res) => res.code === currentResponse.code
445
+ )
446
+
447
+ if (currentResIndex !== -1) {
448
+ setFieldValue(
449
+ `responses[${currentResIndex}].content.schema.properties`,
450
+ value
451
+ )
452
+ } else {
453
+ const clonedResponses = structuredClone(method.responses)
454
+
455
+ clonedResponses.push({
456
+ code: selectedStatusCode.value.toString(),
457
+ content: {
458
+ contentType: 'application/json',
459
+ schema: {
460
+ type: 'object',
461
+ properties: value,
462
+ },
463
+ },
464
+ })
465
+
466
+ setFieldValue('responses', clonedResponses)
467
+ }
468
+ }}
469
+ onValidation={() => null}
470
+ />
471
+ }
472
+ />
473
+ </div>
474
+ }
475
+ />
476
+ <CommonDialog
477
+ status="error"
478
+ content={
479
+ <p
480
+ style={{
481
+ textAlign: 'center',
482
+ fontWeight: 400,
483
+ fontSize: '1rem',
484
+ lineHeight: '1.4375rem',
485
+ }}
486
+ className="delete-msg-container"
487
+ >
488
+ Are you sure you want to delete
489
+ <span className="plan-name">
490
+ {' '}
491
+ Parameter <strong>{selectedParamName}</strong>
492
+ </span>
493
+ ?
494
+ </p>
495
+ }
496
+ onSubmit={{
497
+ onClick: confirmDeleteParameter,
498
+ text: 'Delete',
499
+ color: 'error',
500
+ fullWidth: true,
501
+ }}
502
+ onCancel={{
503
+ text: 'Cancel',
504
+ color: 'normal',
505
+ fullWidth: true,
506
+ }}
507
+ onClose={() => setOpenDeleteDialog(false)}
508
+ open={openDeleteDialog}
509
+ icon={<SVGLoader src={deleteOutlinedIcon} width="4.0625rem" height="4.0625rem" />}
510
+ />
511
+ </div>
512
+ )
513
+ }
514
+
515
+ export default MethodsAccordion