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

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 (104) hide show
  1. package/.editorconfig +12 -12
  2. package/.prettierignore +7 -7
  3. package/.prettierrc +15 -15
  4. package/dist/{2e10bbdb265df50e.svg → 43595976d1fdccbf.svg} +4 -4
  5. package/dist/{8789eb84283ea95b.svg → 56dc416b683db280.svg} +5 -5
  6. package/dist/{bb8b87cace25e052.svg → 64efc2716808c4a4.svg} +3 -3
  7. package/dist/{d32ce84bbd78babd.svg → 72db3b05a96dd600.svg} +3 -3
  8. package/dist/{d501922060662842.svg → 844eba3f2e42a9eb.svg} +3 -3
  9. package/dist/_virtual/index3.js +1 -1
  10. package/dist/_virtual/index4.js +1 -1
  11. package/dist/_virtual/index5.js +1 -1
  12. package/dist/_virtual/index6.js +1 -1
  13. package/dist/{070dc6ecd197bc80.svg → a7568b270e175038.svg} +8 -8
  14. package/dist/{9bdff13f8d8fa48a.svg → af16a554be8c4d69.svg} +3 -3
  15. package/dist/{7f54eeb0bb2d1150.svg → b82c7612e73342f3.svg} +3 -3
  16. package/dist/node_modules/toposort/index.js +1 -1
  17. package/dist/node_modules/yup/index.esm.js +1 -1
  18. package/dist/src/assets/icons/AddRow.svg.js +1 -1
  19. package/dist/src/assets/icons/AddRow.svg.js.map +1 -1
  20. package/dist/src/assets/icons/CheckMarkSquare.svg.js +1 -1
  21. package/dist/src/assets/icons/CheckMarkSquare.svg.js.map +1 -1
  22. package/dist/src/assets/icons/CloseIcon.svg.js +1 -1
  23. package/dist/src/assets/icons/CloseIcon.svg.js.map +1 -1
  24. package/dist/src/assets/icons/DeleteIcon.svg.js +1 -1
  25. package/dist/src/assets/icons/DeleteIcon.svg.js.map +1 -1
  26. package/dist/src/assets/icons/DownArrow.svg.js +1 -1
  27. package/dist/src/assets/icons/DownArrow.svg.js.map +1 -1
  28. package/dist/src/assets/icons/EditIcon.svg.js +1 -1
  29. package/dist/src/assets/icons/EditIcon.svg.js.map +1 -1
  30. package/dist/src/assets/icons/UpArrow.svg.js +1 -1
  31. package/dist/src/assets/icons/UpArrow.svg.js.map +1 -1
  32. package/dist/src/assets/icons/deleteOutlinedIcon.svg.js +1 -1
  33. package/dist/src/assets/icons/deleteOutlinedIcon.svg.js.map +1 -1
  34. package/dist/src/components/Chips/Chips.js.map +1 -1
  35. package/dist/src/components/InfoForm/InfoForm.js +1 -1
  36. package/dist/src/components/InfoForm/InfoForm.js.map +1 -1
  37. package/dist/src/components/JsonInput/JsonInput.js.map +1 -1
  38. package/dist/src/components/LivePreview/LivePreview.js.map +1 -1
  39. package/dist/src/components/MethodAccordion/MethodAccordion.js.map +1 -1
  40. package/dist/src/components/SVGLoader/SVGLoader.js.map +1 -1
  41. package/dist/src/components/SectionHead/SectionHead.js.map +1 -1
  42. package/dist/src/components/SimpleLabelValue/SimpleLabelValue.js.map +1 -1
  43. package/dist/src/components/Tooltip/Tooltip.js.map +1 -1
  44. package/dist/src/components/dialog/index.js.map +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 +1 -1
  50. package/dist/src/constants/regex.js.map +1 -1
  51. package/dist/src/helpers/layout.helper.js.map +1 -1
  52. package/dist/src/helpers/methodAccordion.helper.js.map +1 -1
  53. package/dist/src/layout/layout.js.map +1 -1
  54. package/dist/src/validator/form.scheme.js.map +1 -1
  55. package/dist/styles.css +335 -335
  56. package/package.json +43 -43
  57. package/rollup.config.js +35 -35
  58. package/src/assets/icons/AddRow.svg +3 -3
  59. package/src/assets/icons/CheckMarkSquare.svg +5 -5
  60. package/src/assets/icons/CloseIcon.svg +4 -4
  61. package/src/assets/icons/DeleteIcon.svg +3 -3
  62. package/src/assets/icons/DownArrow.svg +3 -3
  63. package/src/assets/icons/EditIcon.svg +3 -3
  64. package/src/assets/icons/UpArrow.svg +3 -3
  65. package/src/assets/icons/deleteOutlinedIcon.svg +8 -8
  66. package/src/assets/icons/index.ts +8 -8
  67. package/src/components/Chips/Chips.tsx +87 -87
  68. package/src/components/Chips/style.scss +147 -147
  69. package/src/components/InfoForm/InfoForm.module.scss +165 -165
  70. package/src/components/InfoForm/InfoForm.tsx +424 -426
  71. package/src/components/JsonInput/JsonInput.tsx +149 -149
  72. package/src/components/JsonInput/style.module.scss +133 -133
  73. package/src/components/LivePreview/LivePreview.module.scss +24 -24
  74. package/src/components/LivePreview/LivePreview.tsx +184 -184
  75. package/src/components/MethodAccordion/MethodAccordion.module.scss +338 -338
  76. package/src/components/MethodAccordion/MethodAccordion.tsx +515 -515
  77. package/src/components/SVGLoader/SVGLoader.tsx +94 -94
  78. package/src/components/SectionHead/SectionHead.scss +29 -29
  79. package/src/components/SectionHead/SectionHead.tsx +22 -22
  80. package/src/components/SimpleLabelValue/SimpleLabelValue.tsx +31 -31
  81. package/src/components/SimpleLabelValue/index.ts +1 -1
  82. package/src/components/SimpleLabelValue/style.scss +30 -30
  83. package/src/components/Tooltip/Tooltip.scss +133 -133
  84. package/src/components/Tooltip/Tooltip.tsx +85 -85
  85. package/src/components/_global.scss +337 -337
  86. package/src/components/dialog/dialog.ts +54 -54
  87. package/src/components/dialog/index.tsx +85 -85
  88. package/src/components/dialog/style.scss +104 -104
  89. package/src/components/table/style.scss +190 -190
  90. package/src/components/table/table.tsx +327 -327
  91. package/src/components/table/tags-table.tsx +348 -348
  92. package/src/constants/index.ts +93 -93
  93. package/src/constants/regex.ts +7 -7
  94. package/src/global.d.ts +13 -13
  95. package/src/helpers/layout.helper.ts +162 -162
  96. package/src/helpers/methodAccordion.helper.ts +19 -19
  97. package/src/index.ts +1 -1
  98. package/src/layout/layout.module.css +61 -61
  99. package/src/layout/layout.tsx +150 -150
  100. package/src/types/layout.type.ts +30 -30
  101. package/src/types/openApi.ts +108 -108
  102. package/src/types/transformedOpenApi.ts +52 -52
  103. package/src/validator/form.scheme.ts +70 -70
  104. package/tsconfig.json +33 -33
@@ -1,515 +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
- {' '}
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
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