@jpmorganchase/elemental-dev-portal 1.0.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/components/BranchSelector/BranchSelector.d.ts +7 -0
  2. package/components/BranchSelector/BranchSelector.spec.d.ts +15 -0
  3. package/components/BranchSelector/BranchSelector.stories.d.ts +29 -0
  4. package/components/DevPortalProvider/index.d.ts +7 -0
  5. package/components/Forbidden.d.ts +1 -0
  6. package/components/Loading.d.ts +1 -0
  7. package/components/NodeContent/NodeContent.d.ts +17 -0
  8. package/components/NodeContent/NodeContent.spec.d.ts +1 -0
  9. package/components/NodeContent/NodeContent.stories.d.ts +43 -0
  10. package/components/NotFound.d.ts +1 -0
  11. package/components/Search/Search.d.ts +13 -0
  12. package/components/Search/Search.stories.d.ts +33 -0
  13. package/components/TableOfContents/TableOfContents.d.ts +12 -0
  14. package/components/TableOfContents/TableOfContents.stories.d.ts +36 -0
  15. package/components/UpgradeToStarter.d.ts +1 -0
  16. package/consts.d.ts +28 -0
  17. package/containers/StoplightProject.d.ts +13 -0
  18. package/containers/StoplightProject.spec.d.ts +1 -0
  19. package/containers/StoplightProject.stories.d.ts +45 -0
  20. package/handlers/getBranches.d.ts +6 -0
  21. package/handlers/getNodeContent.d.ts +12 -0
  22. package/handlers/getNodes.d.ts +9 -0
  23. package/handlers/getTableOfContents.d.ts +7 -0
  24. package/handlers/getWorkspace.d.ts +6 -0
  25. package/hooks/useGetBranches.d.ts +3 -0
  26. package/hooks/useGetNodeContent.d.ts +5 -0
  27. package/hooks/useGetNodes.d.ts +7 -0
  28. package/hooks/useGetTableOfContents.d.ts +4 -0
  29. package/hooks/useGetWorkspace.d.ts +3 -0
  30. package/index.esm.js +682 -0
  31. package/index.js +726 -0
  32. package/index.mjs +682 -0
  33. package/package.json +17 -70
  34. package/styles.min.css +1 -0
  35. package/types.d.ts +65 -0
  36. package/version.d.ts +1 -0
  37. package/web-components/components.d.ts +1 -0
  38. package/web-components/index.d.ts +1 -0
  39. package/web-components.min.js +2 -0
  40. package/web-components.min.js.LICENSE.txt +187 -0
  41. package/.storybook/main.js +0 -1
  42. package/.storybook/manager.js +0 -1
  43. package/.storybook/preview.jsx +0 -46
  44. package/jest.config.js +0 -10
  45. package/src/__fixtures__/branches.json +0 -26
  46. package/src/__fixtures__/node-content.json +0 -257
  47. package/src/__fixtures__/table-of-contents.json +0 -144
  48. package/src/components/BranchSelector/BranchSelector.spec.tsx +0 -63
  49. package/src/components/BranchSelector/BranchSelector.stories.tsx +0 -41
  50. package/src/components/BranchSelector/BranchSelector.tsx +0 -50
  51. package/src/components/DevPortalProvider/index.tsx +0 -19
  52. package/src/components/Forbidden.tsx +0 -11
  53. package/src/components/Loading.tsx +0 -9
  54. package/src/components/NodeContent/NodeContent.spec.tsx +0 -54
  55. package/src/components/NodeContent/NodeContent.stories.tsx +0 -60
  56. package/src/components/NodeContent/NodeContent.tsx +0 -171
  57. package/src/components/NotFound.tsx +0 -11
  58. package/src/components/Search/Search.stories.tsx +0 -73
  59. package/src/components/Search/Search.tsx +0 -133
  60. package/src/components/TableOfContents/TableOfContents.stories.tsx +0 -54
  61. package/src/components/TableOfContents/TableOfContents.tsx +0 -51
  62. package/src/components/UpgradeToStarter.tsx +0 -22
  63. package/src/consts.ts +0 -32
  64. package/src/containers/StoplightProject.spec.tsx +0 -78
  65. package/src/containers/StoplightProject.stories.tsx +0 -28
  66. package/src/containers/StoplightProject.tsx +0 -213
  67. package/src/handlers/__tests__/getBranches.test.ts +0 -30
  68. package/src/handlers/__tests__/getNodeContent.test.ts +0 -35
  69. package/src/handlers/__tests__/getNodes.test.ts +0 -38
  70. package/src/handlers/__tests__/getTableOfContents.test.ts +0 -34
  71. package/src/handlers/__tests__/getWorkspace.test.ts +0 -30
  72. package/src/handlers/getBranches.ts +0 -27
  73. package/src/handlers/getNodeContent.ts +0 -53
  74. package/src/handlers/getNodes.ts +0 -69
  75. package/src/handlers/getTableOfContents.ts +0 -30
  76. package/src/handlers/getWorkspace.ts +0 -27
  77. package/src/hooks/__tests__/dataFetching.spec.tsx +0 -42
  78. package/src/hooks/useGetBranches.ts +0 -17
  79. package/src/hooks/useGetNodeContent.ts +0 -24
  80. package/src/hooks/useGetNodes.ts +0 -34
  81. package/src/hooks/useGetTableOfContents.ts +0 -15
  82. package/src/hooks/useGetWorkspace.tsx +0 -13
  83. package/src/styles.css +0 -1
  84. package/src/types.ts +0 -81
  85. package/src/version.ts +0 -2
  86. package/src/web-components/__stories__/StoplightProject.stories.tsx +0 -33
  87. package/src/web-components/components.ts +0 -17
  88. package/src/web-components/index.ts +0 -3
  89. package/tsconfig.build.json +0 -18
  90. package/tsconfig.json +0 -7
  91. package/web-components.config.js +0 -1
  92. /package/{src/components/BranchSelector/index.tsx → components/BranchSelector/index.d.ts} +0 -0
  93. /package/{src/components/NodeContent/index.tsx → components/NodeContent/index.d.ts} +0 -0
  94. /package/{src/components/Search/index.tsx → components/Search/index.d.ts} +0 -0
  95. /package/{src/components/TableOfContents/index.tsx → components/TableOfContents/index.d.ts} +0 -0
  96. /package/{src/index.ts → index.d.ts} +0 -0
@@ -1,133 +0,0 @@
1
- import { faSearch, faSpinner } from '@fortawesome/free-solid-svg-icons';
2
- import {
3
- NodeTypeColors,
4
- NodeTypeIconDefs,
5
- withMosaicProvider,
6
- withPersistenceBoundary,
7
- withQueryClientProvider,
8
- withStyles,
9
- } from '@stoplight/elements-core';
10
- import { Box, Flex, Icon, Input, ListBox, ListBoxItem, Modal, ModalProps } from '@stoplight/mosaic';
11
- import { flow } from 'lodash';
12
- import * as React from 'react';
13
-
14
- import { NodeSearchResult } from '../../types';
15
-
16
- export type SearchProps = {
17
- isLoading?: boolean;
18
- search?: string;
19
- searchResults?: NodeSearchResult[];
20
- onSearch: (search: string) => void;
21
- onClick: (result: NodeSearchResult) => void;
22
- isOpen?: boolean;
23
- onClose: ModalProps['onClose'];
24
- };
25
-
26
- const SearchImpl = ({ isLoading, search, searchResults, isOpen, onClose, onClick, onSearch }: SearchProps) => {
27
- const listBoxRef = React.useRef<HTMLDivElement>(null);
28
-
29
- const onChange = React.useCallback(e => onSearch(e.currentTarget.value), [onSearch]);
30
-
31
- const onKeyDown = React.useCallback(e => {
32
- // Focus the search results on arrow down
33
- if (e.key === 'ArrowDown') {
34
- e.preventDefault();
35
- listBoxRef.current?.focus();
36
- }
37
- }, []);
38
-
39
- const onSelectionChange = React.useCallback(
40
- keys => {
41
- const selectedId = keys.values().next().value;
42
- const selectedResult = searchResults?.find(
43
- searchResult => `${searchResult.id}-${searchResult.project_id}` === selectedId,
44
- );
45
- if (selectedResult) {
46
- onClick(selectedResult);
47
- }
48
- },
49
- [searchResults, onClick],
50
- );
51
-
52
- return (
53
- <Modal
54
- renderHeader={() => (
55
- <Input
56
- appearance="minimal"
57
- borderB
58
- size="lg"
59
- icon={<Box as={Icon} ml={1} icon={isLoading ? faSpinner : faSearch} spin={isLoading} />}
60
- autoFocus
61
- placeholder="Search..."
62
- value={search}
63
- onChange={onChange}
64
- onKeyDown={onKeyDown}
65
- />
66
- )}
67
- isOpen={!!isOpen}
68
- onClose={onClose}
69
- >
70
- {searchResults && searchResults.length > 0 ? (
71
- <ListBox
72
- ref={listBoxRef}
73
- aria-label="Search"
74
- overflowY="auto"
75
- h={80}
76
- m={-5}
77
- items={searchResults}
78
- selectionMode="single"
79
- onSelectionChange={onSelectionChange}
80
- >
81
- {(searchResult: NodeSearchResult) => {
82
- return (
83
- <ListBoxItem key={`${searchResult.id}-${searchResult.project_id}`} textValue={searchResult.title}>
84
- <Box p={3} borderB>
85
- <Flex align="center">
86
- <Box
87
- as={Icon}
88
- w={4}
89
- icon={NodeTypeIconDefs[searchResult.type]}
90
- style={{ color: NodeTypeColors[searchResult.type] }}
91
- />
92
-
93
- <Box
94
- flex={1}
95
- fontSize="lg"
96
- dangerouslySetInnerHTML={{ __html: searchResult.highlighted.name ?? '' }}
97
- fontWeight="medium"
98
- textOverflow="overflow-ellipsis"
99
- mx={2}
100
- />
101
-
102
- <Box fontSize="sm" color="muted">
103
- {searchResult.project_name}
104
- </Box>
105
- </Flex>
106
-
107
- <Box
108
- dangerouslySetInnerHTML={{ __html: searchResult.highlighted.summary ?? '' }}
109
- color="muted"
110
- fontSize="sm"
111
- mt={1}
112
- ml={6}
113
- />
114
- </Box>
115
- </ListBoxItem>
116
- );
117
- }}
118
- </ListBox>
119
- ) : (
120
- <Flex w="full" h={80} align="center" justify="center" m={-5}>
121
- No search results
122
- </Flex>
123
- )}
124
- </Modal>
125
- );
126
- };
127
-
128
- export const Search = flow(
129
- withStyles,
130
- withPersistenceBoundary,
131
- withMosaicProvider,
132
- withQueryClientProvider,
133
- )(SearchImpl);
@@ -1,54 +0,0 @@
1
- import { Story } from '@storybook/react';
2
- import * as React from 'react';
3
-
4
- import { useGetTableOfContents } from '../../hooks/useGetTableOfContents';
5
- import { TableOfContents } from './';
6
-
7
- // Wrapper to show how to use the node content hook
8
- const TableOfContentsWrapper = ({ projectId, branchSlug }: { projectId: string; branchSlug?: string }) => {
9
- const { data } = useGetTableOfContents({ projectId, branchSlug });
10
-
11
- return data ? (
12
- <TableOfContents
13
- activeId="b3A6MTE0"
14
- tableOfContents={data}
15
- Link={({ children, ...props }) => {
16
- return (
17
- <a
18
- onClick={() => {
19
- console.log('Link clicked!', props);
20
- }}
21
- >
22
- {children}
23
- </a>
24
- );
25
- }}
26
- style={{
27
- width: '300px',
28
- }}
29
- />
30
- ) : (
31
- <>Loading</>
32
- );
33
- };
34
-
35
- export default {
36
- title: 'Public/TableOfContents',
37
- component: TableOfContentsWrapper,
38
- argTypes: {
39
- projectId: { table: { category: 'Input' } },
40
- branchSlug: { table: { category: 'Input' } },
41
- platformUrl: { table: { category: 'Input' } },
42
- },
43
- args: {
44
- projectId: 'cHJqOjYwNjYx',
45
- branchSlug: '',
46
- platformUrl: 'https://stoplight.io',
47
- },
48
- };
49
-
50
- export const Playground: Story<{ nodeSlug: string; projectId: string; branchSlug?: string }> = args => (
51
- <TableOfContentsWrapper {...args} />
52
- );
53
-
54
- Playground.storyName = 'Studio Demo';
@@ -1,51 +0,0 @@
1
- import {
2
- CustomLinkComponent,
3
- PoweredByLink,
4
- TableOfContents as ElementsTableOfContents,
5
- } from '@stoplight/elements-core';
6
- import { BoxProps, Flex } from '@stoplight/mosaic';
7
- import * as React from 'react';
8
-
9
- import { ProjectTableOfContents } from '../../types';
10
-
11
- export type TableOfContentsProps = BoxProps<'div'> & {
12
- activeId: string;
13
- tableOfContents: ProjectTableOfContents;
14
- Link: CustomLinkComponent;
15
- collapseTableOfContents?: boolean;
16
- externalScrollbar?: boolean;
17
- onLinkClick?(): void;
18
- };
19
-
20
- export const TableOfContents = ({
21
- tableOfContents,
22
- activeId,
23
- Link,
24
- collapseTableOfContents = false,
25
- externalScrollbar,
26
- onLinkClick,
27
- ...boxProps
28
- }: TableOfContentsProps) => {
29
- return (
30
- <Flex bg="canvas-100" {...boxProps} flexDirection="col" maxH="full">
31
- <Flex flexGrow flexShrink overflowY="auto">
32
- <ElementsTableOfContents
33
- tree={tableOfContents.items}
34
- activeId={activeId}
35
- Link={Link}
36
- maxDepthOpenByDefault={collapseTableOfContents ? 0 : 1}
37
- externalScrollbar={externalScrollbar}
38
- onLinkClick={onLinkClick}
39
- />
40
- </Flex>
41
-
42
- {tableOfContents.hide_powered_by ? null : (
43
- <PoweredByLink
44
- source={activeId}
45
- pathname={typeof window !== 'undefined' ? window.location.pathname : ''}
46
- packageType="elements-dev-portal"
47
- />
48
- )}
49
- </Flex>
50
- );
51
- };
@@ -1,22 +0,0 @@
1
- import { Box, Flex, Icon } from '@stoplight/mosaic';
2
- import React from 'react';
3
-
4
- export const UpgradeToStarter = () => (
5
- <Flex
6
- as="a"
7
- href="https://stoplight.io/pricing/"
8
- target="_blank"
9
- rel="noreferrer noopener"
10
- justify="center"
11
- alignItems="center"
12
- w="full"
13
- minH="screen"
14
- color="muted"
15
- flexDirection="col"
16
- >
17
- <Icon icon={['fas', 'exclamation-triangle']} size="4x" />
18
- <Box pt={3}>
19
- Please upgrade your Stoplight Workspace to the Starter Plan to use Elements Dev Portal in production.
20
- </Box>
21
- </Flex>
22
- );
package/src/consts.ts DELETED
@@ -1,32 +0,0 @@
1
- const ROOT_CACHE_KEY = '@stoplight/elements-dev-portal/client-query';
2
-
3
- export const devPortalCacheKeys = {
4
- all: [ROOT_CACHE_KEY] as const,
5
-
6
- projects: () => [ROOT_CACHE_KEY, 'projects'] as const,
7
- project: (projectId: string) => [...devPortalCacheKeys.projects(), projectId] as const,
8
- projectsList: () => [...devPortalCacheKeys.projects(), 'list'] as const,
9
- projectDetails: (projectId: string) => [...devPortalCacheKeys.project(projectId), 'details'] as const,
10
-
11
- branches: (projectId: string) => [...devPortalCacheKeys.project(projectId), 'branches'] as const,
12
- branch: (projectId: string, branch: string) => [...devPortalCacheKeys.branches(projectId), branch] as const,
13
- branchesList: (projectId: string) => [...devPortalCacheKeys.branches(projectId), 'list'] as const,
14
- branchDetails: (projectId: string, branch: string) =>
15
- [...devPortalCacheKeys.branch(projectId, branch), 'details'] as const,
16
- branchTOC: (projectId: string, branch: string) => [...devPortalCacheKeys.branch(projectId, branch), 'toc'] as const,
17
-
18
- branchNodes: (projectId: string, branch: string) =>
19
- [...devPortalCacheKeys.branch(projectId, branch), 'nodes'] as const,
20
- branchNode: (projectId: string, branch: string, node: string) =>
21
- [...devPortalCacheKeys.branchNodes(projectId, branch), node] as const,
22
- branchNodesList: (projectId: string, branch: string) =>
23
- [...devPortalCacheKeys.branchNodes(projectId, branch), 'list'] as const,
24
- branchNodeDetails: (projectId: string, branch: string, node: string) =>
25
- [...devPortalCacheKeys.branchNode(projectId, branch, node), 'details'] as const,
26
-
27
- search: () => [...devPortalCacheKeys.all, 'search'],
28
- searchNodes: (filters: { projectIds?: string[]; branchSlug?: string; workspaceId?: string; search?: string }) => [
29
- ...devPortalCacheKeys.search(),
30
- filters,
31
- ],
32
- };
@@ -1,78 +0,0 @@
1
- import '@testing-library/jest-dom';
2
-
3
- import { render, screen } from '@testing-library/react';
4
- import fetchMock from 'jest-fetch-mock';
5
- import * as React from 'react';
6
-
7
- import branches from '../__fixtures__/branches.json';
8
- import nodeContent from '../__fixtures__/node-content.json';
9
- import tableOfContents from '../__fixtures__/table-of-contents.json';
10
- import { StoplightProject } from './StoplightProject';
11
-
12
- describe('Stoplight Project', () => {
13
- beforeEach(() => {
14
- fetchMock.mockResponse(request => {
15
- if (request.url.match(/\/api\/v1\/projects\/[a-zA-Z0-9_.-]+\/table-of-contents/i)) {
16
- return Promise.resolve({
17
- body: JSON.stringify(tableOfContents),
18
- status: 200,
19
- statusText: 'OK',
20
- headers: [],
21
- });
22
- } else if (request.url.match(/\/api\/v1\/projects\/[a-zA-Z0-9_.-]+\/nodes/i)) {
23
- return Promise.resolve({
24
- body: JSON.stringify(nodeContent),
25
- status: 200,
26
- statusText: 'OK',
27
- headers: [],
28
- });
29
- } else if (request.url.match(/\/api\/v1\/projects\/[a-zA-Z0-9_.-]+\/branches/i)) {
30
- return Promise.resolve({
31
- body: JSON.stringify(branches),
32
- status: 200,
33
- statusText: 'OK',
34
- headers: [],
35
- });
36
- } else {
37
- return Promise.resolve({ status: 404, statusText: 'Not Found', headers: [], body: '' });
38
- }
39
- });
40
- fetchMock.enableMocks();
41
- });
42
-
43
- afterEach(() => {
44
- fetchMock.disableMocks();
45
- });
46
-
47
- it('loads correctly using memory router', async () => {
48
- render(<StoplightProject router="memory" projectId="cHJqOjYwNjYx" platformUrl="https://stoplight.io" />);
49
-
50
- expect(
51
- await screen.findByText(
52
- 'Markdown is supported in descriptions. Add information here for users to get accustomed to endpoints',
53
- {},
54
- { timeout: 10000 },
55
- ),
56
- ).toBeInTheDocument();
57
- });
58
-
59
- it('loads correctly using static router', async () => {
60
- render(
61
- <StoplightProject
62
- router="static"
63
- projectId="cHJqOjYwNjYx"
64
- basePath=""
65
- staticRouterPath="/b3A6Mzg5NDM2-create-todo"
66
- platformUrl="https://stoplight.io"
67
- />,
68
- );
69
-
70
- expect(
71
- await screen.findByText(
72
- 'Markdown is supported in descriptions. Add information here for users to get accustomed to endpoints',
73
- {},
74
- { timeout: 10000 },
75
- ),
76
- ).toBeInTheDocument();
77
- });
78
- });
@@ -1,28 +0,0 @@
1
- import { Story } from '@storybook/react';
2
- import * as React from 'react';
3
-
4
- import { StoplightProject, StoplightProjectProps } from './StoplightProject';
5
-
6
- export default {
7
- title: 'Public/StoplightProject',
8
- component: StoplightProject,
9
- argTypes: {
10
- projectId: { table: { category: 'Input' } },
11
- hideTryIt: { table: { category: 'Input' } },
12
- hideMocking: { table: { category: 'Input' } },
13
- basePath: { table: { category: 'Routing' } },
14
- router: { table: { category: 'Routing' } },
15
- platformUrl: { table: { category: 'Advanced' } },
16
- },
17
- args: {
18
- router: 'memory',
19
- platformUrl: 'https://stoplight.io',
20
- },
21
- };
22
-
23
- export const Playground: Story<StoplightProjectProps> = args => <StoplightProject {...args} />;
24
- Playground.storyName = 'Studio Demo';
25
- Playground.args = {
26
- projectId: 'cHJqOjYwNjYx',
27
- platformUrl: 'https://stoplight.io',
28
- };
@@ -1,213 +0,0 @@
1
- import {
2
- findFirstNode,
3
- ReactRouterMarkdownLink,
4
- RouterTypeContext,
5
- RoutingProps,
6
- SidebarLayout,
7
- useRouter,
8
- withStyles,
9
- } from '@stoplight/elements-core';
10
- import * as React from 'react';
11
- import { Link, Redirect, Route, useHistory, useParams } from 'react-router-dom';
12
-
13
- import { BranchSelector } from '../components/BranchSelector';
14
- import { DevPortalProvider } from '../components/DevPortalProvider';
15
- import { Forbidden } from '../components/Forbidden';
16
- import { Loading } from '../components/Loading';
17
- import { NodeContent } from '../components/NodeContent';
18
- import { NotFound } from '../components/NotFound';
19
- import { TableOfContents } from '../components/TableOfContents';
20
- import { UpgradeToStarter } from '../components/UpgradeToStarter';
21
- import { ResponseError } from '../handlers/getNodeContent';
22
- import { useGetBranches } from '../hooks/useGetBranches';
23
- import { useGetNodeContent } from '../hooks/useGetNodeContent';
24
- import { useGetTableOfContents } from '../hooks/useGetTableOfContents';
25
-
26
- export interface StoplightProjectProps extends RoutingProps {
27
- /**
28
- * The ID of the Stoplight Project.
29
- * @example "d2s6NDE1NTU"
30
- */
31
- projectId: string;
32
- /**
33
- * If your company runs an on-premise deployment of Stoplight,
34
- * set this prop to point the StoplightProject component at the URL of that instance.
35
- */
36
- platformUrl?: string;
37
-
38
- /**
39
- * Allows to hide TryIt component
40
- */
41
- hideTryIt?: boolean;
42
-
43
- /**
44
- * Allows to hide mocking button
45
- */
46
- hideMocking?: boolean;
47
-
48
- /**
49
- * Allows to hide export button
50
- * @default false
51
- */
52
- hideExport?: boolean;
53
-
54
- /**
55
- * If set to true, all table of contents panels will be collapsed.
56
- * @default false
57
- */
58
- collapseTableOfContents?: boolean;
59
-
60
- /**
61
- * Fetch credentials policy for TryIt component
62
- * For more information: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
63
- * @default "omit"
64
- */
65
-
66
- tryItCredentialsPolicy?: 'omit' | 'include' | 'same-origin';
67
-
68
- /**
69
- * URL of a CORS proxy that will be used to send requests in TryIt.
70
- * Provided url will be prepended to an URL of an actual request.
71
- * @default false
72
- */
73
- tryItCorsProxy?: string;
74
- }
75
-
76
- const StoplightProjectImpl: React.FC<StoplightProjectProps> = ({
77
- projectId,
78
- hideTryIt,
79
- hideMocking,
80
- hideExport,
81
- collapseTableOfContents = false,
82
- tryItCredentialsPolicy,
83
- tryItCorsProxy,
84
- }) => {
85
- const { branchSlug = '', nodeSlug = '' } = useParams<{ branchSlug?: string; nodeSlug: string }>();
86
- const history = useHistory();
87
-
88
- const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
89
- const { data: branches } = useGetBranches({ projectId });
90
- const {
91
- data: node,
92
- isLoading: isLoadingNode,
93
- isError,
94
- error: nodeError,
95
- } = useGetNodeContent({
96
- nodeSlug,
97
- projectId,
98
- branchSlug,
99
- });
100
- const container = React.useRef<HTMLDivElement>(null);
101
-
102
- if (!nodeSlug && isTocFetched && tableOfContents?.items) {
103
- const firstNode = findFirstNode(tableOfContents.items);
104
- if (firstNode) {
105
- return <Redirect to={branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}`} />;
106
- }
107
- }
108
-
109
- let elem: JSX.Element;
110
- if (isLoadingNode || !isTocFetched) {
111
- elem = <Loading />;
112
- } else if (isError) {
113
- if (nodeError instanceof ResponseError) {
114
- if (nodeError.code === 402) {
115
- elem = <UpgradeToStarter />;
116
- } else if (nodeError.code === 403) {
117
- elem = <Forbidden />;
118
- } else {
119
- elem = <NotFound />;
120
- }
121
- } else {
122
- elem = <NotFound />;
123
- }
124
- } else if (!node) {
125
- elem = <NotFound />;
126
- } else if (node?.slug && nodeSlug !== node.slug) {
127
- // Handle redirect to node's slug
128
- return <Redirect to={branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}`} />;
129
- } else {
130
- elem = (
131
- <NodeContent
132
- node={node}
133
- Link={ReactRouterMarkdownLink}
134
- hideTryIt={hideTryIt}
135
- hideMocking={hideMocking}
136
- hideExport={hideExport}
137
- tryItCredentialsPolicy={tryItCredentialsPolicy}
138
- tryItCorsProxy={tryItCorsProxy}
139
- />
140
- );
141
- }
142
-
143
- const handleTocClick = () => {
144
- if (container.current) {
145
- container.current.scrollIntoView();
146
- }
147
- };
148
-
149
- return (
150
- <SidebarLayout
151
- ref={container}
152
- sidebar={
153
- <>
154
- {branches && branches.length > 1 ? (
155
- <BranchSelector
156
- branchSlug={branchSlug}
157
- branches={branches}
158
- onChange={branch =>
159
- history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${branch.slug}/${nodeSlug}`)
160
- }
161
- />
162
- ) : null}
163
- {tableOfContents ? (
164
- <TableOfContents
165
- activeId={node?.id || nodeSlug?.split('-')[0] || ''}
166
- tableOfContents={tableOfContents}
167
- Link={Link}
168
- collapseTableOfContents={collapseTableOfContents}
169
- onLinkClick={handleTocClick}
170
- />
171
- ) : null}
172
- </>
173
- }
174
- >
175
- {elem}
176
- </SidebarLayout>
177
- );
178
- };
179
-
180
- const StoplightProjectRouter = ({
181
- platformUrl,
182
- basePath = '/',
183
- staticRouterPath = '',
184
- router = 'history',
185
- ...props
186
- }: StoplightProjectProps) => {
187
- const { Router, routerProps } = useRouter(router, basePath, staticRouterPath);
188
-
189
- return (
190
- <DevPortalProvider platformUrl={platformUrl}>
191
- <RouterTypeContext.Provider value={router}>
192
- <Router {...routerProps} key={basePath}>
193
- <Route path="/branches/:branchSlug/:nodeSlug" exact>
194
- <StoplightProjectImpl {...props} />
195
- </Route>
196
-
197
- <Route path="/:nodeSlug" exact>
198
- <StoplightProjectImpl {...props} />
199
- </Route>
200
-
201
- <Route path="/" exact>
202
- <StoplightProjectImpl {...props} />
203
- </Route>
204
- </Router>
205
- </RouterTypeContext.Provider>
206
- </DevPortalProvider>
207
- );
208
- };
209
-
210
- /**
211
- * The StoplightProject component displays a traditional documentation UI for an existing Stoplight Project.
212
- */
213
- export const StoplightProject = withStyles(StoplightProjectRouter);
@@ -1,30 +0,0 @@
1
- import fetchMock from 'jest-fetch-mock';
2
-
3
- import { getBranches } from '../getBranches';
4
-
5
- describe('getBranches', () => {
6
- beforeEach(() => {
7
- fetchMock.resetMocks();
8
- localStorage.clear();
9
- });
10
-
11
- it('should URI encode the parameters in the request URL', async () => {
12
- fetchMock.mockResolvedValue(
13
- new Response('{}', {
14
- status: 200,
15
- statusText: 'OK',
16
- headers: [],
17
- }),
18
- );
19
-
20
- await getBranches({
21
- projectId: 'some/slash',
22
- });
23
-
24
- expect(fetchMock).toBeCalledWith('https://stoplight.io/api/v1/projects/some%2Fslash/branches', {
25
- headers: expect.objectContaining({
26
- 'Stoplight-Elements-Version': expect.any(String),
27
- }),
28
- });
29
- });
30
- });
@@ -1,35 +0,0 @@
1
- import fetchMock from 'jest-fetch-mock';
2
-
3
- import { getNodeContent } from '../getNodeContent';
4
-
5
- describe('getNodeContent', () => {
6
- beforeEach(() => {
7
- fetchMock.resetMocks();
8
- localStorage.clear();
9
- });
10
-
11
- it('should URI encode the parameters in the request URL', async () => {
12
- fetchMock.mockResolvedValue(
13
- new Response('{}', {
14
- status: 200,
15
- statusText: 'OK',
16
- headers: [],
17
- }),
18
- );
19
-
20
- await getNodeContent({
21
- nodeSlug: 'node&slug',
22
- projectId: 'some/slash',
23
- branchSlug: 'test+branch',
24
- });
25
-
26
- expect(fetchMock).toBeCalledWith(
27
- 'https://stoplight.io/api/v1/projects/some%2Fslash/nodes/node%26slug?branch=test%2Bbranch',
28
- {
29
- headers: expect.objectContaining({
30
- 'Stoplight-Elements-Version': expect.any(String),
31
- }),
32
- },
33
- );
34
- });
35
- });