@stoplight/elements-dev-portal 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { Menu, FieldButton, Modal, Input, Box, Icon, ListBox, ListBoxItem, Flex, VStack, Heading } from '@stoplight/mosaic';
1
+ import { Menu, FieldButton, Modal, Input, Box, Icon, ListBox, ListBoxItem, Flex, VStack, Heading, Button, useModalState } from '@stoplight/mosaic';
2
2
  import * as React from 'react';
3
3
  import React__default, { useRef, useEffect, useMemo, useCallback, useState } from 'react';
4
- import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, MockingProvider, Docs, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, RouterTypeContext, findFirstNode, ReactRouterMarkdownLink, SidebarLayout } from '@stoplight/elements-core';
4
+ import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, LinkHeading, MockingProvider, Docs, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, RouterTypeContext, useResponsiveLayout, findFirstNode, ReactRouterMarkdownLink, SidebarLayout } from '@stoplight/elements-core';
5
5
  import { resolve, dirname } from '@stoplight/path';
6
6
  import { NodeType } from '@stoplight/types';
7
7
  import flow from 'lodash/flow.js';
8
- import { Route, useParams, useHistory, Redirect, Link } from 'react-router-dom';
8
+ import { Link, Route, useParams, useHistory, Redirect } from 'react-router-dom';
9
9
  import { useQuery } from 'react-query';
10
10
 
11
11
  const BranchSelector = ({ branchSlug, branches, onChange }) => {
@@ -37,10 +37,61 @@ const PlatformProvider = ({ platformUrl = 'https://stoplight.io', platformAuthTo
37
37
  };
38
38
  const DevPortalProvider = withPersistenceBoundary(withQueryClientProvider(withMosaicProvider(PlatformProvider)));
39
39
 
40
+ /*! *****************************************************************************
41
+ Copyright (c) Microsoft Corporation.
42
+
43
+ Permission to use, copy, modify, and/or distribute this software for any
44
+ purpose with or without fee is hereby granted.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
47
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
48
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
49
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
50
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
51
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52
+ PERFORMANCE OF THIS SOFTWARE.
53
+ ***************************************************************************** */
54
+
55
+ function __rest(s, e) {
56
+ var t = {};
57
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
58
+ t[p] = s[p];
59
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
60
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
61
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
62
+ t[p[i]] = s[p[i]];
63
+ }
64
+ return t;
65
+ }
66
+
67
+ function __awaiter(thisArg, _arguments, P, generator) {
68
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
69
+ return new (P || (P = Promise))(function (resolve, reject) {
70
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
71
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
72
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
73
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
74
+ });
75
+ }
76
+
40
77
  const NodeContent = ({ node, Link, hideMocking, refResolver, maxRefDepth, tryItCorsProxy, tryItCredentialsPolicy, nodeHasChanged, nodeUnsupported, compact, hideTryIt, hideTryItPanel, hideExport, onExportRequest, }) => {
41
78
  var _a, _b, _c, _d;
42
79
  return (React.createElement(NodeLinkContext.Provider, { value: [node, Link] },
43
- React.createElement(MarkdownComponentsProvider, { value: { a: LinkComponent } },
80
+ React.createElement(MarkdownComponentsProvider, { value: {
81
+ a: LinkComponent,
82
+ h2: (_a) => {
83
+ var props = __rest(_a, ["color"]);
84
+ return React.createElement(LinkHeading, Object.assign({ size: 2 }, props));
85
+ },
86
+ h3: (_a) => {
87
+ var props = __rest(_a, ["color"]);
88
+ return React.createElement(LinkHeading, Object.assign({ size: 3 }, props));
89
+ },
90
+ h4: (_a) => {
91
+ var props = __rest(_a, ["color"]);
92
+ return React.createElement(LinkHeading, Object.assign({ size: 4 }, props));
93
+ },
94
+ } },
44
95
  React.createElement(MockingProvider, { mockUrl: node.links.mock_url, hideMocking: hideMocking },
45
96
  React.createElement(Docs, { nodeType: node.type, nodeData: node.data, nodeTitle: node.title, layoutOptions: {
46
97
  compact,
@@ -164,43 +215,6 @@ const SearchResultsList = ({ searchResults, onClick, isEmbedded, showDivider = t
164
215
  const SearchResults = flow(withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(SearchResultsList);
165
216
  const Search = flow(withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(SearchImpl);
166
217
 
167
- /*! *****************************************************************************
168
- Copyright (c) Microsoft Corporation.
169
-
170
- Permission to use, copy, modify, and/or distribute this software for any
171
- purpose with or without fee is hereby granted.
172
-
173
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
174
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
175
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
176
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
177
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
178
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
179
- PERFORMANCE OF THIS SOFTWARE.
180
- ***************************************************************************** */
181
-
182
- function __rest(s, e) {
183
- var t = {};
184
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
185
- t[p] = s[p];
186
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
187
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
188
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
189
- t[p[i]] = s[p[i]];
190
- }
191
- return t;
192
- }
193
-
194
- function __awaiter(thisArg, _arguments, P, generator) {
195
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
196
- return new (P || (P = Promise))(function (resolve, reject) {
197
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
198
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
199
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
200
- step((generator = generator.apply(thisArg, _arguments || [])).next());
201
- });
202
- }
203
-
204
218
  const TableOfContents = (_a) => {
205
219
  var { tableOfContents, activeId, Link, collapseTableOfContents = false, externalScrollbar, isInResponsiveMode = false, onLinkClick } = _a, boxProps = __rest(_a, ["tableOfContents", "activeId", "Link", "collapseTableOfContents", "externalScrollbar", "isInResponsiveMode", "onLinkClick"]);
206
220
  return (React.createElement(Flex, Object.assign({ bg: isInResponsiveMode ? 'canvas' : 'canvas-100' }, boxProps, { flexDirection: "col", maxH: "full" }),
@@ -245,11 +259,29 @@ const NotFound = () => (React__default.createElement(Flex, { align: "center", ju
245
259
  React__default.createElement(Heading, { size: 1 }, "Not Found"),
246
260
  React__default.createElement(Box, { as: "p" }, "Could not find what you are looking for"))));
247
261
 
262
+ const SearchOverlay = ({ isFetching, search, setSearch, data, toc, nodeSlug, projectSlug, branchSlug, isSearchShowing, onClose, onClick, }) => {
263
+ return (React.createElement(Modal, { isOpen: isSearchShowing, onClose: onClose },
264
+ React.createElement(Box, { className: "sl-overlay", bg: "canvas", overflowY: "scroll", "data-test": "search-overlay" },
265
+ React.createElement(Flex, { alignItems: "center", h: "3xl", px: 7, bg: "canvas", borderB: true, pos: "sticky", zIndex: 20 },
266
+ React.createElement(Flex, { w: "full" },
267
+ React.createElement(Box, { pt: 1, pr: 2 },
268
+ React.createElement(Button, { appearance: "minimal", onClick: () => {
269
+ onClose();
270
+ }, "data-test": "search-overlay-back-button" },
271
+ React.createElement(Icon, { icon: ['fas', 'arrow-left'], color: "gray", size: "lg" }))),
272
+ React.createElement(Input, { border: true, "data-test": "docs-search-input", display: "inline-block", appearance: "minimal", icon: React.createElement(Box, { as: Icon, ml: 1, icon: isFetching ? faSpinner : faSearch, spin: isFetching }), autoFocus: true, placeholder: projectSlug ? 'Search within the project' : 'Search...', value: search, onChange: e => {
273
+ setSearch(e.currentTarget.value);
274
+ }, type: "search", w: "full", size: "lg" }))),
275
+ React.createElement(Box, { px: 5, py: toc && !search ? 0 : 5, "data-test": "responsive-project-toc" },
276
+ toc && !search && projectSlug && (React.createElement(TableOfContents, { tableOfContents: Object.assign(Object.assign({}, toc), { hide_powered_by: true }), activeId: nodeSlug || '', Link: Link, onLinkClick: onClick })),
277
+ search && (React.createElement(SearchResults, { searchResults: data, onClick: item => onClick(item), isEmbedded: true, showDivider: false }))))));
278
+ };
279
+
248
280
  const UpgradeToStarter = () => (React__default.createElement(Flex, { as: "a", href: "https://stoplight.io/pricing/", target: "_blank", rel: "noreferrer noopener", justify: "center", alignItems: "center", w: "full", minH: "screen", color: "muted", flexDirection: "col" },
249
281
  React__default.createElement(Icon, { icon: ['fas', 'exclamation-triangle'], size: "4x" }),
250
282
  React__default.createElement(Box, { pt: 3 }, "Please upgrade your Stoplight Workspace to the Starter Plan to use Elements Dev Portal in production.")));
251
283
 
252
- const appVersion = '2.0.0';
284
+ const appVersion = '2.0.1';
253
285
 
254
286
  class ResponseError extends Error {
255
287
  constructor(message, responseCode) {
@@ -305,148 +337,6 @@ function useGetNodeContent({ nodeSlug, projectId, branchSlug, }) {
305
337
  return useQuery([...devPortalCacheKeys.branchNodeDetails(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : '', nodeSlug), platformUrl, platformAuthToken], () => getNodeContent({ nodeSlug, projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: nodeSlug && projectId ? true : false });
306
338
  }
307
339
 
308
- const getTableOfContents = ({ projectId, branchSlug, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
309
- const encodedProjectId = encodeURIComponent(projectId);
310
- const encodedBranchSlug = branchSlug ? encodeURIComponent(branchSlug) : '';
311
- const branchQuery = encodedBranchSlug ? `?branch=${encodedBranchSlug}` : '';
312
- const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}/table-of-contents${branchQuery}`, {
313
- headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
314
- });
315
- const data = yield response.json();
316
- if (!response.ok) {
317
- throw new Error(data);
318
- }
319
- return data;
320
- });
321
-
322
- function useGetTableOfContents({ projectId, branchSlug }) {
323
- const { platformUrl, platformAuthToken } = React.useContext(PlatformContext);
324
- return useQuery([...devPortalCacheKeys.branchTOC(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : ''), platformUrl, platformAuthToken], () => getTableOfContents({ projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: projectId ? true : false });
325
- }
326
-
327
- const StoplightProjectImpl = ({ projectId, hideTryIt, hideMocking, hideExport, collapseTableOfContents = false, tryItCredentialsPolicy, tryItCorsProxy, }) => {
328
- const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
329
- const branchSlug = decodeURIComponent(encodedBranchSlug);
330
- const history = useHistory();
331
- const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
332
- const { data: branches } = useGetBranches({ projectId });
333
- const { data: node, isLoading: isLoadingNode, isError, error: nodeError, } = useGetNodeContent({
334
- nodeSlug,
335
- projectId,
336
- branchSlug,
337
- });
338
- const container = React.useRef(null);
339
- if (!nodeSlug && isTocFetched && (tableOfContents === null || tableOfContents === void 0 ? void 0 : tableOfContents.items)) {
340
- const firstNode = findFirstNode(tableOfContents.items);
341
- if (firstNode) {
342
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}` });
343
- }
344
- }
345
- let elem;
346
- if (isLoadingNode || !isTocFetched) {
347
- elem = React.createElement(Loading, null);
348
- }
349
- else if (isError) {
350
- if (nodeError instanceof ResponseError) {
351
- if (nodeError.code === 402) {
352
- elem = React.createElement(UpgradeToStarter, null);
353
- }
354
- else if (nodeError.code === 403) {
355
- elem = React.createElement(Forbidden, null);
356
- }
357
- else {
358
- elem = React.createElement(NotFound, null);
359
- }
360
- }
361
- else {
362
- elem = React.createElement(NotFound, null);
363
- }
364
- }
365
- else if (!node) {
366
- elem = React.createElement(NotFound, null);
367
- }
368
- else if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
369
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}` });
370
- }
371
- else {
372
- elem = (React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }));
373
- }
374
- const handleTocClick = () => {
375
- if (container.current) {
376
- container.current.scrollIntoView();
377
- }
378
- };
379
- return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
380
- branches && branches.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches, onChange: branch => {
381
- const encodedBranchSlug = encodeURIComponent(branch.slug);
382
- history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${encodedBranchSlug}/${nodeSlug}`);
383
- } })) : null,
384
- tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) }, elem));
385
- };
386
- const StoplightProjectRouter = (_a) => {
387
- var { platformUrl, basePath = '/', staticRouterPath = '', router = 'history' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
388
- const { Router, routerProps } = useRouter(router, basePath, staticRouterPath);
389
- return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
390
- React.createElement(RouterTypeContext.Provider, { value: router },
391
- React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
392
- React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug+", exact: true },
393
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
394
- React.createElement(Route, { path: "/:nodeSlug+", exact: true },
395
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
396
- React.createElement(Route, { path: "/", exact: true },
397
- React.createElement(StoplightProjectImpl, Object.assign({}, props)))))));
398
- };
399
- const StoplightProject = withStyles(StoplightProjectRouter);
400
-
401
- const getNodes = ({ workspaceId, branchSlug, projectIds, search, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
402
- const queryParams = [];
403
- let fetchedWorkspaceId = workspaceId || '';
404
- if (!workspaceId && (projectIds === null || projectIds === void 0 ? void 0 : projectIds.length)) {
405
- const encodedProjectId = encodeURIComponent(projectIds[0]);
406
- const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}`, {
407
- headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
408
- });
409
- const data = yield response.json();
410
- fetchedWorkspaceId = data.workspace.id;
411
- }
412
- if (projectIds && projectIds.length) {
413
- queryParams.push(...projectIds.map((projectId, index) => {
414
- const encodedProjectId = encodeURIComponent(projectId);
415
- return `project_ids[${index}]=${encodedProjectId}`;
416
- }));
417
- }
418
- if (search) {
419
- const encodedSearch = encodeURIComponent(search);
420
- queryParams.push(`search=${encodedSearch}`);
421
- }
422
- if (branchSlug) {
423
- const encodedBranchSlug = encodeURIComponent(branchSlug);
424
- queryParams.push(`branch=${encodedBranchSlug}`);
425
- }
426
- const query = queryParams.length ? `?${queryParams.join('&')}` : '';
427
- const encodedWorkspaceId = encodeURIComponent(fetchedWorkspaceId);
428
- const response = yield fetch(`${platformUrl}/api/v1/workspaces/${encodedWorkspaceId}/nodes${query}`, {
429
- headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
430
- });
431
- const data = yield response.json();
432
- if (!response.ok) {
433
- throw new Error(data);
434
- }
435
- return data;
436
- });
437
-
438
- const getWorkspace = ({ projectIds, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
439
- const encodedProjectId = encodeURIComponent(projectIds[0]);
440
- const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}`, {
441
- headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
442
- });
443
- const data = yield response.json();
444
- if (!response.ok) {
445
- throw new Error(data);
446
- }
447
- return data;
448
- });
449
-
450
340
  /**
451
341
  * Creates a debounced function that delays invoking `func` until after `wait`
452
342
  * milliseconds have elapsed since the last time the debounced function was
@@ -674,6 +564,43 @@ function useDebounce(value, delay, options) {
674
564
  return [state, { cancel: debounced.cancel, isPending: debounced.isPending, flush: debounced.flush }];
675
565
  }
676
566
 
567
+ const getNodes = ({ workspaceId, branchSlug, projectIds, search, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
568
+ const queryParams = [];
569
+ let fetchedWorkspaceId = workspaceId || '';
570
+ if (!workspaceId && (projectIds === null || projectIds === void 0 ? void 0 : projectIds.length)) {
571
+ const encodedProjectId = encodeURIComponent(projectIds[0]);
572
+ const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}`, {
573
+ headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
574
+ });
575
+ const data = yield response.json();
576
+ fetchedWorkspaceId = data.workspace.id;
577
+ }
578
+ if (projectIds && projectIds.length) {
579
+ queryParams.push(...projectIds.map((projectId, index) => {
580
+ const encodedProjectId = encodeURIComponent(projectId);
581
+ return `project_ids[${index}]=${encodedProjectId}`;
582
+ }));
583
+ }
584
+ if (search) {
585
+ const encodedSearch = encodeURIComponent(search);
586
+ queryParams.push(`search=${encodedSearch}`);
587
+ }
588
+ if (branchSlug) {
589
+ const encodedBranchSlug = encodeURIComponent(branchSlug);
590
+ queryParams.push(`branch=${encodedBranchSlug}`);
591
+ }
592
+ const query = queryParams.length ? `?${queryParams.join('&')}` : '';
593
+ const encodedWorkspaceId = encodeURIComponent(fetchedWorkspaceId);
594
+ const response = yield fetch(`${platformUrl}/api/v1/workspaces/${encodedWorkspaceId}/nodes${query}`, {
595
+ headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
596
+ });
597
+ const data = yield response.json();
598
+ if (!response.ok) {
599
+ throw new Error(data);
600
+ }
601
+ return data;
602
+ });
603
+
677
604
  function useGetNodes({ search, workspaceId, projectIds, branch, pause, }) {
678
605
  const { platformUrl, platformAuthToken } = React.useContext(PlatformContext);
679
606
  const [debounceSearch] = useDebounce(search, 500);
@@ -684,6 +611,127 @@ function useGetNodes({ search, workspaceId, projectIds, branch, pause, }) {
684
611
  ], () => getNodes({ workspaceId, projectIds, branchSlug: branch, search: debounceSearch, platformUrl, platformAuthToken }), { enabled: !pause, keepPreviousData: true });
685
612
  }
686
613
 
614
+ const getTableOfContents = ({ projectId, branchSlug, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
615
+ const encodedProjectId = encodeURIComponent(projectId);
616
+ const encodedBranchSlug = branchSlug ? encodeURIComponent(branchSlug) : '';
617
+ const branchQuery = encodedBranchSlug ? `?branch=${encodedBranchSlug}` : '';
618
+ const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}/table-of-contents${branchQuery}`, {
619
+ headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
620
+ });
621
+ const data = yield response.json();
622
+ if (!response.ok) {
623
+ throw new Error(data);
624
+ }
625
+ return data;
626
+ });
627
+
628
+ function useGetTableOfContents({ projectId, branchSlug }) {
629
+ const { platformUrl, platformAuthToken } = React.useContext(PlatformContext);
630
+ return useQuery([...devPortalCacheKeys.branchTOC(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : ''), platformUrl, platformAuthToken], () => getTableOfContents({ projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: projectId ? true : false });
631
+ }
632
+
633
+ const StoplightProjectImpl = ({ projectId, hideTryIt, hideMocking, hideExport, collapseTableOfContents = false, tryItCredentialsPolicy, tryItCorsProxy, }) => {
634
+ const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
635
+ const branchSlug = decodeURIComponent(encodedBranchSlug);
636
+ const history = useHistory();
637
+ const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
638
+ const { data: branches } = useGetBranches({ projectId });
639
+ const { data: node, isLoading: isLoadingNode, isError, error: nodeError, } = useGetNodeContent({
640
+ nodeSlug,
641
+ projectId,
642
+ branchSlug,
643
+ });
644
+ const { isOpen, open, close } = useModalState();
645
+ const [search, setSearch] = React.useState('');
646
+ const onSearchResultClick = (item) => {
647
+ close();
648
+ };
649
+ const { isResponsiveLayoutEnabled } = useResponsiveLayout();
650
+ const { data, isFetching } = useGetNodes({
651
+ search,
652
+ projectIds: [projectId],
653
+ pause: !isResponsiveLayoutEnabled,
654
+ });
655
+ const container = React.useRef(null);
656
+ if (!nodeSlug && isTocFetched && (tableOfContents === null || tableOfContents === void 0 ? void 0 : tableOfContents.items)) {
657
+ const firstNode = findFirstNode(tableOfContents.items);
658
+ if (firstNode) {
659
+ return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}` });
660
+ }
661
+ }
662
+ let elem;
663
+ if (isLoadingNode || !isTocFetched) {
664
+ elem = React.createElement(Loading, null);
665
+ }
666
+ else if (isError) {
667
+ if (nodeError instanceof ResponseError) {
668
+ if (nodeError.code === 402) {
669
+ elem = React.createElement(UpgradeToStarter, null);
670
+ }
671
+ else if (nodeError.code === 403) {
672
+ elem = React.createElement(Forbidden, null);
673
+ }
674
+ else {
675
+ elem = React.createElement(NotFound, null);
676
+ }
677
+ }
678
+ else {
679
+ elem = React.createElement(NotFound, null);
680
+ }
681
+ }
682
+ else if (!node) {
683
+ elem = React.createElement(NotFound, null);
684
+ }
685
+ else if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
686
+ return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}` });
687
+ }
688
+ else {
689
+ elem = (React.createElement(React.Fragment, null,
690
+ React.createElement(Button, { "data-test": "show-project-search-overlay", onPress: open, appearance: "default", w: "full", rounded: "lg", borderColor: "light" },
691
+ React.createElement(Icon, { icon: faSearch }),
692
+ React.createElement(Box, { pl: 2 }, node.title)),
693
+ React.createElement(SearchOverlay, { toc: tableOfContents, projectSlug: nodeSlug, branchSlug: branchSlug, nodeSlug: nodeSlug, isFetching: isFetching || !isTocFetched, search: search, setSearch: setSearch, data: data, isSearchShowing: isOpen, onClose: close, onClick: onSearchResultClick }),
694
+ React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })));
695
+ }
696
+ const handleTocClick = () => {
697
+ if (container.current) {
698
+ container.current.scrollIntoView();
699
+ }
700
+ };
701
+ return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
702
+ branches && branches.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches, onChange: branch => {
703
+ const encodedBranchSlug = encodeURIComponent(branch.slug);
704
+ history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${encodedBranchSlug}/${nodeSlug}`);
705
+ } })) : null,
706
+ tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) }, elem));
707
+ };
708
+ const StoplightProjectRouter = (_a) => {
709
+ var { platformUrl, basePath = '/', staticRouterPath = '', router = 'history' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
710
+ const { Router, routerProps } = useRouter(router, basePath, staticRouterPath);
711
+ return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
712
+ React.createElement(RouterTypeContext.Provider, { value: router },
713
+ React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
714
+ React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug+", exact: true },
715
+ React.createElement(StoplightProjectImpl, Object.assign({}, props))),
716
+ React.createElement(Route, { path: "/:nodeSlug+", exact: true },
717
+ React.createElement(StoplightProjectImpl, Object.assign({}, props))),
718
+ React.createElement(Route, { path: "/", exact: true },
719
+ React.createElement(StoplightProjectImpl, Object.assign({}, props)))))));
720
+ };
721
+ const StoplightProject = withStyles(StoplightProjectRouter);
722
+
723
+ const getWorkspace = ({ projectIds, platformUrl = 'https://stoplight.io', platformAuthToken, }) => __awaiter(void 0, void 0, void 0, function* () {
724
+ const encodedProjectId = encodeURIComponent(projectIds[0]);
725
+ const response = yield fetch(`${platformUrl}/api/v1/projects/${encodedProjectId}`, {
726
+ headers: Object.assign({ 'Stoplight-Elements-Version': appVersion }, (platformAuthToken && { Authorization: `Bearer ${platformAuthToken}` })),
727
+ });
728
+ const data = yield response.json();
729
+ if (!response.ok) {
730
+ throw new Error(data);
731
+ }
732
+ return data;
733
+ });
734
+
687
735
  function useGetWorkspace({ projectIds }) {
688
736
  const { platformUrl, platformAuthToken } = React.useContext(PlatformContext);
689
737
  return useQuery([...devPortalCacheKeys.searchNodes({ projectIds }), platformUrl, platformAuthToken], () => getWorkspace({ projectIds, platformUrl, platformAuthToken }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-dev-portal",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "UI components for composing beautiful developer documentation.",
5
5
  "keywords": [],
6
6
  "main": "./index.js",
@@ -26,7 +26,7 @@
26
26
  "react-dom": ">=16.8"
27
27
  },
28
28
  "dependencies": {
29
- "@stoplight/elements-core": "~8.0.0",
29
+ "@stoplight/elements-core": "~8.0.1",
30
30
  "@stoplight/markdown-viewer": "^5.5.0",
31
31
  "@stoplight/mosaic": "^1.46.1",
32
32
  "@stoplight/path": "^1.3.2",