@stoplight/elements-core 7.13.7 → 7.14.0
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/__fixtures__/operations/urlencoded-post-oneof.d.ts +3 -0
- package/components/TryIt/Body/FormDataBody.d.ts +8 -2
- package/components/TryIt/Parameters/parameter-utils.d.ts +6 -3
- package/components/TryIt/TryIt.stories.d.ts +1 -0
- package/index.esm.js +75 -37
- package/index.js +76 -37
- package/index.mjs +75 -37
- package/package.json +7 -6
- package/hooks/useChosenServerUrl.d.ts +0 -6
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { Choice } from '@stoplight/json-schema-viewer';
|
|
1
2
|
import { IMediaTypeContent } from '@stoplight/types';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import { BodyParameterValues, ParameterOptional } from './request-body-utils';
|
|
4
|
-
interface FormDataBodyProps {
|
|
5
|
+
export interface FormDataBodyProps {
|
|
5
6
|
specification: IMediaTypeContent;
|
|
6
7
|
values: BodyParameterValues;
|
|
7
8
|
onChangeValues: (newValues: BodyParameterValues) => void;
|
|
@@ -9,4 +10,9 @@ interface FormDataBodyProps {
|
|
|
9
10
|
isAllowedEmptyValues: ParameterOptional;
|
|
10
11
|
}
|
|
11
12
|
export declare const FormDataBody: React.FC<FormDataBodyProps>;
|
|
12
|
-
export {
|
|
13
|
+
export interface OneOfMenuProps {
|
|
14
|
+
choices: Choice[];
|
|
15
|
+
choice: Choice;
|
|
16
|
+
onChange: (choice: Choice) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function OneOfMenu({ choices: subSchemas, choice, onChange }: OneOfMenuProps): JSX.Element | null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { RegularNode, SchemaNode } from '@stoplight/json-schema-tree';
|
|
1
2
|
import type { IHttpParam, INodeExample, INodeExternalExample } from '@stoplight/types';
|
|
2
|
-
import { JSONSchema7Definition } from 'json-schema';
|
|
3
|
+
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
|
|
3
4
|
export declare type ParameterSpec = Pick<IHttpParam, 'name' | 'schema' | 'required'> & {
|
|
4
5
|
examples?: (Omit<INodeExample, 'id'> | Omit<INodeExternalExample, 'id'>)[];
|
|
5
6
|
};
|
|
@@ -17,7 +18,7 @@ export declare function exampleOptions(parameter: ParameterSpec): {
|
|
|
17
18
|
value: string;
|
|
18
19
|
label: string;
|
|
19
20
|
}[] | null;
|
|
20
|
-
export declare function parameterSupportsFileUpload(parameter
|
|
21
|
+
export declare function parameterSupportsFileUpload(parameter?: Pick<ParameterSpec, 'schema'>): boolean | undefined;
|
|
21
22
|
export declare function getPlaceholderForParameter(parameter: ParameterSpec): string;
|
|
22
23
|
export declare const initialParameterValues: (params: readonly ParameterSpec[]) => Record<string, string>;
|
|
23
24
|
export declare function mapSchemaPropertiesToParameters(properties: {
|
|
@@ -25,9 +26,11 @@ export declare function mapSchemaPropertiesToParameters(properties: {
|
|
|
25
26
|
}, required: string[] | undefined): {
|
|
26
27
|
required?: boolean | undefined;
|
|
27
28
|
name: string;
|
|
28
|
-
schema:
|
|
29
|
+
schema: JSONSchema7 | undefined;
|
|
29
30
|
examples: {
|
|
30
31
|
key: string;
|
|
31
32
|
value: any;
|
|
32
33
|
}[] | undefined;
|
|
33
34
|
}[];
|
|
35
|
+
export declare function toParameterSpec(jsonTreeNode: RegularNode): ParameterSpec;
|
|
36
|
+
export declare function isRequired(n: SchemaNode): boolean | undefined;
|
|
@@ -6,6 +6,7 @@ export declare const SimpleGET: Story<TryItProps>;
|
|
|
6
6
|
export declare const WithParameters: Story<TryItProps>;
|
|
7
7
|
export declare const WithVariables: Story<TryItProps>;
|
|
8
8
|
export declare const UrlEncoded: Story<TryItProps>;
|
|
9
|
+
export declare const UrlEncodedOneOf: Story<TryItProps>;
|
|
9
10
|
export declare const Multipart: Story<TryItProps>;
|
|
10
11
|
export declare const RequestBodySchema: Story<TryItProps>;
|
|
11
12
|
export declare const RequestBodyExamples: Story<TryItProps>;
|
package/index.esm.js
CHANGED
|
@@ -25,8 +25,11 @@ import filter from 'lodash/filter.js';
|
|
|
25
25
|
import flatten from 'lodash/flatten.js';
|
|
26
26
|
import { nanoid } from 'nanoid';
|
|
27
27
|
import curry from 'lodash/curry.js';
|
|
28
|
+
import { isRegularNode, SchemaTree } from '@stoplight/json-schema-tree';
|
|
29
|
+
import { useChoices, visibleChildren, JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
28
30
|
import omit from 'lodash/omit.js';
|
|
29
31
|
import keyBy from 'lodash/keyBy.js';
|
|
32
|
+
import last from 'lodash/last.js';
|
|
30
33
|
import map from 'lodash/map.js';
|
|
31
34
|
import mapValues from 'lodash/mapValues.js';
|
|
32
35
|
import isString from 'lodash/isString.js';
|
|
@@ -40,7 +43,6 @@ import uniqBy from 'lodash/uniqBy.js';
|
|
|
40
43
|
import formatXml from 'xml-formatter';
|
|
41
44
|
import entries from 'lodash/entries.js';
|
|
42
45
|
import keys from 'lodash/keys.js';
|
|
43
|
-
import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
44
46
|
import sortBy from 'lodash/sortBy.js';
|
|
45
47
|
import isEmpty from 'lodash/isEmpty.js';
|
|
46
48
|
import isNil from 'lodash/isNil.js';
|
|
@@ -495,21 +497,6 @@ function createNamedContext(name, defaultValue) {
|
|
|
495
497
|
return context;
|
|
496
498
|
}
|
|
497
499
|
|
|
498
|
-
const ALPHANUMERIC = /[^A-Za-z0-9]+$/;
|
|
499
|
-
function useChosenServerUrl(chosenServerUrl) {
|
|
500
|
-
const match = ALPHANUMERIC.exec(chosenServerUrl);
|
|
501
|
-
if (match === null) {
|
|
502
|
-
return {
|
|
503
|
-
leading: chosenServerUrl,
|
|
504
|
-
trailing: null,
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
leading: chosenServerUrl.substring(0, match.index),
|
|
509
|
-
trailing: chosenServerUrl.substring(match.index),
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
500
|
const getBreakpoints = (compact) => {
|
|
514
501
|
if (!compact)
|
|
515
502
|
return undefined;
|
|
@@ -1191,7 +1178,9 @@ function exampleOptions(parameter) {
|
|
|
1191
1178
|
}
|
|
1192
1179
|
function parameterSupportsFileUpload(parameter) {
|
|
1193
1180
|
var _a, _b, _c;
|
|
1194
|
-
return (
|
|
1181
|
+
return (parameter &&
|
|
1182
|
+
parameter.schema &&
|
|
1183
|
+
((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
|
|
1195
1184
|
(((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
|
|
1196
1185
|
((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
|
|
1197
1186
|
}
|
|
@@ -1247,6 +1236,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
|
|
|
1247
1236
|
return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
|
|
1248
1237
|
? [{ key: 'example', value: schema.examples[0] }]
|
|
1249
1238
|
: undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
|
|
1239
|
+
}
|
|
1240
|
+
function toParameterSpec(jsonTreeNode) {
|
|
1241
|
+
var _a;
|
|
1242
|
+
const isBoolean = jsonTreeNode.primaryType === 'boolean';
|
|
1243
|
+
const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
|
|
1244
|
+
const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
|
|
1245
|
+
? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
|
|
1246
|
+
: undefined;
|
|
1247
|
+
const lastJsonPathSegment = (_a = last(jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
|
|
1248
|
+
return {
|
|
1249
|
+
name: lastJsonPathSegment,
|
|
1250
|
+
schema,
|
|
1251
|
+
examples,
|
|
1252
|
+
required: isRequired(jsonTreeNode),
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function isRequired(n) {
|
|
1256
|
+
if (!isRegularNode(n)) {
|
|
1257
|
+
return undefined;
|
|
1258
|
+
}
|
|
1259
|
+
const name = last(n.path);
|
|
1260
|
+
if (name === undefined) {
|
|
1261
|
+
return undefined;
|
|
1262
|
+
}
|
|
1263
|
+
const parent = n.parent;
|
|
1264
|
+
if (parent === null || !isRegularNode(parent)) {
|
|
1265
|
+
return undefined;
|
|
1266
|
+
}
|
|
1267
|
+
return parent.required !== null && parent.required.includes(name);
|
|
1250
1268
|
}
|
|
1251
1269
|
|
|
1252
1270
|
const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
|
|
@@ -1276,31 +1294,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
|
|
|
1276
1294
|
};
|
|
1277
1295
|
|
|
1278
1296
|
const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
|
|
1279
|
-
const schema =
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1297
|
+
const schema = React.useMemo(() => {
|
|
1298
|
+
var _a;
|
|
1299
|
+
const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
|
|
1300
|
+
const tree = new SchemaTree(schema, { mergeAllOf: true, refResolver: null });
|
|
1301
|
+
tree.populate();
|
|
1302
|
+
return tree.root.children[0];
|
|
1303
|
+
}, [specification]);
|
|
1304
|
+
const { selectedChoice, choices, setSelectedChoice } = useChoices(schema);
|
|
1305
|
+
const formFieldRows = visibleChildren(selectedChoice.type);
|
|
1306
|
+
const onSchemaChange = (choice) => {
|
|
1307
|
+
onChangeValues({});
|
|
1308
|
+
setSelectedChoice(choice);
|
|
1309
|
+
};
|
|
1290
1310
|
return (React.createElement(Panel, { defaultIsOpen: true },
|
|
1291
|
-
React.createElement(Panel.Titlebar,
|
|
1292
|
-
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" },
|
|
1293
|
-
|
|
1311
|
+
React.createElement(Panel.Titlebar, { rightComponent: React.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
|
|
1312
|
+
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
|
|
1313
|
+
.filter(isRegularNode)
|
|
1314
|
+
.map(toParameterSpec)
|
|
1315
|
+
.map(parameter => {
|
|
1316
|
+
var _a, _b;
|
|
1294
1317
|
const supportsFileUpload = parameterSupportsFileUpload(parameter);
|
|
1295
|
-
const value = values[parameter.name];
|
|
1318
|
+
const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
|
|
1296
1319
|
if (supportsFileUpload) {
|
|
1297
1320
|
return (React.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
|
|
1298
1321
|
? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
|
|
1299
1322
|
: onChangeValues(omit(values, parameter.name)) }));
|
|
1300
1323
|
}
|
|
1301
|
-
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (
|
|
1324
|
+
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
|
|
1302
1325
|
}))));
|
|
1303
|
-
};
|
|
1326
|
+
};
|
|
1327
|
+
function OneOfMenu({ choices: subSchemas, choice, onChange }) {
|
|
1328
|
+
var _a;
|
|
1329
|
+
const onSubSchemaSelect = React.useCallback(onChange, [onChange]);
|
|
1330
|
+
const menuItems = React.useMemo(() => subSchemas.map(subSchema => {
|
|
1331
|
+
const label = subSchema.title;
|
|
1332
|
+
return {
|
|
1333
|
+
id: `request-subschema-${label}`,
|
|
1334
|
+
title: label,
|
|
1335
|
+
onPress: () => onSubSchemaSelect(subSchema),
|
|
1336
|
+
};
|
|
1337
|
+
}), [subSchemas, onSubSchemaSelect]);
|
|
1338
|
+
if (!subSchemas || subSchemas.length < 2) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
|
|
1342
|
+
return (React.createElement(Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React.createElement(Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
|
|
1343
|
+
}
|
|
1304
1344
|
|
|
1305
1345
|
const fileToBase64 = (file) => new Promise((resolve, reject) => {
|
|
1306
1346
|
const reader = new FileReader();
|
|
@@ -2662,11 +2702,9 @@ function MethodPath({ method, path }) {
|
|
|
2662
2702
|
function MethodPathInner({ method, path, chosenServerUrl }) {
|
|
2663
2703
|
const isDark = useThemeIsDark();
|
|
2664
2704
|
const fullUrl = `${chosenServerUrl}${path}`;
|
|
2665
|
-
const { leading, trailing } = useChosenServerUrl(chosenServerUrl);
|
|
2666
2705
|
const pathElem = (React.createElement(Flex, { overflowX: "hidden", fontSize: "lg", userSelect: "all" },
|
|
2667
2706
|
React.createElement(Box, { dir: "rtl", color: "muted", textOverflow: "truncate", overflowX: "hidden" },
|
|
2668
|
-
|
|
2669
|
-
trailing !== null && (React.createElement(Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, trailing))),
|
|
2707
|
+
React.createElement(Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, chosenServerUrl)),
|
|
2670
2708
|
React.createElement(Box, { fontWeight: "semibold", flex: 1 }, path)));
|
|
2671
2709
|
return (React.createElement(HStack, { spacing: 3, pl: 2.5, pr: 4, py: 2, bg: "canvas-50", rounded: "lg", fontFamily: "mono", display: "inline-flex", maxW: "full", title: fullUrl },
|
|
2672
2710
|
React.createElement(Box, { py: 1, px: 2.5, rounded: "lg", bg: !isDark ? HttpMethodColors[method] : 'canvas-100', color: !isDark ? 'on-primary' : 'body', fontSize: "lg", fontWeight: "semibold", textTransform: "uppercase" }, method),
|
package/index.js
CHANGED
|
@@ -27,8 +27,11 @@ var filter = require('lodash/filter.js');
|
|
|
27
27
|
var flatten = require('lodash/flatten.js');
|
|
28
28
|
var nanoid = require('nanoid');
|
|
29
29
|
var curry = require('lodash/curry.js');
|
|
30
|
+
var jsonSchemaTree = require('@stoplight/json-schema-tree');
|
|
31
|
+
var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
|
|
30
32
|
var omit = require('lodash/omit.js');
|
|
31
33
|
var keyBy = require('lodash/keyBy.js');
|
|
34
|
+
var last = require('lodash/last.js');
|
|
32
35
|
var map = require('lodash/map.js');
|
|
33
36
|
var mapValues = require('lodash/mapValues.js');
|
|
34
37
|
var isString = require('lodash/isString.js');
|
|
@@ -42,7 +45,6 @@ var uniqBy = require('lodash/uniqBy.js');
|
|
|
42
45
|
var formatXml = require('xml-formatter');
|
|
43
46
|
var entries = require('lodash/entries.js');
|
|
44
47
|
var keys = require('lodash/keys.js');
|
|
45
|
-
var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
|
|
46
48
|
var sortBy = require('lodash/sortBy.js');
|
|
47
49
|
var isEmpty = require('lodash/isEmpty.js');
|
|
48
50
|
var isNil = require('lodash/isNil.js');
|
|
@@ -87,6 +89,7 @@ var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
|
87
89
|
var curry__default = /*#__PURE__*/_interopDefaultLegacy(curry);
|
|
88
90
|
var omit__default = /*#__PURE__*/_interopDefaultLegacy(omit);
|
|
89
91
|
var keyBy__default = /*#__PURE__*/_interopDefaultLegacy(keyBy);
|
|
92
|
+
var last__default = /*#__PURE__*/_interopDefaultLegacy(last);
|
|
90
93
|
var map__default = /*#__PURE__*/_interopDefaultLegacy(map);
|
|
91
94
|
var mapValues__default = /*#__PURE__*/_interopDefaultLegacy(mapValues);
|
|
92
95
|
var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString);
|
|
@@ -551,21 +554,6 @@ function createNamedContext(name, defaultValue) {
|
|
|
551
554
|
return context;
|
|
552
555
|
}
|
|
553
556
|
|
|
554
|
-
const ALPHANUMERIC = /[^A-Za-z0-9]+$/;
|
|
555
|
-
function useChosenServerUrl(chosenServerUrl) {
|
|
556
|
-
const match = ALPHANUMERIC.exec(chosenServerUrl);
|
|
557
|
-
if (match === null) {
|
|
558
|
-
return {
|
|
559
|
-
leading: chosenServerUrl,
|
|
560
|
-
trailing: null,
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
return {
|
|
564
|
-
leading: chosenServerUrl.substring(0, match.index),
|
|
565
|
-
trailing: chosenServerUrl.substring(match.index),
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
|
|
569
557
|
const getBreakpoints = (compact) => {
|
|
570
558
|
if (!compact)
|
|
571
559
|
return undefined;
|
|
@@ -1247,7 +1235,9 @@ function exampleOptions(parameter) {
|
|
|
1247
1235
|
}
|
|
1248
1236
|
function parameterSupportsFileUpload(parameter) {
|
|
1249
1237
|
var _a, _b, _c;
|
|
1250
|
-
return (
|
|
1238
|
+
return (parameter &&
|
|
1239
|
+
parameter.schema &&
|
|
1240
|
+
((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
|
|
1251
1241
|
(((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
|
|
1252
1242
|
((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
|
|
1253
1243
|
}
|
|
@@ -1303,6 +1293,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
|
|
|
1303
1293
|
return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
|
|
1304
1294
|
? [{ key: 'example', value: schema.examples[0] }]
|
|
1305
1295
|
: undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
|
|
1296
|
+
}
|
|
1297
|
+
function toParameterSpec(jsonTreeNode) {
|
|
1298
|
+
var _a;
|
|
1299
|
+
const isBoolean = jsonTreeNode.primaryType === 'boolean';
|
|
1300
|
+
const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
|
|
1301
|
+
const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
|
|
1302
|
+
? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
|
|
1303
|
+
: undefined;
|
|
1304
|
+
const lastJsonPathSegment = (_a = last__default["default"](jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
|
|
1305
|
+
return {
|
|
1306
|
+
name: lastJsonPathSegment,
|
|
1307
|
+
schema,
|
|
1308
|
+
examples,
|
|
1309
|
+
required: isRequired(jsonTreeNode),
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
function isRequired(n) {
|
|
1313
|
+
if (!jsonSchemaTree.isRegularNode(n)) {
|
|
1314
|
+
return undefined;
|
|
1315
|
+
}
|
|
1316
|
+
const name = last__default["default"](n.path);
|
|
1317
|
+
if (name === undefined) {
|
|
1318
|
+
return undefined;
|
|
1319
|
+
}
|
|
1320
|
+
const parent = n.parent;
|
|
1321
|
+
if (parent === null || !jsonSchemaTree.isRegularNode(parent)) {
|
|
1322
|
+
return undefined;
|
|
1323
|
+
}
|
|
1324
|
+
return parent.required !== null && parent.required.includes(name);
|
|
1306
1325
|
}
|
|
1307
1326
|
|
|
1308
1327
|
const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
|
|
@@ -1332,31 +1351,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
|
|
|
1332
1351
|
};
|
|
1333
1352
|
|
|
1334
1353
|
const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
|
|
1335
|
-
const schema =
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1354
|
+
const schema = React__namespace.useMemo(() => {
|
|
1355
|
+
var _a;
|
|
1356
|
+
const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
|
|
1357
|
+
const tree = new jsonSchemaTree.SchemaTree(schema, { mergeAllOf: true, refResolver: null });
|
|
1358
|
+
tree.populate();
|
|
1359
|
+
return tree.root.children[0];
|
|
1360
|
+
}, [specification]);
|
|
1361
|
+
const { selectedChoice, choices, setSelectedChoice } = jsonSchemaViewer.useChoices(schema);
|
|
1362
|
+
const formFieldRows = jsonSchemaViewer.visibleChildren(selectedChoice.type);
|
|
1363
|
+
const onSchemaChange = (choice) => {
|
|
1364
|
+
onChangeValues({});
|
|
1365
|
+
setSelectedChoice(choice);
|
|
1366
|
+
};
|
|
1346
1367
|
return (React__namespace.createElement(mosaic.Panel, { defaultIsOpen: true },
|
|
1347
|
-
React__namespace.createElement(mosaic.Panel.Titlebar,
|
|
1348
|
-
React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" },
|
|
1349
|
-
|
|
1368
|
+
React__namespace.createElement(mosaic.Panel.Titlebar, { rightComponent: React__namespace.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
|
|
1369
|
+
React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
|
|
1370
|
+
.filter(jsonSchemaTree.isRegularNode)
|
|
1371
|
+
.map(toParameterSpec)
|
|
1372
|
+
.map(parameter => {
|
|
1373
|
+
var _a, _b;
|
|
1350
1374
|
const supportsFileUpload = parameterSupportsFileUpload(parameter);
|
|
1351
|
-
const value = values[parameter.name];
|
|
1375
|
+
const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
|
|
1352
1376
|
if (supportsFileUpload) {
|
|
1353
1377
|
return (React__namespace.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
|
|
1354
1378
|
? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
|
|
1355
1379
|
: onChangeValues(omit__default["default"](values, parameter.name)) }));
|
|
1356
1380
|
}
|
|
1357
|
-
return (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (
|
|
1381
|
+
return (React__namespace.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
|
|
1358
1382
|
}))));
|
|
1359
|
-
};
|
|
1383
|
+
};
|
|
1384
|
+
function OneOfMenu({ choices: subSchemas, choice, onChange }) {
|
|
1385
|
+
var _a;
|
|
1386
|
+
const onSubSchemaSelect = React__namespace.useCallback(onChange, [onChange]);
|
|
1387
|
+
const menuItems = React__namespace.useMemo(() => subSchemas.map(subSchema => {
|
|
1388
|
+
const label = subSchema.title;
|
|
1389
|
+
return {
|
|
1390
|
+
id: `request-subschema-${label}`,
|
|
1391
|
+
title: label,
|
|
1392
|
+
onPress: () => onSubSchemaSelect(subSchema),
|
|
1393
|
+
};
|
|
1394
|
+
}), [subSchemas, onSubSchemaSelect]);
|
|
1395
|
+
if (!subSchemas || subSchemas.length < 2) {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
|
|
1399
|
+
return (React__namespace.createElement(mosaic.Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React__namespace.createElement(mosaic.Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
|
|
1400
|
+
}
|
|
1360
1401
|
|
|
1361
1402
|
const fileToBase64 = (file) => new Promise((resolve, reject) => {
|
|
1362
1403
|
const reader = new FileReader();
|
|
@@ -2718,11 +2759,9 @@ function MethodPath({ method, path }) {
|
|
|
2718
2759
|
function MethodPathInner({ method, path, chosenServerUrl }) {
|
|
2719
2760
|
const isDark = mosaic.useThemeIsDark();
|
|
2720
2761
|
const fullUrl = `${chosenServerUrl}${path}`;
|
|
2721
|
-
const { leading, trailing } = useChosenServerUrl(chosenServerUrl);
|
|
2722
2762
|
const pathElem = (React__namespace.createElement(mosaic.Flex, { overflowX: "hidden", fontSize: "lg", userSelect: "all" },
|
|
2723
2763
|
React__namespace.createElement(mosaic.Box, { dir: "rtl", color: "muted", textOverflow: "truncate", overflowX: "hidden" },
|
|
2724
|
-
|
|
2725
|
-
trailing !== null && (React__namespace.createElement(mosaic.Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, trailing))),
|
|
2764
|
+
React__namespace.createElement(mosaic.Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, chosenServerUrl)),
|
|
2726
2765
|
React__namespace.createElement(mosaic.Box, { fontWeight: "semibold", flex: 1 }, path)));
|
|
2727
2766
|
return (React__namespace.createElement(mosaic.HStack, { spacing: 3, pl: 2.5, pr: 4, py: 2, bg: "canvas-50", rounded: "lg", fontFamily: "mono", display: "inline-flex", maxW: "full", title: fullUrl },
|
|
2728
2767
|
React__namespace.createElement(mosaic.Box, { py: 1, px: 2.5, rounded: "lg", bg: !isDark ? HttpMethodColors[method] : 'canvas-100', color: !isDark ? 'on-primary' : 'body', fontSize: "lg", fontWeight: "semibold", textTransform: "uppercase" }, method),
|
package/index.mjs
CHANGED
|
@@ -25,8 +25,11 @@ import filter from 'lodash/filter.js';
|
|
|
25
25
|
import flatten from 'lodash/flatten.js';
|
|
26
26
|
import { nanoid } from 'nanoid';
|
|
27
27
|
import curry from 'lodash/curry.js';
|
|
28
|
+
import { isRegularNode, SchemaTree } from '@stoplight/json-schema-tree';
|
|
29
|
+
import { useChoices, visibleChildren, JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
28
30
|
import omit from 'lodash/omit.js';
|
|
29
31
|
import keyBy from 'lodash/keyBy.js';
|
|
32
|
+
import last from 'lodash/last.js';
|
|
30
33
|
import map from 'lodash/map.js';
|
|
31
34
|
import mapValues from 'lodash/mapValues.js';
|
|
32
35
|
import isString from 'lodash/isString.js';
|
|
@@ -40,7 +43,6 @@ import uniqBy from 'lodash/uniqBy.js';
|
|
|
40
43
|
import formatXml from 'xml-formatter';
|
|
41
44
|
import entries from 'lodash/entries.js';
|
|
42
45
|
import keys from 'lodash/keys.js';
|
|
43
|
-
import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
44
46
|
import sortBy from 'lodash/sortBy.js';
|
|
45
47
|
import isEmpty from 'lodash/isEmpty.js';
|
|
46
48
|
import isNil from 'lodash/isNil.js';
|
|
@@ -495,21 +497,6 @@ function createNamedContext(name, defaultValue) {
|
|
|
495
497
|
return context;
|
|
496
498
|
}
|
|
497
499
|
|
|
498
|
-
const ALPHANUMERIC = /[^A-Za-z0-9]+$/;
|
|
499
|
-
function useChosenServerUrl(chosenServerUrl) {
|
|
500
|
-
const match = ALPHANUMERIC.exec(chosenServerUrl);
|
|
501
|
-
if (match === null) {
|
|
502
|
-
return {
|
|
503
|
-
leading: chosenServerUrl,
|
|
504
|
-
trailing: null,
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
leading: chosenServerUrl.substring(0, match.index),
|
|
509
|
-
trailing: chosenServerUrl.substring(match.index),
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
500
|
const getBreakpoints = (compact) => {
|
|
514
501
|
if (!compact)
|
|
515
502
|
return undefined;
|
|
@@ -1191,7 +1178,9 @@ function exampleOptions(parameter) {
|
|
|
1191
1178
|
}
|
|
1192
1179
|
function parameterSupportsFileUpload(parameter) {
|
|
1193
1180
|
var _a, _b, _c;
|
|
1194
|
-
return (
|
|
1181
|
+
return (parameter &&
|
|
1182
|
+
parameter.schema &&
|
|
1183
|
+
((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'string' &&
|
|
1195
1184
|
(((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
|
|
1196
1185
|
((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
|
|
1197
1186
|
}
|
|
@@ -1247,6 +1236,35 @@ function mapSchemaPropertiesToParameters(properties, required) {
|
|
|
1247
1236
|
return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples && schema.examples[0]
|
|
1248
1237
|
? [{ key: 'example', value: schema.examples[0] }]
|
|
1249
1238
|
: undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
|
|
1239
|
+
}
|
|
1240
|
+
function toParameterSpec(jsonTreeNode) {
|
|
1241
|
+
var _a;
|
|
1242
|
+
const isBoolean = jsonTreeNode.primaryType === 'boolean';
|
|
1243
|
+
const schema = !isBoolean ? jsonTreeNode.fragment : undefined;
|
|
1244
|
+
const examples = !isBoolean && jsonTreeNode.fragment.examples && jsonTreeNode.fragment.examples[0]
|
|
1245
|
+
? [{ key: 'example', value: jsonTreeNode.fragment.examples[0] }]
|
|
1246
|
+
: undefined;
|
|
1247
|
+
const lastJsonPathSegment = (_a = last(jsonTreeNode.path)) !== null && _a !== void 0 ? _a : '<<UNKNOWN>>';
|
|
1248
|
+
return {
|
|
1249
|
+
name: lastJsonPathSegment,
|
|
1250
|
+
schema,
|
|
1251
|
+
examples,
|
|
1252
|
+
required: isRequired(jsonTreeNode),
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function isRequired(n) {
|
|
1256
|
+
if (!isRegularNode(n)) {
|
|
1257
|
+
return undefined;
|
|
1258
|
+
}
|
|
1259
|
+
const name = last(n.path);
|
|
1260
|
+
if (name === undefined) {
|
|
1261
|
+
return undefined;
|
|
1262
|
+
}
|
|
1263
|
+
const parent = n.parent;
|
|
1264
|
+
if (parent === null || !isRegularNode(parent)) {
|
|
1265
|
+
return undefined;
|
|
1266
|
+
}
|
|
1267
|
+
return parent.required !== null && parent.required.includes(name);
|
|
1250
1268
|
}
|
|
1251
1269
|
|
|
1252
1270
|
const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
|
|
@@ -1276,31 +1294,53 @@ const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptio
|
|
|
1276
1294
|
};
|
|
1277
1295
|
|
|
1278
1296
|
const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
|
|
1279
|
-
const schema =
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1297
|
+
const schema = React.useMemo(() => {
|
|
1298
|
+
var _a;
|
|
1299
|
+
const schema = (_a = specification.schema) !== null && _a !== void 0 ? _a : {};
|
|
1300
|
+
const tree = new SchemaTree(schema, { mergeAllOf: true, refResolver: null });
|
|
1301
|
+
tree.populate();
|
|
1302
|
+
return tree.root.children[0];
|
|
1303
|
+
}, [specification]);
|
|
1304
|
+
const { selectedChoice, choices, setSelectedChoice } = useChoices(schema);
|
|
1305
|
+
const formFieldRows = visibleChildren(selectedChoice.type);
|
|
1306
|
+
const onSchemaChange = (choice) => {
|
|
1307
|
+
onChangeValues({});
|
|
1308
|
+
setSelectedChoice(choice);
|
|
1309
|
+
};
|
|
1290
1310
|
return (React.createElement(Panel, { defaultIsOpen: true },
|
|
1291
|
-
React.createElement(Panel.Titlebar,
|
|
1292
|
-
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" },
|
|
1293
|
-
|
|
1311
|
+
React.createElement(Panel.Titlebar, { rightComponent: React.createElement(OneOfMenu, { choices: choices, choice: selectedChoice, onChange: onSchemaChange }) }, "Body"),
|
|
1312
|
+
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, formFieldRows
|
|
1313
|
+
.filter(isRegularNode)
|
|
1314
|
+
.map(toParameterSpec)
|
|
1315
|
+
.map(parameter => {
|
|
1316
|
+
var _a, _b;
|
|
1294
1317
|
const supportsFileUpload = parameterSupportsFileUpload(parameter);
|
|
1295
|
-
const value = values[parameter.name];
|
|
1318
|
+
const value = values[(_a = parameter.name) !== null && _a !== void 0 ? _a : ''];
|
|
1296
1319
|
if (supportsFileUpload) {
|
|
1297
1320
|
return (React.createElement(FileUploadParameterEditor, { key: parameter.name, parameter: parameter, value: value instanceof File ? value : undefined, onChange: newValue => newValue
|
|
1298
1321
|
? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
|
|
1299
1322
|
: onChangeValues(omit(values, parameter.name)) }));
|
|
1300
1323
|
}
|
|
1301
|
-
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (
|
|
1324
|
+
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: value => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_b = isAllowedEmptyValues[parameter.name]) !== null && _b !== void 0 ? _b : false }));
|
|
1302
1325
|
}))));
|
|
1303
|
-
};
|
|
1326
|
+
};
|
|
1327
|
+
function OneOfMenu({ choices: subSchemas, choice, onChange }) {
|
|
1328
|
+
var _a;
|
|
1329
|
+
const onSubSchemaSelect = React.useCallback(onChange, [onChange]);
|
|
1330
|
+
const menuItems = React.useMemo(() => subSchemas.map(subSchema => {
|
|
1331
|
+
const label = subSchema.title;
|
|
1332
|
+
return {
|
|
1333
|
+
id: `request-subschema-${label}`,
|
|
1334
|
+
title: label,
|
|
1335
|
+
onPress: () => onSubSchemaSelect(subSchema),
|
|
1336
|
+
};
|
|
1337
|
+
}), [subSchemas, onSubSchemaSelect]);
|
|
1338
|
+
if (!subSchemas || subSchemas.length < 2) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
const title = (_a = choice === null || choice === void 0 ? void 0 : choice.title) !== null && _a !== void 0 ? _a : 'Variants';
|
|
1342
|
+
return (React.createElement(Menu, { "aria-label": title, items: menuItems, renderTrigger: ({ isOpen }) => (React.createElement(Button, { appearance: "minimal", size: "sm", iconRight: ['fas', 'sort'], active: isOpen, "data-testid": "oneof-menu" }, title)) }));
|
|
1343
|
+
}
|
|
1304
1344
|
|
|
1305
1345
|
const fileToBase64 = (file) => new Promise((resolve, reject) => {
|
|
1306
1346
|
const reader = new FileReader();
|
|
@@ -2662,11 +2702,9 @@ function MethodPath({ method, path }) {
|
|
|
2662
2702
|
function MethodPathInner({ method, path, chosenServerUrl }) {
|
|
2663
2703
|
const isDark = useThemeIsDark();
|
|
2664
2704
|
const fullUrl = `${chosenServerUrl}${path}`;
|
|
2665
|
-
const { leading, trailing } = useChosenServerUrl(chosenServerUrl);
|
|
2666
2705
|
const pathElem = (React.createElement(Flex, { overflowX: "hidden", fontSize: "lg", userSelect: "all" },
|
|
2667
2706
|
React.createElement(Box, { dir: "rtl", color: "muted", textOverflow: "truncate", overflowX: "hidden" },
|
|
2668
|
-
|
|
2669
|
-
trailing !== null && (React.createElement(Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, trailing))),
|
|
2707
|
+
React.createElement(Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, chosenServerUrl)),
|
|
2670
2708
|
React.createElement(Box, { fontWeight: "semibold", flex: 1 }, path)));
|
|
2671
2709
|
return (React.createElement(HStack, { spacing: 3, pl: 2.5, pr: 4, py: 2, bg: "canvas-50", rounded: "lg", fontFamily: "mono", display: "inline-flex", maxW: "full", title: fullUrl },
|
|
2672
2710
|
React.createElement(Box, { py: 1, px: 2.5, rounded: "lg", bg: !isDark ? HttpMethodColors[method] : 'canvas-100', color: !isDark ? 'on-primary' : 'body', fontSize: "lg", fontWeight: "semibold", textTransform: "uppercase" }, method),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoplight/elements-core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.14.0",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"web-components.min.js",
|
|
@@ -28,17 +28,18 @@
|
|
|
28
28
|
"@stoplight/json": "^3.18.1",
|
|
29
29
|
"@stoplight/json-schema-ref-parser": "^9.0.5",
|
|
30
30
|
"@stoplight/json-schema-sampler": "0.2.3",
|
|
31
|
-
"@stoplight/json-schema-
|
|
31
|
+
"@stoplight/json-schema-tree": "^2.2.5",
|
|
32
|
+
"@stoplight/json-schema-viewer": "^4.13.0",
|
|
32
33
|
"@stoplight/markdown-viewer": "^5.6.0",
|
|
33
|
-
"@stoplight/mosaic": "^1.44.
|
|
34
|
-
"@stoplight/mosaic-code-editor": "^1.44.
|
|
35
|
-
"@stoplight/mosaic-code-viewer": "^1.44.
|
|
34
|
+
"@stoplight/mosaic": "^1.44.4",
|
|
35
|
+
"@stoplight/mosaic-code-editor": "^1.44.4",
|
|
36
|
+
"@stoplight/mosaic-code-viewer": "^1.44.4",
|
|
36
37
|
"@stoplight/path": "^1.3.2",
|
|
37
38
|
"@stoplight/react-error-boundary": "^2.0.0",
|
|
38
39
|
"@stoplight/types": "^14.0.0",
|
|
39
40
|
"@stoplight/yaml": "^4.2.3",
|
|
40
41
|
"classnames": "^2.2.6",
|
|
41
|
-
"httpsnippet-lite": "^3.0.
|
|
42
|
+
"httpsnippet-lite": "^3.0.5",
|
|
42
43
|
"jotai": "1.3.9",
|
|
43
44
|
"json-schema": "^0.4.0",
|
|
44
45
|
"lodash": "^4.17.19",
|