Browse Source

SONAR-9521 Add sparator between ws descriptions (hum and rewrite to ts)

tags/6.6-RC1
Grégoire Aubert 6 years ago
parent
commit
6103fc329f
35 changed files with 1930 additions and 945 deletions
  1. 18
    5
      server/sonar-web/src/main/js/api/web-api.ts
  2. 0
    178
      server/sonar-web/src/main/js/apps/web-api/components/Action.js
  3. 181
    0
      server/sonar-web/src/main/js/apps/web-api/components/Action.tsx
  4. 18
    27
      server/sonar-web/src/main/js/apps/web-api/components/ActionChangelog.tsx
  5. 35
    0
      server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.tsx
  6. 0
    84
      server/sonar-web/src/main/js/apps/web-api/components/Domain.js
  7. 76
    0
      server/sonar-web/src/main/js/apps/web-api/components/Domain.tsx
  8. 7
    7
      server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.tsx
  9. 0
    82
      server/sonar-web/src/main/js/apps/web-api/components/Menu.js
  10. 72
    0
      server/sonar-web/src/main/js/apps/web-api/components/Menu.tsx
  11. 0
    138
      server/sonar-web/src/main/js/apps/web-api/components/Params.js
  12. 139
    0
      server/sonar-web/src/main/js/apps/web-api/components/Params.tsx
  13. 20
    5
      server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.tsx
  14. 18
    31
      server/sonar-web/src/main/js/apps/web-api/components/Search.tsx
  15. 29
    40
      server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
  16. 75
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Action-test.tsx
  17. 1
    1
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/ActionChangelog-test.tsx
  18. 0
    64
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js
  19. 96
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.tsx
  20. 104
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Menu-test.tsx
  21. 23
    20
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.tsx
  22. 50
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/ResponseExample-test.tsx
  23. 13
    13
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/Search-test.tsx
  24. 160
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap
  25. 0
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/ActionChangelog-test.tsx.snap
  26. 0
    230
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap
  27. 369
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.tsx.snap
  28. 248
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Menu-test.tsx.snap
  29. 55
    7
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.tsx.snap
  30. 23
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/ResponseExample-test.tsx.snap
  31. 70
    0
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap
  32. 5
    0
      server/sonar-web/src/main/js/apps/web-api/styles/web-api.css
  33. 8
    9
      server/sonar-web/src/main/js/apps/web-api/utils.ts
  34. 6
    4
      server/sonar-web/src/main/js/components/icons-components/LinkIcon.tsx
  35. 11
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 18
- 5
server/sonar-web/src/main/js/api/web-api.ts View File

@@ -19,6 +19,11 @@
*/
import { getJSON } from '../helpers/request';

export interface Changelog {
description: string;
version: string;
}

export interface Param {
key: string;
defaultValue?: string;
@@ -28,20 +33,22 @@ export interface Param {
deprecatedSince?: string;
exampleValue?: string;
internal: boolean;
maxValuesAllowed?: number;
possibleValues?: string[];
required: boolean;
since?: string;
}

export interface Action {
key: string;
changelog: Changelog[];
description: string;
deprecatedSince?: string;
since?: string;
internal: boolean;
post: boolean;
hasResponseExample: boolean;
changelog: Array<{ version: string; description: string }>;
internal: boolean;
params?: Param[];
post: boolean;
since?: string;
}

export interface Domain {
@@ -50,6 +57,12 @@ export interface Domain {
deprecated: boolean;
internal: boolean;
path: string;
since?: string;
}

export interface Example {
example: string;
format: string;
}

export function fetchWebApi(showInternal: boolean = true): Promise<Array<Domain>> {
@@ -62,6 +75,6 @@ export function fetchWebApi(showInternal: boolean = true): Promise<Array<Domain>
);
}

export function fetchResponseExample(domain: string, action: string): Promise<{ example: string }> {
export function fetchResponseExample(domain: string, action: string): Promise<Example> {
return getJSON('/api/webservices/response_example', { controller: domain, action });
}

+ 0
- 178
server/sonar-web/src/main/js/apps/web-api/components/Action.js View File

@@ -1,178 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.
*/
// @flow
import React from 'react';
import { Link } from 'react-router';
import classNames from 'classnames';
import { getActionKey } from '../utils';
import Params from './Params';
import ResponseExample from './ResponseExample';
import ActionChangelog from './ActionChangelog';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import LinkIcon from '../../../components/icons-components/LinkIcon';
import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
/*:: import type { Action as ActionType, Domain as DomainType } from '../../../api/web-api'; */

/*::
type Props = {
action: ActionType,
domain: DomainType,
showDeprecated: boolean,
showInternal: boolean
};
*/

/*::
type State = {
showChangelog: boolean,
showParams: boolean,
showResponse: boolean
};
*/

export default class Action extends React.PureComponent {
/*:: props: Props; */

state /*: State */ = {
showChangelog: false,
showParams: false,
showResponse: false
};

handleShowParamsClick = (e /*: SyntheticInputEvent */) => {
e.preventDefault();
this.setState({
showChangelog: false,
showResponse: false,
showParams: !this.state.showParams
});
};

handleShowResponseClick = (e /*: SyntheticInputEvent */) => {
e.preventDefault();
this.setState({
showChangelog: false,
showParams: false,
showResponse: !this.state.showResponse
});
};

handleChangelogClick = (e /*: SyntheticInputEvent */) => {
e.preventDefault();
this.setState({
showChangelog: !this.state.showChangelog,
showParams: false,
showResponse: false
});
};

render() {
const { action, domain } = this.props;
const { showChangelog, showParams, showResponse } = this.state;
const verb = action.post ? 'POST' : 'GET';
const actionKey = getActionKey(domain.path, action.key);

return (
<div id={actionKey} className="web-api-action">
<TooltipsContainer>
<header className="web-api-action-header">
<Link
to={{ pathname: '/web_api/' + actionKey }}
className="spacer-right link-no-underline">
<LinkIcon />
</Link>

<h3 className="web-api-action-title">
{verb}&nbsp;{actionKey}
</h3>

{action.internal &&
<span className="spacer-left">
<InternalBadge />
</span>}

{action.since &&
<span className="spacer-left badge">
since {action.since}
</span>}

{action.deprecatedSince &&
<span className="spacer-left">
<DeprecatedBadge since={action.deprecatedSince} />
</span>}
</header>
</TooltipsContainer>

<div
className="web-api-action-description markdown"
dangerouslySetInnerHTML={{ __html: action.description }}
/>

{(action.params || action.hasResponseExample) &&
<ul className="web-api-action-actions tabs">
{action.params &&
<li>
<a
className={classNames({ selected: showParams })}
href="#"
onClick={this.handleShowParamsClick}>
Parameters
</a>
</li>}

{action.hasResponseExample &&
<li>
<a
className={classNames({ selected: showResponse })}
href="#"
onClick={this.handleShowResponseClick}>
Response Example
</a>
</li>}

{action.changelog.length > 0 &&
<li>
<a
className={classNames({ selected: showChangelog })}
href="#"
onClick={this.handleChangelogClick}>
Changelog
</a>
</li>}
</ul>}

{showParams &&
action.params &&
<Params
params={action.params}
showDeprecated={this.props.showDeprecated}
showInternal={this.props.showInternal}
/>}

{showResponse &&
action.hasResponseExample &&
<ResponseExample domain={domain} action={action} />}

{showChangelog && <ActionChangelog changelog={action.changelog} />}
</div>
);
}
}

+ 181
- 0
server/sonar-web/src/main/js/apps/web-api/components/Action.tsx View File

@@ -0,0 +1,181 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 { Link } from 'react-router';
import * as classNames from 'classnames';
import { getActionKey } from '../utils';
import Params from './Params';
import ResponseExample from './ResponseExample';
import ActionChangelog from './ActionChangelog';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import LinkIcon from '../../../components/icons-components/LinkIcon';
import { Action as ActionType, Domain as DomainType } from '../../../api/web-api';
import { translate, translateWithParameters } from '../../../helpers/l10n';

interface Props {
action: ActionType;
domain: DomainType;
showDeprecated: boolean;
showInternal: boolean;
}

interface State {
showChangelog: boolean;
showParams: boolean;
showResponse: boolean;
}

export default class Action extends React.PureComponent<Props, State> {
state: State = {
showChangelog: false,
showParams: false,
showResponse: false
};

handleShowParamsClick = (e: React.SyntheticEvent<HTMLElement>) => {
e.preventDefault();
this.setState({
showChangelog: false,
showResponse: false,
showParams: !this.state.showParams
});
};

handleShowResponseClick = (e: React.SyntheticEvent<HTMLElement>) => {
e.preventDefault();
this.setState({
showChangelog: false,
showParams: false,
showResponse: !this.state.showResponse
});
};

handleChangelogClick = (e: React.SyntheticEvent<HTMLElement>) => {
e.preventDefault();
this.setState({
showChangelog: !this.state.showChangelog,
showParams: false,
showResponse: false
});
};

renderTabs() {
const { action } = this.props;
const { showChangelog, showParams, showResponse } = this.state;

if (action.params || action.hasResponseExample || action.changelog.length > 0) {
return (
<ul className="web-api-action-actions tabs">
{action.params &&
<li>
<a
className={classNames({ selected: showParams })}
href="#"
onClick={this.handleShowParamsClick}>
{translate('api_documentation.parameters')}
</a>
</li>}

{action.hasResponseExample &&
<li>
<a
className={classNames({ selected: showResponse })}
href="#"
onClick={this.handleShowResponseClick}>
{translate('api_documentation.response_example')}
</a>
</li>}

{action.changelog.length > 0 &&
<li>
<a
className={classNames({ selected: showChangelog })}
href="#"
onClick={this.handleChangelogClick}>
{translate('api_documentation.changelog')}
</a>
</li>}
</ul>
);
}

return <hr />;
}

render() {
const { action, domain } = this.props;
const { showChangelog, showParams, showResponse } = this.state;
const verb = action.post ? 'POST' : 'GET';
const actionKey = getActionKey(domain.path, action.key);

return (
<div id={actionKey} className="web-api-action">
<header className="web-api-action-header">
<Link
to={{ pathname: '/web_api/' + actionKey }}
className="spacer-right link-no-underline">
<LinkIcon />
</Link>

<h3 className="web-api-action-title">
{verb}&nbsp;{actionKey}
</h3>

{action.internal &&
<span className="spacer-left">
<InternalBadge />
</span>}

{action.since &&
<span className="spacer-left badge">
{translateWithParameters('since_x', action.since)}
</span>}

{action.deprecatedSince &&
<span className="spacer-left">
<DeprecatedBadge since={action.deprecatedSince} />
</span>}
</header>

<div
className="web-api-action-description markdown"
dangerouslySetInnerHTML={{ __html: action.description }}
/>

{this.renderTabs()}

{showParams &&
action.params &&
<Params
params={action.params}
showDeprecated={this.props.showDeprecated}
showInternal={this.props.showInternal}
/>}

{showResponse &&
action.hasResponseExample &&
<ResponseExample domain={domain} action={action} />}

{showChangelog && <ActionChangelog changelog={action.changelog} />}
</div>
);
}
}

server/sonar-web/src/main/js/apps/web-api/components/ActionChangelog.js → server/sonar-web/src/main/js/apps/web-api/components/ActionChangelog.tsx View File

@@ -17,33 +17,24 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
import React from 'react';
import * as React from 'react';
import { Changelog } from '../../../api/web-api';

/*::
type Props = {
changelog: Array<{
description: string,
version: string
}>
};
*/

export default class ActionChangelog extends React.PureComponent {
/*:: props: Props; */
interface Props {
changelog: Changelog[];
}

render() {
return (
<ul className="big-spacer-top">
{this.props.changelog.map((item, index) =>
<li key={index} className="spacer-top">
<span className="spacer-right badge">
{item.version}
</span>
{item.description}
</li>
)}
</ul>
);
}
export default function ActionChangelog({ changelog }: Props) {
return (
<ul className="big-spacer-top">
{changelog.map((item, index) =>
<li key={index} className="spacer-top">
<span className="spacer-right badge">
{item.version}
</span>
{item.description}
</li>
)}
</ul>
);
}

+ 35
- 0
server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.tsx View File

@@ -0,0 +1,35 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 Tooltip from '../../../components/controls/Tooltip';
import { translate, translateWithParameters } from '../../../helpers/l10n';

export default function DeprecatedBadge({ since }: { since?: string }) {
const label = since
? translateWithParameters('api_documentation.depracated_since_x', since)
: translate('api_documentation.depracated');
return (
<Tooltip overlay={translate('api_documentation.deprecation_tooltip')}>
<span className="badge badge-warning">
{label}
</span>
</Tooltip>
);
}

+ 0
- 84
server/sonar-web/src/main/js/apps/web-api/components/Domain.js View File

@@ -1,84 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.
*/
// @flow
import React from 'react';
import Action from './Action';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import { getActionKey, actionsFilter } from '../utils';
/*:: import type { Domain as DomainType } from '../../../api/web-api'; */

/*::
type Props = {
domain: DomainType,
showDeprecated: boolean,
showInternal: boolean,
searchQuery: string
};
*/

export default class Domain extends React.PureComponent {
/*:: props: Props; */

render() {
const { domain, showInternal, showDeprecated, searchQuery } = this.props;
const filteredActions = domain.actions.filter(action =>
actionsFilter(showDeprecated, showInternal, searchQuery, domain, action)
);

return (
<div className="web-api-domain">
<header className="web-api-domain-header">
<h2 className="web-api-domain-title">
{domain.path}
</h2>

{domain.deprecated &&
<span className="spacer-left">
<DeprecatedBadge />
</span>}

{domain.internal &&
<span className="spacer-left">
<InternalBadge />
</span>}
</header>

{domain.description &&
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={{ __html: domain.description }}
/>}

<div className="web-api-domain-actions">
{filteredActions.map(action =>
<Action
key={getActionKey(domain.path, action.key)}
action={action}
domain={domain}
showDeprecated={showDeprecated}
showInternal={showInternal}
/>
)}
</div>
</div>
);
}
}

+ 76
- 0
server/sonar-web/src/main/js/apps/web-api/components/Domain.tsx View File

@@ -0,0 +1,76 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 Action from './Action';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import { getActionKey, actionsFilter } from '../utils';
import { Domain as DomainType } from '../../../api/web-api';

interface Props {
domain: DomainType;
showDeprecated: boolean;
showInternal: boolean;
searchQuery: string;
}

export default function Domain({ domain, showInternal, showDeprecated, searchQuery }: Props) {
const filteredActions = domain.actions.filter(action =>
actionsFilter(showDeprecated, showInternal, searchQuery, domain, action)
);

return (
<div className="web-api-domain">
<header className="web-api-domain-header">
<h2 className="web-api-domain-title">
{domain.path}
</h2>

{domain.deprecated &&
<span className="spacer-left">
<DeprecatedBadge />
</span>}

{domain.internal &&
<span className="spacer-left">
<InternalBadge />
</span>}
</header>

{domain.description &&
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={{ __html: domain.description }}
/>}

<div className="web-api-domain-actions">
{filteredActions.map(action =>
<Action
key={getActionKey(domain.path, action.key)}
action={action}
domain={domain}
showDeprecated={showDeprecated}
showInternal={showInternal}
/>
)}
</div>
</div>
);
}

server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.js → server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.tsx View File

@@ -17,16 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import * as React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n';

export default function InternalBadge() {
return (
<span
className="badge badge-danger"
title={translate('api_documentation.internal_tooltip')}
data-toggle="tooltip">
internal
</span>
<Tooltip overlay={translate('api_documentation.internal_tooltip')}>
<span className="badge badge-danger">
{translate('internal')}
</span>
</Tooltip>
);
}

+ 0
- 82
server/sonar-web/src/main/js/apps/web-api/components/Menu.js View File

@@ -1,82 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.
*/
// @flow
import React from 'react';
import { Link } from 'react-router';
import classNames from 'classnames';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
import { isDomainPathActive, actionsFilter } from '../utils';
/*:: import type { Domain as DomainType } from '../../../api/web-api'; */

/*::
type Props = {
domains: Array<DomainType>,
showDeprecated: boolean,
showInternal: boolean,
searchQuery: string,
splat: string
};
*/

export default class Menu extends React.PureComponent {
/*:: props: Props; */

render() {
const { domains, showInternal, showDeprecated, searchQuery, splat } = this.props;
const filteredDomains = (domains || [])
.map(domain => {
const filteredActions = domain.actions.filter(action =>
actionsFilter(showDeprecated, showInternal, searchQuery, domain, action)
);
return { ...domain, filteredActions };
})
.filter(domain => domain.filteredActions.length);

return (
<div className="api-documentation-results panel">
<TooltipsContainer>
<div className="list-group">
{filteredDomains.map(domain =>
<Link
key={domain.path}
className={classNames('list-group-item', {
active: isDomainPathActive(domain.path, splat)
})}
to={'/web_api/' + domain.path}>
<h3 className="list-group-item-heading">
{domain.path}
{domain.deprecated && <DeprecatedBadge />}
{domain.internal && <InternalBadge />}
</h3>
{domain.description &&
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={{ __html: domain.description }}
/>}
</Link>
)}
</div>
</TooltipsContainer>
</div>
);
}
}

+ 72
- 0
server/sonar-web/src/main/js/apps/web-api/components/Menu.tsx View File

@@ -0,0 +1,72 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 { Link } from 'react-router';
import * as classNames from 'classnames';
import DeprecatedBadge from './DeprecatedBadge';
import InternalBadge from './InternalBadge';
import { isDomainPathActive, actionsFilter } from '../utils';
import { Domain } from '../../../api/web-api';

interface Props {
domains: Domain[];
showDeprecated: boolean;
showInternal: boolean;
searchQuery: string;
splat: string;
}

export default function Menu(props: Props) {
const { domains, showInternal, showDeprecated, searchQuery, splat } = props;
const filteredDomains = (domains || [])
.map(domain => {
const filteredActions = domain.actions.filter(action =>
actionsFilter(showDeprecated, showInternal, searchQuery, domain, action)
);
return { ...domain, filteredActions };
})
.filter(domain => domain.filteredActions.length);

return (
<div className="api-documentation-results panel">
<div className="list-group">
{filteredDomains.map(domain =>
<Link
key={domain.path}
className={classNames('list-group-item', {
active: isDomainPathActive(domain.path, splat)
})}
to={'/web_api/' + domain.path}>
<h3 className="list-group-item-heading">
{domain.path}
{domain.deprecated && <DeprecatedBadge />}
{domain.internal && <InternalBadge />}
</h3>
{domain.description &&
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={{ __html: domain.description }}
/>}
</Link>
)}
</div>
</div>
);
}

+ 0
- 138
server/sonar-web/src/main/js/apps/web-api/components/Params.js View File

@@ -1,138 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.
*/
// @flow
import React from 'react';
import InternalBadge from './InternalBadge';
import DeprecatedBadge from './DeprecatedBadge';
/*:: import type { Param } from '../../../api/web-api'; */

export default class Params extends React.PureComponent {
/*:: props: {
showDeprecated: boolean,
showInternal: boolean,
params: Array<Param>
};
*/

render() {
const { showDeprecated, showInternal, params } = this.props;
const displayedParameters = params
.filter(p => showDeprecated || !p.deprecatedSince)
.filter(p => showInternal || !p.internal);
return (
<div className="web-api-params">
<table>
<tbody>
{displayedParameters.map(param =>
<tr key={param.key}>
<td className="markdown" style={{ width: 180 }}>
<code>
{param.key}
</code>

{param.internal &&
<div className="little-spacer-top">
<InternalBadge />
</div>}

{param.deprecatedSince &&
<div className="little-spacer-top">
<DeprecatedBadge since={param.deprecatedSince} />
</div>}

{showDeprecated &&
param.deprecatedKey &&
<div className="little-spacer-top">
<code>
{param.deprecatedKey}
</code>
</div>}

{showDeprecated &&
param.deprecatedKey &&
param.deprecatedKeySince &&
<div className="little-spacer-top">
<DeprecatedBadge since={param.deprecatedKeySince} />
</div>}

<div className="note little-spacer-top">
{param.required ? 'required' : 'optional'}
</div>

{param.since &&
<div className="note little-spacer-top">
since {param.since}
</div>}
</td>

<td>
<div
className="markdown"
dangerouslySetInnerHTML={{ __html: param.description }}
/>
</td>

<td style={{ width: 250 }}>
{param.possibleValues &&
<div>
<h4>Possible values</h4>
<ul className="list-styled">
{param.possibleValues.map(value =>
<li key={value} className="little-spacer-top">
<code>
{value}
</code>
</li>
)}
</ul>
</div>}

{param.defaultValue &&
<div className="little-spacer-top">
<h4>Default value</h4>
<code>
{param.defaultValue}
</code>
</div>}

{param.exampleValue &&
<div className="little-spacer-top">
<h4>Example value</h4>
<code>
{param.exampleValue}
</code>
</div>}

{param.maxValuesAllowed != null &&
<div className="little-spacer-top">
<h4>Maximum allowed values</h4>
<code>
{param.maxValuesAllowed}
</code>
</div>}
</td>
</tr>
)}
</tbody>
</table>
</div>
);
}
}

+ 139
- 0
server/sonar-web/src/main/js/apps/web-api/components/Params.tsx View File

@@ -0,0 +1,139 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 InternalBadge from './InternalBadge';
import DeprecatedBadge from './DeprecatedBadge';
import { Param } from '../../../api/web-api';
import { translate, translateWithParameters } from '../../../helpers/l10n';

interface Props {
params: Param[];
showDeprecated: boolean;
showInternal: boolean;
}

export default function Params({ params, showDeprecated, showInternal }: Props) {
const displayedParameters = params
.filter(p => showDeprecated || !p.deprecatedSince)
.filter(p => showInternal || !p.internal);
return (
<div className="web-api-params">
<table>
<tbody>
{displayedParameters.map(param =>
<tr key={param.key}>
<td className="markdown" style={{ width: 180 }}>
<code>
{param.key}
</code>

{param.internal &&
<div className="little-spacer-top">
<InternalBadge />
</div>}

{param.deprecatedSince &&
<div className="little-spacer-top">
<DeprecatedBadge since={param.deprecatedSince} />
</div>}

{showDeprecated &&
param.deprecatedKey &&
<div className="little-spacer-top">
<code>
{param.deprecatedKey}
</code>
</div>}

{showDeprecated &&
param.deprecatedKey &&
param.deprecatedKeySince &&
<div className="little-spacer-top">
<DeprecatedBadge since={param.deprecatedKeySince} />
</div>}

<div className="note little-spacer-top">
{param.required ? 'required' : 'optional'}
</div>

{param.since &&
<div className="note little-spacer-top">
{translateWithParameters('since_x', param.since)}
</div>}
</td>

<td>
<div className="markdown" dangerouslySetInnerHTML={{ __html: param.description }} />
</td>

<td style={{ width: 250 }}>
{param.possibleValues &&
<div>
<h4>
{translate('api_documentation.possible_values')}
</h4>
<ul className="list-styled">
{param.possibleValues.map(value =>
<li key={value} className="little-spacer-top">
<code>
{value}
</code>
</li>
)}
</ul>
</div>}

{param.defaultValue &&
<div className="little-spacer-top">
<h4>
{translate('api_documentation.default_values')}
</h4>
<code>
{param.defaultValue}
</code>
</div>}

{param.exampleValue &&
<div className="little-spacer-top">
<h4>
{translate('api_documentation.example_values')}
</h4>
<code>
{param.exampleValue}
</code>
</div>}

{param.maxValuesAllowed != null &&
<div className="little-spacer-top">
<h4>
{translate('api_documentation.max_values')}
</h4>
<code>
{param.maxValuesAllowed}
</code>
</div>}
</td>
</tr>
)}
</tbody>
</table>
</div>
);
}

server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.js → server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.tsx View File

@@ -17,18 +17,33 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import { fetchResponseExample as fetchResponseExampleApi } from '../../../api/web-api';
import * as React from 'react';
import {
Action,
Domain,
Example,
fetchResponseExample as fetchResponseExampleApi
} from '../../../api/web-api';

export default class ResponseExample extends React.PureComponent {
state = {};
interface Props {
action: Action;
domain: Domain;
}

interface State {
responseExample?: Example;
}

export default class ResponseExample extends React.PureComponent<Props, State> {
mounted: boolean;
state: State = {};

componentDidMount() {
this.mounted = true;
this.fetchResponseExample();
}

componentDidUpdate(nextProps) {
componentDidUpdate(nextProps: Props) {
if (nextProps.action !== this.props.action) {
this.fetchResponseExample();
}

server/sonar-web/src/main/js/apps/web-api/components/Search.js → server/sonar-web/src/main/js/apps/web-api/components/Search.tsx View File

@@ -17,51 +17,38 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
import React from 'react';
import * as React from 'react';
import { debounce } from 'lodash';
import Checkbox from '../../../components/controls/Checkbox';
import HelpIcon from '../../../components/icons-components/HelpIcon';
import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n';

/*::
type Props = {
showDeprecated: boolean,
showInternal: boolean,
onSearch: string => void,
onToggleInternal: () => void,
onToggleDeprecated: () => void
};
*/

/*::
type State = {
query: string
};
*/
interface Props {
showDeprecated: boolean;
showInternal: boolean;
onSearch: (search: string) => void;
onToggleInternal: () => void;
onToggleDeprecated: () => void;
}

export default class Search extends React.PureComponent {
/*:: actuallySearch: () => void; */
/*:: props: Props; */
/*:: state: State; */
interface State {
query: string;
}

constructor(props /*: Props */) {
export default class Search extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = { query: '' };
this.actuallySearch = debounce(this.actuallySearch, 250);
}

handleSearch = (e /*: SyntheticInputEvent */) => {
const { value } = e.target;
this.setState({ query: value });
handleSearch = (e: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ query: e.currentTarget.value });
this.actuallySearch();
};

actuallySearch = () => {
const { onSearch } = this.props;
onSearch(this.state.query);
};
actuallySearch = () => this.props.onSearch(this.state.query);

render() {
const { showInternal, showDeprecated, onToggleInternal, onToggleDeprecated } = this.props;
@@ -82,7 +69,7 @@ export default class Search extends React.PureComponent {
<div className="big-spacer-top">
<Checkbox checked={showInternal} onCheck={onToggleInternal}>
<span className="little-spacer-left">
{translate('api_documentation.show_deprecated')}
{translate('api_documentation.show_internal')}
</span>
</Checkbox>
<Tooltip overlay={translate('api_documentation.internal_tooltip')} placement="right">
@@ -95,7 +82,7 @@ export default class Search extends React.PureComponent {
<div className="spacer-top">
<Checkbox checked={showDeprecated} onCheck={onToggleDeprecated}>
<span className="little-spacer-left">
{translate('api_documentation.show_internal')}
{translate('api_documentation.show_deprecated')}
</span>
</Checkbox>
<Tooltip overlay={translate('api_documentation.deprecation_tooltip')} placement="right">

server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js → server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx View File

@@ -17,39 +17,43 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import * as React from 'react';
import * as PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import { Link } from 'react-router';
import { fetchWebApi } from '../../../api/web-api';
import { Domain as DomainType, fetchWebApi } from '../../../api/web-api';
import Menu from './Menu';
import Search from './Search';
import Domain from './Domain';
import { getActionKey, isDomainPathActive } from '../utils';
import { scrollToElement } from '../../../helpers/scrolling';
import { translate } from '../../../helpers/l10n';
/*:: import type { Domain as DomainType } from '../../../api/web-api'; */
import '../styles/web-api.css';

/*::
type State = {
domains: Array<DomainType>,
searchQuery: string,
showDeprecated: boolean,
showInternal: boolean
};
*/

export default class WebApiApp extends React.PureComponent {
/*:: mounted: boolean; */
/*:: scrollToAction: () => void; */
state /*: State */ = {
interface Props {
params: { splat?: string };
}

interface State {
domains: DomainType[];
searchQuery: string;
showDeprecated: boolean;
showInternal: boolean;
}

export default class WebApiApp extends React.PureComponent<Props, State> {
mounted: boolean;
state: State = {
domains: [],
searchQuery: '',
showDeprecated: false,
showInternal: false
};

static contextTypes = {
router: PropTypes.object.isRequired
};

componentDidMount() {
this.mounted = true;
this.fetchList();
@@ -72,7 +76,7 @@ export default class WebApiApp extends React.PureComponent {
}
}

fetchList(cb /*: void | () => void */) {
fetchList(cb?: () => void) {
fetchWebApi().then(domains => {
if (this.mounted) {
this.setState({ domains }, cb);
@@ -82,21 +86,13 @@ export default class WebApiApp extends React.PureComponent {

scrollToAction = () => {
const splat = this.props.params.splat || '';
this.scrollToElement(splat);
};

scrollToElement(id /*: string */) {
const element = document.getElementById(id);

if (element) {
const rect = element.getBoundingClientRect();
const top = rect.top + window.pageYOffset - 20;

window.scrollTo(0, top);
const action = document.getElementById(splat);
if (action) {
scrollToElement(action, { topOffset: 20, bottomOffset: 20 });
} else {
window.scrollTo(0, 0);
}
}
};

toggleInternalInitially() {
const splat = this.props.params.splat || '';
@@ -117,9 +113,7 @@ export default class WebApiApp extends React.PureComponent {
}
}

handleSearch = (searchQuery /*: string */) => {
this.setState({ searchQuery });
};
handleSearch = (searchQuery: string) => this.setState({ searchQuery });

handleToggleInternal = () => {
const splat = this.props.params.splat || '';
@@ -135,9 +129,8 @@ export default class WebApiApp extends React.PureComponent {
this.setState({ showInternal });
};

handleToggleDeprecated = () => {
handleToggleDeprecated = () =>
this.setState(state => ({ showDeprecated: !state.showDeprecated }));
};

render() {
const splat = this.props.params.splat || '';
@@ -196,7 +189,3 @@ export default class WebApiApp extends React.PureComponent {
);
}
}

WebApiApp.contextTypes = {
router: PropTypes.object.isRequired
};

+ 75
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/Action-test.tsx View File

@@ -0,0 +1,75 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 Action from '../Action';

const ACTION = {
key: 'foo',
changelog: [{ description: 'Changelog desc', version: '5.0' }],
description: 'Foo Desc',
hasResponseExample: true,
internal: false,
params: [
{
key: 'param',
description: 'Param desc',
internal: true,
required: true
}
],
post: false
};
const DOMAIN = {
actions: [ACTION],
path: 'foo',
description: 'API Foo',
deprecated: false,
internal: false
};

const PROPS = {
action: ACTION,
domain: DOMAIN,
showDeprecated: false,
showInternal: false
};

it('should render correctly', () => {
expect(shallow(<Action {...PROPS} />)).toMatchSnapshot();
});

it('should display the params', () => {
const wrapper = shallow(<Action {...PROPS} />);
wrapper.setState({ showParams: true });
expect(wrapper.find('Params')).toMatchSnapshot();
});

it('should display the response example', () => {
const wrapper = shallow(<Action {...PROPS} />);
wrapper.setState({ showResponse: true });
expect(wrapper.find('ResponseExample')).toMatchSnapshot();
});

it('should display the changelog', () => {
const wrapper = shallow(<Action {...PROPS} />);
wrapper.setState({ showChangelog: true });
expect(wrapper.find('ActionChangelog')).toMatchSnapshot();
});

server/sonar-web/src/main/js/apps/web-api/components/__tests__/ActionChangelog-test.js → server/sonar-web/src/main/js/apps/web-api/components/__tests__/ActionChangelog-test.tsx View File

@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import * as React from 'react';
import { shallow } from 'enzyme';
import ActionChangelog from '../ActionChangelog';


+ 0
- 64
server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js View File

@@ -1,64 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 React from 'react';
import { shallow } from 'enzyme';
import Domain from '../Domain';

it('should render deprecated actions', () => {
const actions = [{ key: 'foo', deprecatedSince: '5.0' }];
const domain = { actions, path: 'api' };
expect(
shallow(<Domain domain={domain} searchQuery="" showDeprecated={true} />)
).toMatchSnapshot();
});

it('should not render deprecated actions', () => {
const actions = [{ key: 'foo', deprecatedSince: '5.0' }];
const domain = { actions, path: 'api' };
expect(
shallow(<Domain domain={domain} searchQuery="" showDeprecated={false} />)
).toMatchSnapshot();
});

it('should render internal actions', () => {
const actions = [{ key: 'foo', internal: true }];
const domain = { actions, path: 'api' };
expect(shallow(<Domain domain={domain} searchQuery="" showInternal={true} />)).toMatchSnapshot();
});

it('should not render internal actions', () => {
const actions = [{ key: 'foo', internal: true }];
const domain = { actions, path: 'api' };
expect(shallow(<Domain domain={domain} searchQuery="" showInternal={false} />)).toMatchSnapshot();
});

it('should render only actions matching the query', () => {
const actions = [{ key: 'foo' }, { key: 'bar' }];
const domain = { actions, path: 'api' };
expect(shallow(<Domain domain={domain} searchQuery="Foo" />)).toMatchSnapshot();
});

it('should also render actions with a description matching the query', () => {
const actions = [{ key: 'foo', description: 'foobar' }, { key: 'bar' }, { key: 'baz' }];
const domain = { actions, path: 'api' };
expect(
shallow(<Domain domain={domain} searchQuery="bar" showDeprecated={false} />)
).toMatchSnapshot();
});

+ 96
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.tsx View File

@@ -0,0 +1,96 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 Domain from '../Domain';

const ACTION = {
key: 'foo',
changelog: [],
description: 'Foo Desc',
hasResponseExample: false,
internal: false,
post: false
};
const DOMAIN = {
actions: [ACTION],
path: 'api',
description: 'API Desc',
deprecated: false,
internal: false
};
const DEFAULT_PROPS = {
domain: DOMAIN,
showDeprecated: false,
showInternal: false,
searchQuery: ''
};

it('should render deprecated actions', () => {
const action = { ...ACTION, deprecatedSince: '5.0' };
const domain = { ...DOMAIN, actions: [action] };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} showDeprecated={true} />)
).toMatchSnapshot();
});

it('should not render deprecated actions', () => {
const action = { ...ACTION, deprecatedSince: '5.0' };
const domain = { ...DOMAIN, actions: [action] };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} showDeprecated={false} />)
).toMatchSnapshot();
});

it('should render internal actions', () => {
const action = { ...ACTION, internal: true };
const domain = { ...DOMAIN, actions: [action] };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} showInternal={true} />)
).toMatchSnapshot();
});

it('should not render internal actions', () => {
const action = { ...ACTION, internal: true };
const domain = { ...DOMAIN, actions: [action] };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} showInternal={false} />)
).toMatchSnapshot();
});

it('should render only actions matching the query', () => {
const actions = [ACTION, { ...ACTION, key: 'bar', description: 'Bar desc' }];
const domain = { ...DOMAIN, actions: actions };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} searchQuery="Foo" />)
).toMatchSnapshot();
});

it('should also render actions with a description matching the query', () => {
const actions = [
ACTION,
{ ...ACTION, key: 'bar', description: 'Bar desc' },
{ ...ACTION, key: 'baz', description: 'foobar' }
];
const domain = { ...DOMAIN, actions: actions };
expect(
shallow(<Domain {...DEFAULT_PROPS} domain={domain} searchQuery="Foo" />)
).toMatchSnapshot();
});

+ 104
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/Menu-test.tsx View File

@@ -0,0 +1,104 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 Menu from '../Menu';

const ACTION = {
key: 'foo',
changelog: [],
description: 'Foo Desc',
hasResponseExample: false,
internal: false,
post: false
};
const DOMAIN1 = {
actions: [ACTION],
path: 'foo',
description: 'API Foo',
deprecated: false,
internal: false
};
const DOMAIN2 = {
actions: [ACTION],
path: 'bar',
description: 'API Bar',
deprecated: false,
internal: false
};
const PROPS = {
domains: [DOMAIN1, DOMAIN2],
showDeprecated: false,
showInternal: false,
searchQuery: '',
splat: ''
};

it('should render deprecated domains', () => {
const domain = {
...DOMAIN2,
deprecatedSince: '5.0',
actions: [{ ...ACTION, deprecatedSince: '5.0' }]
};
const domains = [DOMAIN1, domain];
expect(shallow(<Menu {...PROPS} domains={domains} showDeprecated={true} />)).toMatchSnapshot();
});

it('should not render deprecated domains', () => {
const domain = {
...DOMAIN2,
deprecatedSince: '5.0',
actions: [{ ...ACTION, deprecatedSince: '5.0' }]
};
const domains = [DOMAIN1, domain];
expect(shallow(<Menu {...PROPS} domains={domains} showDeprecated={false} />)).toMatchSnapshot();
});

it('should render internal domains', () => {
const domain = { ...DOMAIN2, internal: true, actions: [{ ...ACTION, internal: true }] };
const domains = [DOMAIN1, domain];
expect(shallow(<Menu {...PROPS} domains={domains} showInternal={true} />)).toMatchSnapshot();
});

it('should not render internal domains', () => {
const domain = { ...DOMAIN2, internal: true, actions: [{ ...ACTION, internal: true }] };
const domains = [DOMAIN1, domain];
expect(shallow(<Menu {...PROPS} domains={domains} showInternal={false} />)).toMatchSnapshot();
});

it('should render only domains with an action matching the query', () => {
const domain = {
...DOMAIN2,
actions: [{ ...ACTION, key: 'bar', path: 'bar', description: 'Bar Desc' }]
};
const domains = [DOMAIN1, domain];
expect(shallow(<Menu {...PROPS} domains={domains} searchQuery="Foo" />)).toMatchSnapshot();
});

it('should also render domains with an actions description matching the query', () => {
const domain = {
...DOMAIN1,
path: 'baz',
description: 'API Baz',
actions: [{ ...ACTION, key: 'baz', path: 'baz', description: 'barbaz' }]
};
const domains = [DOMAIN1, DOMAIN2, domain];
expect(shallow(<Menu {...PROPS} domains={domains} searchQuery="Bar" />)).toMatchSnapshot();
});

server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.js → server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.tsx View File

@@ -17,37 +17,40 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import * as React from 'react';
import { shallow } from 'enzyme';
import Params from '../Params';

it('should render deprecated parameters', () => {
const DEFAULT_PARAM = {
key: 'foo',
description: 'Foo desc',
internal: false,
required: false
};

it('should render deprecated and internal parameters', () => {
const params = [
{
key: 'foo',
deprecatedSince: '5.0'
}
{ ...DEFAULT_PARAM, deprecatedSince: '5.0' },
{ ...DEFAULT_PARAM, deprecatedSince: '5.0', internal: true }
];
expect(shallow(<Params params={params} showDeprecated={true} />)).toMatchSnapshot();
expect(
shallow(<Params params={params} showDeprecated={true} showInternal={true} />)
).toMatchSnapshot();
});

it('should not render deprecated parameters', () => {
const params = [
{
key: 'foo',
deprecatedSince: '5.0'
}
];
expect(shallow(<Params params={params} showDeprecated={false} />)).toMatchSnapshot();
const params = [{ ...DEFAULT_PARAM, deprecatedSince: '5.0' }];
expect(
shallow(<Params params={params} showDeprecated={false} showInternal={false} />)
).toMatchSnapshot();
});

it('should render deprecated key', () => {
const params = [
{
key: 'foo',
deprecatedKey: 'foo-deprecated',
deprecatedKeySince: '5.0'
}
{ ...DEFAULT_PARAM, deprecatedKey: 'foo-deprecated', deprecatedSince: '5.0' },
{ ...DEFAULT_PARAM, deprecatedSince: '5.0', internal: true }
];
expect(shallow(<Params params={params} showDeprecated={true} />)).toMatchSnapshot();
expect(
shallow(<Params params={params} showDeprecated={true} showInternal={false} />)
).toMatchSnapshot();
});

+ 50
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/ResponseExample-test.tsx View File

@@ -0,0 +1,50 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 ResponseExample from '../ResponseExample';

const ACTION = {
key: 'foo',
changelog: [],
description: 'Foo Desc',
hasResponseExample: false,
internal: false,
post: false
};
const DOMAIN = {
actions: [ACTION],
path: 'foo',
description: 'API Foo',
deprecated: false,
internal: false
};

const PROPS = {
action: ACTION,
domain: DOMAIN
};

it('should render correctly after fetching an example', () => {
const wrapper = shallow(<ResponseExample {...PROPS} />);
expect(wrapper).toMatchSnapshot();
wrapper.setState({ responseExample: { format: 'json', example: 'my example' } });
expect(wrapper).toMatchSnapshot();
});

server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.js → server/sonar-web/src/main/js/apps/web-api/components/__tests__/Search-test.tsx View File

@@ -17,18 +17,18 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import { translate } from '../../../helpers/l10n';
import * as React from 'react';
import { shallow } from 'enzyme';
import Search from '../Search';

export default function DeprecatedBadge({ since }) {
const label = since ? `deprecated since ${since}` : 'deprecated';
const PROPS = {
showDeprecated: false,
showInternal: false,
onSearch: () => {},
onToggleInternal: () => {},
onToggleDeprecated: () => {}
};

return (
<span
className="badge badge-warning"
title={translate('api_documentation.deprecation_tooltip')}
data-toggle="tooltip">
{label}
</span>
);
}
it('should render correctly', () => {
expect(shallow(<Search {...PROPS} />)).toMatchSnapshot();
});

+ 160
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Action-test.tsx.snap View File

@@ -0,0 +1,160 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should display the changelog 1`] = `
<ActionChangelog
changelog={
Array [
Object {
"description": "Changelog desc",
"version": "5.0",
},
]
}
/>
`;

exports[`should display the params 1`] = `
<Params
params={
Array [
Object {
"description": "Param desc",
"internal": true,
"key": "param",
"required": true,
},
]
}
showDeprecated={false}
showInternal={false}
/>
`;

exports[`should display the response example 1`] = `
<ResponseExample
action={
Object {
"changelog": Array [
Object {
"description": "Changelog desc",
"version": "5.0",
},
],
"description": "Foo Desc",
"hasResponseExample": true,
"internal": false,
"key": "foo",
"params": Array [
Object {
"description": "Param desc",
"internal": true,
"key": "param",
"required": true,
},
],
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [
Object {
"description": "Changelog desc",
"version": "5.0",
},
],
"description": "Foo Desc",
"hasResponseExample": true,
"internal": false,
"key": "foo",
"params": Array [
Object {
"description": "Param desc",
"internal": true,
"key": "param",
"required": true,
},
],
"post": false,
},
],
"deprecated": false,
"description": "API Foo",
"internal": false,
"path": "foo",
}
}
/>
`;

exports[`should render correctly 1`] = `
<div
className="web-api-action"
id="foo/foo"
>
<header
className="web-api-action-header"
>
<Link
className="spacer-right link-no-underline"
onlyActiveOnIndex={false}
style={Object {}}
to={
Object {
"pathname": "/web_api/foo/foo",
}
}
>
<LinkIcon />
</Link>
<h3
className="web-api-action-title"
>
GET
 
foo/foo
</h3>
</header>
<div
className="web-api-action-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "Foo Desc",
}
}
/>
<ul
className="web-api-action-actions tabs"
>
<li>
<a
className=""
href="#"
onClick={[Function]}
>
api_documentation.parameters
</a>
</li>
<li>
<a
className=""
href="#"
onClick={[Function]}
>
api_documentation.response_example
</a>
</li>
<li>
<a
className=""
href="#"
onClick={[Function]}
>
api_documentation.changelog
</a>
</li>
</ul>
</div>
`;

server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/ActionChangelog-test.js.snap → server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/ActionChangelog-test.tsx.snap View File


+ 0
- 230
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap View File

@@ -1,230 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should also render actions with a description matching the query 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"description": "foobar",
"key": "foo",
}
}
domain={
Object {
"actions": Array [
Object {
"description": "foobar",
"key": "foo",
},
Object {
"key": "bar",
},
Object {
"key": "baz",
},
],
"path": "api",
}
}
showDeprecated={false}
/>
<Action
action={
Object {
"key": "bar",
}
}
domain={
Object {
"actions": Array [
Object {
"description": "foobar",
"key": "foo",
},
Object {
"key": "bar",
},
Object {
"key": "baz",
},
],
"path": "api",
}
}
showDeprecated={false}
/>
</div>
</div>
`;

exports[`should not render deprecated actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
/>
</div>
`;

exports[`should not render internal actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
/>
</div>
`;

exports[`should render deprecated actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"deprecatedSince": "5.0",
"key": "foo",
}
}
domain={
Object {
"actions": Array [
Object {
"deprecatedSince": "5.0",
"key": "foo",
},
],
"path": "api",
}
}
showDeprecated={true}
/>
</div>
</div>
`;

exports[`should render internal actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"internal": true,
"key": "foo",
}
}
domain={
Object {
"actions": Array [
Object {
"internal": true,
"key": "foo",
},
],
"path": "api",
}
}
showInternal={true}
/>
</div>
</div>
`;

exports[`should render only actions matching the query 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"key": "foo",
}
}
domain={
Object {
"actions": Array [
Object {
"key": "foo",
},
Object {
"key": "bar",
},
],
"path": "api",
}
}
/>
</div>
</div>
`;

+ 369
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.tsx.snap View File

@@ -0,0 +1,369 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should also render actions with a description matching the query 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
},
Object {
"changelog": Array [],
"description": "Bar desc",
"hasResponseExample": false,
"internal": false,
"key": "bar",
"post": false,
},
Object {
"changelog": Array [],
"description": "foobar",
"hasResponseExample": false,
"internal": false,
"key": "baz",
"post": false,
},
],
"deprecated": false,
"description": "API Desc",
"internal": false,
"path": "api",
}
}
showDeprecated={false}
showInternal={false}
/>
<Action
action={
Object {
"changelog": Array [],
"description": "foobar",
"hasResponseExample": false,
"internal": false,
"key": "baz",
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
},
Object {
"changelog": Array [],
"description": "Bar desc",
"hasResponseExample": false,
"internal": false,
"key": "bar",
"post": false,
},
Object {
"changelog": Array [],
"description": "foobar",
"hasResponseExample": false,
"internal": false,
"key": "baz",
"post": false,
},
],
"deprecated": false,
"description": "API Desc",
"internal": false,
"path": "api",
}
}
showDeprecated={false}
showInternal={false}
/>
</div>
</div>
`;

exports[`should not render deprecated actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
/>
</div>
`;

exports[`should not render internal actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
/>
</div>
`;

exports[`should render deprecated actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"changelog": Array [],
"deprecatedSince": "5.0",
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [],
"deprecatedSince": "5.0",
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
},
],
"deprecated": false,
"description": "API Desc",
"internal": false,
"path": "api",
}
}
showDeprecated={true}
showInternal={false}
/>
</div>
</div>
`;

exports[`should render internal actions 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": true,
"key": "foo",
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": true,
"key": "foo",
"post": false,
},
],
"deprecated": false,
"description": "API Desc",
"internal": false,
"path": "api",
}
}
showDeprecated={false}
showInternal={true}
/>
</div>
</div>
`;

exports[`should render only actions matching the query 1`] = `
<div
className="web-api-domain"
>
<header
className="web-api-domain-header"
>
<h2
className="web-api-domain-title"
>
api
</h2>
</header>
<div
className="web-api-domain-description markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Desc",
}
}
/>
<div
className="web-api-domain-actions"
>
<Action
action={
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
}
}
domain={
Object {
"actions": Array [
Object {
"changelog": Array [],
"description": "Foo Desc",
"hasResponseExample": false,
"internal": false,
"key": "foo",
"post": false,
},
Object {
"changelog": Array [],
"description": "Bar desc",
"hasResponseExample": false,
"internal": false,
"key": "bar",
"post": false,
},
],
"deprecated": false,
"description": "API Desc",
"internal": false,
"path": "api",
}
}
showDeprecated={false}
showInternal={false}
/>
</div>
</div>
`;

+ 248
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Menu-test.tsx.snap View File

@@ -0,0 +1,248 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should also render domains with an actions description matching the query 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/bar"
>
<h3
className="list-group-item-heading"
>
bar
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Bar",
}
}
/>
</Link>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/baz"
>
<h3
className="list-group-item-heading"
>
baz
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Baz",
}
}
/>
</Link>
</div>
</div>
`;

exports[`should not render deprecated domains 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/foo"
>
<h3
className="list-group-item-heading"
>
foo
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Foo",
}
}
/>
</Link>
</div>
</div>
`;

exports[`should not render internal domains 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/foo"
>
<h3
className="list-group-item-heading"
>
foo
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Foo",
}
}
/>
</Link>
</div>
</div>
`;

exports[`should render deprecated domains 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/foo"
>
<h3
className="list-group-item-heading"
>
foo
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Foo",
}
}
/>
</Link>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/bar"
>
<h3
className="list-group-item-heading"
>
bar
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Bar",
}
}
/>
</Link>
</div>
</div>
`;

exports[`should render internal domains 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/foo"
>
<h3
className="list-group-item-heading"
>
foo
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Foo",
}
}
/>
</Link>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/bar"
>
<h3
className="list-group-item-heading"
>
bar
<InternalBadge />
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Bar",
}
}
/>
</Link>
</div>
</div>
`;

exports[`should render only domains with an action matching the query 1`] = `
<div
className="api-documentation-results panel"
>
<div
className="list-group"
>
<Link
className="list-group-item"
onlyActiveOnIndex={false}
style={Object {}}
to="/web_api/foo"
>
<h3
className="list-group-item-heading"
>
foo
</h3>
<div
className="list-group-item-text markdown"
dangerouslySetInnerHTML={
Object {
"__html": "API Foo",
}
}
/>
</Link>
</div>
</div>
`;

server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.js.snap → server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.tsx.snap View File

@@ -10,7 +10,7 @@ exports[`should not render deprecated parameters 1`] = `
</div>
`;

exports[`should render deprecated key 1`] = `
exports[`should render deprecated and internal parameters 1`] = `
<div
className="web-api-params"
>
@@ -31,9 +31,50 @@ exports[`should render deprecated key 1`] = `
<div
className="little-spacer-top"
>
<code>
foo-deprecated
</code>
<DeprecatedBadge
since="5.0"
/>
</div>
<div
className="note little-spacer-top"
>
optional
</div>
</td>
<td>
<div
className="markdown"
dangerouslySetInnerHTML={
Object {
"__html": "Foo desc",
}
}
/>
</td>
<td
style={
Object {
"width": 250,
}
}
/>
</tr>
<tr>
<td
className="markdown"
style={
Object {
"width": 180,
}
}
>
<code>
foo
</code>
<div
className="little-spacer-top"
>
<InternalBadge />
</div>
<div
className="little-spacer-top"
@@ -53,7 +94,7 @@ exports[`should render deprecated key 1`] = `
className="markdown"
dangerouslySetInnerHTML={
Object {
"__html": undefined,
"__html": "Foo desc",
}
}
/>
@@ -71,7 +112,7 @@ exports[`should render deprecated key 1`] = `
</div>
`;

exports[`should render deprecated parameters 1`] = `
exports[`should render deprecated key 1`] = `
<div
className="web-api-params"
>
@@ -96,6 +137,13 @@ exports[`should render deprecated parameters 1`] = `
since="5.0"
/>
</div>
<div
className="little-spacer-top"
>
<code>
foo-deprecated
</code>
</div>
<div
className="note little-spacer-top"
>
@@ -107,7 +155,7 @@ exports[`should render deprecated parameters 1`] = `
className="markdown"
dangerouslySetInnerHTML={
Object {
"__html": undefined,
"__html": "Foo desc",
}
}
/>

+ 23
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/ResponseExample-test.tsx.snap View File

@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly after fetching an example 1`] = `
<div
className="web-api-response"
/>
`;

exports[`should render correctly after fetching an example 2`] = `
<div
className="web-api-response"
>
<pre
style={
Object {
"whiteSpace": "pre-wrap",
}
}
>
my example
</pre>
</div>
`;

+ 70
- 0
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap View File

@@ -0,0 +1,70 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<div
className="web-api-search"
>
<div>
<i
className="icon-search"
/>
<input
className="spacer-left input-large"
onChange={[Function]}
placeholder="search_verb"
type="search"
value=""
/>
</div>
<div
className="big-spacer-top"
>
<Checkbox
checked={false}
onCheck={[Function]}
thirdState={false}
>
<span
className="little-spacer-left"
>
api_documentation.show_internal
</span>
</Checkbox>
<Tooltip
overlay="api_documentation.internal_tooltip"
placement="right"
>
<span>
<HelpIcon
className="spacer-left text-info"
/>
</span>
</Tooltip>
</div>
<div
className="spacer-top"
>
<Checkbox
checked={false}
onCheck={[Function]}
thirdState={false}
>
<span
className="little-spacer-left"
>
api_documentation.show_deprecated
</span>
</Checkbox>
<Tooltip
overlay="api_documentation.deprecation_tooltip"
placement="right"
>
<span>
<HelpIcon
className="spacer-left text-info"
/>
</span>
</Tooltip>
</div>
</div>
`;

+ 5
- 0
server/sonar-web/src/main/js/apps/web-api/styles/web-api.css View File

@@ -48,6 +48,11 @@
margin-top: 10px;
}

.web-api-action hr {
margin: 10px 0 0;
background-color: #ddd;
}

.web-api-params,
.web-api-response {
margin-top: 10px;

server/sonar-web/src/main/js/apps/web-api/utils.js → server/sonar-web/src/main/js/apps/web-api/utils.ts View File

@@ -17,15 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//@flow
/*:: import type { Domain, Action } from '../../api/web-api'; */
import { Domain, Action } from '../../api/web-api';

export function actionsFilter(
showDeprecated /*: boolean */,
showInternal /*: boolean */,
searchQuery /*: string */,
domain /*: Domain */,
action /*: Action */
showDeprecated: boolean,
showInternal: boolean,
searchQuery: string,
domain: Domain,
action: Action
) {
const lowSearchQuery = searchQuery.toLowerCase();
return (
@@ -36,11 +35,11 @@ export function actionsFilter(
);
}

export function getActionKey(domainPath /*: string */, actionKey /*: string */) {
export function getActionKey(domainPath: string, actionKey: string) {
return domainPath + '/' + actionKey;
}

export const isDomainPathActive = (path /*: string */, splat /*: string */) => {
export const isDomainPathActive = (path: string, splat: string) => {
const pathTokens = path.split('/');
const splatTokens = splat.split('/');


server/sonar-web/src/main/js/components/icons-components/LinkIcon.js → server/sonar-web/src/main/js/components/icons-components/LinkIcon.tsx View File

@@ -17,12 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
import React from 'react';
import * as React from 'react';

/*:: type Props = { className?: string, size?: number }; */
interface Props {
className?: string;
size?: number;
}

export default function LinkIcon({ className, size = 14 } /*: Props */) {
export default function LinkIcon({ className, size = 14 }: Props) {
/* eslint-disable max-len */
return (
<svg

+ 11
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -2875,6 +2875,17 @@ api_documentation.internal_tooltip=Use at your own risk; internal services are s
api_documentation.page=Web API
api_documentation.show_deprecated=Show Deprecated API
api_documentation.show_internal=Show Internal API
api_documentation.possible_values=Possible values
api_documentation.default_values=Default value
api_documentation.example_values=Example value
api_documentation.max_values=Maximum allowed values
api_documentation.internal=internal
api_documentation.deprecated=deprecated
api_documentation.depracated_since_x=deprecated since {0}
api_documentation.parameters=Parameters
api_documentation.response_example=Response Example
api_documentation.changelog=Changelog


#------------------------------------------------------------------------------
#

Loading…
Cancel
Save