@digi-frontend/dgate-api-documentation 1.0.20 → 1.0.25
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.
- package/dist/_virtual/index3.js +1 -1
- package/dist/_virtual/index4.js +1 -1
- package/dist/_virtual/index5.js +1 -1
- package/dist/_virtual/index6.js +1 -1
- package/dist/node_modules/toposort/index.js +1 -1
- package/dist/node_modules/yup/index.esm.js +1 -1
- package/dist/src/components/InfoForm/InfoForm.js +1 -1
- package/dist/src/components/InfoForm/InfoForm.js.map +1 -1
- package/dist/src/components/JsonInput/JsonInput.js +1 -1
- package/dist/src/components/JsonInput/JsonInput.js.map +1 -1
- package/dist/src/components/LivePreview/LivePreview.js +1 -1
- package/dist/src/components/LivePreview/LivePreview.js.map +1 -1
- package/dist/src/components/MethodAccordion/MethodAccordion.js +1 -1
- package/dist/src/components/MethodAccordion/MethodAccordion.js.map +1 -1
- package/dist/src/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/src/components/table/table.js +1 -1
- package/dist/src/components/table/table.js.map +1 -1
- package/dist/src/components/table/tags-table.js +1 -1
- package/dist/src/components/table/tags-table.js.map +1 -1
- package/dist/src/constants/regex.js +1 -1
- package/dist/src/constants/regex.js.map +1 -1
- package/dist/src/layout/layout.js +1 -1
- package/dist/src/layout/layout.js.map +1 -1
- package/dist/src/validator/form.scheme.js +1 -1
- package/dist/src/validator/form.scheme.js.map +1 -1
- package/dist/styles.css +488 -488
- package/dist/types/components/Tooltip/Tooltip.d.ts +2 -2
- package/dist/types/constants/regex.d.ts +1 -0
- package/dist/types/layout/layout.d.ts +2 -1
- package/dist/types/validator/form.scheme.d.ts +1 -1
- package/package.json +2 -2
- package/src/components/InfoForm/InfoForm.tsx +37 -15
- package/src/components/JsonInput/JsonInput.tsx +7 -1
- package/src/components/LivePreview/LivePreview.tsx +40 -22
- package/src/components/MethodAccordion/MethodAccordion.tsx +37 -15
- package/src/components/Tooltip/Tooltip.scss +3 -3
- package/src/components/Tooltip/Tooltip.tsx +2 -3
- package/src/components/table/table.tsx +3 -1
- package/src/components/table/tags-table.tsx +27 -5
- package/src/constants/regex.ts +1 -0
- package/src/layout/layout.tsx +49 -7
- package/src/validator/form.scheme.ts +9 -9
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
+
import { TippyProps } from '@tippyjs/react';
|
|
2
3
|
import 'tippy.js/dist/tippy.css';
|
|
3
4
|
import './Tooltip.scss';
|
|
4
|
-
interface TooltipProps {
|
|
5
|
-
children: ReactNode;
|
|
5
|
+
interface TooltipProps extends TippyProps {
|
|
6
6
|
content: ReactNode;
|
|
7
7
|
success?: boolean;
|
|
8
8
|
onMouseEnter?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
@@ -3,6 +3,7 @@ import { OpenAPIFile } from '../types/openApi';
|
|
|
3
3
|
interface ILayoutProps {
|
|
4
4
|
openApiJson?: OpenAPIFile;
|
|
5
5
|
handleSave?: (values: unknown) => unknown;
|
|
6
|
+
setIsFormDirty?: any;
|
|
6
7
|
}
|
|
7
|
-
declare const Layout: ({ openApiJson, handleSave }: ILayoutProps) => JSX.Element;
|
|
8
|
+
declare const Layout: ({ openApiJson, handleSave, setIsFormDirty }: ILayoutProps) => JSX.Element;
|
|
8
9
|
export default Layout;
|
package/package.json
CHANGED
|
@@ -30,7 +30,10 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
30
30
|
if (values && values.components && values.components.securitySchemes) {
|
|
31
31
|
const authenticatorKeys = Object.keys(values.components.securitySchemes)
|
|
32
32
|
if (authenticatorKeys.length) {
|
|
33
|
-
setAuthType(
|
|
33
|
+
setAuthType(
|
|
34
|
+
values.components.securitySchemes[authenticatorKeys[0]].scheme ||
|
|
35
|
+
values.components.securitySchemes[authenticatorKeys[0]].type
|
|
36
|
+
)
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
}, [])
|
|
@@ -94,6 +97,26 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
94
97
|
tagName: item.name,
|
|
95
98
|
description: (
|
|
96
99
|
<div className={styles.paramDescContainer}>
|
|
100
|
+
<Tooltip
|
|
101
|
+
key={`${index}-description`}
|
|
102
|
+
allowHTML
|
|
103
|
+
disabled={values.tags[index].description?.length <= 12}
|
|
104
|
+
content={<div style={{ padding: '0.625rem' }}>{values.tags[index].description}</div>}
|
|
105
|
+
arrowWithBorder
|
|
106
|
+
placement="bottom-end"
|
|
107
|
+
type="function"
|
|
108
|
+
delay={[0, 0]}
|
|
109
|
+
onShow={() => tooltipRefs[index]?.hide()}
|
|
110
|
+
>
|
|
111
|
+
<p style={{ alignSelf: 'center', fontWeight: 600, fontSize: '1rem' }}>
|
|
112
|
+
{values.tags[index].description
|
|
113
|
+
? values.tags[index].description.substring(0, 12)
|
|
114
|
+
: readOnly && '-'}
|
|
115
|
+
{values.tags[index].description && values.tags[index].description.length > 12
|
|
116
|
+
? '...'
|
|
117
|
+
: ''}
|
|
118
|
+
</p>
|
|
119
|
+
</Tooltip>
|
|
97
120
|
<Tooltip
|
|
98
121
|
arrowWithBorder
|
|
99
122
|
placement="bottom-end"
|
|
@@ -137,14 +160,7 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
137
160
|
variant="link"
|
|
138
161
|
color="action"
|
|
139
162
|
endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
|
|
140
|
-
>
|
|
141
|
-
{values.tags[index].description
|
|
142
|
-
? values.tags[index].description.substring(0, 12)
|
|
143
|
-
: '-'}
|
|
144
|
-
{values.tags[index].description && values.tags[index].description.length > 12
|
|
145
|
-
? '...'
|
|
146
|
-
: ''}
|
|
147
|
-
</Button>
|
|
163
|
+
></Button>
|
|
148
164
|
) : (
|
|
149
165
|
<Button
|
|
150
166
|
className={styles.editDescBtn}
|
|
@@ -292,7 +308,7 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
292
308
|
setFieldValue('info.title', '')
|
|
293
309
|
}}
|
|
294
310
|
errorMsg={errors?.info?.title}
|
|
295
|
-
|
|
311
|
+
restrictedCharactersRegex={regex.basic}
|
|
296
312
|
/>
|
|
297
313
|
<div className={styles.apiDocRow}>
|
|
298
314
|
<Input
|
|
@@ -310,14 +326,16 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
310
326
|
label="Description"
|
|
311
327
|
value={values?.info?.description}
|
|
312
328
|
maxLength={120}
|
|
329
|
+
required
|
|
313
330
|
onChange={(value: string) => {
|
|
314
|
-
|
|
331
|
+
if (value === '' || regex.ASCII.test(value)) {
|
|
332
|
+
setFieldValue('info.description', value)
|
|
333
|
+
}
|
|
315
334
|
}}
|
|
316
335
|
onClear={() => {
|
|
317
336
|
setFieldValue('info.description', '')
|
|
318
337
|
}}
|
|
319
338
|
errorMessage={errors?.info?.description}
|
|
320
|
-
restrictedCharsRegex={regex.restrictNone}
|
|
321
339
|
/>
|
|
322
340
|
<div className={styles.paramsTable}>
|
|
323
341
|
<TagsTable
|
|
@@ -343,17 +361,21 @@ const InfoForm = ({ readOnly }: { readOnly?: boolean }) => {
|
|
|
343
361
|
className="delete-msg-container"
|
|
344
362
|
>
|
|
345
363
|
Are you sure you want to delete
|
|
346
|
-
<span className="plan-name">
|
|
364
|
+
<span className="plan-name">
|
|
365
|
+
{' '}
|
|
366
|
+
Tag <strong>{selectedTagName}</strong>
|
|
367
|
+
</span>
|
|
368
|
+
?
|
|
347
369
|
</p>
|
|
348
370
|
}
|
|
349
371
|
onSubmit={{
|
|
350
372
|
onClick: confirmDeleteTag,
|
|
351
|
-
text: '
|
|
373
|
+
text: 'Delete',
|
|
352
374
|
color: 'error',
|
|
353
375
|
fullWidth: true,
|
|
354
376
|
}}
|
|
355
377
|
onCancel={{
|
|
356
|
-
text: '
|
|
378
|
+
text: 'Cancel',
|
|
357
379
|
color: 'normal',
|
|
358
380
|
fullWidth: true,
|
|
359
381
|
}}
|
|
@@ -2,6 +2,12 @@ import React, { useEffect, useState } from 'react'
|
|
|
2
2
|
import yaml from 'js-yaml'
|
|
3
3
|
import styles from './style.module.scss'
|
|
4
4
|
|
|
5
|
+
const errorMapping = {
|
|
6
|
+
BOTH: 'Invalid JSON or YAML format',
|
|
7
|
+
JSON: 'Invalid JSON format',
|
|
8
|
+
YML: 'Invalid YAML format',
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
const JsonInput = ({
|
|
6
12
|
placeholder,
|
|
7
13
|
label,
|
|
@@ -129,7 +135,7 @@ const JsonInput = ({
|
|
|
129
135
|
)}
|
|
130
136
|
</div>
|
|
131
137
|
{(errorMessage || (value !== '' && isValid === false)) && (
|
|
132
|
-
<p className={styles['error-message']}>{errorMessage ||
|
|
138
|
+
<p className={styles['error-message']}>{errorMessage || errorMapping[acceptType]}</p>
|
|
133
139
|
)}
|
|
134
140
|
</div>
|
|
135
141
|
)
|
|
@@ -7,6 +7,7 @@ import { useFormikContext } from 'formik'
|
|
|
7
7
|
import { methodColorMapping, tagsTableHeaders } from '../../constants/index'
|
|
8
8
|
import TagsTable from '../table/tags-table'
|
|
9
9
|
import { Button } from 'digitinary-ui'
|
|
10
|
+
import Tooltip from '../../components/Tooltip/Tooltip'
|
|
10
11
|
|
|
11
12
|
interface LivePreviewProps {
|
|
12
13
|
transformedData?: TransformedOpenApi
|
|
@@ -37,12 +38,23 @@ const LivePreview: React.FC<LivePreviewProps> = ({ transformedData }) => {
|
|
|
37
38
|
id: index,
|
|
38
39
|
tagName: item.name,
|
|
39
40
|
description: (
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</
|
|
45
|
-
|
|
41
|
+
<Tooltip
|
|
42
|
+
key={`${index}-description`}
|
|
43
|
+
allowHTML
|
|
44
|
+
disabled={item.description?.length <= 12}
|
|
45
|
+
content={<div style={{ padding: '0.625rem' }}>{item.description}</div>}
|
|
46
|
+
arrowWithBorder
|
|
47
|
+
placement="bottom-end"
|
|
48
|
+
type="function"
|
|
49
|
+
delay={[0, 0]}
|
|
50
|
+
>
|
|
51
|
+
<div className={styles.paramDescContainer}>
|
|
52
|
+
<p className={styles.editDescBtn}>
|
|
53
|
+
{item.description ? item.description.substring(0, 12) : '-'}
|
|
54
|
+
{item.description && item.description.length > 12 ? '...' : ''}
|
|
55
|
+
</p>
|
|
56
|
+
</div>
|
|
57
|
+
</Tooltip>
|
|
46
58
|
),
|
|
47
59
|
externalDocs: (
|
|
48
60
|
<div className={styles.paramDescContainer}>
|
|
@@ -91,6 +103,7 @@ const LivePreview: React.FC<LivePreviewProps> = ({ transformedData }) => {
|
|
|
91
103
|
),
|
|
92
104
|
}))
|
|
93
105
|
}
|
|
106
|
+
|
|
94
107
|
return (
|
|
95
108
|
<div>
|
|
96
109
|
<div className="row">
|
|
@@ -99,7 +112,11 @@ const LivePreview: React.FC<LivePreviewProps> = ({ transformedData }) => {
|
|
|
99
112
|
<SimpleLabelValue
|
|
100
113
|
key={'APIAuthenticationType'}
|
|
101
114
|
label={'API authentication type: '}
|
|
102
|
-
value={
|
|
115
|
+
value={
|
|
116
|
+
!!securityKey
|
|
117
|
+
? securitySchemes[securityKey].scheme || securitySchemes[securityKey].type
|
|
118
|
+
: '-'
|
|
119
|
+
}
|
|
103
120
|
/>
|
|
104
121
|
<SimpleLabelValue key={'version'} label={'Version: '} value={info?.version || '-'} />
|
|
105
122
|
<SimpleLabelValue
|
|
@@ -124,20 +141,22 @@ const LivePreview: React.FC<LivePreviewProps> = ({ transformedData }) => {
|
|
|
124
141
|
<div className={styles.methodsContainer} key={path.path}>
|
|
125
142
|
{Object.entries(
|
|
126
143
|
path.methods
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
.sort(
|
|
145
|
+
(a, b) => methodColorMapping[a.type].order + methodColorMapping[b.type].order
|
|
146
|
+
)
|
|
147
|
+
.reduce((groupedMethods, method) => {
|
|
148
|
+
// Handle methods without tags
|
|
149
|
+
const tags = method.tags?.length ? method?.tags : ['default']
|
|
150
|
+
|
|
151
|
+
tags.forEach((tag) => {
|
|
152
|
+
if (!groupedMethods[tag]) {
|
|
153
|
+
groupedMethods[tag] = []
|
|
154
|
+
}
|
|
155
|
+
groupedMethods[tag].push(method)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return groupedMethods
|
|
159
|
+
}, {})
|
|
141
160
|
).map(([tag, methods]) => (
|
|
142
161
|
<div key={tag}>
|
|
143
162
|
<h3>{tag}</h3>
|
|
@@ -147,7 +166,6 @@ const LivePreview: React.FC<LivePreviewProps> = ({ transformedData }) => {
|
|
|
147
166
|
method={method}
|
|
148
167
|
path={path.path}
|
|
149
168
|
tags={values.tags}
|
|
150
|
-
handleSave={() => null}
|
|
151
169
|
/>
|
|
152
170
|
))}
|
|
153
171
|
</div>
|
|
@@ -100,6 +100,31 @@ const MethodsAccordion = ({
|
|
|
100
100
|
description: (
|
|
101
101
|
<div className={styles.paramDescContainer}>
|
|
102
102
|
<Tooltip
|
|
103
|
+
key={`${index}-description`}
|
|
104
|
+
allowHTML
|
|
105
|
+
disabled={method.parameters[index].description?.length <= 12}
|
|
106
|
+
content={
|
|
107
|
+
<div style={{ padding: '0.625rem' }}>{method.parameters[index].description}</div>
|
|
108
|
+
}
|
|
109
|
+
arrowWithBorder
|
|
110
|
+
placement="bottom-end"
|
|
111
|
+
type="function"
|
|
112
|
+
delay={[0, 0]}
|
|
113
|
+
onShow={() => tooltipRefs[index]?.hide()}
|
|
114
|
+
>
|
|
115
|
+
<p style={{ alignSelf: 'center' }}>
|
|
116
|
+
{method.parameters[index].description
|
|
117
|
+
? method.parameters[index].description.substring(0, 12)
|
|
118
|
+
: '-'}
|
|
119
|
+
{method.parameters[index].description &&
|
|
120
|
+
method.parameters[index].description.length > 12
|
|
121
|
+
? '...'
|
|
122
|
+
: ''}
|
|
123
|
+
</p>
|
|
124
|
+
</Tooltip>
|
|
125
|
+
<Tooltip
|
|
126
|
+
key={`${index}-add-edit-description`}
|
|
127
|
+
allowHTML
|
|
103
128
|
arrowWithBorder
|
|
104
129
|
placement="bottom-end"
|
|
105
130
|
type="function"
|
|
@@ -142,15 +167,7 @@ const MethodsAccordion = ({
|
|
|
142
167
|
variant="link"
|
|
143
168
|
color="action"
|
|
144
169
|
endIcon={<SVGLoader src={EditIcon} width="1.5rem" height="1.5rem" />}
|
|
145
|
-
>
|
|
146
|
-
{method.parameters[index].description
|
|
147
|
-
? method.parameters[index].description.substring(0, 12)
|
|
148
|
-
: '-'}
|
|
149
|
-
{method.parameters[index].description &&
|
|
150
|
-
method.parameters[index].description.length > 12
|
|
151
|
-
? '...'
|
|
152
|
-
: ''}
|
|
153
|
-
</Button>
|
|
170
|
+
></Button>
|
|
154
171
|
) : (
|
|
155
172
|
<Button
|
|
156
173
|
className={styles.editDescBtn}
|
|
@@ -210,14 +227,13 @@ const MethodsAccordion = ({
|
|
|
210
227
|
|
|
211
228
|
useEffect(() => {
|
|
212
229
|
if (method?.parameters) {
|
|
213
|
-
setTableRecords(generateTableData(method.parameters))
|
|
214
230
|
setTableData(method.parameters)
|
|
215
231
|
}
|
|
216
232
|
}, [method, path])
|
|
217
233
|
|
|
218
234
|
useEffect(() => {
|
|
219
235
|
// prepare tags selection list
|
|
220
|
-
if (
|
|
236
|
+
if (method?.tags.length || tags.length) {
|
|
221
237
|
const convertedStringArray = (method?.tags || [])?.map((item) => ({
|
|
222
238
|
label: capitalize(item),
|
|
223
239
|
value: item,
|
|
@@ -230,6 +246,7 @@ const MethodsAccordion = ({
|
|
|
230
246
|
const filteredArray = mergedArray.filter(
|
|
231
247
|
(value, index, self) => index === self.findIndex((t) => t.value === value.value)
|
|
232
248
|
)
|
|
249
|
+
|
|
233
250
|
setSelectionTags(filteredArray)
|
|
234
251
|
}
|
|
235
252
|
}, [tags, method])
|
|
@@ -287,7 +304,7 @@ const MethodsAccordion = ({
|
|
|
287
304
|
isMultiple={true}
|
|
288
305
|
withSearch={false}
|
|
289
306
|
clearable={false}
|
|
290
|
-
/>
|
|
307
|
+
/>
|
|
291
308
|
{!readOnly ? (
|
|
292
309
|
<TextArea
|
|
293
310
|
className={styles.methodDesc}
|
|
@@ -343,6 +360,7 @@ const MethodsAccordion = ({
|
|
|
343
360
|
}
|
|
344
361
|
children={
|
|
345
362
|
<JsonInput
|
|
363
|
+
acceptType="JSON"
|
|
346
364
|
withFooter={!readOnly}
|
|
347
365
|
className={'jsonField'}
|
|
348
366
|
placeholder="Enter your request body as a JSON object...."
|
|
@@ -399,6 +417,7 @@ const MethodsAccordion = ({
|
|
|
399
417
|
}
|
|
400
418
|
children={
|
|
401
419
|
<JsonInput
|
|
420
|
+
acceptType="JSON"
|
|
402
421
|
withFooter={!readOnly}
|
|
403
422
|
className={'jsonField'}
|
|
404
423
|
placeholder="Enter your response as a JSON object..."
|
|
@@ -451,17 +470,20 @@ const MethodsAccordion = ({
|
|
|
451
470
|
className="delete-msg-container"
|
|
452
471
|
>
|
|
453
472
|
Are you sure you want to delete
|
|
454
|
-
<span className="plan-name">
|
|
473
|
+
<span className="plan-name">
|
|
474
|
+
Parameter <strong>{selectedParamName}</strong>
|
|
475
|
+
</span>
|
|
476
|
+
?
|
|
455
477
|
</p>
|
|
456
478
|
}
|
|
457
479
|
onSubmit={{
|
|
458
480
|
onClick: confirmDeleteParameter,
|
|
459
|
-
text: '
|
|
481
|
+
text: 'Delete',
|
|
460
482
|
color: 'error',
|
|
461
483
|
fullWidth: true,
|
|
462
484
|
}}
|
|
463
485
|
onCancel={{
|
|
464
|
-
text: '
|
|
486
|
+
text: 'Cancel',
|
|
465
487
|
color: 'normal',
|
|
466
488
|
fullWidth: true,
|
|
467
489
|
}}
|
|
@@ -113,15 +113,15 @@
|
|
|
113
113
|
height: 1px;
|
|
114
114
|
|
|
115
115
|
&:before {
|
|
116
|
-
width:
|
|
117
|
-
height:
|
|
116
|
+
width: 0.625rem;
|
|
117
|
+
height: 0.625rem;
|
|
118
118
|
background-color: white;
|
|
119
119
|
transform: rotate(45deg);
|
|
120
120
|
border: none;
|
|
121
121
|
border-left: 1px solid #d8dae5 !important;
|
|
122
122
|
border-top: 1px solid #d8dae5 !important;
|
|
123
123
|
z-index: 20000000000;
|
|
124
|
-
top: -0.
|
|
124
|
+
top: -0.45rem;
|
|
125
125
|
transform-origin: center !important;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect, ReactNode } from 'react'
|
|
2
|
-
import Tippy from '@tippyjs/react'
|
|
2
|
+
import Tippy, { TippyProps } from '@tippyjs/react'
|
|
3
3
|
import 'tippy.js/dist/tippy.css'
|
|
4
4
|
import './Tooltip.scss'
|
|
5
5
|
|
|
6
|
-
interface TooltipProps {
|
|
7
|
-
children: ReactNode
|
|
6
|
+
interface TooltipProps extends TippyProps {
|
|
8
7
|
content: ReactNode
|
|
9
8
|
success?: boolean
|
|
10
9
|
onMouseEnter?: (event: React.MouseEvent<HTMLDivElement>) => void
|
|
@@ -8,6 +8,7 @@ import styles from '../MethodAccordion/MethodAccordion.module.scss'
|
|
|
8
8
|
import { useFormik } from 'formik'
|
|
9
9
|
import * as yup from 'yup'
|
|
10
10
|
import { capitalize } from '../../helpers/methodAccordion.helper'
|
|
11
|
+
import regex from '../../constants/regex'
|
|
11
12
|
|
|
12
13
|
const ParamterTable = ({
|
|
13
14
|
id,
|
|
@@ -131,6 +132,7 @@ const ParamterTable = ({
|
|
|
131
132
|
}} // Pass the value directly
|
|
132
133
|
value={values.name} // Bind value to the state
|
|
133
134
|
disabled={readOnly}
|
|
135
|
+
restrictedCharactersRegex={regex.basic}
|
|
134
136
|
/>
|
|
135
137
|
</div>
|
|
136
138
|
</td>
|
|
@@ -225,7 +227,7 @@ const ParamterTable = ({
|
|
|
225
227
|
<TextArea
|
|
226
228
|
value={text || values.description}
|
|
227
229
|
onChange={(value) => {
|
|
228
|
-
setText(value)
|
|
230
|
+
if (value === '' || regex.ASCII.test(value)) setText(value)
|
|
229
231
|
}}
|
|
230
232
|
disabled={readOnly}
|
|
231
233
|
placeholder="Describe parameter..."
|
|
@@ -8,6 +8,9 @@ import { AddRow, EditIcon, DeleteIcon } from '../../assets/icons'
|
|
|
8
8
|
import styles from '../MethodAccordion/MethodAccordion.module.scss'
|
|
9
9
|
import { useFormik } from 'formik'
|
|
10
10
|
import * as yup from 'yup'
|
|
11
|
+
import regex from '../../constants/regex'
|
|
12
|
+
|
|
13
|
+
const urlRegex = /^(https?:\/\/)?(www\.)?([a-zA-Z0-9-]+(\.[a-zA-Z]{2,})+)(\/[^\s]*)?$/
|
|
11
14
|
|
|
12
15
|
const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow, readOnly }) => {
|
|
13
16
|
const [text, setText] = useState('')
|
|
@@ -28,7 +31,20 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
28
31
|
validationSchema: yup.object().shape({
|
|
29
32
|
name: yup.string().required('Tag name is required'),
|
|
30
33
|
description: yup.string().optional(),
|
|
31
|
-
externalDocs: yup
|
|
34
|
+
externalDocs: yup
|
|
35
|
+
.object()
|
|
36
|
+
.shape({
|
|
37
|
+
url: yup
|
|
38
|
+
.string()
|
|
39
|
+
.matches(urlRegex, 'Invalid URL')
|
|
40
|
+
.when('description', (description, schema) => {
|
|
41
|
+
return description?.at(0)
|
|
42
|
+
? schema.required('URL is required when description is provided')
|
|
43
|
+
: schema.optional()
|
|
44
|
+
}),
|
|
45
|
+
description: yup.string().optional(),
|
|
46
|
+
})
|
|
47
|
+
.optional(),
|
|
32
48
|
}),
|
|
33
49
|
onSubmit: (values) => {
|
|
34
50
|
saveNewRow(values)
|
|
@@ -38,7 +54,9 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
38
54
|
resetForm()
|
|
39
55
|
setIsFormOpen(false)
|
|
40
56
|
},
|
|
57
|
+
validateOnChange: true,
|
|
41
58
|
})
|
|
59
|
+
|
|
42
60
|
return (
|
|
43
61
|
<div className="tableSectionContainer">
|
|
44
62
|
<div className="tableContainer">
|
|
@@ -107,7 +125,7 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
107
125
|
size="large"
|
|
108
126
|
type="text"
|
|
109
127
|
onChange={(value) => {
|
|
110
|
-
setFieldValue('name', value)
|
|
128
|
+
!regex.basic.test(value) && setFieldValue('name', value)
|
|
111
129
|
}} // Pass the value directly
|
|
112
130
|
value={values.name} // Bind value to the state
|
|
113
131
|
disabled={readOnly}
|
|
@@ -131,7 +149,7 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
131
149
|
<TextArea
|
|
132
150
|
value={text || values.description}
|
|
133
151
|
onChange={(value) => {
|
|
134
|
-
setText(value)
|
|
152
|
+
if (value === '' || regex.ASCII.test(value)) setText(value)
|
|
135
153
|
}}
|
|
136
154
|
disabled={readOnly}
|
|
137
155
|
placeholder="Describe Tag..."
|
|
@@ -184,7 +202,9 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
184
202
|
placeholder="Describe External Doc..."
|
|
185
203
|
value={externalDesc || values.externalDocs.description}
|
|
186
204
|
disabled={readOnly}
|
|
187
|
-
onChange={(value) =>
|
|
205
|
+
onChange={(value) => {
|
|
206
|
+
if (value === '' || regex.ASCII.test(value)) setExternalDesc(value)
|
|
207
|
+
}}
|
|
188
208
|
/>
|
|
189
209
|
<p className={_styles.editDescTooltipContent_header}>
|
|
190
210
|
External Docs Link
|
|
@@ -193,7 +213,9 @@ const TagsTable = ({ id, headCells, data, isFormOpen, setIsFormOpen, saveNewRow,
|
|
|
193
213
|
placeholder="External Docs Link..."
|
|
194
214
|
value={externalUrl || values.externalDocs.url}
|
|
195
215
|
disabled={readOnly}
|
|
196
|
-
onChange={(value) =>
|
|
216
|
+
onChange={(value) => {
|
|
217
|
+
if (value === '' || regex.ASCII.test(value)) setExternalUrl(value)
|
|
218
|
+
}}
|
|
197
219
|
/>
|
|
198
220
|
{!readOnly && (
|
|
199
221
|
<Button
|
package/src/constants/regex.ts
CHANGED
package/src/layout/layout.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JSX, useEffect } from 'react'
|
|
1
|
+
import { JSX, useEffect, useState } from 'react'
|
|
2
2
|
import { Alert, Button } from 'digitinary-ui'
|
|
3
3
|
import MethodsAccordion from '../components/MethodAccordion/MethodAccordion'
|
|
4
4
|
import styles from './layout.module.css'
|
|
@@ -11,13 +11,15 @@ import { FormikProvider, useFormik } from 'formik'
|
|
|
11
11
|
import { schemaValidation } from '../validator/form.scheme'
|
|
12
12
|
import { TransformedOpenApi } from '@entities/transformedOpenApi'
|
|
13
13
|
import { methodColorMapping } from '../constants/index'
|
|
14
|
+
import CommonDialog from '../components/dialog'
|
|
14
15
|
|
|
15
16
|
interface ILayoutProps {
|
|
16
17
|
openApiJson?: OpenAPIFile
|
|
17
18
|
handleSave?: (values: unknown) => unknown
|
|
19
|
+
setIsFormDirty?: any
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
const Layout = ({ openApiJson, handleSave }: ILayoutProps): JSX.Element => {
|
|
22
|
+
const Layout = ({ openApiJson, handleSave, setIsFormDirty }: ILayoutProps): JSX.Element => {
|
|
21
23
|
const clonedOpenApiJson = structuredClone(openApiJson)
|
|
22
24
|
const transformedOpenApi = transformOpenApiObject(clonedOpenApiJson)
|
|
23
25
|
const formik = useFormik<TransformedOpenApi>({
|
|
@@ -35,13 +37,21 @@ const Layout = ({ openApiJson, handleSave }: ILayoutProps): JSX.Element => {
|
|
|
35
37
|
validateForm(values)
|
|
36
38
|
},
|
|
37
39
|
})
|
|
40
|
+
const [isPublishDialogOpen, setIsPublishDialogOpen] = useState(false)
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (setIsFormDirty) {
|
|
44
|
+
setIsFormDirty(formik.dirty)
|
|
45
|
+
}
|
|
46
|
+
}, [formik.dirty])
|
|
38
47
|
|
|
39
48
|
return (
|
|
40
49
|
<div className={styles.docsLayout}>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
{formik.dirty && (
|
|
51
|
+
<Alert className={styles.apiDocAlert} color="warning" severity="warning">
|
|
52
|
+
There are changes you made may not be saved
|
|
53
|
+
</Alert>
|
|
54
|
+
)}
|
|
45
55
|
<div className={styles.layoutContainer}>
|
|
46
56
|
<div className={`${styles.editorSide} ${styles.docSide}`}>
|
|
47
57
|
<SectionHead
|
|
@@ -56,7 +66,8 @@ const Layout = ({ openApiJson, handleSave }: ILayoutProps): JSX.Element => {
|
|
|
56
66
|
type="submit"
|
|
57
67
|
variant="contained"
|
|
58
68
|
color="primary"
|
|
59
|
-
onClick={
|
|
69
|
+
onClick={() => setIsPublishDialogOpen(true)}
|
|
70
|
+
disabled={!formik.isValid || formik.isSubmitting}
|
|
60
71
|
>
|
|
61
72
|
Save
|
|
62
73
|
</Button>
|
|
@@ -97,6 +108,37 @@ const Layout = ({ openApiJson, handleSave }: ILayoutProps): JSX.Element => {
|
|
|
97
108
|
)}
|
|
98
109
|
</div>
|
|
99
110
|
</div>
|
|
111
|
+
<CommonDialog
|
|
112
|
+
status="warning"
|
|
113
|
+
content={
|
|
114
|
+
<p
|
|
115
|
+
style={{
|
|
116
|
+
textAlign: 'center',
|
|
117
|
+
fontWeight: 400,
|
|
118
|
+
fontSize: '1rem',
|
|
119
|
+
lineHeight: '1.4375rem',
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
Are you sure you want to Publish your changes?
|
|
123
|
+
</p>
|
|
124
|
+
}
|
|
125
|
+
onSubmit={{
|
|
126
|
+
onClick: () => {
|
|
127
|
+
formik.handleSubmit()
|
|
128
|
+
setIsPublishDialogOpen(false)
|
|
129
|
+
},
|
|
130
|
+
text: 'Publish',
|
|
131
|
+
color: 'warning',
|
|
132
|
+
fullWidth: true,
|
|
133
|
+
}}
|
|
134
|
+
onCancel={{
|
|
135
|
+
text: 'Cancel',
|
|
136
|
+
color: 'normal',
|
|
137
|
+
fullWidth: true,
|
|
138
|
+
}}
|
|
139
|
+
onClose={() => setIsPublishDialogOpen(false)}
|
|
140
|
+
open={isPublishDialogOpen}
|
|
141
|
+
/>
|
|
100
142
|
</div>
|
|
101
143
|
)
|
|
102
144
|
}
|