From 10d9e0eb4ec208dba63e6c8bc2920adb788b04be Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 13 Mar 2017 17:28:41 +0100 Subject: SONAR-8779 hide deprecated api by default --- server/sonar-web/src/main/js/api/web-api.js | 4 +- .../src/main/js/apps/web-api/components/Action.js | 144 +++++++++++---------- .../src/main/js/apps/web-api/components/Domain.js | 66 ++++++---- .../src/main/js/apps/web-api/components/Menu.js | 66 ++++++---- .../src/main/js/apps/web-api/components/Params.js | 17 ++- .../src/main/js/apps/web-api/components/Search.js | 127 ++++++++++-------- .../main/js/apps/web-api/components/WebApiApp.js | 90 +++++++------ .../web-api/components/__tests__/Domain-test.js | 40 ++++++ .../web-api/components/__tests__/Params-test.js | 18 ++- .../__tests__/__snapshots__/Domain-test.js.snap | 49 +++++++ .../__tests__/__snapshots__/Params-test.js.snap | 56 ++++++++ 11 files changed, 446 insertions(+), 231 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js create mode 100644 server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap diff --git a/server/sonar-web/src/main/js/api/web-api.js b/server/sonar-web/src/main/js/api/web-api.js index bc58899bf9d..bd4803322fd 100644 --- a/server/sonar-web/src/main/js/api/web-api.js +++ b/server/sonar-web/src/main/js/api/web-api.js @@ -51,6 +51,7 @@ export type Action = { export type Domain = { actions: Array, description: string, + deprecated: boolean, internal: boolean, path: string }; @@ -60,9 +61,10 @@ export function fetchWebApi (showInternal: boolean = true): Promise r.webServices.map(domain => { + const deprecated = !domain.actions.find(action => !action.deprecatedSince); const internal = !domain.actions.find(action => !action.internal); - return { ...domain, internal }; + return { ...domain, deprecated, internal }; })); } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Action.js b/server/sonar-web/src/main/js/apps/web-api/components/Action.js index 0226a5d1a0c..8cb26123911 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Action.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Action.js @@ -17,6 +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. */ +// @flow import React from 'react'; import { Link } from 'react-router'; import { getActionKey } from '../utils'; @@ -25,24 +26,35 @@ import ResponseExample from './ResponseExample'; import DeprecatedBadge from './DeprecatedBadge'; import InternalBadge from './InternalBadge'; import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin'; +import type { Action as ActionType, Domain as DomainType } from '../../../api/web-api'; -export default class Action extends React.Component { - static propTypes = { - showInternal: React.PropTypes.bool - }; +type Props = { + action: ActionType, + domain: DomainType, + showDeprecated: boolean, + showInternal: boolean +}; + +type State = { + showParams: boolean, + showResponse: boolean +}; + +export default class Action extends React.PureComponent { + props: Props; - state = { + state: State = { showParams: false, showResponse: false }; - handleShowParamsClick (e) { + handleShowParamsClick (e: SyntheticInputEvent) { e.preventDefault(); this.refs.toggleParameters.blur(); this.setState({ showResponse: false, showParams: !this.state.showParams }); } - handleShowResponseClick (e) { + handleShowResponseClick (e: SyntheticInputEvent) { e.preventDefault(); this.refs.toggleResponse.blur(); this.setState({ showParams: false, showResponse: !this.state.showResponse }); @@ -55,69 +67,61 @@ export default class Action extends React.Component { const actionKey = getActionKey(domain.path, action.key); return ( -
- -
- - -

- {verb} {actionKey} -

- - {action.internal && ( - - - - )} - - {action.since && ( - since {action.since} - )} - - {action.deprecatedSince && ( - - - - )} -
-
- -
- - {(action.params || action.hasResponseExample) && ( - - )} - - {showParams && action.params && } - - {showResponse && action.hasResponseExample && } -
+
+ +
+ + +

+ {verb} {actionKey} +

+ + {action.internal && + + + } + + {action.since && since {action.since}} + + {action.deprecatedSince && + + + } +
+
+ +
+ + {(action.params || action.hasResponseExample) && + } + + {showParams && + action.params && + } + + {showResponse && + action.hasResponseExample && + } +
); } } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Domain.js b/server/sonar-web/src/main/js/apps/web-api/components/Domain.js index bb41c979a85..0cfbb1de482 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Domain.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Domain.js @@ -17,50 +17,60 @@ * 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 } from '../utils'; +import type { Domain as DomainType } from '../../../api/web-api'; -export default function Domain ({ domain, showInternal, showOnlyDeprecated, searchQuery }) { - const filteredActions = domain.actions - .filter(action => { - return showInternal || !action.internal; - }) - .filter(action => { - return !showOnlyDeprecated || (showOnlyDeprecated && action.deprecatedSince); - }) - .filter(action => { - const actionKey = getActionKey(domain.path, action.key); - return actionKey.indexOf(searchQuery) !== -1; - }); +type Props = { + domain: DomainType, + showDeprecated: boolean, + showInternal: boolean, + searchQuery: string +}; - return ( +export default class Domain extends React.PureComponent { + props: Props; + + render () { + const { domain, showInternal, showDeprecated, searchQuery } = this.props; + const filteredActions = domain.actions + .filter(action => showInternal || !action.internal) + .filter(action => showDeprecated || !action.deprecatedSince) + .filter(action => getActionKey(domain.path, action.key).indexOf(searchQuery) !== -1); + + return (

{domain.path}

- {domain.internal && ( - - - - )} + {domain.deprecated && + + + } + + {domain.internal && + + + }
- {domain.description && ( -

{domain.description}

- )} + {domain.description &&

{domain.description}

}
{filteredActions.map(action => ( - + ))}
- ); + ); + } } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js index 260587ce4ee..b2bea00727f 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js @@ -17,53 +17,63 @@ * 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 { getActionKey, isDomainPathActive } from '../utils'; +import type { Domain as DomainType } from '../../../api/web-api'; -export default function Menu ({ domains, showInternal, showOnlyDeprecated, searchQuery, splat }) { - const filteredDomains = (domains || []) +type Props = { + domains: Array, + 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 => { - return showInternal || !action.internal; - }) - .filter(action => { - return !showOnlyDeprecated || (showOnlyDeprecated && action.deprecatedSince); - }) - .filter(action => { - const actionKey = getActionKey(domain.path, action.key); - return actionKey.indexOf(searchQuery) !== -1; - }); + .filter(action => showInternal || !action.internal) + .filter(action => showDeprecated || !action.deprecatedSince) + .filter(action => getActionKey(domain.path, action.key).indexOf(searchQuery) !== -1); return { ...domain, filteredActions }; }) .filter(domain => domain.filteredActions.length); - return ( + return (
{filteredDomains.map(domain => ( - -

- {domain.path} - {domain.internal && ( - - )} -

-

- {domain.description} -

- + +

+ {domain.path} + {domain.deprecated && } + {domain.internal && } +

+

+ {domain.description} +

+ ))}
- ); + ); + } } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Params.js b/server/sonar-web/src/main/js/apps/web-api/components/Params.js index ac8459cc2f2..bba2118bfa0 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Params.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Params.js @@ -25,13 +25,16 @@ import type { Param } from '../../../api/web-api'; export default class Params extends React.PureComponent { props: { - params: Array, - showInternal: boolean + showDeprecated: boolean, + showInternal: boolean, + params: Array }; render () { - const { showInternal, params } = this.props; - const displayedParameters = showInternal ? params : params.filter(p => !p.internal); + const { showDeprecated, showInternal, params } = this.props; + const displayedParameters = params + .filter(p => showDeprecated || !p.deprecatedSince) + .filter(p => showInternal || !p.internal); return (
@@ -52,12 +55,14 @@ export default class Params extends React.PureComponent {
} - {param.deprecatedKey && + {showDeprecated && + param.deprecatedKey &&
{param.deprecatedKey}
} - {param.deprecatedKey && + {showDeprecated && + param.deprecatedKey && param.deprecatedKeySince &&
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Search.js b/server/sonar-web/src/main/js/apps/web-api/components/Search.js index 66f5da7cda4..233ad109a57 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Search.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/Search.js @@ -17,20 +17,37 @@ * 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 debounce from 'lodash/debounce'; import Checkbox from '../../../components/controls/Checkbox'; import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin'; import { translate } from '../../../helpers/l10n'; -export default class Search extends React.Component { - constructor (props) { +type Props = { + showDeprecated: boolean, + showInternal: boolean, + onSearch: (string) => void, + onToggleInternal: () => void, + onToggleDeprecated: () => void +}; + +type State = { + query: string +}; + +export default class Search extends React.PureComponent { + actuallySearch: () => void; + props: Props; + state: State; + + constructor (props: Props) { super(props); this.state = { query: '' }; this.actuallySearch = debounce(this.actuallySearch.bind(this), 250); } - handleSearch (e) { + handleSearch (e: SyntheticInputEvent) { const { value } = e.target; this.setState({ query: value }); this.actuallySearch(); @@ -42,64 +59,60 @@ export default class Search extends React.Component { } render () { - const { showInternal, showOnlyDeprecated, onToggleInternal, onToggleDeprecated } = this.props; + const { showInternal, showDeprecated, onToggleInternal, onToggleDeprecated } = this.props; return ( -
-
- - -
+
+
+ + +
- -
- - {' '} - - Show Internal API - - -
-
+ +
+ + {' '} + + Show Internal API + + +
+
- -
- - {' '} - - Show Only Deprecated API - - -
-
-
+ +
+ + {' '} + + Show Deprecated API + + +
+
+
); } } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js index 867bae7a974..6251e209c40 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js @@ -17,6 +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. */ +// @flow import React from 'react'; import { Link } from 'react-router'; import { fetchWebApi } from '../../../api/web-api'; @@ -24,14 +25,24 @@ import Menu from './Menu'; import Search from './Search'; import Domain from './Domain'; import { getActionKey, isDomainPathActive } from '../utils'; +import type { Domain as DomainType } from '../../../api/web-api'; import '../styles/web-api.css'; -export default class WebApiApp extends React.Component { - state = { +type State = { + domains: Array, + searchQuery: string, + showDeprecated: boolean, + showInternal: boolean +}; + +export default class WebApiApp extends React.PureComponent { + mounted: boolean; + scrollToAction: () => void; + state: State = { domains: [], searchQuery: '', - showInternal: false, - showOnlyDeprecated: false + showDeprecated: false, + showInternal: false }; componentDidMount () { @@ -51,7 +62,7 @@ export default class WebApiApp extends React.Component { document.getElementById('footer').classList.remove('search-navigator-footer'); } - fetchList (cb) { + fetchList (cb?: () => void) { fetchWebApi().then(domains => { if (this.mounted) { this.setState({ domains }, cb); @@ -64,7 +75,7 @@ export default class WebApiApp extends React.Component { this.scrollToElement(splat); } - scrollToElement (id) { + scrollToElement (id: string) { const element = document.getElementById(id); if (element) { @@ -96,7 +107,7 @@ export default class WebApiApp extends React.Component { } } - handleSearch (searchQuery) { + handleSearch (searchQuery: string) { this.setState({ searchQuery }); } @@ -115,50 +126,49 @@ export default class WebApiApp extends React.Component { } handleToggleDeprecated () { - this.setState({ showOnlyDeprecated: !this.state.showOnlyDeprecated }); + this.setState(state => ({ showDeprecated: !state.showDeprecated })); } render () { const splat = this.props.params.splat || ''; - const { domains, showInternal, showOnlyDeprecated, searchQuery } = this.state; + const { domains, showInternal, showDeprecated, searchQuery } = this.state; const domain = domains.find(domain => isDomainPathActive(domain.path, splat)); return ( -
-
-
- -

Web API

- -
- - - - +
+
+
+ +

Web API

+
-
- {domain && ( - - )} -
+ + + +
+ +
+ {domain && + }
+
); } } diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js new file mode 100644 index 00000000000..e503202d181 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Domain-test.js @@ -0,0 +1,40 @@ +/* + * 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()).toMatchSnapshot(); +}); + +it('should not render deprecated actions', () => { + const actions = [{ + key: 'foo', + deprecatedSince: '5.0' + }]; + const domain = { actions, path: 'api' }; + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.js b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.js index c3d0a92834c..8d3f89da3dd 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.js +++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/Params-test.js @@ -21,11 +21,27 @@ import React from 'react'; import { shallow } from 'enzyme'; import Params from '../Params'; +it('should render deprecated parameters', () => { + const params = [{ + key: 'foo', + deprecatedSince: '5.0' + }]; + expect(shallow()).toMatchSnapshot(); +}); + +it('should not render deprecated parameters', () => { + const params = [{ + key: 'foo', + deprecatedSince: '5.0' + }]; + expect(shallow()).toMatchSnapshot(); +}); + it('should render deprecated key', () => { const params = [{ key: 'foo', deprecatedKey: 'foo-deprecated', deprecatedKeySince: '5.0' }]; - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap new file mode 100644 index 00000000000..49b0fcb5b79 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Domain-test.js.snap @@ -0,0 +1,49 @@ +exports[`test should not render deprecated actions 1`] = ` +
+
+

+ api +

+
+
+
+`; + +exports[`test should render deprecated actions 1`] = ` +
+
+

+ api +

+
+
+ +
+
+`; diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.js.snap b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.js.snap index e96ab29ed2d..5bc2426ebef 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.js.snap +++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Params-test.js.snap @@ -1,3 +1,12 @@ +exports[`test should not render deprecated parameters 1`] = ` +
+ + +
+
+`; + exports[`test should render deprecated key 1`] = `
@@ -50,3 +59,50 @@ exports[`test should render deprecated key 1`] = `
`; + +exports[`test should render deprecated parameters 1`] = ` +
+ + + + + + + +
+ + foo + +
+ +
+
+ optional +
+
+
+
+
+
+`; -- cgit v1.2.3