aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/components/docs
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-07-13 12:27:02 +0200
committerSonarTech <sonartech@sonarsource.com>2018-07-25 20:21:20 +0200
commitb998b44aafeff3726122bbc491e2c84aed284b61 (patch)
treefbc8aea8d272107b7aeeec6b89e6cee1eac93ef6 /server/sonar-web/src/main/js/components/docs
parent4423587a87475044fb3eea1229eca5f52177db95 (diff)
downloadsonarqube-b998b44aafeff3726122bbc491e2c84aed284b61.tar.gz
sonarqube-b998b44aafeff3726122bbc491e2c84aed284b61.zip
SONAR-11013 Add search capabilities to the embedded documentation (#513)
Diffstat (limited to 'server/sonar-web/src/main/js/components/docs')
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocInclude.tsx75
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx23
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocParagraph.tsx35
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocTooltip.tsx71
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx17
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap36
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap16
7 files changed, 46 insertions, 227 deletions
diff --git a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx b/server/sonar-web/src/main/js/components/docs/DocInclude.tsx
deleted file mode 100644
index d499b27c22c..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { lazyLoad } from '../lazyLoad';
-
-const DocMarkdownBlock = lazyLoad(() => import('./DocMarkdownBlock'));
-
-interface Props {
- className?: string;
- path: string;
-}
-
-interface State {
- content?: string;
-}
-
-export default class DocInclude extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- this.fetchContent();
- }
-
- componentWillReceiveProps(nextProps: Props) {
- if (nextProps.path !== this.props.path) {
- this.setState({ content: undefined });
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.path !== this.props.path) {
- this.fetchContent();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchContent = () => {
- // even if `this.props.path` starts with `/`,
- // it is important to keep `Docs/` in the string to let webpack correctly resolve imports
- import(`Docs/${this.props.path.substr(1)}.md`).then(
- ({ default: content }) => {
- if (this.mounted) {
- this.setState({ content });
- }
- },
- () => {}
- );
- };
-
- render() {
- return <DocMarkdownBlock className={this.props.className} content={this.state.content} />;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
index 0bc5350b297..c61a7212c52 100644
--- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
+++ b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
@@ -23,11 +23,9 @@ import remark from 'remark';
import reactRenderer from 'remark-react';
import remarkToc from 'remark-toc';
import DocLink from './DocLink';
-import DocParagraph from './DocParagraph';
import DocImg from './DocImg';
import DocTooltipLink from './DocTooltipLink';
-import { separateFrontMatter } from '../../helpers/markdown';
-import { isSonarCloud } from '../../helpers/system';
+import { separateFrontMatter, filterContent } from '../../helpers/markdown';
import { scrollToElement } from '../../helpers/scrolling';
interface Props {
@@ -59,7 +57,6 @@ export default class DocMarkdownBlock extends React.PureComponent<Props> {
{displayH1 && <h1>{parsed.frontmatter.title}</h1>}
{
remark()
- // .use(remarkInclude)
.use(remarkToc, { maxDepth: 3 })
.use(reactRenderer, {
remarkReactComponents: {
@@ -69,8 +66,6 @@ export default class DocMarkdownBlock extends React.PureComponent<Props> {
a: isTooltip
? withChildProps(DocTooltipLink, childProps)
: withChildProps(DocLink, { onAnchorClick: this.handleAnchorClick }),
- // used to handle `@include`
- p: DocParagraph,
// use custom img tag to render documentation images
img: DocImg
},
@@ -91,19 +86,3 @@ function withChildProps<P>(
return <WrappedComponent customProps={childProps} {...props} />;
};
}
-
-function filterContent(content: string) {
- const beginning = isSonarCloud() ? '<!-- sonarqube -->' : '<!-- sonarcloud -->';
- const ending = isSonarCloud() ? '<!-- /sonarqube -->' : '<!-- /sonarcloud -->';
-
- let newContent = content;
- let start = newContent.indexOf(beginning);
- let end = newContent.indexOf(ending);
- while (start !== -1 && end !== -1) {
- newContent = newContent.substring(0, start) + newContent.substring(end + ending.length);
- start = newContent.indexOf(beginning);
- end = newContent.indexOf(ending);
- }
-
- return newContent;
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocParagraph.tsx b/server/sonar-web/src/main/js/components/docs/DocParagraph.tsx
deleted file mode 100644
index 54b34660482..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocParagraph.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 DocInclude from './DocInclude';
-
-const INCLUDE = '@include';
-
-export default function DocParagraph(props: React.HTMLAttributes<HTMLParagraphElement>) {
- if (Array.isArray(props.children) && props.children.length === 1) {
- const child = props.children[0];
- if (typeof child === 'string' && child.startsWith(INCLUDE)) {
- const includePath = child.substr(INCLUDE.length + 1);
- return <DocInclude path={includePath} />;
- }
- }
-
- return <p {...props} />;
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
index 3f7d4ec0195..a912b43c7b3 100644
--- a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
+++ b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
@@ -26,82 +26,55 @@ const DocMarkdownBlock = lazyLoad(() => import('./DocMarkdownBlock'));
interface Props {
className?: string;
children?: React.ReactNode;
- /** Key of the documentation chunk */
- doc: string;
+ // Use as `import(/* webpackMode: "eager" */ 'Docs/tooltips/foo/bar.md')`
+ doc: Promise<{ default: string }>;
overlayProps?: { [k: string]: string };
}
interface State {
content?: string;
- loading: boolean;
open: boolean;
}
export default class DocTooltip extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: false, open: false };
+ state: State = { open: false };
componentDidMount() {
- this.mounted = true;
+ this.props.doc.then(
+ ({ default: content }) => {
+ this.setState({ content });
+ },
+ () => {}
+ );
document.addEventListener('scroll', this.close, true);
}
- componentWillReceiveProps(nextProps: Props) {
- if (nextProps.doc !== this.props.doc) {
- this.setState({ content: undefined, loading: false, open: false });
- }
- }
-
componentWillUnmount() {
- this.mounted = false;
document.removeEventListener('scroll', this.close, true);
}
- fetchContent = () => {
- this.setState({ loading: true });
- import(`Docs/tooltips/${this.props.doc}.md`).then(
- ({ default: content }) => {
- if (this.mounted) {
- this.setState({ content, loading: false });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
close = () => {
this.setState({ open: false });
};
- renderOverlay() {
- return (
- <div className="abs-width-300">
- {this.state.loading ? (
- <i className="spinner" />
- ) : (
- <DocMarkdownBlock
- childProps={this.props.overlayProps}
- className="cut-margins"
- content={this.state.content}
- isTooltip={true}
- />
- )}
- </div>
- );
- }
-
render() {
- return (
+ return this.state.content ? (
<HelpTooltip
className={this.props.className}
- onShow={this.fetchContent}
- overlay={this.renderOverlay()}>
+ overlay={
+ <div className="abs-width-300">
+ <DocMarkdownBlock
+ childProps={this.props.overlayProps}
+ className="cut-margins"
+ content={this.state.content}
+ isTooltip={true}
+ />
+ </div>
+ }>
{this.props.children}
</HelpTooltip>
+ ) : (
+ this.props.children || null
);
}
}
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
index 570b68e37c0..8e933bddbcd 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
@@ -20,20 +20,11 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import DocTooltip from '../DocTooltip';
+import { waitAndUpdate } from '../../../helpers/testUtils';
-jest.useFakeTimers();
-
-it('should render', () => {
- const wrapper = shallow(<DocTooltip doc="foo/bar" />);
- wrapper.setState({ content: 'this is *bold* text', open: true, loading: true });
+it('should render', async () => {
+ const wrapper = shallow(<DocTooltip doc={Promise.resolve({ default: 'this is *bold* text' })} />);
expect(wrapper).toMatchSnapshot();
- wrapper.setState({ loading: false });
+ await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});
-
-it('should reset state when receiving new doc', () => {
- const wrapper = shallow(<DocTooltip doc="foo/bar" />);
- wrapper.setState({ content: 'this is *bold* text', open: true });
- wrapper.setProps({ doc: 'baz' });
- expect(wrapper.state()).toEqual({ content: undefined, loading: false, open: false });
-});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
index c47b4d7fe4b..c84fe63dedf 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
@@ -7,39 +7,39 @@ exports[`should cut sonarqube/sonarcloud content 1`] = `
<React.Fragment
key="h-1"
>
- <DocParagraph
+ <p
key="h-2"
>
some
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-3"
>
sonarqube
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-4"
>
long
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-5"
>
multiline
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-6"
>
text
- </DocParagraph>
+ </p>
</React.Fragment>
</div>
`;
@@ -51,25 +51,25 @@ exports[`should cut sonarqube/sonarcloud content 2`] = `
<React.Fragment
key="h-1"
>
- <DocParagraph
+ <p
key="h-2"
>
some
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-3"
>
sonarcloud
- </DocParagraph>
+ </p>
- <DocParagraph
+ <p
key="h-4"
>
text
- </DocParagraph>
+ </p>
</React.Fragment>
</div>
`;
@@ -81,7 +81,7 @@ exports[`should render simple markdown 1`] = `
<React.Fragment
key="h-1"
>
- <DocParagraph
+ <p
key="h-2"
>
this is
@@ -91,7 +91,7 @@ exports[`should render simple markdown 1`] = `
bold
</em>
text
- </DocParagraph>
+ </p>
</React.Fragment>
</div>
`;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
index f19fea4d065..2c996886133 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
@@ -1,23 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render 1`] = `
-<HelpTooltip
- onShow={[Function]}
- overlay={
- <div
- className="abs-width-300"
- >
- <i
- className="spinner"
- />
- </div>
- }
-/>
-`;
+exports[`should render 1`] = `""`;
exports[`should render 2`] = `
<HelpTooltip
- onShow={[Function]}
overlay={
<div
className="abs-width-300"