@stoplight/elements-core 7.8.0 → 7.9.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.
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ import { ServerVariable } from '../../../utils/http-spec/IServer';
3
+ interface ServerVariablesProps<P extends keyof any = string> {
4
+ variables: readonly ServerVariable[];
5
+ values: Record<P, string>;
6
+ onChangeValue: (variableName: P, newValue: string) => void;
7
+ }
8
+ export declare const ServerVariables: React.FC<ServerVariablesProps>;
9
+ export {};
@@ -0,0 +1,11 @@
1
+ import { SelectProps } from '@stoplight/mosaic';
2
+ import * as React from 'react';
3
+ import { ServerVariable } from '../../../utils/http-spec/IServer';
4
+ interface VariableProps {
5
+ variable: ServerVariable;
6
+ value?: string;
7
+ onChange: SelectProps['onChange'];
8
+ validate?: boolean;
9
+ }
10
+ export declare const VariableEditor: React.FC<VariableProps>;
11
+ export {};
@@ -0,0 +1,4 @@
1
+ export declare const useServerVariables: () => {
2
+ serverVariables: {};
3
+ updateServerVariableValue: (name: string, value: string) => void;
4
+ };
@@ -4,6 +4,7 @@ declare const _default: Meta<TryItProps>;
4
4
  export default _default;
5
5
  export declare const SimpleGET: Story<TryItProps>;
6
6
  export declare const WithParameters: Story<TryItProps>;
7
+ export declare const WithVariables: Story<TryItProps>;
7
8
  export declare const UrlEncoded: Story<TryItProps>;
8
9
  export declare const Multipart: Story<TryItProps>;
9
10
  export declare const RequestBodySchema: Story<TryItProps>;
@@ -3,3 +3,4 @@ import { TryItWithRequestSamplesProps } from './TryItWithRequestSamples';
3
3
  declare const _default: Meta<TryItWithRequestSamplesProps>;
4
4
  export default _default;
5
5
  export declare const WithParameters: Story<TryItWithRequestSamplesProps>;
6
+ export declare const WithVariables: Story<TryItWithRequestSamplesProps>;
@@ -7,6 +7,7 @@ interface BuildRequestInput {
7
7
  httpOperation: IHttpOperation;
8
8
  mediaTypeContent: IMediaTypeContent | undefined;
9
9
  parameterValues: Dictionary<string, string>;
10
+ serverVariableValues: Dictionary<string, string>;
10
11
  bodyInput?: BodyParameterValues | string;
11
12
  mockData?: MockData;
12
13
  auth?: HttpSecuritySchemeWithValues;
@@ -18,7 +19,7 @@ export declare const getQueryParams: ({ httpOperation, parameterValues, }: Pick<
18
19
  name: string;
19
20
  value: string;
20
21
  }[];
21
- export declare function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials, corsProxy, }: BuildRequestInput): Promise<Parameters<typeof fetch>>;
22
- export declare function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }: BuildRequestInput): Promise<HarRequest>;
22
+ export declare function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, serverVariableValues, mockData, auth, chosenServer, credentials, corsProxy, }: BuildRequestInput): Promise<Parameters<typeof fetch>>;
23
+ export declare function buildHarRequest({ httpOperation, bodyInput, parameterValues, serverVariableValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }: BuildRequestInput): Promise<HarRequest>;
23
24
  export declare function getAcceptedMimeTypes(httpOperation: IHttpOperation): string[];
24
25
  export {};
package/index.esm.js CHANGED
@@ -16,7 +16,6 @@ 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';
20
19
  import URI from 'urijs';
21
20
  import { CodeViewer } from '@stoplight/mosaic-code-viewer';
22
21
  import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
@@ -42,6 +41,7 @@ import entries from 'lodash/entries.js';
42
41
  import keys from 'lodash/keys.js';
43
42
  import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
44
43
  import sortBy from 'lodash/sortBy.js';
44
+ import isEmpty from 'lodash/isEmpty.js';
45
45
  import isNil from 'lodash/isNil.js';
46
46
  import omitBy from 'lodash/omitBy.js';
47
47
  import { HashLink } from 'react-router-hash-link';
@@ -496,10 +496,7 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
496
496
  const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
497
497
  let url = server.url;
498
498
  if (inlineDefaults) {
499
- url = getServerUrlWithDefaultValues(server);
500
- }
501
- else if (isEmpty(server.variables)) {
502
- url = resolveUrl(server.url);
499
+ url = getServerUrlWithVariableValues(server, {});
503
500
  }
504
501
  return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
505
502
  });
@@ -512,7 +509,18 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
512
509
  }
513
510
  return servers.filter(isValidServer);
514
511
  };
512
+ const getServerVariables = (server) => {
513
+ var _a;
514
+ return Object.entries((_a = server === null || server === void 0 ? void 0 : server.variables) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => ({
515
+ name: key,
516
+ default: value.default,
517
+ description: value.description,
518
+ enum: value.enum,
519
+ }));
520
+ };
515
521
  function resolveUrl(urlString) {
522
+ if (urlString === null)
523
+ return null;
516
524
  let url;
517
525
  try {
518
526
  url = URI(urlString);
@@ -532,14 +540,15 @@ function resolveUrl(urlString) {
532
540
  }
533
541
  return null;
534
542
  }
535
- const getServerUrlWithDefaultValues = (server) => {
543
+ const getServerUrlWithVariableValues = (server, values) => {
536
544
  var _a;
537
545
  let urlString = server.url;
538
546
  const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
539
547
  variables.forEach(([variableName, variableInfo]) => {
540
- urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
548
+ var _a;
549
+ urlString = urlString.replaceAll(`{${variableName}}`, (_a = values[variableName]) !== null && _a !== void 0 ? _a : variableInfo.default);
541
550
  });
542
- return resolveUrl(urlString);
551
+ return urlString;
543
552
  };
544
553
 
545
554
  const persistAtom = (key, atomInstance) => {
@@ -1418,11 +1427,11 @@ const useTextRequestBodyState = (mediaTypeContent) => {
1418
1427
  };
1419
1428
 
1420
1429
  const nameAndValueObjectToPair = ({ name, value }) => [name, value];
1421
- const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, }) => {
1430
+ const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, serverVariableValues, }) => {
1422
1431
  var _a;
1423
1432
  const server = chosenServer || ((_a = httpOperation.servers) === null || _a === void 0 ? void 0 : _a[0]);
1424
- const chosenServerUrl = server && getServerUrlWithDefaultValues(server);
1425
- const serverUrl = (mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin;
1433
+ const chosenServerUrl = server && getServerUrlWithVariableValues(server, serverVariableValues);
1434
+ const serverUrl = resolveUrl((mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin);
1426
1435
  if (corsProxy && !mockData) {
1427
1436
  return `${corsProxy}${serverUrl}`;
1428
1437
  }
@@ -1499,10 +1508,10 @@ const getQueryParams = ({ httpOperation, parameterValues, }) => {
1499
1508
  return acc;
1500
1509
  }, []);
1501
1510
  };
1502
- function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1511
+ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, serverVariableValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1503
1512
  var _a, _b, _c;
1504
1513
  return __awaiter(this, void 0, void 0, function* () {
1505
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1514
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1506
1515
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1507
1516
  const queryParams = getQueryParams({ httpOperation, parameterValues });
1508
1517
  const rawHeaders = filterOutAuthorizationParams((_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : [], httpOperation.security)
@@ -1575,10 +1584,10 @@ const runAuthRequestEhancements = (auth, queryParams, headers) => {
1575
1584
  }
1576
1585
  return [newQueryParams, newHeaders];
1577
1586
  };
1578
- function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1587
+ function buildHarRequest({ httpOperation, bodyInput, parameterValues, serverVariableValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1579
1588
  var _a, _b, _c, _d;
1580
1589
  return __awaiter(this, void 0, void 0, function* () {
1581
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1590
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1582
1591
  const mimeType = (_a = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _a !== void 0 ? _a : 'application/json';
1583
1592
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1584
1593
  const queryParams = getQueryParams({ httpOperation, parameterValues });
@@ -1900,8 +1909,18 @@ class NetworkError extends Error {
1900
1909
  }
1901
1910
  const isNetworkError = (error) => error instanceof NetworkError;
1902
1911
 
1912
+ const persistedServerVariableValuesAtom = atom({});
1913
+ const useServerVariables = () => {
1914
+ const [serverVariables, setPersistedServerVariableValues] = useAtom(persistedServerVariableValuesAtom);
1915
+ const updateServerVariableValue = (name, value) => {
1916
+ setPersistedServerVariableValues(Object.assign({}, serverVariables, { [name]: value }));
1917
+ };
1918
+ return { serverVariables, updateServerVariableValue };
1919
+ };
1920
+
1903
1921
  const ServersDropdown = ({ servers }) => {
1904
1922
  const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
1923
+ const { serverVariables } = useServerVariables();
1905
1924
  const serverItems = [
1906
1925
  {
1907
1926
  type: 'option_group',
@@ -1915,7 +1934,7 @@ const ServersDropdown = ({ servers }) => {
1915
1934
  ...servers.map((server, i) => ({
1916
1935
  id: server.url,
1917
1936
  title: server.description,
1918
- description: server.url,
1937
+ description: getServerUrlWithVariableValues(server, serverVariables),
1919
1938
  value: server.url,
1920
1939
  })),
1921
1940
  ],
@@ -1925,6 +1944,21 @@ const ServersDropdown = ({ servers }) => {
1925
1944
  };
1926
1945
  ServersDropdown.displayName = 'ServersDropdown';
1927
1946
 
1947
+ const VariableEditor = ({ variable, value, onChange }) => {
1948
+ const inputId = useUniqueId(`id_${variable.name}_`);
1949
+ return (React.createElement(React.Fragment, null,
1950
+ React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
1951
+ React.createElement(Text, { mx: 3 }, ":"),
1952
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
1953
+ React.createElement(Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
1954
+ };
1955
+
1956
+ const ServerVariables = ({ variables, values, onChangeValue }) => {
1957
+ return (React.createElement(Panel, { defaultIsOpen: true },
1958
+ React.createElement(Panel.Titlebar, null, "Server Variables"),
1959
+ React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid ServerVariablesContent" }, variables.map(variable => (React.createElement(VariableEditor, { key: variable.name, variable: variable, value: values[variable.name], onChange: (value) => onChangeValue(variable.name, String(value)) }))))));
1960
+ };
1961
+
1928
1962
  const defaultServers = [];
1929
1963
  const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
1930
1964
  var _a, _b, _c, _d, _e, _f, _g;
@@ -1941,10 +1975,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1941
1975
  const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
1942
1976
  const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
1943
1977
  const servers = React.useMemo(() => {
1944
- return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
1978
+ return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, false);
1945
1979
  }, [httpOperation.servers, mockUrl]);
1946
1980
  const firstServer = servers[0] || null;
1947
1981
  const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
1982
+ const serverVariables = getServerVariables(chosenServer);
1983
+ const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
1948
1984
  const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
1949
1985
  const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
1950
1986
  const getValues = () => Object.keys(bodyParameterValues)
@@ -1966,7 +2002,8 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1966
2002
  React.useEffect(() => {
1967
2003
  let isMounted = true;
1968
2004
  if (onRequestChange || embeddedInMd) {
1969
- buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
2005
+ buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, serverVariableValues,
2006
+ httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1970
2007
  corsProxy })).then(request => {
1971
2008
  if (isMounted) {
1972
2009
  if (onRequestChange) {
@@ -1986,6 +2023,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1986
2023
  parameterValuesWithDefaults,
1987
2024
  formDataState.isFormDataBody,
1988
2025
  bodyParameterValues,
2026
+ serverVariableValues,
1989
2027
  isAllowedEmptyValues,
1990
2028
  textRequestBody,
1991
2029
  operationAuthValue,
@@ -2003,6 +2041,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2003
2041
  const mockData = isMockingEnabled ? getMockData(mockUrl, httpOperation, mockingOptions) : undefined;
2004
2042
  const request = yield buildFetchRequest({
2005
2043
  parameterValues: parameterValuesWithDefaults,
2044
+ serverVariableValues,
2006
2045
  httpOperation,
2007
2046
  mediaTypeContent,
2008
2047
  bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
@@ -2043,6 +2082,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2043
2082
  const isOnlySendButton = !((_d = httpOperation.security) === null || _d === void 0 ? void 0 : _d.length) && !allParameters.length && !formDataState.isFormDataBody && !mediaTypeContent;
2044
2083
  const tryItPanelContents = (React.createElement(React.Fragment, null,
2045
2084
  ((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
2085
+ serverVariables.length > 0 && (React.createElement(ServerVariables, { variables: serverVariables, values: serverVariableValues, onChangeValue: updateServerVariableValue })),
2046
2086
  allParameters.length > 0 && (React.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
2047
2087
  formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
2048
2088
  React.createElement(Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
package/index.js CHANGED
@@ -18,7 +18,6 @@ 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');
22
21
  var URI = require('urijs');
23
22
  var mosaicCodeViewer = require('@stoplight/mosaic-code-viewer');
24
23
  var httpsnippetLite = require('httpsnippet-lite');
@@ -44,6 +43,7 @@ var entries = require('lodash/entries.js');
44
43
  var keys = require('lodash/keys.js');
45
44
  var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
46
45
  var sortBy = require('lodash/sortBy.js');
46
+ var isEmpty = require('lodash/isEmpty.js');
47
47
  var isNil = require('lodash/isNil.js');
48
48
  var omitBy = require('lodash/omitBy.js');
49
49
  var reactRouterHashLink = require('react-router-hash-link');
@@ -79,7 +79,6 @@ var isArray__default = /*#__PURE__*/_interopDefaultLegacy(isArray);
79
79
  var isPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(isPlainObject);
80
80
  var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
81
81
  var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
82
- var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
83
82
  var URI__default = /*#__PURE__*/_interopDefaultLegacy(URI);
84
83
  var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
85
84
  var capitalize__default = /*#__PURE__*/_interopDefaultLegacy(capitalize);
@@ -100,6 +99,7 @@ var formatXml__default = /*#__PURE__*/_interopDefaultLegacy(formatXml);
100
99
  var entries__default = /*#__PURE__*/_interopDefaultLegacy(entries);
101
100
  var keys__default = /*#__PURE__*/_interopDefaultLegacy(keys);
102
101
  var sortBy__default = /*#__PURE__*/_interopDefaultLegacy(sortBy);
102
+ var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
103
103
  var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
104
104
  var omitBy__default = /*#__PURE__*/_interopDefaultLegacy(omitBy);
105
105
  var $RefParser__default = /*#__PURE__*/_interopDefaultLegacy($RefParser);
@@ -552,10 +552,7 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
552
552
  const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
553
553
  let url = server.url;
554
554
  if (inlineDefaults) {
555
- url = getServerUrlWithDefaultValues(server);
556
- }
557
- else if (isEmpty__default["default"](server.variables)) {
558
- url = resolveUrl(server.url);
555
+ url = getServerUrlWithVariableValues(server, {});
559
556
  }
560
557
  return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
561
558
  });
@@ -568,7 +565,18 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
568
565
  }
569
566
  return servers.filter(isValidServer);
570
567
  };
568
+ const getServerVariables = (server) => {
569
+ var _a;
570
+ return Object.entries((_a = server === null || server === void 0 ? void 0 : server.variables) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => ({
571
+ name: key,
572
+ default: value.default,
573
+ description: value.description,
574
+ enum: value.enum,
575
+ }));
576
+ };
571
577
  function resolveUrl(urlString) {
578
+ if (urlString === null)
579
+ return null;
572
580
  let url;
573
581
  try {
574
582
  url = URI__default["default"](urlString);
@@ -588,14 +596,15 @@ function resolveUrl(urlString) {
588
596
  }
589
597
  return null;
590
598
  }
591
- const getServerUrlWithDefaultValues = (server) => {
599
+ const getServerUrlWithVariableValues = (server, values) => {
592
600
  var _a;
593
601
  let urlString = server.url;
594
602
  const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
595
603
  variables.forEach(([variableName, variableInfo]) => {
596
- urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
604
+ var _a;
605
+ urlString = urlString.replaceAll(`{${variableName}}`, (_a = values[variableName]) !== null && _a !== void 0 ? _a : variableInfo.default);
597
606
  });
598
- return resolveUrl(urlString);
607
+ return urlString;
599
608
  };
600
609
 
601
610
  const persistAtom = (key, atomInstance) => {
@@ -1474,11 +1483,11 @@ const useTextRequestBodyState = (mediaTypeContent) => {
1474
1483
  };
1475
1484
 
1476
1485
  const nameAndValueObjectToPair = ({ name, value }) => [name, value];
1477
- const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, }) => {
1486
+ const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, serverVariableValues, }) => {
1478
1487
  var _a;
1479
1488
  const server = chosenServer || ((_a = httpOperation.servers) === null || _a === void 0 ? void 0 : _a[0]);
1480
- const chosenServerUrl = server && getServerUrlWithDefaultValues(server);
1481
- const serverUrl = (mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin;
1489
+ const chosenServerUrl = server && getServerUrlWithVariableValues(server, serverVariableValues);
1490
+ const serverUrl = resolveUrl((mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin);
1482
1491
  if (corsProxy && !mockData) {
1483
1492
  return `${corsProxy}${serverUrl}`;
1484
1493
  }
@@ -1555,10 +1564,10 @@ const getQueryParams = ({ httpOperation, parameterValues, }) => {
1555
1564
  return acc;
1556
1565
  }, []);
1557
1566
  };
1558
- function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1567
+ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, serverVariableValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1559
1568
  var _a, _b, _c;
1560
1569
  return tslib.__awaiter(this, void 0, void 0, function* () {
1561
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1570
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1562
1571
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1563
1572
  const queryParams = getQueryParams({ httpOperation, parameterValues });
1564
1573
  const rawHeaders = filterOutAuthorizationParams((_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : [], httpOperation.security)
@@ -1631,10 +1640,10 @@ const runAuthRequestEhancements = (auth, queryParams, headers) => {
1631
1640
  }
1632
1641
  return [newQueryParams, newHeaders];
1633
1642
  };
1634
- function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1643
+ function buildHarRequest({ httpOperation, bodyInput, parameterValues, serverVariableValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1635
1644
  var _a, _b, _c, _d;
1636
1645
  return tslib.__awaiter(this, void 0, void 0, function* () {
1637
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1646
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1638
1647
  const mimeType = (_a = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _a !== void 0 ? _a : 'application/json';
1639
1648
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1640
1649
  const queryParams = getQueryParams({ httpOperation, parameterValues });
@@ -1956,8 +1965,18 @@ class NetworkError extends Error {
1956
1965
  }
1957
1966
  const isNetworkError = (error) => error instanceof NetworkError;
1958
1967
 
1968
+ const persistedServerVariableValuesAtom = jotai.atom({});
1969
+ const useServerVariables = () => {
1970
+ const [serverVariables, setPersistedServerVariableValues] = jotai.useAtom(persistedServerVariableValuesAtom);
1971
+ const updateServerVariableValue = (name, value) => {
1972
+ setPersistedServerVariableValues(Object.assign({}, serverVariables, { [name]: value }));
1973
+ };
1974
+ return { serverVariables, updateServerVariableValue };
1975
+ };
1976
+
1959
1977
  const ServersDropdown = ({ servers }) => {
1960
1978
  const [chosenServer, setChosenServer] = jotai.useAtom(chosenServerAtom);
1979
+ const { serverVariables } = useServerVariables();
1961
1980
  const serverItems = [
1962
1981
  {
1963
1982
  type: 'option_group',
@@ -1971,7 +1990,7 @@ const ServersDropdown = ({ servers }) => {
1971
1990
  ...servers.map((server, i) => ({
1972
1991
  id: server.url,
1973
1992
  title: server.description,
1974
- description: server.url,
1993
+ description: getServerUrlWithVariableValues(server, serverVariables),
1975
1994
  value: server.url,
1976
1995
  })),
1977
1996
  ],
@@ -1981,6 +2000,21 @@ const ServersDropdown = ({ servers }) => {
1981
2000
  };
1982
2001
  ServersDropdown.displayName = 'ServersDropdown';
1983
2002
 
2003
+ const VariableEditor = ({ variable, value, onChange }) => {
2004
+ const inputId = useUniqueId(`id_${variable.name}_`);
2005
+ return (React__namespace.createElement(React__namespace.Fragment, null,
2006
+ React__namespace.createElement(mosaic.Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2007
+ React__namespace.createElement(mosaic.Text, { mx: 3 }, ":"),
2008
+ React__namespace.createElement("div", null, variable.enum ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
2009
+ React__namespace.createElement(mosaic.Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
2010
+ };
2011
+
2012
+ const ServerVariables = ({ variables, values, onChangeValue }) => {
2013
+ return (React__namespace.createElement(mosaic.Panel, { defaultIsOpen: true },
2014
+ React__namespace.createElement(mosaic.Panel.Titlebar, null, "Server Variables"),
2015
+ React__namespace.createElement(mosaic.Panel.Content, { className: "sl-overflow-y-auto ParameterGrid ServerVariablesContent" }, variables.map(variable => (React__namespace.createElement(VariableEditor, { key: variable.name, variable: variable, value: values[variable.name], onChange: (value) => onChangeValue(variable.name, String(value)) }))))));
2016
+ };
2017
+
1984
2018
  const defaultServers = [];
1985
2019
  const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
1986
2020
  var _a, _b, _c, _d, _e, _f, _g;
@@ -1997,10 +2031,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1997
2031
  const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
1998
2032
  const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
1999
2033
  const servers = React__namespace.useMemo(() => {
2000
- return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
2034
+ return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, false);
2001
2035
  }, [httpOperation.servers, mockUrl]);
2002
2036
  const firstServer = servers[0] || null;
2003
2037
  const [chosenServer, setChosenServer] = jotai.useAtom(chosenServerAtom);
2038
+ const serverVariables = getServerVariables(chosenServer);
2039
+ const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
2004
2040
  const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
2005
2041
  const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
2006
2042
  const getValues = () => Object.keys(bodyParameterValues)
@@ -2022,7 +2058,8 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2022
2058
  React__namespace.useEffect(() => {
2023
2059
  let isMounted = true;
2024
2060
  if (onRequestChange || embeddedInMd) {
2025
- buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
2061
+ buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, serverVariableValues,
2062
+ httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
2026
2063
  corsProxy })).then(request => {
2027
2064
  if (isMounted) {
2028
2065
  if (onRequestChange) {
@@ -2042,6 +2079,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2042
2079
  parameterValuesWithDefaults,
2043
2080
  formDataState.isFormDataBody,
2044
2081
  bodyParameterValues,
2082
+ serverVariableValues,
2045
2083
  isAllowedEmptyValues,
2046
2084
  textRequestBody,
2047
2085
  operationAuthValue,
@@ -2059,6 +2097,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2059
2097
  const mockData = isMockingEnabled ? getMockData(mockUrl, httpOperation, mockingOptions) : undefined;
2060
2098
  const request = yield buildFetchRequest({
2061
2099
  parameterValues: parameterValuesWithDefaults,
2100
+ serverVariableValues,
2062
2101
  httpOperation,
2063
2102
  mediaTypeContent,
2064
2103
  bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
@@ -2099,6 +2138,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2099
2138
  const isOnlySendButton = !((_d = httpOperation.security) === null || _d === void 0 ? void 0 : _d.length) && !allParameters.length && !formDataState.isFormDataBody && !mediaTypeContent;
2100
2139
  const tryItPanelContents = (React__namespace.createElement(React__namespace.Fragment, null,
2101
2140
  ((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React__namespace.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
2141
+ serverVariables.length > 0 && (React__namespace.createElement(ServerVariables, { variables: serverVariables, values: serverVariableValues, onChangeValue: updateServerVariableValue })),
2102
2142
  allParameters.length > 0 && (React__namespace.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
2103
2143
  formDataState.isFormDataBody ? (React__namespace.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React__namespace.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
2104
2144
  React__namespace.createElement(mosaic.Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
package/index.mjs CHANGED
@@ -16,7 +16,6 @@ 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';
20
19
  import URI from 'urijs';
21
20
  import { CodeViewer } from '@stoplight/mosaic-code-viewer';
22
21
  import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
@@ -42,6 +41,7 @@ import entries from 'lodash/entries.js';
42
41
  import keys from 'lodash/keys.js';
43
42
  import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
44
43
  import sortBy from 'lodash/sortBy.js';
44
+ import isEmpty from 'lodash/isEmpty.js';
45
45
  import isNil from 'lodash/isNil.js';
46
46
  import omitBy from 'lodash/omitBy.js';
47
47
  import { HashLink } from 'react-router-hash-link';
@@ -496,10 +496,7 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
496
496
  const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
497
497
  let url = server.url;
498
498
  if (inlineDefaults) {
499
- url = getServerUrlWithDefaultValues(server);
500
- }
501
- else if (isEmpty(server.variables)) {
502
- url = resolveUrl(server.url);
499
+ url = getServerUrlWithVariableValues(server, {});
503
500
  }
504
501
  return Object.assign(Object.assign({}, server), { url, description: server.description || fallbackDescription });
505
502
  });
@@ -512,7 +509,18 @@ const getServersToDisplay = (originalServers, mockUrl, inlineDefaults) => {
512
509
  }
513
510
  return servers.filter(isValidServer);
514
511
  };
512
+ const getServerVariables = (server) => {
513
+ var _a;
514
+ return Object.entries((_a = server === null || server === void 0 ? void 0 : server.variables) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => ({
515
+ name: key,
516
+ default: value.default,
517
+ description: value.description,
518
+ enum: value.enum,
519
+ }));
520
+ };
515
521
  function resolveUrl(urlString) {
522
+ if (urlString === null)
523
+ return null;
516
524
  let url;
517
525
  try {
518
526
  url = URI(urlString);
@@ -532,14 +540,15 @@ function resolveUrl(urlString) {
532
540
  }
533
541
  return null;
534
542
  }
535
- const getServerUrlWithDefaultValues = (server) => {
543
+ const getServerUrlWithVariableValues = (server, values) => {
536
544
  var _a;
537
545
  let urlString = server.url;
538
546
  const variables = Object.entries((_a = server.variables) !== null && _a !== void 0 ? _a : {});
539
547
  variables.forEach(([variableName, variableInfo]) => {
540
- urlString = urlString.replaceAll(`{${variableName}}`, variableInfo.default);
548
+ var _a;
549
+ urlString = urlString.replaceAll(`{${variableName}}`, (_a = values[variableName]) !== null && _a !== void 0 ? _a : variableInfo.default);
541
550
  });
542
- return resolveUrl(urlString);
551
+ return urlString;
543
552
  };
544
553
 
545
554
  const persistAtom = (key, atomInstance) => {
@@ -1418,11 +1427,11 @@ const useTextRequestBodyState = (mediaTypeContent) => {
1418
1427
  };
1419
1428
 
1420
1429
  const nameAndValueObjectToPair = ({ name, value }) => [name, value];
1421
- const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, }) => {
1430
+ const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, serverVariableValues, }) => {
1422
1431
  var _a;
1423
1432
  const server = chosenServer || ((_a = httpOperation.servers) === null || _a === void 0 ? void 0 : _a[0]);
1424
- const chosenServerUrl = server && getServerUrlWithDefaultValues(server);
1425
- const serverUrl = (mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin;
1433
+ const chosenServerUrl = server && getServerUrlWithVariableValues(server, serverVariableValues);
1434
+ const serverUrl = resolveUrl((mockData === null || mockData === void 0 ? void 0 : mockData.url) || chosenServerUrl || window.location.origin);
1426
1435
  if (corsProxy && !mockData) {
1427
1436
  return `${corsProxy}${serverUrl}`;
1428
1437
  }
@@ -1499,10 +1508,10 @@ const getQueryParams = ({ httpOperation, parameterValues, }) => {
1499
1508
  return acc;
1500
1509
  }, []);
1501
1510
  };
1502
- function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1511
+ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, serverVariableValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1503
1512
  var _a, _b, _c;
1504
1513
  return __awaiter(this, void 0, void 0, function* () {
1505
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1514
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1506
1515
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1507
1516
  const queryParams = getQueryParams({ httpOperation, parameterValues });
1508
1517
  const rawHeaders = filterOutAuthorizationParams((_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : [], httpOperation.security)
@@ -1575,10 +1584,10 @@ const runAuthRequestEhancements = (auth, queryParams, headers) => {
1575
1584
  }
1576
1585
  return [newQueryParams, newHeaders];
1577
1586
  };
1578
- function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1587
+ function buildHarRequest({ httpOperation, bodyInput, parameterValues, serverVariableValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1579
1588
  var _a, _b, _c, _d;
1580
1589
  return __awaiter(this, void 0, void 0, function* () {
1581
- const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1590
+ const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy, serverVariableValues });
1582
1591
  const mimeType = (_a = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _a !== void 0 ? _a : 'application/json';
1583
1592
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase()) && bodyInput !== undefined;
1584
1593
  const queryParams = getQueryParams({ httpOperation, parameterValues });
@@ -1900,8 +1909,18 @@ class NetworkError extends Error {
1900
1909
  }
1901
1910
  const isNetworkError = (error) => error instanceof NetworkError;
1902
1911
 
1912
+ const persistedServerVariableValuesAtom = atom({});
1913
+ const useServerVariables = () => {
1914
+ const [serverVariables, setPersistedServerVariableValues] = useAtom(persistedServerVariableValuesAtom);
1915
+ const updateServerVariableValue = (name, value) => {
1916
+ setPersistedServerVariableValues(Object.assign({}, serverVariables, { [name]: value }));
1917
+ };
1918
+ return { serverVariables, updateServerVariableValue };
1919
+ };
1920
+
1903
1921
  const ServersDropdown = ({ servers }) => {
1904
1922
  const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
1923
+ const { serverVariables } = useServerVariables();
1905
1924
  const serverItems = [
1906
1925
  {
1907
1926
  type: 'option_group',
@@ -1915,7 +1934,7 @@ const ServersDropdown = ({ servers }) => {
1915
1934
  ...servers.map((server, i) => ({
1916
1935
  id: server.url,
1917
1936
  title: server.description,
1918
- description: server.url,
1937
+ description: getServerUrlWithVariableValues(server, serverVariables),
1919
1938
  value: server.url,
1920
1939
  })),
1921
1940
  ],
@@ -1925,6 +1944,21 @@ const ServersDropdown = ({ servers }) => {
1925
1944
  };
1926
1945
  ServersDropdown.displayName = 'ServersDropdown';
1927
1946
 
1947
+ const VariableEditor = ({ variable, value, onChange }) => {
1948
+ const inputId = useUniqueId(`id_${variable.name}_`);
1949
+ return (React.createElement(React.Fragment, null,
1950
+ React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
1951
+ React.createElement(Text, { mx: 3 }, ":"),
1952
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
1953
+ React.createElement(Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
1954
+ };
1955
+
1956
+ const ServerVariables = ({ variables, values, onChangeValue }) => {
1957
+ return (React.createElement(Panel, { defaultIsOpen: true },
1958
+ React.createElement(Panel.Titlebar, null, "Server Variables"),
1959
+ React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid ServerVariablesContent" }, variables.map(variable => (React.createElement(VariableEditor, { key: variable.name, variable: variable, value: values[variable.name], onChange: (value) => onChangeValue(variable.name, String(value)) }))))));
1960
+ };
1961
+
1928
1962
  const defaultServers = [];
1929
1963
  const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
1930
1964
  var _a, _b, _c, _d, _e, _f, _g;
@@ -1941,10 +1975,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1941
1975
  const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
1942
1976
  const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
1943
1977
  const servers = React.useMemo(() => {
1944
- return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, true);
1978
+ return getServersToDisplay(httpOperation.servers || defaultServers, mockUrl, false);
1945
1979
  }, [httpOperation.servers, mockUrl]);
1946
1980
  const firstServer = servers[0] || null;
1947
1981
  const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
1982
+ const serverVariables = getServerVariables(chosenServer);
1983
+ const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
1948
1984
  const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
1949
1985
  const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
1950
1986
  const getValues = () => Object.keys(bodyParameterValues)
@@ -1966,7 +2002,8 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1966
2002
  React.useEffect(() => {
1967
2003
  let isMounted = true;
1968
2004
  if (onRequestChange || embeddedInMd) {
1969
- buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
2005
+ buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, serverVariableValues,
2006
+ httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
1970
2007
  corsProxy })).then(request => {
1971
2008
  if (isMounted) {
1972
2009
  if (onRequestChange) {
@@ -1986,6 +2023,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
1986
2023
  parameterValuesWithDefaults,
1987
2024
  formDataState.isFormDataBody,
1988
2025
  bodyParameterValues,
2026
+ serverVariableValues,
1989
2027
  isAllowedEmptyValues,
1990
2028
  textRequestBody,
1991
2029
  operationAuthValue,
@@ -2003,6 +2041,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2003
2041
  const mockData = isMockingEnabled ? getMockData(mockUrl, httpOperation, mockingOptions) : undefined;
2004
2042
  const request = yield buildFetchRequest({
2005
2043
  parameterValues: parameterValuesWithDefaults,
2044
+ serverVariableValues,
2006
2045
  httpOperation,
2007
2046
  mediaTypeContent,
2008
2047
  bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
@@ -2043,6 +2082,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
2043
2082
  const isOnlySendButton = !((_d = httpOperation.security) === null || _d === void 0 ? void 0 : _d.length) && !allParameters.length && !formDataState.isFormDataBody && !mediaTypeContent;
2044
2083
  const tryItPanelContents = (React.createElement(React.Fragment, null,
2045
2084
  ((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
2085
+ serverVariables.length > 0 && (React.createElement(ServerVariables, { variables: serverVariables, values: serverVariableValues, onChangeValue: updateServerVariableValue })),
2046
2086
  allParameters.length > 0 && (React.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
2047
2087
  formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
2048
2088
  React.createElement(Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-core",
3
- "version": "7.8.0",
3
+ "version": "7.9.0",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",
@@ -1,3 +1,9 @@
1
- import type { IServer } from '@stoplight/types';
1
+ import type { Dictionary, INodeVariable, IServer } from '@stoplight/types';
2
+ export declare type ServerVariable = INodeVariable & {
3
+ name: string;
4
+ };
2
5
  export declare const getServersToDisplay: (originalServers: IServer[], mockUrl: string | undefined, inlineDefaults: boolean) => IServer[];
3
- export declare const getServerUrlWithDefaultValues: (server: IServer) => string | null;
6
+ export declare const getServerVariables: (server?: IServer | null) => ServerVariable[];
7
+ export declare const getServerVariableDefaults: (server: IServer) => Record<string, string>;
8
+ export declare function resolveUrl(urlString: string | null): string | null;
9
+ export declare const getServerUrlWithVariableValues: (server: IServer, values: Dictionary<string, string>) => string;