export interface DocVersion {
current: boolean;
+ lts?: boolean;
value: string;
}
* 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 { Link } from 'gatsby';
+import * as React from 'react';
import CategoryBlockLink from './CategoryBlockLink';
import ExternalLink from './ExternalLink';
-import PageLink from './PageLink';
-import Search from './Search';
-import SearchEntryResult from './SearchEntryResult';
-import VersionSelect from './VersionSelect';
import DownloadIcon from './icons/DownloadIcon';
import {
getNavTree,
+ getOpenChainFromPath,
isDocsNavigationBlock,
isDocsNavigationExternalLink,
- getOpenChainFromPath,
testPathAgainstUrl
} from './navTreeUtils';
+import PageLink from './PageLink';
+import Search from './Search';
+import SearchEntryResult from './SearchEntryResult';
+import VersionSelect from './VersionSelect';
+import { DocNavigationItem, DocVersion, SearchResult } from '../@types/types';
import { MarkdownRemark } from '../@types/graphql-types';
-import { SearchResult, DocVersion, DocNavigationItem } from '../@types/types';
interface Props {
location: Location;
render() {
const { versions } = this.state;
+ const { version } = this.props;
+
const currentVersion = versions.find(v => v.current);
+ const ltsVersion = versions.find(v => Boolean(v.lts));
+
const selectedVersionValue =
- currentVersion && this.props.version === 'latest' ? currentVersion.value : this.props.version;
+ currentVersion && version === 'latest' ? currentVersion.value : version;
const isOnCurrentVersion = !currentVersion || selectedVersionValue === currentVersion.value;
+ const isOnLTSVersion = ltsVersion && version === ltsVersion.value;
+
return (
<div className="page-sidebar">
<div className="sidebar-header">
<img
alt="Continuous Code Quality"
className="sidebar-logo"
- src={`/${this.props.version}/images/SonarQubeIcon.svg`}
+ src={`/${version}/images/SonarQubeIcon.svg`}
title="Continuous Code Quality"
width="160"
/>
selectedVersionValue={selectedVersionValue}
versions={versions}
/>
- {this.state.loaded && !isOnCurrentVersion && (
+ {this.state.loaded && !isOnCurrentVersion && !isOnLTSVersion && (
<div className="alert alert-warning">
- This is an archived version of the doc for{' '}
- <b>SonarQube version {this.props.version}</b>. <a href="/">See Documentation</a> for
- current functionnality.
+ This is an archived version of the doc for <b>SonarQube version {version}</b>.{' '}
+ <a href="/">See Documentation</a> for current functionnality.
</div>
)}
</div>
<DownloadIcon /> SonarQube
</a>
<a href="https://community.sonarsource.com/" rel="noopener noreferrer" target="_blank">
- <img alt="Community" src={`/${this.props.version}/images/community.svg`} /> Community
+ <img alt="Community" src={`/${version}/images/community.svg`} /> Community
</a>
<a
className="icon-only"
href="https://twitter.com/SonarQube"
rel="noopener noreferrer"
target="_blank">
- <img alt="Twitter" src={`/${this.props.version}/images/twitter.svg`} />
+ <img alt="Twitter" src={`/${version}/images/twitter.svg`} />
</a>
<a
className="icon-only"
href="https://www.sonarsource.com/resources/product-news/"
rel="noopener noreferrer"
target="_blank">
- <img alt="Product News" src={`/${this.props.version}/images/newspaper.svg`} />
+ <img alt="Product News" src={`/${version}/images/newspaper.svg`} />
<span className="tooltip">Product News</span>
</a>
</div>
return (
<li key={version.value}>
<a href={version.current ? '/' : '/' + version.value}>
- <span className={version.current ? 'current' : ''}>{version.value}</span>
+ <span className={version.current || version.lts ? 'current' : ''}>
+ {version.value + (version.lts ? ' LTS' : '')}
+ </span>
</a>
</li>
);
beforeEach(() => {
(fetch as FetchMock).resetMocks();
(fetch as FetchMock).mockResponse(`[
- { "value": "2.0", "current": true },
+ { "value": "3.0", "current": true },
+ { "value": "2.0", "current": false, "lts": true },
{ "value": "1.0", "current": false }
]`);
});
-it('should render correctly', () => {
+it('should render correctly', async () => {
const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
+ await new Promise(setImmediate);
+
+ expect(wrapper).toMatchSnapshot('default');
+ expect(wrapper.setProps({ version: '1.0' })).toMatchSnapshot('show warning');
+ expect(wrapper.setProps({ version: '2.0' })).toMatchSnapshot('lts');
});
function shallowRender(props: Partial<Sidebar['props']> = {}) {
- return shallow(
+ return shallow<Sidebar>(
<Sidebar
location={{ pathname: '/foo/baz/foo/bar' } as Location}
pages={[
}
} as MarkdownRemark
]}
- version="2.0"
+ version="3.0"
{...props}
/>
);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import OutsideClickHandler from '../OutsideClickHandler';
+import VersionSelect from '../VersionSelect';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+
+ const wrapper = shallowRender();
+ wrapper.setState({ open: true });
+ expect(wrapper).toMatchSnapshot('open');
+
+ expect(shallowRender({ isOnCurrentVersion: true })).toMatchSnapshot('on current version');
+});
+
+it('should handle open/closing the list', () => {
+ const wrapper = shallowRender();
+
+ wrapper.find('button').simulate('click');
+ expect(wrapper.state().open).toBe(true);
+ wrapper.find('button').simulate('click');
+ expect(wrapper.state().open).toBe(false);
+
+ wrapper.setState({ open: true });
+ wrapper.find(OutsideClickHandler).prop('onClickOutside')();
+ expect(wrapper.state().open).toBe(false);
+});
+
+function shallowRender(props: Partial<VersionSelect['props']> = {}) {
+ return shallow<VersionSelect>(
+ <VersionSelect
+ isOnCurrentVersion={false}
+ selectedVersionValue="1.0"
+ versions={[
+ { value: '3.0', current: true },
+ { value: '2.0', current: false, lts: true },
+ { value: '1.0', current: false }
+ ]}
+ {...props}
+ />
+ );
+}
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly 1`] = `
+exports[`should render correctly: default 1`] = `
<div
className="page-sidebar"
>
<img
alt="Continuous Code Quality"
className="sidebar-logo"
- src="/2.0/images/SonarQubeIcon.svg"
+ src="/3.0/images/SonarQubeIcon.svg"
title="Continuous Code Quality"
width="160"
/>
</ForwardRef>
<VersionSelect
isOnCurrentVersion={true}
+ selectedVersionValue="3.0"
+ versions={
+ Array [
+ Object {
+ "current": true,
+ "value": "3.0",
+ },
+ Object {
+ "current": false,
+ "lts": true,
+ "value": "2.0",
+ },
+ Object {
+ "current": false,
+ "value": "1.0",
+ },
+ ]
+ }
+ />
+ </div>
+ <div
+ className="page-indexes"
+ >
+ <Search
+ navigation={
+ Array [
+ "/foo/",
+ Object {
+ "children": Array [
+ "/foo/bar/",
+ "/foo/baz/",
+ Object {
+ "children": Array [
+ "/foo/baz/bar/",
+ "/foo/baz/foo/",
+ Object {
+ "children": Array [
+ "/foo/baz/foo/bar/",
+ "/foo/baz/foo/baz",
+ ],
+ "title": "Foo Baz Foo subs",
+ },
+ ],
+ "title": "Foo Baz subs",
+ },
+ ],
+ "title": "Foo subs",
+ },
+ "/bar/",
+ Object {
+ "children": Array [
+ Object {
+ "title": "External link 1",
+ "url": "http://example.com/1",
+ },
+ "/bar/foo/",
+ ],
+ "title": "Bar subs",
+ },
+ Object {
+ "title": "External link 2",
+ "url": "http://example.com/2",
+ },
+ ]
+ }
+ onResultsChange={[Function]}
+ pages={
+ Array [
+ Object {
+ "fields": Object {
+ "slug": "/foo/",
+ },
+ "frontmatter": Object {
+ "title": "Foo",
+ },
+ },
+ Object {
+ "fields": Object {
+ "slug": "/foo/baz/bar",
+ },
+ "frontmatter": Object {
+ "title": "Foo Baz Bar",
+ },
+ },
+ Object {
+ "fields": Object {
+ "slug": "/bar/",
+ },
+ "frontmatter": Object {
+ "title": "Bar",
+ },
+ },
+ ]
+ }
+ />
+ <nav>
+ <PageLink
+ className="page-indexes-link"
+ key="/foo/"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ node={
+ Object {
+ "fields": Object {
+ "slug": "/foo/",
+ },
+ "frontmatter": Object {
+ "title": "Foo",
+ },
+ }
+ }
+ />
+ <CategoryLink
+ key="Foo subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo subs"
+ >
+ <CategoryLink
+ key="Foo Baz subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo Baz subs"
+ >
+ <Component />
+ <CategoryLink
+ key="Foo Baz Foo subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo Baz Foo subs"
+ />
+ </CategoryLink>
+ </CategoryLink>
+ <PageLink
+ className="page-indexes-link"
+ key="/bar/"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ node={
+ Object {
+ "fields": Object {
+ "slug": "/bar/",
+ },
+ "frontmatter": Object {
+ "title": "Bar",
+ },
+ }
+ }
+ />
+ <CategoryLink
+ key="Bar subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={false}
+ title="Bar subs"
+ >
+ <ExternalLink
+ external="http://example.com/1"
+ key="External link 1"
+ title="External link 1"
+ />
+ </CategoryLink>
+ <ExternalLink
+ external="http://example.com/2"
+ key="External link 2"
+ title="External link 2"
+ />
+ </nav>
+ </div>
+ <div
+ className="sidebar-footer"
+ >
+ <a
+ href="https://www.sonarqube.org/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <DownloadIcon />
+ SonarQube
+ </a>
+ <a
+ href="https://community.sonarsource.com/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Community"
+ src="/3.0/images/community.svg"
+ />
+ Community
+ </a>
+ <a
+ className="icon-only"
+ href="https://twitter.com/SonarQube"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Twitter"
+ src="/3.0/images/twitter.svg"
+ />
+ </a>
+ <a
+ className="icon-only"
+ href="https://www.sonarsource.com/resources/product-news/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Product News"
+ src="/3.0/images/newspaper.svg"
+ />
+ <span
+ className="tooltip"
+ >
+ Product News
+ </span>
+ </a>
+ </div>
+</div>
+`;
+
+exports[`should render correctly: lts 1`] = `
+<div
+ className="page-sidebar"
+>
+ <div
+ className="sidebar-header"
+ >
+ <ForwardRef
+ to="/"
+ >
+ <img
+ alt="Continuous Code Quality"
+ className="sidebar-logo"
+ src="/2.0/images/SonarQubeIcon.svg"
+ title="Continuous Code Quality"
+ width="160"
+ />
+ </ForwardRef>
+ <VersionSelect
+ isOnCurrentVersion={false}
selectedVersionValue="2.0"
- versions={Array []}
+ versions={
+ Array [
+ Object {
+ "current": true,
+ "value": "3.0",
+ },
+ Object {
+ "current": false,
+ "lts": true,
+ "value": "2.0",
+ },
+ Object {
+ "current": false,
+ "value": "1.0",
+ },
+ ]
+ }
/>
</div>
<div
</div>
</div>
`;
+
+exports[`should render correctly: show warning 1`] = `
+<div
+ className="page-sidebar"
+>
+ <div
+ className="sidebar-header"
+ >
+ <ForwardRef
+ to="/"
+ >
+ <img
+ alt="Continuous Code Quality"
+ className="sidebar-logo"
+ src="/1.0/images/SonarQubeIcon.svg"
+ title="Continuous Code Quality"
+ width="160"
+ />
+ </ForwardRef>
+ <VersionSelect
+ isOnCurrentVersion={false}
+ selectedVersionValue="1.0"
+ versions={
+ Array [
+ Object {
+ "current": true,
+ "value": "3.0",
+ },
+ Object {
+ "current": false,
+ "lts": true,
+ "value": "2.0",
+ },
+ Object {
+ "current": false,
+ "value": "1.0",
+ },
+ ]
+ }
+ />
+ <div
+ className="alert alert-warning"
+ >
+ This is an archived version of the doc for
+ <b>
+ SonarQube version
+ 1.0
+ </b>
+ .
+
+ <a
+ href="/"
+ >
+ See Documentation
+ </a>
+ for current functionnality.
+ </div>
+ </div>
+ <div
+ className="page-indexes"
+ >
+ <Search
+ navigation={
+ Array [
+ "/foo/",
+ Object {
+ "children": Array [
+ "/foo/bar/",
+ "/foo/baz/",
+ Object {
+ "children": Array [
+ "/foo/baz/bar/",
+ "/foo/baz/foo/",
+ Object {
+ "children": Array [
+ "/foo/baz/foo/bar/",
+ "/foo/baz/foo/baz",
+ ],
+ "title": "Foo Baz Foo subs",
+ },
+ ],
+ "title": "Foo Baz subs",
+ },
+ ],
+ "title": "Foo subs",
+ },
+ "/bar/",
+ Object {
+ "children": Array [
+ Object {
+ "title": "External link 1",
+ "url": "http://example.com/1",
+ },
+ "/bar/foo/",
+ ],
+ "title": "Bar subs",
+ },
+ Object {
+ "title": "External link 2",
+ "url": "http://example.com/2",
+ },
+ ]
+ }
+ onResultsChange={[Function]}
+ pages={
+ Array [
+ Object {
+ "fields": Object {
+ "slug": "/foo/",
+ },
+ "frontmatter": Object {
+ "title": "Foo",
+ },
+ },
+ Object {
+ "fields": Object {
+ "slug": "/foo/baz/bar",
+ },
+ "frontmatter": Object {
+ "title": "Foo Baz Bar",
+ },
+ },
+ Object {
+ "fields": Object {
+ "slug": "/bar/",
+ },
+ "frontmatter": Object {
+ "title": "Bar",
+ },
+ },
+ ]
+ }
+ />
+ <nav>
+ <PageLink
+ className="page-indexes-link"
+ key="/foo/"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ node={
+ Object {
+ "fields": Object {
+ "slug": "/foo/",
+ },
+ "frontmatter": Object {
+ "title": "Foo",
+ },
+ }
+ }
+ />
+ <CategoryLink
+ key="Foo subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo subs"
+ >
+ <CategoryLink
+ key="Foo Baz subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo Baz subs"
+ >
+ <Component />
+ <CategoryLink
+ key="Foo Baz Foo subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={true}
+ title="Foo Baz Foo subs"
+ />
+ </CategoryLink>
+ </CategoryLink>
+ <PageLink
+ className="page-indexes-link"
+ key="/bar/"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ node={
+ Object {
+ "fields": Object {
+ "slug": "/bar/",
+ },
+ "frontmatter": Object {
+ "title": "Bar",
+ },
+ }
+ }
+ />
+ <CategoryLink
+ key="Bar subs"
+ location={
+ Object {
+ "pathname": "/foo/baz/foo/bar",
+ }
+ }
+ openByDefault={false}
+ title="Bar subs"
+ >
+ <ExternalLink
+ external="http://example.com/1"
+ key="External link 1"
+ title="External link 1"
+ />
+ </CategoryLink>
+ <ExternalLink
+ external="http://example.com/2"
+ key="External link 2"
+ title="External link 2"
+ />
+ </nav>
+ </div>
+ <div
+ className="sidebar-footer"
+ >
+ <a
+ href="https://www.sonarqube.org/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <DownloadIcon />
+ SonarQube
+ </a>
+ <a
+ href="https://community.sonarsource.com/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Community"
+ src="/1.0/images/community.svg"
+ />
+ Community
+ </a>
+ <a
+ className="icon-only"
+ href="https://twitter.com/SonarQube"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Twitter"
+ src="/1.0/images/twitter.svg"
+ />
+ </a>
+ <a
+ className="icon-only"
+ href="https://www.sonarsource.com/resources/product-news/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <img
+ alt="Product News"
+ src="/1.0/images/newspaper.svg"
+ />
+ <span
+ className="tooltip"
+ >
+ Product News
+ </span>
+ </a>
+ </div>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+ className="version-select"
+>
+ <button
+ onClick={[Function]}
+ type="button"
+ >
+ Docs
+ <span
+ className=""
+ >
+ 1.0
+ </span>
+ <ChevronDownIcon
+ size={10}
+ />
+ </button>
+</div>
+`;
+
+exports[`should render correctly: on current version 1`] = `
+<div
+ className="version-select"
+>
+ <button
+ onClick={[Function]}
+ type="button"
+ >
+ Docs
+ <span
+ className="current"
+ >
+ 1.0
+ </span>
+ <ChevronDownIcon
+ size={10}
+ />
+ </button>
+</div>
+`;
+
+exports[`should render correctly: open 1`] = `
+<div
+ className="version-select"
+>
+ <button
+ onClick={[Function]}
+ type="button"
+ >
+ Docs
+ <span
+ className=""
+ >
+ 1.0
+ </span>
+ <ChevronUpIcon
+ size={10}
+ />
+ </button>
+ <OutsideClickHandler
+ onClickOutside={[Function]}
+ >
+ <ul>
+ <li
+ key="3.0"
+ >
+ <a
+ href="/"
+ >
+ <span
+ className="current"
+ >
+ 3.0
+ </span>
+ </a>
+ </li>
+ <li
+ key="2.0"
+ >
+ <a
+ href="/2.0"
+ >
+ <span
+ className="current"
+ >
+ 2.0 LTS
+ </span>
+ </a>
+ </li>
+ <li
+ key="1.0"
+ >
+ <a
+ href="/1.0"
+ >
+ <span
+ className=""
+ >
+ 1.0
+ </span>
+ </a>
+ </li>
+ </ul>
+ </OutsideClickHandler>
+</div>
+`;
font-size: 15px;
margin: 0;
padding: 4px 16px;
- text-align: center;
+ text-align: left;
transition: all 0.2s ease;
+ white-space: nowrap;
}
.version-select ul li:hover {
[
{ "value": "7.3", "current": true },
{ "value": "7.2", "current": false },
- { "value": "7.1", "current": false },
+ { "value": "7.1", "current": false, "lts": true },
{ "value": "7.0", "current": false }
]
parse-filepath "^1.0.1"
slash "^1.0.0"
-gatsby-plugin-polyfill-io@^1.1.0:
+gatsby-plugin-polyfill-io@1.1.0:
version "1.1.0"
resolved "https://repox.jfrog.io/repox/api/npm/npm/gatsby-plugin-polyfill-io/-/gatsby-plugin-polyfill-io-1.1.0.tgz#61424c773ae123680e50b9a6692a4b939a1e6e13"
integrity sha1-YUJMdzrhI2gOULmmaSpLk5oebhM=