From 9ee9132d8b4b41cbec7f8ceede2ebfcf2524e9b3 Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Mon, 15 Apr 2019 11:39:11 +0200 Subject: [PATCH] SONAR-11955 Allow more levels in embedded documentation, and make it DRYer by re-using logic from sonar-docs --- server/sonar-web/package.json | 4 +- .../js/app/styles/components/list-groups.css | 18 ++- .../js/apps/documentation/components/App.tsx | 6 +- .../js/apps/documentation/components/Menu.tsx | 90 +++++++-------- .../documentation/components/MenuBlock.tsx | 77 ++++++++++--- .../documentation/components/MenuItem.tsx | 11 +- .../components/SearchResults.tsx | 6 +- .../apps/documentation/components/Sidebar.tsx | 5 +- .../components/__tests__/App-test.tsx | 44 +++++++- .../components/__tests__/Menu-test.tsx | 20 ++-- .../components/__tests__/MenuBlock-test.tsx | 105 ++++++++++-------- .../components/__tests__/MenuItem-test.tsx | 39 +++++++ .../__tests__/__snapshots__/App-test.tsx.snap | 42 ++++++- .../__snapshots__/Menu-test.tsx.snap | 77 +++++++++++-- .../__snapshots__/MenuBlock-test.tsx.snap | 71 ++++++++++-- .../__snapshots__/MenuItem-test.tsx.snap | 43 +++++++ .../src/main/js/apps/documentation/utils.ts | 34 +----- 17 files changed, 503 insertions(+), 189 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index aa29cfae17b..42c94db162d 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -178,7 +178,9 @@ ], "moduleNameMapper": { "^.+\\.(md|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/config/jest/FileStub.js", - "^.+\\.css$": "/config/jest/CSSStub.js" + "^.+\\.css$": "/config/jest/CSSStub.js", + "^Docs/@types/types$": "/../sonar-docs/src/@types/types.d.ts", + "^Docs/(.*)": "/../sonar-docs/src/$1" }, "setupFiles": [ "/config/polyfills.js", diff --git a/server/sonar-web/src/main/js/app/styles/components/list-groups.css b/server/sonar-web/src/main/js/app/styles/components/list-groups.css index 28dd7b44ab2..9217a8d7eee 100644 --- a/server/sonar-web/src/main/js/app/styles/components/list-groups.css +++ b/server/sonar-web/src/main/js/app/styles/components/list-groups.css @@ -22,13 +22,29 @@ padding-left: 0; } -.list-group-item { +.list-group-item, +button.list-group-item { position: relative; z-index: var(--normalZIndex); display: block; margin-bottom: -1px; padding: 5px 10px; border: 1px solid transparent; + width: 100%; + box-sizing: border-box; + text-align: left; +} + +.list-group-item.depth-1 { + padding-left: 31px; +} + +.list-group-item.depth-2 { + padding-left: 51px; +} + +.list-group-item.depth-3 { + padding-left: 71px; } .list-group-item:last-child { diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx index 27e3cc941e8..00933eee7e4 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import Helmet from 'react-helmet'; import { Link } from 'react-router'; +import { DocNavigationItem } from 'Docs/@types/types'; import * as navigationTreeSonarQube from 'Docs/../static/SonarQubeNavigationTree.json'; import * as navigationTreeSonarCloud from 'Docs/../static/SonarCloudNavigationTree.json'; import Sidebar from './Sidebar'; @@ -31,7 +32,6 @@ import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock'; import { translate } from '../../../helpers/l10n'; import { isSonarCloud } from '../../../helpers/system'; import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages'; -import { DocsNavigationItem } from '../utils'; import '../styles.css'; interface Props { @@ -52,8 +52,8 @@ export default class App extends React.PureComponent { render() { const tree = isSonarCloud() - ? ((navigationTreeSonarCloud as any).default as DocsNavigationItem[]) - : ((navigationTreeSonarQube as any).default as DocsNavigationItem[]); + ? ((navigationTreeSonarCloud as any).default as DocNavigationItem[]) + : ((navigationTreeSonarQube as any).default as DocNavigationItem[]); const { splat = '' } = this.props.params; const page = this.pages.find(p => p.url === '/' + splat); const mainTitle = translate('documentation.page_title'); diff --git a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx b/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx index 5e79aaee92b..188eba9e078 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx @@ -18,79 +18,71 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import MenuBlock from './MenuBlock'; -import { MenuItem } from './MenuItem'; -import { MenuExternalLink } from './MenuExternalLink'; +import { DocNavigationItem } from 'Docs/@types/types'; import { - DocumentationEntry, - DocsNavigationBlock, - getNodeFromUrl, isDocsNavigationBlock, isDocsNavigationExternalLink, - DocsNavigationItem -} from '../utils'; + getOpenChainFromPath +} from 'Docs/components/navTreeUtils'; +import MenuBlock from './MenuBlock'; +import { MenuItem } from './MenuItem'; +import { MenuExternalLink } from './MenuExternalLink'; +import { DocumentationEntry, getNodeFromUrl } from '../utils'; interface Props { - navigation: DocsNavigationItem[]; + navigation: DocNavigationItem[]; pages: DocumentationEntry[]; splat: string; } interface State { - openBlockTitle: string; + openChain: DocNavigationItem[]; } export default class Menu extends React.PureComponent { constructor(props: Props) { super(props); this.state = { - openBlockTitle: this.getOpenBlockFromLocation(this.props.splat) + openChain: getOpenChainFromPath(this.props.splat, this.props.navigation) }; } componentWillReceiveProps(nextProps: Props) { if (this.props.splat !== nextProps.splat) { - this.setState({ openBlockTitle: this.getOpenBlockFromLocation(nextProps.splat) }); + this.setState({ openChain: getOpenChainFromPath(nextProps.splat, nextProps.navigation) }); } } - getOpenBlockFromLocation(splat: string) { - const element = this.props.navigation.find( - item => isDocsNavigationBlock(item) && item.children.some(child => '/' + splat === child) - ); - return element ? (element as DocsNavigationBlock).title : ''; - } - - toggleBlock = (title: string) => { - this.setState(state => ({ openBlockTitle: state.openBlockTitle === title ? '' : title })); - }; - render() { - return this.props.navigation.map(item => { - if (isDocsNavigationBlock(item)) { - return ( - - ); - } - if (isDocsNavigationExternalLink(item)) { - return ; - } - return ( - - ); - }); + const { openChain } = this.state; + return ( + <> + {this.props.navigation.map(item => { + if (isDocsNavigationBlock(item)) { + return ( + + ); + } + if (isDocsNavigationExternalLink(item)) { + return ; + } + return ( + + ); + })} + + ); } } diff --git a/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx b/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx index 12efdae21d3..0a350e98ce3 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx @@ -18,40 +18,85 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import * as classNames from 'classnames'; +import { DocsNavigationBlock, DocNavigationItem } from 'Docs/@types/types'; +import { isDocsNavigationBlock } from 'Docs/components/navTreeUtils'; import { MenuItem } from './MenuItem'; -import { DocumentationEntry, DocsNavigationBlock, getNodeFromUrl } from '../utils'; import OpenCloseIcon from '../../../components/icons-components/OpenCloseIcon'; +import { ButtonLink } from '../../../components/ui/buttons'; +import { DocumentationEntry, getNodeFromUrl } from '../utils'; interface Props { block: DocsNavigationBlock; - onToggle: (title: string) => void; - open: boolean; + depth?: number; + openByDefault: boolean; + openChain: DocNavigationItem[]; pages: DocumentationEntry[]; splat: string; title: string; } -export default class MenuBlock extends React.PureComponent { - handleClick = (event: React.MouseEvent) => { - event.stopPropagation(); - event.preventDefault(); - this.props.onToggle(this.props.title); +interface State { + open: boolean; +} + +export default class MenuBlock extends React.PureComponent { + state: State; + + constructor(props: Props) { + super(props); + this.state = { + open: props.openByDefault !== undefined ? props.openByDefault : false + }; + } + + handleClick = () => { + this.setState(prevState => ({ + open: !prevState.open + })); + }; + + renderMenuItems = (block: DocsNavigationBlock): React.ReactNode => { + const { depth = 0, openChain, pages, splat } = this.props; + return block.children.map(item => { + if (typeof item === 'string') { + return ( + + ); + } else if (isDocsNavigationBlock(item)) { + return ( + + ); + } else { + return null; + } + }); }; render() { - const { open, block, pages, title, splat } = this.props; + const { block, depth = 0, title } = this.props; + const { open } = this.state; + const maxDepth = Math.min(depth, 3); return ( <> - + 0 })} + onClick={this.handleClick}>

- + {title}

-
- {open && - block.children.map(item => ( - - ))} + + {open && this.renderMenuItems(block)} ); } diff --git a/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx b/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx index 7ae2df5626e..61a82f4ca0a 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx @@ -20,25 +20,26 @@ import * as React from 'react'; import * as classNames from 'classnames'; import { Link } from 'react-router'; +import { testPathAgainstUrl } from 'Docs/components/navTreeUtils'; import { DocumentationEntry } from '../utils'; interface Props { - indent: boolean; + depth?: number; node: DocumentationEntry | undefined; splat: string; } -export function MenuItem({ indent, node, splat }: Props) { +export function MenuItem({ depth = 0, node, splat }: Props) { if (!node) { return null; } - const active = node.url === '/' + splat; + const active = testPathAgainstUrl(node.url, splat); + const maxDepth = Math.min(depth, 3); return ( 0 })} key={node.url} - style={{ paddingLeft: indent ? 31 : 10 }} to={'/documentation' + node.url}>

{node.navTitle || node.title}

diff --git a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx b/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx index e2db1c0bf6b..70756e20ab0 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx @@ -20,11 +20,13 @@ import * as React from 'react'; import lunr, { LunrBuilder, LunrIndex, LunrToken } from 'lunr'; import { sortBy } from 'lodash'; +import { getUrlsList } from 'Docs/components/navTreeUtils'; +import { DocNavigationItem } from 'Docs/@types/types'; import SearchResultEntry, { SearchResult } from './SearchResultEntry'; -import { DocumentationEntry, getUrlsList, DocsNavigationItem } from '../utils'; +import { DocumentationEntry } from '../utils'; interface Props { - navigation: DocsNavigationItem[]; + navigation: DocNavigationItem[]; pages: DocumentationEntry[]; query: string; splat: string; diff --git a/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx b/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx index 5dfdfe20e7f..c3d3df60e3d 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx @@ -18,13 +18,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { DocNavigationItem } from 'Docs/@types/types'; import Menu from './Menu'; import SearchResults from './SearchResults'; -import { DocumentationEntry, DocsNavigationItem } from '../utils'; +import { DocumentationEntry } from '../utils'; import SearchBox from '../../../components/controls/SearchBox'; interface Props { - navigation: DocsNavigationItem[]; + navigation: DocNavigationItem[]; pages: DocumentationEntry[]; splat: string; } diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx index 82d70d4876a..3f211b75b3e 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx @@ -19,8 +19,9 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import { addSideBarClass, removeSideBarClass } from '../../../../helpers/pages'; import App from '../App'; +import { addSideBarClass, removeSideBarClass } from '../../../../helpers/pages'; +import { isSonarCloud } from '../../../../helpers/system'; jest.mock('../../../../components/common/ScreenPositionHelper', () => ({ default: class ScreenPositionHelper extends React.Component<{ @@ -33,12 +34,29 @@ jest.mock('../../../../components/common/ScreenPositionHelper', () => ({ } })); +jest.mock('../../../../helpers/system', () => ({ + isSonarCloud: jest.fn().mockReturnValue(false) +})); + jest.mock( 'Docs/../static/SonarQubeNavigationTree.json', () => [ { title: 'SonarQube', - children: ['/lorem/ipsum/'] + children: [ + '/lorem/ipsum/', + { + title: 'Child category', + children: [ + '/lorem/ipsum/dolor', + { + title: 'Grandchild category', + children: ['/lorem/ipsum/sit'] + }, + '/lorem/ipsum/amet' + ] + } + ] } ], { virtual: true } @@ -49,7 +67,20 @@ jest.mock( () => [ { title: 'SonarCloud', - children: ['/lorem/ipsum/'] + children: [ + '/lorem/ipsum/', + { + title: 'Child category', + children: [ + '/lorem/ipsum/dolor', + { + title: 'Grandchild category', + children: ['/lorem/ipsum/sit'] + }, + '/lorem/ipsum/amet' + ] + } + ] } ], { virtual: true } @@ -67,7 +98,7 @@ jest.mock('../../pages', () => { }; }); -it('should render correctly', () => { +it('should render correctly for SonarQube', () => { const wrapper = shallowRender(); expect(wrapper).toMatchSnapshot(); @@ -79,6 +110,11 @@ it('should render correctly', () => { expect(removeSideBarClass).toBeCalled(); }); +it('should render correctly for SonarCloud', () => { + (isSonarCloud as jest.Mock).mockReturnValue(true); + expect(shallowRender()).toMatchSnapshot(); +}); + it("should show a 404 if the page doesn't exist", () => { const wrapper = shallowRender({ params: { splat: 'unknown' } }); expect(wrapper).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx index 41cb6a416c7..ba3cb93e0a1 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx @@ -44,13 +44,15 @@ const pages = [ ]; it('should render hierarchical menu', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); + const wrapper = shallow( + + ); + + expect(wrapper).toMatchSnapshot(); + wrapper.setProps({ splat: 'baz/bar' }); + expect(wrapper).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx index 8853a5a04ef..ddcd636ca58 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx @@ -20,57 +20,70 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import MenuBlock from '../MenuBlock'; - -const block = { - title: 'Foo', - children: ['/bar/', '/baz/'] -}; - -const pages = [ - { - content: 'bar', - relativeName: '/bar/', - text: 'bar', - title: 'Bar', - navTitle: undefined, - url: '/bar/' - }, - { - content: 'baz', - relativeName: '/baz/', - text: 'baz', - title: 'baz', - navTitle: 'baznav', - url: '/baz/' - } -]; +import { click } from '../../../../helpers/testUtils'; it('should render a closed menu block', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); + expect(shallowRender()).toMatchSnapshot(); }); it('should render an opened menu block', () => { + expect(shallowRender({ openByDefault: true })).toMatchSnapshot(); +}); + +it('should not render a high depth differently than a depth of 3', () => { expect( - shallow( - - ) + shallowRender({ block: { title: 'Foo', children: ['/foo'] }, depth: 6 }) ).toMatchSnapshot(); }); + +it('can be opened and closed', () => { + const wrapper = shallowRender(); + expect(wrapper.state('open')).toBe(false); + click(wrapper.find('ButtonLink')); + expect(wrapper.state('open')).toBe(true); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx new file mode 100644 index 00000000000..8f3e327a172 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { MenuItem } from '../MenuItem'; +import { DocumentationEntry } from '../../utils'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should render correctly if the current node matches the splat', () => { + expect(shallowRender({ splat: 'bar' })).toMatchSnapshot(); +}); + +it('should not render a high depth differently than a depth of 3', () => { + expect(shallowRender({ depth: 6 })).toMatchSnapshot(); +}); + +function shallowRender(props = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap index 5537387b421..972604838ab 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap @@ -1,6 +1,44 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly 1`] = ` +exports[`should render correctly for SonarCloud 1`] = ` +
+ + + + +
+
+
+ + +
+
+
+
+`; + +exports[`should render correctly for SonarQube 1`] = `
@@ -43,7 +81,7 @@ exports[`should render correctly 1`] = `
`; -exports[`should render correctly 2`] = ` +exports[`should render correctly for SonarQube 2`] = `
, + /> , -] + /> + +`; + +exports[`should render hierarchical menu 2`] = ` + + + + `; diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap index 0ee9f2fbead..6d5600201c8 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap @@ -1,10 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`should not render a high depth differently than a depth of 3 1`] = ` + + +

+ + Foo +

+
+
+`; + exports[`should render a closed menu block 1`] = ` -

- Foobarbaz + Foo

-
+
`; exports[`should render an opened menu block 1`] = ` -

Foo

-
+ +
`; diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap new file mode 100644 index 00000000000..795f0dbdd79 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should not render a high depth differently than a depth of 3 1`] = ` + +

+ +`; + +exports[`should render correctly 1`] = ` + +

+ +`; + +exports[`should render correctly if the current node matches the splat 1`] = ` + +

+ +`; diff --git a/server/sonar-web/src/main/js/apps/documentation/utils.ts b/server/sonar-web/src/main/js/apps/documentation/utils.ts index 88b831c7325..d0970169cad 100644 --- a/server/sonar-web/src/main/js/apps/documentation/utils.ts +++ b/server/sonar-web/src/main/js/apps/documentation/utils.ts @@ -17,20 +17,10 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { sortBy, flatten } from 'lodash'; +import { sortBy } from 'lodash'; export type DocumentationEntryScope = 'sonarqube' | 'sonarcloud' | 'static'; -export interface DocsNavigationBlock { - title: string; - children: string[]; -} - -export interface DocsNavigationExternalLink { - title: string; - url: string; -} - export interface DocumentationEntry { content: string; relativeName: string; @@ -40,28 +30,6 @@ export interface DocumentationEntry { url: string; } -export type DocsNavigationItem = string | DocsNavigationBlock | DocsNavigationExternalLink; - -export function isDocsNavigationBlock(item: DocsNavigationItem): item is DocsNavigationBlock { - return typeof item === 'object' && !(item as any).url; -} - -export function isDocsNavigationExternalLink( - item: DocsNavigationItem -): item is DocsNavigationExternalLink { - return typeof item === 'object' && (item as any).url; -} - -export function getUrlsList(navigation: DocsNavigationItem[]): string[] { - return flatten( - navigation - .filter(item => !isDocsNavigationExternalLink(item)) - .map((item: string | DocsNavigationBlock) => - isDocsNavigationBlock(item) ? item.children : [item] - ) - ); -} - export function getNodeFromUrl(pages: DocumentationEntry[], url: string) { return pages.find(p => p.url === url); } -- 2.39.5