@gitbook/react-openapi 1.1.10 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/InteractiveSection.d.ts +4 -0
  3. package/dist/InteractiveSection.jsx +11 -11
  4. package/dist/OpenAPICodeSample.d.ts +2 -1
  5. package/dist/OpenAPICodeSample.jsx +6 -5
  6. package/dist/OpenAPICodeSampleInteractive.d.ts +3 -0
  7. package/dist/OpenAPICodeSampleInteractive.jsx +19 -43
  8. package/dist/OpenAPICodeSampleSelector.d.ts +3 -4
  9. package/dist/OpenAPICodeSampleSelector.jsx +6 -11
  10. package/dist/OpenAPICopyButton.d.ts +2 -0
  11. package/dist/OpenAPICopyButton.jsx +5 -2
  12. package/dist/OpenAPIDisclosure.d.ts +4 -3
  13. package/dist/OpenAPIDisclosure.jsx +8 -11
  14. package/dist/OpenAPIDisclosureGroup.d.ts +7 -3
  15. package/dist/OpenAPIDisclosureGroup.jsx +18 -18
  16. package/dist/OpenAPIExample.d.ts +4 -22
  17. package/dist/OpenAPIExample.jsx +5 -72
  18. package/dist/OpenAPIMediaType.d.ts +21 -0
  19. package/dist/OpenAPIMediaType.jsx +61 -0
  20. package/dist/OpenAPIOperation.d.ts +3 -2
  21. package/dist/OpenAPIOperation.jsx +9 -68
  22. package/dist/OpenAPIOperationDescription.d.ts +9 -0
  23. package/dist/OpenAPIOperationDescription.jsx +22 -0
  24. package/dist/OpenAPIOperationStability.d.ts +9 -0
  25. package/dist/OpenAPIOperationStability.jsx +27 -0
  26. package/dist/OpenAPIPath.d.ts +2 -0
  27. package/dist/OpenAPIPath.jsx +3 -2
  28. package/dist/OpenAPIRequestBody.d.ts +3 -1
  29. package/dist/OpenAPIRequestBody.jsx +4 -3
  30. package/dist/OpenAPIResponse.d.ts +1 -1
  31. package/dist/OpenAPIResponse.jsx +1 -1
  32. package/dist/OpenAPIResponseExample.d.ts +3 -2
  33. package/dist/OpenAPIResponseExample.jsx +24 -63
  34. package/dist/OpenAPIResponseExampleContent.d.ts +19 -0
  35. package/dist/OpenAPIResponseExampleContent.jsx +57 -0
  36. package/dist/OpenAPIResponses.d.ts +1 -1
  37. package/dist/OpenAPIResponses.jsx +49 -36
  38. package/dist/OpenAPISchema.d.ts +1 -1
  39. package/dist/OpenAPISchema.jsx +103 -15
  40. package/dist/OpenAPISchemaName.d.ts +2 -0
  41. package/dist/OpenAPISchemaName.jsx +19 -10
  42. package/dist/OpenAPISchemaServer.d.ts +1 -1
  43. package/dist/OpenAPISecurities.d.ts +2 -1
  44. package/dist/OpenAPISecurities.jsx +11 -10
  45. package/dist/OpenAPISelect.d.ts +10 -3
  46. package/dist/OpenAPISelect.jsx +20 -9
  47. package/dist/OpenAPISpec.d.ts +3 -2
  48. package/dist/OpenAPISpec.jsx +11 -9
  49. package/dist/OpenAPIWebhook.d.ts +10 -0
  50. package/dist/OpenAPIWebhook.jsx +23 -0
  51. package/dist/OpenAPIWebhookExample.d.ts +6 -0
  52. package/dist/OpenAPIWebhookExample.jsx +41 -0
  53. package/dist/ScalarApiButton.d.ts +2 -0
  54. package/dist/ScalarApiButton.jsx +4 -3
  55. package/dist/StaticSection.d.ts +4 -1
  56. package/dist/StaticSection.jsx +13 -4
  57. package/dist/code-samples.js +57 -39
  58. package/dist/common/OpenAPIColumnSpec.d.ts +6 -0
  59. package/dist/common/OpenAPIColumnSpec.jsx +20 -0
  60. package/dist/common/OpenAPIOperationDescription.d.ts +6 -0
  61. package/dist/common/OpenAPIOperationDescription.jsx +19 -0
  62. package/dist/common/OpenAPIStability.d.ts +4 -0
  63. package/dist/common/OpenAPIStability.jsx +15 -0
  64. package/dist/common/OpenAPISummary.d.ts +6 -0
  65. package/dist/common/OpenAPISummary.jsx +30 -0
  66. package/dist/context.d.ts +23 -2
  67. package/dist/context.js +32 -0
  68. package/dist/getOrCreateStoreByKey.d.ts +1 -1
  69. package/dist/getOrCreateStoreByKey.js +0 -1
  70. package/dist/index.d.ts +5 -1
  71. package/dist/index.js +3 -0
  72. package/dist/resolveOpenAPIWebhook.d.ts +11 -0
  73. package/dist/resolveOpenAPIWebhook.js +127 -0
  74. package/dist/schemas/OpenAPISchemas.d.ts +2 -2
  75. package/dist/schemas/OpenAPISchemas.jsx +19 -23
  76. package/dist/stringifyOpenAPI.d.ts +1 -1
  77. package/dist/stringifyOpenAPI.js +6 -3
  78. package/dist/translate.d.ts +10 -0
  79. package/dist/translate.jsx +75 -0
  80. package/dist/translations/de.d.ts +37 -0
  81. package/dist/translations/de.js +37 -0
  82. package/dist/translations/en.d.ts +37 -0
  83. package/dist/translations/en.js +37 -0
  84. package/dist/translations/es.d.ts +37 -0
  85. package/dist/translations/es.js +37 -0
  86. package/dist/translations/fr.d.ts +37 -0
  87. package/dist/translations/fr.js +37 -0
  88. package/dist/translations/index.d.ts +341 -0
  89. package/dist/translations/index.js +27 -0
  90. package/dist/translations/ja.d.ts +37 -0
  91. package/dist/translations/ja.js +37 -0
  92. package/dist/translations/nl.d.ts +37 -0
  93. package/dist/translations/nl.js +37 -0
  94. package/dist/translations/no.d.ts +37 -0
  95. package/dist/translations/no.js +37 -0
  96. package/dist/translations/pt-br.d.ts +37 -0
  97. package/dist/translations/pt-br.js +37 -0
  98. package/dist/translations/types.d.ts +5 -0
  99. package/dist/translations/types.js +1 -0
  100. package/dist/translations/zh.d.ts +37 -0
  101. package/dist/translations/zh.js +37 -0
  102. package/dist/tsconfig.build.tsbuildinfo +1 -1
  103. package/dist/types.d.ts +8 -50
  104. package/dist/util/example.d.ts +35 -0
  105. package/dist/util/example.jsx +103 -0
  106. package/dist/utils.d.ts +18 -0
  107. package/dist/utils.js +57 -0
  108. package/package.json +3 -3
  109. package/src/InteractiveSection.tsx +16 -14
  110. package/src/OpenAPICodeSample.tsx +22 -4
  111. package/src/OpenAPICodeSampleInteractive.tsx +38 -58
  112. package/src/OpenAPICodeSampleSelector.tsx +19 -12
  113. package/src/OpenAPICopyButton.tsx +7 -2
  114. package/src/OpenAPIDisclosure.tsx +20 -22
  115. package/src/OpenAPIDisclosureGroup.tsx +41 -22
  116. package/src/OpenAPIExample.tsx +8 -82
  117. package/src/OpenAPIMediaType.tsx +139 -0
  118. package/src/OpenAPIOperation.tsx +11 -100
  119. package/src/OpenAPIOperationDescription.tsx +34 -0
  120. package/src/OpenAPIOperationStability.tsx +39 -0
  121. package/src/OpenAPIPath.tsx +4 -1
  122. package/src/OpenAPIRequestBody.tsx +9 -4
  123. package/src/OpenAPIResponse.tsx +2 -2
  124. package/src/OpenAPIResponseExample.tsx +39 -108
  125. package/src/OpenAPIResponseExampleContent.tsx +123 -0
  126. package/src/OpenAPIResponses.tsx +84 -62
  127. package/src/OpenAPISchema.test.ts +80 -0
  128. package/src/OpenAPISchema.tsx +123 -16
  129. package/src/OpenAPISchemaName.tsx +26 -11
  130. package/src/OpenAPISchemaServer.tsx +1 -1
  131. package/src/OpenAPISecurities.tsx +33 -12
  132. package/src/OpenAPISelect.tsx +42 -16
  133. package/src/OpenAPISpec.tsx +21 -10
  134. package/src/OpenAPIWebhook.tsx +33 -0
  135. package/src/OpenAPIWebhookExample.tsx +60 -0
  136. package/src/ScalarApiButton.tsx +6 -6
  137. package/src/StaticSection.tsx +37 -5
  138. package/src/code-samples.test.ts +3 -1
  139. package/src/code-samples.ts +67 -54
  140. package/src/common/OpenAPIColumnSpec.tsx +31 -0
  141. package/src/common/OpenAPIOperationDescription.tsx +31 -0
  142. package/src/common/OpenAPIStability.tsx +23 -0
  143. package/src/common/OpenAPISummary.tsx +45 -0
  144. package/src/context.ts +37 -2
  145. package/src/getOrCreateStoreByKey.ts +1 -3
  146. package/src/index.ts +5 -1
  147. package/src/resolveOpenAPIWebhook.ts +99 -0
  148. package/src/schemas/OpenAPISchemas.tsx +34 -34
  149. package/src/stringifyOpenAPI.ts +11 -3
  150. package/src/translate.tsx +80 -0
  151. package/src/translations/de.ts +37 -0
  152. package/src/translations/en.ts +37 -0
  153. package/src/translations/es.ts +37 -0
  154. package/src/translations/fr.ts +37 -0
  155. package/src/translations/index.ts +33 -0
  156. package/src/translations/ja.ts +37 -0
  157. package/src/translations/nl.ts +37 -0
  158. package/src/translations/no.ts +37 -0
  159. package/src/translations/pt-br.ts +37 -0
  160. package/src/translations/types.ts +7 -0
  161. package/src/translations/zh.ts +37 -0
  162. package/src/types.ts +11 -53
  163. package/src/util/example.tsx +129 -0
  164. package/src/utils.ts +67 -0
@@ -35,6 +35,86 @@ describe('getSchemaAlternatives', () => {
35
35
  ]);
36
36
  });
37
37
 
38
+ it('merges string enum', () => {
39
+ expect(
40
+ getSchemaAlternatives({
41
+ oneOf: [
42
+ {
43
+ oneOf: [
44
+ {
45
+ type: 'string',
46
+ enum: ['a', 'b'],
47
+ },
48
+ {
49
+ type: 'string',
50
+ enum: ['c', 'd'],
51
+ nullable: true,
52
+ },
53
+ ],
54
+ },
55
+ ],
56
+ })
57
+ ).toEqual([
58
+ {
59
+ type: 'string',
60
+ enum: ['a', 'b', 'c', 'd'],
61
+ nullable: true,
62
+ },
63
+ ]);
64
+ });
65
+
66
+ it('merges objects with allOf', () => {
67
+ expect(
68
+ getSchemaAlternatives({
69
+ allOf: [
70
+ {
71
+ type: 'object',
72
+ properties: {
73
+ name: {
74
+ type: 'string',
75
+ },
76
+ map: {
77
+ type: 'string',
78
+ },
79
+ description: {
80
+ type: 'string',
81
+ },
82
+ },
83
+ required: ['name'],
84
+ },
85
+ {
86
+ type: 'object',
87
+ properties: {
88
+ externalId: {
89
+ type: 'string',
90
+ },
91
+ },
92
+ required: ['map', 'externalId'],
93
+ },
94
+ ],
95
+ })
96
+ ).toEqual([
97
+ {
98
+ type: 'object',
99
+ properties: {
100
+ name: {
101
+ type: 'string',
102
+ },
103
+ map: {
104
+ type: 'string',
105
+ },
106
+ description: {
107
+ type: 'string',
108
+ },
109
+ externalId: {
110
+ type: 'string',
111
+ },
112
+ },
113
+ required: ['name', 'map', 'externalId'],
114
+ },
115
+ ]);
116
+ });
117
+
38
118
  it('should not flatten oneOf and allOf', () => {
39
119
  expect(
40
120
  getSchemaAlternatives({
@@ -10,9 +10,10 @@ import { Markdown } from './Markdown';
10
10
  import { OpenAPICopyButton } from './OpenAPICopyButton';
11
11
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
12
12
  import { OpenAPISchemaName } from './OpenAPISchemaName';
13
+ import type { OpenAPIClientContext } from './context';
13
14
  import { retrocycle } from './decycle';
14
15
  import { stringifyOpenAPI } from './stringifyOpenAPI';
15
- import type { OpenAPIClientContext } from './types';
16
+ import { tString } from './translate';
16
17
  import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
17
18
 
18
19
  type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
@@ -40,7 +41,7 @@ function OpenAPISchemaProperty(props: {
40
41
 
41
42
  return (
42
43
  <div id={id} className={clsx('openapi-schema', className)}>
43
- <OpenAPISchemaPresentation property={property} />
44
+ <OpenAPISchemaPresentation context={context} property={property} />
44
45
  {(() => {
45
46
  const circularRefId = parentCircularRefs.get(schema);
46
47
  // Avoid recursing infinitely, and instead render a link to the parent schema
@@ -54,7 +55,12 @@ function OpenAPISchemaProperty(props: {
54
55
  const properties = getSchemaProperties(schema);
55
56
  if (properties?.length) {
56
57
  return (
57
- <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
58
+ <OpenAPIDisclosure
59
+ icon={context.icons.plus}
60
+ label={(isExpanded) =>
61
+ getDisclosureLabel({ schema, isExpanded, context })
62
+ }
63
+ >
58
64
  <OpenAPISchemaProperties
59
65
  properties={properties}
60
66
  circularRefs={circularRefs}
@@ -208,7 +214,10 @@ function OpenAPISchemaAlternative(props: {
208
214
  {description ? (
209
215
  <Markdown source={description} className="openapi-schema-description" />
210
216
  ) : null}
211
- <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
217
+ <OpenAPIDisclosure
218
+ icon={context.icons.plus}
219
+ label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
220
+ >
212
221
  {properties?.length ? (
213
222
  <OpenAPISchemaProperties
214
223
  properties={properties}
@@ -246,8 +255,9 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
246
255
  */
247
256
  function OpenAPISchemaEnum(props: {
248
257
  schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
258
+ context: OpenAPIClientContext;
249
259
  }) {
250
- const { schema } = props;
260
+ const { schema, context } = props;
251
261
 
252
262
  const enumValues = (() => {
253
263
  // Render x-gitbook-enum first, as it has a different format
@@ -290,6 +300,7 @@ function OpenAPISchemaEnum(props: {
290
300
  value={item.value}
291
301
  label={item.description}
292
302
  withTooltip={!!item.description}
303
+ context={context}
293
304
  >
294
305
  <code>{`${item.value}`}</code>
295
306
  </OpenAPICopyButton>
@@ -302,9 +313,13 @@ function OpenAPISchemaEnum(props: {
302
313
  /**
303
314
  * Render the top row of a schema. e.g: name, type, and required status.
304
315
  */
305
- function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry }) {
316
+ function OpenAPISchemaPresentation(props: {
317
+ property: OpenAPISchemaPropertyEntry;
318
+ context: OpenAPIClientContext;
319
+ }) {
306
320
  const {
307
321
  property: { schema, propertyName, required },
322
+ context,
308
323
  } = props;
309
324
 
310
325
  const description = resolveDescription(schema);
@@ -317,6 +332,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
317
332
  type={getSchemaTitle(schema)}
318
333
  propertyName={propertyName}
319
334
  required={required}
335
+ context={context}
320
336
  />
321
337
  {typeof schema['x-deprecated-sunset'] === 'string' ? (
322
338
  <div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
@@ -349,7 +365,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
349
365
  Pattern: <code>{schema.pattern}</code>
350
366
  </span>
351
367
  ) : null}
352
- <OpenAPISchemaEnum schema={schema} />
368
+ <OpenAPISchemaEnum schema={schema} context={context} />
353
369
  </div>
354
370
  );
355
371
  }
@@ -444,7 +460,91 @@ export function getSchemaAlternatives(
444
460
  }
445
461
 
446
462
  const [type, schemas] = alternatives;
447
- return flattenAlternatives(type, schemas, new Set(ancestors).add(schema));
463
+ return mergeAlternatives(
464
+ type,
465
+ flattenAlternatives(type, schemas, new Set(ancestors).add(schema))
466
+ );
467
+ }
468
+
469
+ /**
470
+ * Merge alternatives of the same type into a single schema.
471
+ * - Merge string enums
472
+ */
473
+ function mergeAlternatives(
474
+ alternativeType: AlternativeType,
475
+ schemasOrRefs: OpenAPIV3.SchemaObject[]
476
+ ): OpenAPIV3.SchemaObject[] | null {
477
+ switch (alternativeType) {
478
+ case 'oneOf': {
479
+ return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
480
+ const latest = acc.at(-1);
481
+
482
+ if (
483
+ latest &&
484
+ latest.type === 'string' &&
485
+ latest.enum &&
486
+ schemaOrRef.type === 'string' &&
487
+ schemaOrRef.enum
488
+ ) {
489
+ latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
490
+ latest.nullable = latest.nullable || schemaOrRef.nullable;
491
+ return acc;
492
+ }
493
+
494
+ acc.push(schemaOrRef);
495
+ return acc;
496
+ }, []);
497
+ }
498
+ case 'allOf': {
499
+ return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
500
+ const latest = acc.at(-1);
501
+
502
+ if (
503
+ latest &&
504
+ latest.type === 'string' &&
505
+ latest.enum &&
506
+ schemaOrRef.type === 'string' &&
507
+ schemaOrRef.enum
508
+ ) {
509
+ const keys = Object.keys(schemaOrRef);
510
+ if (keys.every((key) => ['type', 'enum', 'nullable'].includes(key))) {
511
+ latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
512
+ latest.nullable = latest.nullable || schemaOrRef.nullable;
513
+ return acc;
514
+ }
515
+ }
516
+
517
+ if (latest && latest.type === 'object' && schemaOrRef.type === 'object') {
518
+ const keys = Object.keys(schemaOrRef);
519
+ if (
520
+ keys.every((key) =>
521
+ ['type', 'properties', 'required', 'nullable'].includes(key)
522
+ )
523
+ ) {
524
+ latest.properties = {
525
+ ...latest.properties,
526
+ ...schemaOrRef.properties,
527
+ };
528
+ latest.required = Array.from(
529
+ new Set([
530
+ ...(Array.isArray(latest.required) ? latest.required : []),
531
+ ...(Array.isArray(schemaOrRef.required)
532
+ ? schemaOrRef.required
533
+ : []),
534
+ ])
535
+ );
536
+ latest.nullable = latest.nullable || schemaOrRef.nullable;
537
+ return acc;
538
+ }
539
+ }
540
+
541
+ acc.push(schemaOrRef);
542
+ return acc;
543
+ }, []);
544
+ }
545
+ default:
546
+ return schemasOrRefs;
547
+ }
448
548
  }
449
549
 
450
550
  function flattenAlternatives(
@@ -502,19 +602,26 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
502
602
  return type;
503
603
  }
504
604
 
505
- function getDisclosureLabel(schema: OpenAPIV3.SchemaObject): string {
605
+ function getDisclosureLabel(props: {
606
+ schema: OpenAPIV3.SchemaObject;
607
+ isExpanded: boolean;
608
+ context: OpenAPIClientContext;
609
+ }) {
610
+ const { schema, isExpanded, context } = props;
611
+ let label: string;
506
612
  if (schema.type === 'array' && !!schema.items) {
507
613
  if (schema.items.oneOf) {
508
- return 'available items';
614
+ label = tString(context.translation, 'available_items').toLowerCase();
509
615
  }
510
-
511
616
  // Fallback to "child attributes" for enums and objects
512
- if (schema.items.enum || schema.items.type === 'object') {
513
- return 'child attributes';
617
+ else if (schema.items.enum || schema.items.type === 'object') {
618
+ label = tString(context.translation, 'child_attributes').toLowerCase();
619
+ } else {
620
+ label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
514
621
  }
515
-
516
- return schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
622
+ } else {
623
+ label = schema.title || tString(context.translation, 'child_attributes').toLowerCase();
517
624
  }
518
625
 
519
- return schema.title || 'child attributes';
626
+ return `${isExpanded ? tString(context.translation, 'hide') : tString(context.translation, 'show')} ${label}`;
520
627
  }
@@ -1,11 +1,14 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import type React from 'react';
3
+ import type { OpenAPIClientContext } from './context';
4
+ import { t, tString } from './translate';
3
5
 
4
6
  interface OpenAPISchemaNameProps {
5
7
  schema?: OpenAPIV3.SchemaObject;
6
8
  propertyName?: string | React.JSX.Element;
7
9
  required?: boolean;
8
10
  type?: string;
11
+ context: OpenAPIClientContext;
9
12
  }
10
13
 
11
14
  /**
@@ -13,9 +16,9 @@ interface OpenAPISchemaNameProps {
13
16
  * It includes the property name, type, required and deprecated status.
14
17
  */
15
18
  export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
16
- const { schema, type, propertyName, required } = props;
19
+ const { schema, type, propertyName, required, context } = props;
17
20
 
18
- const additionalItems = schema && getAdditionalItems(schema);
21
+ const additionalItems = schema && getAdditionalItems(schema, context);
19
22
 
20
23
  return (
21
24
  <span className="openapi-schema-name">
@@ -30,33 +33,45 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
30
33
  <span className="openapi-schema-type">{additionalItems}</span>
31
34
  ) : null}
32
35
  </span>
33
- {schema?.readOnly ? <span className="openapi-schema-readonly">read-only</span> : null}
36
+ {schema?.readOnly ? (
37
+ <span className="openapi-schema-readonly">
38
+ {t(context.translation, 'read_only')}
39
+ </span>
40
+ ) : null}
34
41
  {schema?.writeOnly ? (
35
- <span className="openapi-schema-writeonly">write-only</span>
42
+ <span className="openapi-schema-writeonly">
43
+ {t(context.translation, 'write_only')}
44
+ </span>
36
45
  ) : null}
37
46
  {required ? (
38
- <span className="openapi-schema-required">required</span>
47
+ <span className="openapi-schema-required">
48
+ {t(context.translation, 'required')}
49
+ </span>
39
50
  ) : (
40
- <span className="openapi-schema-optional">optional</span>
51
+ <span className="openapi-schema-optional">
52
+ {t(context.translation, 'optional')}
53
+ </span>
41
54
  )}
42
- {schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
55
+ {schema?.deprecated ? (
56
+ <span className="openapi-deprecated">{t(context.translation, 'deprecated')}</span>
57
+ ) : null}
43
58
  </span>
44
59
  );
45
60
  }
46
61
 
47
- function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
62
+ function getAdditionalItems(schema: OpenAPIV3.SchemaObject, context: OpenAPIClientContext): string {
48
63
  let additionalItems = '';
49
64
 
50
65
  if (schema.minimum || schema.minLength || schema.minItems) {
51
- additionalItems += ` · min: ${schema.minimum || schema.minLength || schema.minItems}`;
66
+ additionalItems += ` · ${tString(context.translation, 'min').toLowerCase()}: ${schema.minimum || schema.minLength || schema.minItems}`;
52
67
  }
53
68
 
54
69
  if (schema.maximum || schema.maxLength || schema.maxItems) {
55
- additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
70
+ additionalItems += ` · ${tString(context.translation, 'max').toLowerCase()}: ${schema.maximum || schema.maxLength || schema.maxItems}`;
56
71
  }
57
72
 
58
73
  if (schema.nullable) {
59
- additionalItems = ' | nullable';
74
+ additionalItems = ` | ${tString(context.translation, 'nullable').toLowerCase()}`;
60
75
  }
61
76
 
62
77
  return additionalItems;
@@ -4,8 +4,8 @@ import {
4
4
  OpenAPISchemaPropertiesFromServer,
5
5
  type OpenAPISchemaPropertyEntry,
6
6
  } from './OpenAPISchema';
7
+ import type { OpenAPIClientContext } from './context';
7
8
  import { decycle } from './decycle';
8
- import type { OpenAPIClientContext } from './types';
9
9
 
10
10
  export function OpenAPISchemaProperties(props: {
11
11
  id?: string;
@@ -1,12 +1,10 @@
1
1
  import { InteractiveSection } from './InteractiveSection';
2
2
  import { Markdown } from './Markdown';
3
3
  import { OpenAPISchemaName } from './OpenAPISchemaName';
4
- import type {
5
- OpenAPIClientContext,
6
- OpenAPIOperationData,
7
- OpenAPISecurityWithRequired,
8
- } from './types';
9
- import { resolveDescription } from './utils';
4
+ import type { OpenAPIClientContext } from './context';
5
+ import { t } from './translate';
6
+ import type { OpenAPIOperationData, OpenAPISecurityWithRequired } from './types';
7
+ import { createStateKey, resolveDescription } from './utils';
10
8
 
11
9
  /**
12
10
  * Present securities authorization that can be used for this operation.
@@ -23,10 +21,12 @@ export function OpenAPISecurities(props: {
23
21
 
24
22
  return (
25
23
  <InteractiveSection
26
- header="Authorizations"
24
+ header={t(context.translation, 'authorizations')}
25
+ stateKey={createStateKey('securities', context.blockKey)}
27
26
  toggeable
28
27
  defaultOpened={false}
29
28
  toggleIcon={context.icons.chevronRight}
29
+ selectIcon={context.icons.chevronDown}
30
30
  className="openapi-securities"
31
31
  tabs={securities.map(([key, security]) => {
32
32
  const description = resolveDescription(security);
@@ -36,7 +36,7 @@ export function OpenAPISecurities(props: {
36
36
  body: (
37
37
  <div className="openapi-schema">
38
38
  <div className="openapi-schema-presentation">
39
- {getLabelForType(security)}
39
+ {getLabelForType(security, context)}
40
40
 
41
41
  {description ? (
42
42
  <Markdown
@@ -53,11 +53,12 @@ export function OpenAPISecurities(props: {
53
53
  );
54
54
  }
55
55
 
56
- function getLabelForType(security: OpenAPISecurityWithRequired) {
56
+ function getLabelForType(security: OpenAPISecurityWithRequired, context: OpenAPIClientContext) {
57
57
  switch (security.type) {
58
58
  case 'apiKey':
59
59
  return (
60
60
  <OpenAPISchemaName
61
+ context={context}
61
62
  propertyName={security.name ?? 'apiKey'}
62
63
  type="string"
63
64
  required={security.required}
@@ -67,6 +68,7 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
67
68
  if (security.scheme === 'basic') {
68
69
  return (
69
70
  <OpenAPISchemaName
71
+ context={context}
70
72
  propertyName="Authorization"
71
73
  type="string"
72
74
  required={security.required}
@@ -79,6 +81,7 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
79
81
  return (
80
82
  <>
81
83
  <OpenAPISchemaName
84
+ context={context}
82
85
  propertyName="Authorization"
83
86
  type="string"
84
87
  required={security.required}
@@ -94,11 +97,29 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
94
97
  );
95
98
  }
96
99
 
97
- return <OpenAPISchemaName propertyName="HTTP" required={security.required} />;
100
+ return (
101
+ <OpenAPISchemaName
102
+ context={context}
103
+ propertyName="HTTP"
104
+ required={security.required}
105
+ />
106
+ );
98
107
  case 'oauth2':
99
- return <OpenAPISchemaName propertyName="OAuth2" required={security.required} />;
108
+ return (
109
+ <OpenAPISchemaName
110
+ context={context}
111
+ propertyName="OAuth2"
112
+ required={security.required}
113
+ />
114
+ );
100
115
  case 'openIdConnect':
101
- return <OpenAPISchemaName propertyName="OpenID Connect" required={security.required} />;
116
+ return (
117
+ <OpenAPISchemaName
118
+ context={context}
119
+ propertyName="OpenID Connect"
120
+ required={security.required}
121
+ />
122
+ );
102
123
  default:
103
124
  // @ts-ignore
104
125
  return security.type;
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import clsx from 'clsx';
4
+ import { useCallback } from 'react';
4
5
  import {
5
6
  Button,
6
7
  type Key,
@@ -13,38 +14,63 @@ import {
13
14
  type SelectProps,
14
15
  SelectValue,
15
16
  } from 'react-aria-components';
17
+ import { useStore } from 'zustand';
18
+ import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
16
19
 
17
20
  export type OpenAPISelectItem = {
18
21
  key: Key;
19
- label: string;
22
+ label: string | React.ReactNode;
20
23
  };
21
24
 
22
25
  interface OpenAPISelectProps<T extends OpenAPISelectItem> extends Omit<SelectProps<T>, 'children'> {
23
26
  items: T[];
24
27
  children: React.ReactNode | ((item: T) => React.ReactNode);
25
- selectedKey?: Key;
26
- onChange?: (key: string | number) => void;
27
28
  placement?: PopoverProps['placement'];
29
+ stateKey?: string;
30
+ /**
31
+ * Icon to display in the select button.
32
+ */
33
+ icon?: React.ReactNode;
34
+ }
35
+
36
+ export function useSelectState(stateKey = 'select-state', initialKey?: Key) {
37
+ const store = useStore(getOrCreateStoreByKey(stateKey, initialKey));
38
+ return {
39
+ key: store.key,
40
+ setKey: useCallback((key: Key | null) => store.setKey(key), [store.setKey]),
41
+ };
28
42
  }
29
43
 
30
44
  export function OpenAPISelect<T extends OpenAPISelectItem>(props: OpenAPISelectProps<T>) {
31
- const { items, children, className, placement } = props;
45
+ const {
46
+ icon = '▼',
47
+ items,
48
+ children,
49
+ className,
50
+ placement,
51
+ stateKey,
52
+ selectedKey,
53
+ onSelectionChange,
54
+ } = props;
55
+
56
+ const state = useSelectState(stateKey, items[0]?.key);
57
+
58
+ const selected = items.find((item) => item.key === state.key) || items[0];
32
59
 
33
60
  return (
34
- <Select {...props} className={clsx('openapi-select', className)}>
61
+ <Select
62
+ aria-label="OpenAPI Select"
63
+ {...props}
64
+ selectedKey={selectedKey || selected?.key}
65
+ onSelectionChange={(key) => {
66
+ onSelectionChange?.(key);
67
+ state.setKey(key);
68
+ }}
69
+ className={clsx('openapi-select', className)}
70
+ >
35
71
  <Button>
36
72
  <SelectValue />
37
- <span aria-hidden="true">
38
- <svg
39
- className="gb-icon"
40
- style={{
41
- maskImage:
42
- "url('https://ka-p.fontawesome.com/releases/v6.6.0/svgs/regular/chevron-down.svg?v=2&token=a463935e93')",
43
- maskRepeat: 'no-repeat',
44
- maskPosition: 'center center',
45
- }}
46
- />
47
- </span>
73
+ {icon}
48
74
  </Button>
49
75
  <Popover placement={placement} className="openapi-select-popover">
50
76
  <ListBox className="openapi-select-listbox" items={items}>
@@ -5,16 +5,23 @@ import { OpenAPIResponses } from './OpenAPIResponses';
5
5
  import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
6
6
  import { OpenAPISecurities } from './OpenAPISecurities';
7
7
  import { StaticSection } from './StaticSection';
8
- import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
8
+ import type { OpenAPIClientContext } from './context';
9
+ import { tString } from './translate';
10
+ import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
9
11
  import { parameterToProperty } from './utils';
10
12
 
11
- export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAPIClientContext }) {
13
+ export function OpenAPISpec(props: {
14
+ data: OpenAPIOperationData | OpenAPIWebhookData;
15
+ context: OpenAPIClientContext;
16
+ }) {
12
17
  const { data, context } = props;
13
18
 
14
- const { operation, securities } = data;
19
+ const { operation } = data;
15
20
 
16
21
  const parameters = operation.parameters ?? [];
17
- const parameterGroups = groupParameters(parameters);
22
+ const parameterGroups = groupParameters(parameters, context);
23
+
24
+ const securities = 'securities' in data ? data.securities : [];
18
25
 
19
26
  return (
20
27
  <>
@@ -42,6 +49,7 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
42
49
  key="body"
43
50
  requestBody={operation.requestBody}
44
51
  context={context}
52
+ data={data}
45
53
  />
46
54
  ) : null}
47
55
  {operation.responses ? (
@@ -55,7 +63,10 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
55
63
  );
56
64
  }
57
65
 
58
- function groupParameters(parameters: OpenAPI.Parameters): Array<{
66
+ function groupParameters(
67
+ parameters: OpenAPI.Parameters,
68
+ context: OpenAPIClientContext
69
+ ): Array<{
59
70
  key: string;
60
71
  label: string;
61
72
  parameters: OpenAPI.Parameters;
@@ -72,7 +83,7 @@ function groupParameters(parameters: OpenAPI.Parameters): Array<{
72
83
  .filter((parameter) => parameter.in)
73
84
  .forEach((parameter) => {
74
85
  const key = parameter.in;
75
- const label = getParameterGroupName(parameter.in);
86
+ const label = getParameterGroupName(parameter.in, context);
76
87
  const group = groups.find((group) => group.key === key);
77
88
  if (group) {
78
89
  group.parameters.push(parameter);
@@ -90,14 +101,14 @@ function groupParameters(parameters: OpenAPI.Parameters): Array<{
90
101
  return groups;
91
102
  }
92
103
 
93
- function getParameterGroupName(paramIn: string): string {
104
+ function getParameterGroupName(paramIn: string, context: OpenAPIClientContext): string {
94
105
  switch (paramIn) {
95
106
  case 'path':
96
- return 'Path parameters';
107
+ return tString(context.translation, 'path_parameters');
97
108
  case 'query':
98
- return 'Query parameters';
109
+ return tString(context.translation, 'query_parameters');
99
110
  case 'header':
100
- return 'Header parameters';
111
+ return tString(context.translation, 'header_parameters');
101
112
  default:
102
113
  return paramIn;
103
114
  }