@stoplight/elements-core 7.7.21 → 7.8.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/components/Docs/HttpService/ServerInfo.d.ts +4 -0
- package/index.esm.js +117 -37
- package/index.js +120 -37
- package/index.mjs +117 -37
- package/package.json +1 -1
- package/utils/http-spec/IServer.d.ts +1 -1
package/index.esm.js
CHANGED
|
@@ -16,6 +16,7 @@ export { DefaultSMDComponents } from '@stoplight/markdown-viewer';
|
|
|
16
16
|
import cn from 'classnames';
|
|
17
17
|
import { atomWithStorage, useAtomValue } from 'jotai/utils';
|
|
18
18
|
import { atom, useAtom, Provider } from 'jotai';
|
|
19
|
+
import isEmpty from 'lodash/isEmpty.js';
|
|
19
20
|
import URI from 'urijs';
|
|
20
21
|
import { CodeViewer } from '@stoplight/mosaic-code-viewer';
|
|
21
22
|
import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
|
|
@@ -41,6 +42,8 @@ import entries from 'lodash/entries.js';
|
|
|
41
42
|
import keys from 'lodash/keys.js';
|
|
42
43
|
import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
43
44
|
import sortBy from 'lodash/sortBy.js';
|
|
45
|
+
import isNil from 'lodash/isNil.js';
|
|
46
|
+
import omitBy from 'lodash/omitBy.js';
|
|
44
47
|
import { HashLink } from 'react-router-hash-link';
|
|
45
48
|
import { QueryClient, useQueryClient, QueryClientProvider } from 'react-query';
|
|
46
49
|
import $RefParser from '@stoplight/json-schema-ref-parser';
|
|
@@ -486,15 +489,20 @@ function useChosenServerUrl(chosenServerUrl) {
|
|
|
486
489
|
const chosenServerAtom = atom(undefined);
|
|
487
490
|
|
|
488
491
|
function isValidServer(server) {
|
|
489
|
-
return server.url !== null
|
|
492
|
+
return server.url !== null;
|
|
490
493
|
}
|
|
491
|
-
const getServersToDisplay = (originalServers, mockUrl) => {
|
|
492
|
-
const servers = originalServers
|
|
493
|
-
.map((server, i) => {
|
|
494
|
+
const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
|
|
495
|
+
const servers = originalServers.map((server, i) => {
|
|
494
496
|
const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
497
|
+
let url = server.url;
|
|
498
|
+
if (inlineDefaults) {
|
|
499
|
+
url = getServerUrlWithDefaultValues(server);
|
|
500
|
+
}
|
|
501
|
+
else if (isEmpty(server.variables)) {
|
|
502
|
+
url = resolveUrl(server.url);
|
|
503
|
+
}
|
|
504
|
+
return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
|
|
505
|
+
});
|
|
498
506
|
if (mockUrl) {
|
|
499
507
|
servers.push({
|
|
500
508
|
id: 'mock',
|
|
@@ -502,27 +510,36 @@ const getServersToDisplay = (originalServers, mockUrl) => {
|
|
|
502
510
|
url: mockUrl,
|
|
503
511
|
});
|
|
504
512
|
}
|
|
505
|
-
return servers;
|
|
513
|
+
return servers.filter(isValidServer);
|
|
506
514
|
};
|
|
507
|
-
|
|
508
|
-
var _a;
|
|
509
|
-
let urlString = server.url;
|
|
510
|
-
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
511
|
-
variables.forEach(([variableName, variableInfo]) => {
|
|
512
|
-
urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
|
|
513
|
-
});
|
|
515
|
+
function resolveUrl(urlString) {
|
|
514
516
|
let url;
|
|
515
517
|
try {
|
|
516
518
|
url = URI(urlString);
|
|
517
519
|
}
|
|
518
|
-
catch (
|
|
520
|
+
catch (_a) {
|
|
519
521
|
return null;
|
|
520
522
|
}
|
|
523
|
+
let stringifiedUrl;
|
|
521
524
|
if (url.is('relative') && typeof window !== 'undefined') {
|
|
522
|
-
|
|
525
|
+
stringifiedUrl = url.absoluteTo(window.location.origin).toString();
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
stringifiedUrl = url.toString();
|
|
523
529
|
}
|
|
524
|
-
|
|
525
|
-
|
|
530
|
+
if (isProperUrl(stringifiedUrl)) {
|
|
531
|
+
return stringifiedUrl.endsWith('/') ? stringifiedUrl.slice(0, -1) : stringifiedUrl;
|
|
532
|
+
}
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
const getServerUrlWithDefaultValues = (server) => {
|
|
536
|
+
var _a;
|
|
537
|
+
let urlString = server.url;
|
|
538
|
+
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
539
|
+
variables.forEach(([variableName, variableInfo]) => {
|
|
540
|
+
urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
|
|
541
|
+
});
|
|
542
|
+
return resolveUrl(urlString);
|
|
526
543
|
};
|
|
527
544
|
|
|
528
545
|
const persistAtom = (key, atomInstance) => {
|
|
@@ -1924,8 +1941,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1924
1941
|
const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
|
|
1925
1942
|
const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
|
|
1926
1943
|
const servers = React.useMemo(() => {
|
|
1927
|
-
|
|
1928
|
-
return toDisplay;
|
|
1944
|
+
return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
|
|
1929
1945
|
}, [httpOperation.servers, mockUrl]);
|
|
1930
1946
|
const firstServer = servers[0] || null;
|
|
1931
1947
|
const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
|
|
@@ -2538,7 +2554,8 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2538
2554
|
const mocking = React.useContext(MockingContext);
|
|
2539
2555
|
const showMocking = !mocking.hideMocking && mockUrl && isProperUrl(mockUrl);
|
|
2540
2556
|
const $mockUrl = showMocking ? mockUrl || mocking.mockUrl : undefined;
|
|
2541
|
-
const serversToDisplay = getServersToDisplay(servers, $mockUrl);
|
|
2557
|
+
const serversToDisplay = React.useMemo(() => getServersToDisplay(servers, $mockUrl, false), [servers, $mockUrl]);
|
|
2558
|
+
const firstServerVariableIndex = React.useMemo(() => serversToDisplay.findIndex(server => !isEmpty(server.variables)), [serversToDisplay]);
|
|
2542
2559
|
if (!showMocking && serversToDisplay.length === 0) {
|
|
2543
2560
|
return null;
|
|
2544
2561
|
}
|
|
@@ -2546,25 +2563,88 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2546
2563
|
React.createElement(Panel, { rounded: true, isCollapsible: false, className: "BaseURLContent", w: "full" },
|
|
2547
2564
|
React.createElement(Panel.Titlebar, { whitespace: "nowrap" }, "API Base URL"),
|
|
2548
2565
|
React.createElement(Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
|
|
2549
|
-
React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, {
|
|
2566
|
+
React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, { defaultIsOpen: index === firstServerVariableIndex, hasAnyServerVariables: firstServerVariableIndex !== -1, key: server.id })))))))));
|
|
2550
2567
|
};
|
|
2551
|
-
const ServerUrl = ({ id, description, url }) => {
|
|
2568
|
+
const ServerUrl = ({ id, description, url, variables, hasAnyServerVariables, defaultIsOpen, }) => {
|
|
2552
2569
|
const { nodeHasChanged } = useOptionsCtx();
|
|
2553
2570
|
const { onCopy, hasCopied } = useClipboard(url);
|
|
2571
|
+
const urlFragments = useSplitUrl(url);
|
|
2554
2572
|
const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id });
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
}
|
|
2573
|
+
const variablesSchema = useVariablesJSONSchema(variables);
|
|
2574
|
+
const titlePaddingLeft = hasAnyServerVariables && !variablesSchema ? 4 : 0;
|
|
2575
|
+
const handleCopyClick = React.useCallback(e => {
|
|
2576
|
+
e.stopPropagation();
|
|
2577
|
+
onCopy();
|
|
2578
|
+
}, [onCopy]);
|
|
2579
|
+
return (React.createElement(Panel, { isCollapsible: !!variablesSchema, defaultIsOpen: defaultIsOpen, w: "full" },
|
|
2580
|
+
React.createElement(Panel.Titlebar, { whitespace: "nowrap" },
|
|
2581
|
+
React.createElement(Text, { pl: titlePaddingLeft, pr: 2, fontWeight: "bold" },
|
|
2582
|
+
description,
|
|
2583
|
+
":"),
|
|
2584
|
+
React.createElement(Tooltip, { placement: "right", renderTrigger: () => (React.createElement(Text, { "aria-label": description }, urlFragments.map(({ kind, value }, i) => (React.createElement(Text, { key: i, fontWeight: kind === 'variable' ? 'semibold' : 'normal' }, value))))) },
|
|
2585
|
+
!hasCopied && (React.createElement(Box, { p: 1, onClick: handleCopyClick, cursor: "pointer" },
|
|
2586
|
+
"Copy Server URL ",
|
|
2587
|
+
React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'copy'] }))),
|
|
2588
|
+
hasCopied && (React.createElement(Box, { p: 1 },
|
|
2589
|
+
"Copied Server URL ",
|
|
2590
|
+
React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'check'] })))),
|
|
2591
|
+
React.createElement(NodeAnnotation, { change: hasChanged, additionalLeftOffset: 16 })),
|
|
2592
|
+
variablesSchema && (React.createElement(Panel.Content, { w: "full" },
|
|
2593
|
+
React.createElement(Box, { pl: 4 },
|
|
2594
|
+
React.createElement(JsonSchemaViewer, { schema: variablesSchema }))))));
|
|
2595
|
+
};
|
|
2596
|
+
function useVariablesJSONSchema(variables) {
|
|
2597
|
+
return React.useMemo(() => {
|
|
2598
|
+
if (isEmpty(variables))
|
|
2599
|
+
return;
|
|
2600
|
+
const propertiesPairs = Object.entries(variables).map(([name, variable]) => [
|
|
2601
|
+
name,
|
|
2602
|
+
Object.assign({ type: 'string' }, omitBy({
|
|
2603
|
+
description: variable.description,
|
|
2604
|
+
enum: variable.enum,
|
|
2605
|
+
default: variable.default,
|
|
2606
|
+
}, isNil)),
|
|
2607
|
+
]);
|
|
2608
|
+
return {
|
|
2609
|
+
type: 'object',
|
|
2610
|
+
properties: Object.fromEntries(propertiesPairs),
|
|
2611
|
+
};
|
|
2612
|
+
}, [variables]);
|
|
2613
|
+
}
|
|
2614
|
+
function useSplitUrl(url) {
|
|
2615
|
+
return React.useMemo(() => {
|
|
2616
|
+
const curly = /[{}]/g;
|
|
2617
|
+
const fragments = [];
|
|
2618
|
+
let startOffset = 0;
|
|
2619
|
+
let curPos = 0;
|
|
2620
|
+
let match;
|
|
2621
|
+
while ((match = curly.exec(url))) {
|
|
2622
|
+
if (match[0] === '{' || startOffset + 1 === match.index) {
|
|
2623
|
+
startOffset = match.index;
|
|
2624
|
+
continue;
|
|
2625
|
+
}
|
|
2626
|
+
if (startOffset !== curPos) {
|
|
2627
|
+
fragments.push({
|
|
2628
|
+
kind: 'static',
|
|
2629
|
+
value: url.slice(curPos, startOffset),
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
const variable = url.slice(startOffset, match.index + 1);
|
|
2633
|
+
fragments.push({
|
|
2634
|
+
kind: 'variable',
|
|
2635
|
+
value: variable,
|
|
2636
|
+
});
|
|
2637
|
+
curPos = startOffset + variable.length;
|
|
2638
|
+
}
|
|
2639
|
+
if (curPos < url.length) {
|
|
2640
|
+
fragments.push({
|
|
2641
|
+
kind: 'static',
|
|
2642
|
+
value: url.slice(curPos),
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
return fragments;
|
|
2646
|
+
}, [url]);
|
|
2647
|
+
}
|
|
2568
2648
|
|
|
2569
2649
|
const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {}, layoutOptions, exportProps }) => {
|
|
2570
2650
|
var _a, _b, _c, _d;
|
package/index.js
CHANGED
|
@@ -18,6 +18,7 @@ var markdownViewer = require('@stoplight/markdown-viewer');
|
|
|
18
18
|
var cn = require('classnames');
|
|
19
19
|
var utils = require('jotai/utils');
|
|
20
20
|
var jotai = require('jotai');
|
|
21
|
+
var isEmpty = require('lodash/isEmpty.js');
|
|
21
22
|
var URI = require('urijs');
|
|
22
23
|
var mosaicCodeViewer = require('@stoplight/mosaic-code-viewer');
|
|
23
24
|
var httpsnippetLite = require('httpsnippet-lite');
|
|
@@ -43,6 +44,8 @@ var entries = require('lodash/entries.js');
|
|
|
43
44
|
var keys = require('lodash/keys.js');
|
|
44
45
|
var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
|
|
45
46
|
var sortBy = require('lodash/sortBy.js');
|
|
47
|
+
var isNil = require('lodash/isNil.js');
|
|
48
|
+
var omitBy = require('lodash/omitBy.js');
|
|
46
49
|
var reactRouterHashLink = require('react-router-hash-link');
|
|
47
50
|
var reactQuery = require('react-query');
|
|
48
51
|
var $RefParser = require('@stoplight/json-schema-ref-parser');
|
|
@@ -76,6 +79,7 @@ var isArray__default = /*#__PURE__*/_interopDefaultLegacy(isArray);
|
|
|
76
79
|
var isPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(isPlainObject);
|
|
77
80
|
var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
|
|
78
81
|
var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
|
|
82
|
+
var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
|
|
79
83
|
var URI__default = /*#__PURE__*/_interopDefaultLegacy(URI);
|
|
80
84
|
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
81
85
|
var capitalize__default = /*#__PURE__*/_interopDefaultLegacy(capitalize);
|
|
@@ -96,6 +100,8 @@ var formatXml__default = /*#__PURE__*/_interopDefaultLegacy(formatXml);
|
|
|
96
100
|
var entries__default = /*#__PURE__*/_interopDefaultLegacy(entries);
|
|
97
101
|
var keys__default = /*#__PURE__*/_interopDefaultLegacy(keys);
|
|
98
102
|
var sortBy__default = /*#__PURE__*/_interopDefaultLegacy(sortBy);
|
|
103
|
+
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
104
|
+
var omitBy__default = /*#__PURE__*/_interopDefaultLegacy(omitBy);
|
|
99
105
|
var $RefParser__default = /*#__PURE__*/_interopDefaultLegacy($RefParser);
|
|
100
106
|
var PropTypes__namespace = /*#__PURE__*/_interopNamespace(PropTypes);
|
|
101
107
|
var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
|
|
@@ -539,15 +545,20 @@ function useChosenServerUrl(chosenServerUrl) {
|
|
|
539
545
|
const chosenServerAtom = jotai.atom(undefined);
|
|
540
546
|
|
|
541
547
|
function isValidServer(server) {
|
|
542
|
-
return server.url !== null
|
|
548
|
+
return server.url !== null;
|
|
543
549
|
}
|
|
544
|
-
const getServersToDisplay = (originalServers, mockUrl) => {
|
|
545
|
-
const servers = originalServers
|
|
546
|
-
.map((server, i) => {
|
|
550
|
+
const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
|
|
551
|
+
const servers = originalServers.map((server, i) => {
|
|
547
552
|
const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
553
|
+
let url = server.url;
|
|
554
|
+
if (inlineDefaults) {
|
|
555
|
+
url = getServerUrlWithDefaultValues(server);
|
|
556
|
+
}
|
|
557
|
+
else if (isEmpty__default["default"](server.variables)) {
|
|
558
|
+
url = resolveUrl(server.url);
|
|
559
|
+
}
|
|
560
|
+
return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
|
|
561
|
+
});
|
|
551
562
|
if (mockUrl) {
|
|
552
563
|
servers.push({
|
|
553
564
|
id: 'mock',
|
|
@@ -555,27 +566,36 @@ const getServersToDisplay = (originalServers, mockUrl) => {
|
|
|
555
566
|
url: mockUrl,
|
|
556
567
|
});
|
|
557
568
|
}
|
|
558
|
-
return servers;
|
|
569
|
+
return servers.filter(isValidServer);
|
|
559
570
|
};
|
|
560
|
-
|
|
561
|
-
var _a;
|
|
562
|
-
let urlString = server.url;
|
|
563
|
-
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
564
|
-
variables.forEach(([variableName, variableInfo]) => {
|
|
565
|
-
urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
|
|
566
|
-
});
|
|
571
|
+
function resolveUrl(urlString) {
|
|
567
572
|
let url;
|
|
568
573
|
try {
|
|
569
574
|
url = URI__default["default"](urlString);
|
|
570
575
|
}
|
|
571
|
-
catch (
|
|
576
|
+
catch (_a) {
|
|
572
577
|
return null;
|
|
573
578
|
}
|
|
579
|
+
let stringifiedUrl;
|
|
574
580
|
if (url.is('relative') && typeof window !== 'undefined') {
|
|
575
|
-
|
|
581
|
+
stringifiedUrl = url.absoluteTo(window.location.origin).toString();
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
stringifiedUrl = url.toString();
|
|
576
585
|
}
|
|
577
|
-
|
|
578
|
-
|
|
586
|
+
if (isProperUrl(stringifiedUrl)) {
|
|
587
|
+
return stringifiedUrl.endsWith('/') ? stringifiedUrl.slice(0, -1) : stringifiedUrl;
|
|
588
|
+
}
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
const getServerUrlWithDefaultValues = (server) => {
|
|
592
|
+
var _a;
|
|
593
|
+
let urlString = server.url;
|
|
594
|
+
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
595
|
+
variables.forEach(([variableName, variableInfo]) => {
|
|
596
|
+
urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
|
|
597
|
+
});
|
|
598
|
+
return resolveUrl(urlString);
|
|
579
599
|
};
|
|
580
600
|
|
|
581
601
|
const persistAtom = (key, atomInstance) => {
|
|
@@ -1977,8 +1997,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1977
1997
|
const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
|
|
1978
1998
|
const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
|
|
1979
1999
|
const servers = React__namespace.useMemo(() => {
|
|
1980
|
-
|
|
1981
|
-
return toDisplay;
|
|
2000
|
+
return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
|
|
1982
2001
|
}, [httpOperation.servers, mockUrl]);
|
|
1983
2002
|
const firstServer = servers[0] || null;
|
|
1984
2003
|
const [chosenServer, setChosenServer] = jotai.useAtom(chosenServerAtom);
|
|
@@ -2591,7 +2610,8 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2591
2610
|
const mocking = React__namespace.useContext(MockingContext);
|
|
2592
2611
|
const showMocking = !mocking.hideMocking && mockUrl && isProperUrl(mockUrl);
|
|
2593
2612
|
const $mockUrl = showMocking ? mockUrl || mocking.mockUrl : undefined;
|
|
2594
|
-
const serversToDisplay = getServersToDisplay(servers, $mockUrl);
|
|
2613
|
+
const serversToDisplay = React__namespace.useMemo(() => getServersToDisplay(servers, $mockUrl, false), [servers, $mockUrl]);
|
|
2614
|
+
const firstServerVariableIndex = React__namespace.useMemo(() => serversToDisplay.findIndex(server => !isEmpty__default["default"](server.variables)), [serversToDisplay]);
|
|
2595
2615
|
if (!showMocking && serversToDisplay.length === 0) {
|
|
2596
2616
|
return null;
|
|
2597
2617
|
}
|
|
@@ -2599,25 +2619,88 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2599
2619
|
React__namespace.createElement(mosaic.Panel, { rounded: true, isCollapsible: false, className: "BaseURLContent", w: "full" },
|
|
2600
2620
|
React__namespace.createElement(mosaic.Panel.Titlebar, { whitespace: "nowrap" }, "API Base URL"),
|
|
2601
2621
|
React__namespace.createElement(mosaic.Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
|
|
2602
|
-
React__namespace.createElement(mosaic.VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React__namespace.createElement(ServerUrl, Object.assign({}, server, {
|
|
2622
|
+
React__namespace.createElement(mosaic.VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React__namespace.createElement(ServerUrl, Object.assign({}, server, { defaultIsOpen: index === firstServerVariableIndex, hasAnyServerVariables: firstServerVariableIndex !== -1, key: server.id })))))))));
|
|
2603
2623
|
};
|
|
2604
|
-
const ServerUrl = ({ id, description, url }) => {
|
|
2624
|
+
const ServerUrl = ({ id, description, url, variables, hasAnyServerVariables, defaultIsOpen, }) => {
|
|
2605
2625
|
const { nodeHasChanged } = useOptionsCtx();
|
|
2606
2626
|
const { onCopy, hasCopied } = mosaic.useClipboard(url);
|
|
2627
|
+
const urlFragments = useSplitUrl(url);
|
|
2607
2628
|
const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id });
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
}
|
|
2629
|
+
const variablesSchema = useVariablesJSONSchema(variables);
|
|
2630
|
+
const titlePaddingLeft = hasAnyServerVariables && !variablesSchema ? 4 : 0;
|
|
2631
|
+
const handleCopyClick = React__namespace.useCallback(e => {
|
|
2632
|
+
e.stopPropagation();
|
|
2633
|
+
onCopy();
|
|
2634
|
+
}, [onCopy]);
|
|
2635
|
+
return (React__namespace.createElement(mosaic.Panel, { isCollapsible: !!variablesSchema, defaultIsOpen: defaultIsOpen, w: "full" },
|
|
2636
|
+
React__namespace.createElement(mosaic.Panel.Titlebar, { whitespace: "nowrap" },
|
|
2637
|
+
React__namespace.createElement(mosaic.Text, { pl: titlePaddingLeft, pr: 2, fontWeight: "bold" },
|
|
2638
|
+
description,
|
|
2639
|
+
":"),
|
|
2640
|
+
React__namespace.createElement(mosaic.Tooltip, { placement: "right", renderTrigger: () => (React__namespace.createElement(mosaic.Text, { "aria-label": description }, urlFragments.map(({ kind, value }, i) => (React__namespace.createElement(mosaic.Text, { key: i, fontWeight: kind === 'variable' ? 'semibold' : 'normal' }, value))))) },
|
|
2641
|
+
!hasCopied && (React__namespace.createElement(mosaic.Box, { p: 1, onClick: handleCopyClick, cursor: "pointer" },
|
|
2642
|
+
"Copy Server URL ",
|
|
2643
|
+
React__namespace.createElement(mosaic.Icon, { className: "sl-ml-1", icon: ['fas', 'copy'] }))),
|
|
2644
|
+
hasCopied && (React__namespace.createElement(mosaic.Box, { p: 1 },
|
|
2645
|
+
"Copied Server URL ",
|
|
2646
|
+
React__namespace.createElement(mosaic.Icon, { className: "sl-ml-1", icon: ['fas', 'check'] })))),
|
|
2647
|
+
React__namespace.createElement(mosaic.NodeAnnotation, { change: hasChanged, additionalLeftOffset: 16 })),
|
|
2648
|
+
variablesSchema && (React__namespace.createElement(mosaic.Panel.Content, { w: "full" },
|
|
2649
|
+
React__namespace.createElement(mosaic.Box, { pl: 4 },
|
|
2650
|
+
React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { schema: variablesSchema }))))));
|
|
2651
|
+
};
|
|
2652
|
+
function useVariablesJSONSchema(variables) {
|
|
2653
|
+
return React__namespace.useMemo(() => {
|
|
2654
|
+
if (isEmpty__default["default"](variables))
|
|
2655
|
+
return;
|
|
2656
|
+
const propertiesPairs = Object.entries(variables).map(([name, variable]) => [
|
|
2657
|
+
name,
|
|
2658
|
+
Object.assign({ type: 'string' }, omitBy__default["default"]({
|
|
2659
|
+
description: variable.description,
|
|
2660
|
+
enum: variable.enum,
|
|
2661
|
+
default: variable.default,
|
|
2662
|
+
}, isNil__default["default"])),
|
|
2663
|
+
]);
|
|
2664
|
+
return {
|
|
2665
|
+
type: 'object',
|
|
2666
|
+
properties: Object.fromEntries(propertiesPairs),
|
|
2667
|
+
};
|
|
2668
|
+
}, [variables]);
|
|
2669
|
+
}
|
|
2670
|
+
function useSplitUrl(url) {
|
|
2671
|
+
return React__namespace.useMemo(() => {
|
|
2672
|
+
const curly = /[{}]/g;
|
|
2673
|
+
const fragments = [];
|
|
2674
|
+
let startOffset = 0;
|
|
2675
|
+
let curPos = 0;
|
|
2676
|
+
let match;
|
|
2677
|
+
while ((match = curly.exec(url))) {
|
|
2678
|
+
if (match[0] === '{' || startOffset + 1 === match.index) {
|
|
2679
|
+
startOffset = match.index;
|
|
2680
|
+
continue;
|
|
2681
|
+
}
|
|
2682
|
+
if (startOffset !== curPos) {
|
|
2683
|
+
fragments.push({
|
|
2684
|
+
kind: 'static',
|
|
2685
|
+
value: url.slice(curPos, startOffset),
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
const variable = url.slice(startOffset, match.index + 1);
|
|
2689
|
+
fragments.push({
|
|
2690
|
+
kind: 'variable',
|
|
2691
|
+
value: variable,
|
|
2692
|
+
});
|
|
2693
|
+
curPos = startOffset + variable.length;
|
|
2694
|
+
}
|
|
2695
|
+
if (curPos < url.length) {
|
|
2696
|
+
fragments.push({
|
|
2697
|
+
kind: 'static',
|
|
2698
|
+
value: url.slice(curPos),
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
return fragments;
|
|
2702
|
+
}, [url]);
|
|
2703
|
+
}
|
|
2621
2704
|
|
|
2622
2705
|
const HttpServiceComponent = React__namespace.memo(({ data: unresolvedData, location = {}, layoutOptions, exportProps }) => {
|
|
2623
2706
|
var _a, _b, _c, _d;
|
package/index.mjs
CHANGED
|
@@ -16,6 +16,7 @@ export { DefaultSMDComponents } from '@stoplight/markdown-viewer';
|
|
|
16
16
|
import cn from 'classnames';
|
|
17
17
|
import { atomWithStorage, useAtomValue } from 'jotai/utils';
|
|
18
18
|
import { atom, useAtom, Provider } from 'jotai';
|
|
19
|
+
import isEmpty from 'lodash/isEmpty.js';
|
|
19
20
|
import URI from 'urijs';
|
|
20
21
|
import { CodeViewer } from '@stoplight/mosaic-code-viewer';
|
|
21
22
|
import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
|
|
@@ -41,6 +42,8 @@ import entries from 'lodash/entries.js';
|
|
|
41
42
|
import keys from 'lodash/keys.js';
|
|
42
43
|
import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
|
|
43
44
|
import sortBy from 'lodash/sortBy.js';
|
|
45
|
+
import isNil from 'lodash/isNil.js';
|
|
46
|
+
import omitBy from 'lodash/omitBy.js';
|
|
44
47
|
import { HashLink } from 'react-router-hash-link';
|
|
45
48
|
import { QueryClient, useQueryClient, QueryClientProvider } from 'react-query';
|
|
46
49
|
import $RefParser from '@stoplight/json-schema-ref-parser';
|
|
@@ -486,15 +489,20 @@ function useChosenServerUrl(chosenServerUrl) {
|
|
|
486
489
|
const chosenServerAtom = atom(undefined);
|
|
487
490
|
|
|
488
491
|
function isValidServer(server) {
|
|
489
|
-
return server.url !== null
|
|
492
|
+
return server.url !== null;
|
|
490
493
|
}
|
|
491
|
-
const getServersToDisplay = (originalServers, mockUrl) => {
|
|
492
|
-
const servers = originalServers
|
|
493
|
-
.map((server, i) => {
|
|
494
|
+
const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
|
|
495
|
+
const servers = originalServers.map((server, i) => {
|
|
494
496
|
const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
497
|
+
let url = server.url;
|
|
498
|
+
if (inlineDefaults) {
|
|
499
|
+
url = getServerUrlWithDefaultValues(server);
|
|
500
|
+
}
|
|
501
|
+
else if (isEmpty(server.variables)) {
|
|
502
|
+
url = resolveUrl(server.url);
|
|
503
|
+
}
|
|
504
|
+
return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
|
|
505
|
+
});
|
|
498
506
|
if (mockUrl) {
|
|
499
507
|
servers.push({
|
|
500
508
|
id: 'mock',
|
|
@@ -502,27 +510,36 @@ const getServersToDisplay = (originalServers, mockUrl) => {
|
|
|
502
510
|
url: mockUrl,
|
|
503
511
|
});
|
|
504
512
|
}
|
|
505
|
-
return servers;
|
|
513
|
+
return servers.filter(isValidServer);
|
|
506
514
|
};
|
|
507
|
-
|
|
508
|
-
var _a;
|
|
509
|
-
let urlString = server.url;
|
|
510
|
-
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
511
|
-
variables.forEach(([variableName, variableInfo]) => {
|
|
512
|
-
urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
|
|
513
|
-
});
|
|
515
|
+
function resolveUrl(urlString) {
|
|
514
516
|
let url;
|
|
515
517
|
try {
|
|
516
518
|
url = URI(urlString);
|
|
517
519
|
}
|
|
518
|
-
catch (
|
|
520
|
+
catch (_a) {
|
|
519
521
|
return null;
|
|
520
522
|
}
|
|
523
|
+
let stringifiedUrl;
|
|
521
524
|
if (url.is('relative') && typeof window !== 'undefined') {
|
|
522
|
-
|
|
525
|
+
stringifiedUrl = url.absoluteTo(window.location.origin).toString();
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
stringifiedUrl = url.toString();
|
|
523
529
|
}
|
|
524
|
-
|
|
525
|
-
|
|
530
|
+
if (isProperUrl(stringifiedUrl)) {
|
|
531
|
+
return stringifiedUrl.endsWith('/') ? stringifiedUrl.slice(0, -1) : stringifiedUrl;
|
|
532
|
+
}
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
const getServerUrlWithDefaultValues = (server) => {
|
|
536
|
+
var _a;
|
|
537
|
+
let urlString = server.url;
|
|
538
|
+
const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
|
|
539
|
+
variables.forEach(([variableName, variableInfo]) => {
|
|
540
|
+
urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
|
|
541
|
+
});
|
|
542
|
+
return resolveUrl(urlString);
|
|
526
543
|
};
|
|
527
544
|
|
|
528
545
|
const persistAtom = (key, atomInstance) => {
|
|
@@ -1924,8 +1941,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1924
1941
|
const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
|
|
1925
1942
|
const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
|
|
1926
1943
|
const servers = React.useMemo(() => {
|
|
1927
|
-
|
|
1928
|
-
return toDisplay;
|
|
1944
|
+
return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
|
|
1929
1945
|
}, [httpOperation.servers, mockUrl]);
|
|
1930
1946
|
const firstServer = servers[0] || null;
|
|
1931
1947
|
const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
|
|
@@ -2538,7 +2554,8 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2538
2554
|
const mocking = React.useContext(MockingContext);
|
|
2539
2555
|
const showMocking = !mocking.hideMocking && mockUrl && isProperUrl(mockUrl);
|
|
2540
2556
|
const $mockUrl = showMocking ? mockUrl || mocking.mockUrl : undefined;
|
|
2541
|
-
const serversToDisplay = getServersToDisplay(servers, $mockUrl);
|
|
2557
|
+
const serversToDisplay = React.useMemo(() => getServersToDisplay(servers, $mockUrl, false), [servers, $mockUrl]);
|
|
2558
|
+
const firstServerVariableIndex = React.useMemo(() => serversToDisplay.findIndex(server => !isEmpty(server.variables)), [serversToDisplay]);
|
|
2542
2559
|
if (!showMocking && serversToDisplay.length === 0) {
|
|
2543
2560
|
return null;
|
|
2544
2561
|
}
|
|
@@ -2546,25 +2563,88 @@ const ServerInfo = ({ servers, mockUrl }) => {
|
|
|
2546
2563
|
React.createElement(Panel, { rounded: true, isCollapsible: false, className: "BaseURLContent", w: "full" },
|
|
2547
2564
|
React.createElement(Panel.Titlebar, { whitespace: "nowrap" }, "API Base URL"),
|
|
2548
2565
|
React.createElement(Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
|
|
2549
|
-
React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, {
|
|
2566
|
+
React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, { defaultIsOpen: index === firstServerVariableIndex, hasAnyServerVariables: firstServerVariableIndex !== -1, key: server.id })))))))));
|
|
2550
2567
|
};
|
|
2551
|
-
const ServerUrl = ({ id, description, url }) => {
|
|
2568
|
+
const ServerUrl = ({ id, description, url, variables, hasAnyServerVariables, defaultIsOpen, }) => {
|
|
2552
2569
|
const { nodeHasChanged } = useOptionsCtx();
|
|
2553
2570
|
const { onCopy, hasCopied } = useClipboard(url);
|
|
2571
|
+
const urlFragments = useSplitUrl(url);
|
|
2554
2572
|
const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id });
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
}
|
|
2573
|
+
const variablesSchema = useVariablesJSONSchema(variables);
|
|
2574
|
+
const titlePaddingLeft = hasAnyServerVariables && !variablesSchema ? 4 : 0;
|
|
2575
|
+
const handleCopyClick = React.useCallback(e => {
|
|
2576
|
+
e.stopPropagation();
|
|
2577
|
+
onCopy();
|
|
2578
|
+
}, [onCopy]);
|
|
2579
|
+
return (React.createElement(Panel, { isCollapsible: !!variablesSchema, defaultIsOpen: defaultIsOpen, w: "full" },
|
|
2580
|
+
React.createElement(Panel.Titlebar, { whitespace: "nowrap" },
|
|
2581
|
+
React.createElement(Text, { pl: titlePaddingLeft, pr: 2, fontWeight: "bold" },
|
|
2582
|
+
description,
|
|
2583
|
+
":"),
|
|
2584
|
+
React.createElement(Tooltip, { placement: "right", renderTrigger: () => (React.createElement(Text, { "aria-label": description }, urlFragments.map(({ kind, value }, i) => (React.createElement(Text, { key: i, fontWeight: kind === 'variable' ? 'semibold' : 'normal' }, value))))) },
|
|
2585
|
+
!hasCopied && (React.createElement(Box, { p: 1, onClick: handleCopyClick, cursor: "pointer" },
|
|
2586
|
+
"Copy Server URL ",
|
|
2587
|
+
React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'copy'] }))),
|
|
2588
|
+
hasCopied && (React.createElement(Box, { p: 1 },
|
|
2589
|
+
"Copied Server URL ",
|
|
2590
|
+
React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'check'] })))),
|
|
2591
|
+
React.createElement(NodeAnnotation, { change: hasChanged, additionalLeftOffset: 16 })),
|
|
2592
|
+
variablesSchema && (React.createElement(Panel.Content, { w: "full" },
|
|
2593
|
+
React.createElement(Box, { pl: 4 },
|
|
2594
|
+
React.createElement(JsonSchemaViewer, { schema: variablesSchema }))))));
|
|
2595
|
+
};
|
|
2596
|
+
function useVariablesJSONSchema(variables) {
|
|
2597
|
+
return React.useMemo(() => {
|
|
2598
|
+
if (isEmpty(variables))
|
|
2599
|
+
return;
|
|
2600
|
+
const propertiesPairs = Object.entries(variables).map(([name, variable]) => [
|
|
2601
|
+
name,
|
|
2602
|
+
Object.assign({ type: 'string' }, omitBy({
|
|
2603
|
+
description: variable.description,
|
|
2604
|
+
enum: variable.enum,
|
|
2605
|
+
default: variable.default,
|
|
2606
|
+
}, isNil)),
|
|
2607
|
+
]);
|
|
2608
|
+
return {
|
|
2609
|
+
type: 'object',
|
|
2610
|
+
properties: Object.fromEntries(propertiesPairs),
|
|
2611
|
+
};
|
|
2612
|
+
}, [variables]);
|
|
2613
|
+
}
|
|
2614
|
+
function useSplitUrl(url) {
|
|
2615
|
+
return React.useMemo(() => {
|
|
2616
|
+
const curly = /[{}]/g;
|
|
2617
|
+
const fragments = [];
|
|
2618
|
+
let startOffset = 0;
|
|
2619
|
+
let curPos = 0;
|
|
2620
|
+
let match;
|
|
2621
|
+
while ((match = curly.exec(url))) {
|
|
2622
|
+
if (match[0] === '{' || startOffset + 1 === match.index) {
|
|
2623
|
+
startOffset = match.index;
|
|
2624
|
+
continue;
|
|
2625
|
+
}
|
|
2626
|
+
if (startOffset !== curPos) {
|
|
2627
|
+
fragments.push({
|
|
2628
|
+
kind: 'static',
|
|
2629
|
+
value: url.slice(curPos, startOffset),
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
const variable = url.slice(startOffset, match.index + 1);
|
|
2633
|
+
fragments.push({
|
|
2634
|
+
kind: 'variable',
|
|
2635
|
+
value: variable,
|
|
2636
|
+
});
|
|
2637
|
+
curPos = startOffset + variable.length;
|
|
2638
|
+
}
|
|
2639
|
+
if (curPos < url.length) {
|
|
2640
|
+
fragments.push({
|
|
2641
|
+
kind: 'static',
|
|
2642
|
+
value: url.slice(curPos),
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
return fragments;
|
|
2646
|
+
}, [url]);
|
|
2647
|
+
}
|
|
2568
2648
|
|
|
2569
2649
|
const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {}, layoutOptions, exportProps }) => {
|
|
2570
2650
|
var _a, _b, _c, _d;
|
package/package.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { IServer } from '@stoplight/types';
|
|
2
|
-
export declare const getServersToDisplay: (originalServers: IServer[], mockUrl
|
|
2
|
+
export declare const getServersToDisplay: (originalServers: IServer[], mockUrl: string | undefined, inlineDefaults: boolean) => IServer[];
|
|
3
3
|
export declare const getServerUrlWithDefaultValues: (server: IServer) => string | null;
|