diff options
Diffstat (limited to 'server/sonar-web/src/main/js/components')
30 files changed, 619 insertions, 414 deletions
diff --git a/server/sonar-web/src/main/js/components/charts/BubbleChart.d.ts b/server/sonar-web/src/main/js/components/charts/BubbleChart.d.ts new file mode 100644 index 00000000000..e1623c22d73 --- /dev/null +++ b/server/sonar-web/src/main/js/components/charts/BubbleChart.d.ts @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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'; + +interface Item { + x: number; + y: number; + size: number; + color?: string; + key?: string; + link?: any; + tooltip?: string; +} + +interface Props { + items: Item[]; + sizeRange?: [number, number]; + displayXGrid?: boolean; + displayXTicks?: boolean; + displayYGrid?: boolean; + displayYTicks?: boolean; + height: number; + padding: [number, number, number, number]; + formatXTick: (tick: number) => string; + formatYTick: (tick: number) => string; + onBubbleClick?: (link?: any) => void; + xDomain?: [number, number]; + yDomain?: [number, number]; +} + +export default class BubbleChart extends React.Component<Props> {} diff --git a/server/sonar-web/src/main/js/components/common/EmptySearch.js b/server/sonar-web/src/main/js/components/common/EmptySearch.tsx index 719a2239c90..24a00094ada 100644 --- a/server/sonar-web/src/main/js/components/common/EmptySearch.js +++ b/server/sonar-web/src/main/js/components/common/EmptySearch.tsx @@ -17,16 +17,15 @@ * 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 { translate } from '../../helpers/l10n'; import './EmptySearch.css'; -const EmptySearch = () => ( - <div className="empty-search"> - <h3>{translate('no_results_search')}</h3> - <p className="big-spacer-top">{translate('no_results_search.2')}</p> - </div> -); - -export default EmptySearch; +export default function EmptySearch() { + return ( + <div className="empty-search"> + <h3>{translate('no_results_search')}</h3> + <p className="big-spacer-top">{translate('no_results_search.2')}</p> + </div> + ); +} diff --git a/server/sonar-web/src/main/js/components/common/__tests__/EmptySearch-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/EmptySearch-test.tsx new file mode 100644 index 00000000000..c9738908af1 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/__tests__/EmptySearch-test.tsx @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 EmptySearch from '../EmptySearch'; + +it('renders', () => { + expect(shallow(<EmptySearch />)).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/EmptySearch-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/EmptySearch-test.tsx.snap new file mode 100644 index 00000000000..34dd6bf65a4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/EmptySearch-test.tsx.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<div + className="empty-search" +> + <h3> + no_results_search + </h3> + <p + className="big-spacer-top" + > + no_results_search.2 + </p> +</div> +`; diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBase.js b/server/sonar-web/src/main/js/components/controls/FavoriteBase.js index ac1d58186b3..d35340dbec5 100644 --- a/server/sonar-web/src/main/js/components/controls/FavoriteBase.js +++ b/server/sonar-web/src/main/js/components/controls/FavoriteBase.js @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import FavoriteIcon from '../common/FavoriteIcon'; +import FavoriteIcon from '../icons-components/FavoriteIcon'; export default class FavoriteBase extends React.PureComponent { static propTypes = { diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.js b/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx index 35260d19d85..0f63872c043 100644 --- a/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.js +++ b/server/sonar-web/src/main/js/components/controls/FavoriteBaseStateless.tsx @@ -17,21 +17,20 @@ * 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 PropTypes from 'prop-types'; -import classNames from 'classnames'; -import FavoriteIcon from '../common/FavoriteIcon'; +import * as React from 'react'; +import * as classNames from 'classnames'; +import FavoriteIcon from '../icons-components/FavoriteIcon'; -export default class FavoriteBaseStateless extends React.PureComponent { - static propTypes = { - favorite: PropTypes.bool.isRequired, - addFavorite: PropTypes.func.isRequired, - removeFavorite: PropTypes.func.isRequired, - className: PropTypes.string - }; +interface Props { + addFavorite: () => void; + className?: string; + favorite: boolean; + removeFavorite: () => void; +} - toggleFavorite = e => { - e.preventDefault(); +export default class FavoriteBaseStateless extends React.PureComponent<Props> { + toggleFavorite = (event: React.SyntheticEvent<HTMLAnchorElement>) => { + event.preventDefault(); if (this.props.favorite) { this.props.removeFavorite(); } else { diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteContainer.js b/server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts index 372cb3b182e..087ace39dbb 100644 --- a/server/sonar-web/src/main/js/components/controls/FavoriteContainer.js +++ b/server/sonar-web/src/main/js/components/controls/FavoriteContainer.ts @@ -25,7 +25,7 @@ import * as api from '../../api/favorites'; import { addGlobalErrorMessage } from '../../store/globalMessages/duck'; import { parseError } from '../../apps/code/utils'; -const addFavorite = componentKey => dispatch => { +const addFavorite = (componentKey: string) => (dispatch: Function) => { // optimistic update dispatch(actionCreators.addFavorite(componentKey)); api.addFavorite(componentKey).catch(error => { @@ -34,7 +34,7 @@ const addFavorite = componentKey => dispatch => { }); }; -const removeFavorite = componentKey => dispatch => { +const removeFavorite = (componentKey: string) => (dispatch: Function) => { // optimistic update dispatch(actionCreators.removeFavorite(componentKey)); api.removeFavorite(componentKey).catch(error => { @@ -43,11 +43,11 @@ const removeFavorite = componentKey => dispatch => { }); }; -const mapStateToProps = (state, ownProps) => ({ +const mapStateToProps = (state: any, ownProps: any) => ({ favorite: isFavorite(state, ownProps.componentKey) }); -const mapDispatchToProps = (dispatch, ownProps) => ({ +const mapDispatchToProps = (dispatch: Function, ownProps: any) => ({ addFavorite: () => dispatch(addFavorite(ownProps.componentKey)), removeFavorite: () => dispatch(removeFavorite(ownProps.componentKey)) }); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx new file mode 100644 index 00000000000..d3ed6358256 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBaseStateless-test.tsx @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 FavoriteBaseStateless from '../FavoriteBaseStateless'; +import { click } from '../../../helpers/testUtils'; + +it('renders', () => { + expect( + shallow( + <FavoriteBaseStateless addFavorite={jest.fn()} favorite={true} removeFavorite={jest.fn()} /> + ) + ).toMatchSnapshot(); +}); + +it('adds favorite', () => { + const addFavorite = jest.fn(); + const wrapper = shallow( + <FavoriteBaseStateless addFavorite={addFavorite} favorite={false} removeFavorite={jest.fn()} /> + ); + click(wrapper); + expect(addFavorite).toBeCalled(); +}); + +it('removes favorite', () => { + const removeFavorite = jest.fn(); + const wrapper = shallow( + <FavoriteBaseStateless + addFavorite={jest.fn()} + favorite={true} + removeFavorite={removeFavorite} + /> + ); + click(wrapper); + expect(removeFavorite).toBeCalled(); +}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap new file mode 100644 index 00000000000..9edbec0cb0f --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBaseStateless-test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<a + className="link-no-underline" + href="#" + onClick={[Function]} +> + <FavoriteIcon + favorite={true} + /> +</a> +`; diff --git a/server/sonar-web/src/main/js/components/common/FavoriteIcon.js b/server/sonar-web/src/main/js/components/icons-components/FavoriteIcon.tsx index 725f2ce960e..a07533ae13f 100644 --- a/server/sonar-web/src/main/js/components/common/FavoriteIcon.js +++ b/server/sonar-web/src/main/js/components/icons-components/FavoriteIcon.tsx @@ -17,34 +17,21 @@ * 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 classNames from 'classnames'; +import * as React from 'react'; +import * as classNames from 'classnames'; -/*:: -type Props = { - className?: string, - favorite: boolean, - size?: number -}; -*/ +interface Props { + className?: string; + favorite: boolean; + size?: number; +} -export default function FavoriteIcon(props /*: Props */) { - /* eslint max-len: 0 */ +export default function FavoriteIcon({ className, favorite, size = 16 }: Props) { return ( - <span - className={classNames( - 'icon-star', - { 'icon-star-favorite': props.favorite }, - props.className - )}> - <svg width={props.size} height={props.size} viewBox="0 0 16 16"> + <span className={classNames('icon-star', { 'icon-star-favorite': favorite }, className)}> + <svg width={size} height={size} viewBox="0 0 16 16"> <path d="M15.4275,5.77678C15.4275,5.90773 15.3501,6.05059 15.1953,6.20536L11.9542,9.36608L12.7221,13.8304C12.728,13.872 12.731,13.9316 12.731,14.0089C12.731,14.1339 12.6998,14.2396 12.6373,14.3259C12.5748,14.4122 12.484,14.4554 12.3649,14.4554C12.2518,14.4554 12.1328,14.4197 12.0078,14.3482L7.99888,12.2411L3.98995,14.3482C3.85901,14.4197 3.73996,14.4554 3.63281,14.4554C3.50781,14.4554 3.41406,14.4122 3.35156,14.3259C3.28906,14.2396 3.25781,14.1339 3.25781,14.0089C3.25781,13.9732 3.26377,13.9137 3.27567,13.8304L4.04353,9.36608L0.793531,6.20536C0.644719,6.04464 0.570313,5.90178 0.570313,5.77678C0.570313,5.55654 0.736979,5.41964 1.07031,5.36606L5.55245,4.71428L7.56138,0.651781C7.67447,0.407729 7.8203,0.285703 7.99888,0.285703C8.17745,0.285703 8.32328,0.407729 8.43638,0.651781L10.4453,4.71428L14.9274,5.36606C15.2608,5.41964 15.4274,5.55654 15.4274,5.77678L15.4275,5.77678Z" /> </svg> </span> ); } - -FavoriteIcon.defaultProps = { - size: 16 -}; diff --git a/server/sonar-web/src/main/js/components/measure/Measure.js b/server/sonar-web/src/main/js/components/measure/Measure.tsx index c95d52f8280..35177b49b95 100644 --- a/server/sonar-web/src/main/js/components/measure/Measure.js +++ b/server/sonar-web/src/main/js/components/measure/Measure.tsx @@ -17,26 +17,29 @@ * 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 Rating from '../ui/Rating'; import Level from '../ui/Level'; import Tooltips from '../controls/Tooltip'; import { formatMeasure, isDiffMetric } from '../../helpers/measures'; -import { formatLeak, getRatingTooltip } from './utils'; -/*:: import type { MeasureEnhanced } from './types'; */ +import { formatLeak, getRatingTooltip, MeasureEnhanced } from './utils'; -/*:: type Props = { - className?: string, - decimals?: ?number, - measure: MeasureEnhanced -}; */ +interface Props { + className?: string; + decimals?: number | null; + measure: MeasureEnhanced; +} -export default function Measure({ className, decimals, measure } /*: Props */) { +export default function Measure({ className, decimals, measure }: Props) { const metric = measure.metric; + const value = isDiffMetric(metric.key) ? measure.leak : measure.value; + + if (value == undefined) { + return null; + } if (metric.type === 'LEVEL') { - return <Level className={className} level={measure.value} />; + return <Level className={className} level={value} />; } if (metric.type !== 'RATING') { @@ -46,8 +49,7 @@ export default function Measure({ className, decimals, measure } /*: Props */) { return <span className={className}>{formattedValue != null ? formattedValue : '–'}</span>; } - const value = isDiffMetric(metric.key) ? measure.leak : measure.value; - const tooltip = getRatingTooltip(metric.key, value); + const tooltip = getRatingTooltip(metric.key, Number(value)); const rating = <Rating value={value} />; if (tooltip) { return ( diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx new file mode 100644 index 00000000000..8929a8bc1c5 --- /dev/null +++ b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +jest.mock('../../../helpers/measures', () => { + const measures = require.requireActual('../../../helpers/measures'); + measures.getRatingTooltip = jest.fn(() => 'tooltip'); + return measures; +}); + +import * as React from 'react'; +import { shallow } from 'enzyme'; +import Measure from '../Measure'; + +it('renders trivial measure', () => { + const measure = { metric: { key: 'coverage', name: 'Coverage', type: 'PERCENT' }, value: '73.0' }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); + +it('renders leak measure', () => { + const measure = { + metric: { key: 'new_coverage', name: 'Coverage on New Code', type: 'PERCENT' }, + leak: '36.0' + }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); + +it('renders LEVEL', () => { + const measure = { + metric: { key: 'quality_gate_status', name: 'Quality Gate', type: 'LEVEL' }, + value: 'ERROR' + }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); + +it('renders known RATING', () => { + const measure = { + metric: { key: 'sqale_rating', name: 'Maintainability Rating', type: 'RATING' }, + value: '3' + }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); + +it('renders unknown RATING', () => { + const measure = { + metric: { key: 'foo_rating', name: 'Foo Rating', type: 'RATING' }, + value: '4' + }; + expect(shallow(<Measure measure={measure} />)).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap b/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap new file mode 100644 index 00000000000..2988d9210e8 --- /dev/null +++ b/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/Measure-test.tsx.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders LEVEL 1`] = ` +<Level + level="ERROR" +/> +`; + +exports[`renders known RATING 1`] = ` +<Tooltip + overlay="tooltip" + placement="bottom" +> + <span> + <Rating + value="3" + /> + </span> +</Tooltip> +`; + +exports[`renders leak measure 1`] = ` +<span> + 36.0% +</span> +`; + +exports[`renders trivial measure 1`] = ` +<span> + 73.0% +</span> +`; + +exports[`renders unknown RATING 1`] = ` +<Rating + value="4" +/> +`; diff --git a/server/sonar-web/src/main/js/components/measure/utils.js b/server/sonar-web/src/main/js/components/measure/utils.ts index 62fef4790d0..017e709491d 100644 --- a/server/sonar-web/src/main/js/components/measure/utils.js +++ b/server/sonar-web/src/main/js/components/measure/utils.ts @@ -17,22 +17,34 @@ * 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 { formatMeasure, formatMeasureVariation, getRatingTooltip as nextGetRatingTooltip, isDiffMetric } from '../../helpers/measures'; -/*:: import type { Measure, MeasureEnhanced } from './types'; */ -/*:: import type { Metric } from '../../store/metrics/actions'; */ +import { Metric } from '../../app/types'; const KNOWN_RATINGS = ['sqale_rating', 'reliability_rating', 'security_rating']; +export interface MeasureIntern { + value?: string; + periods?: Array<{ index: number; value: string }>; +} + +export interface Measure extends MeasureIntern { + metric: string; +} + +export interface MeasureEnhanced extends MeasureIntern { + metric: Metric; + leak?: string | undefined | undefined; +} + export function enhanceMeasure( - measure /*: Measure */, - metrics /*: { [string]: Metric } */ -) /*: MeasureEnhanced */ { + measure: Measure, + metrics: { [key: string]: Metric } +): MeasureEnhanced { return { value: measure.value, periods: measure.periods, @@ -41,7 +53,7 @@ export function enhanceMeasure( }; } -export function formatLeak(value /*: ?string*/, metric /*: Metric*/, options /*: Object*/) { +export function formatLeak(value: string | undefined, metric: Metric, options: any): string { if (isDiffMetric(metric.key)) { return formatMeasure(value, metric.type, options); } else { @@ -49,18 +61,18 @@ export function formatLeak(value /*: ?string*/, metric /*: Metric*/, options /*: } } -export function getLeakValue(measure /*: ?Measure*/) /*: ?string*/ { +export function getLeakValue(measure: Measure | undefined): string | undefined { if (!measure || !measure.periods) { - return null; + return undefined; } const period = measure.periods.find(period => period.index === 1); - return period ? period.value : null; + return period && period.value; } -export function getRatingTooltip(metricKey /*: string */, value /*: ?string*/) { +export function getRatingTooltip(metricKey: string, value: number): string | undefined { const finalMetricKey = isDiffMetric(metricKey) ? metricKey.substr(4) : metricKey; if (KNOWN_RATINGS.includes(finalMetricKey)) { return nextGetRatingTooltip(finalMetricKey, value); } - return null; + return undefined; } diff --git a/server/sonar-web/src/main/js/components/shared/Organization.js b/server/sonar-web/src/main/js/components/shared/Organization.tsx index 1c3d5abf574..f411de59496 100644 --- a/server/sonar-web/src/main/js/components/shared/Organization.js +++ b/server/sonar-web/src/main/js/components/shared/Organization.tsx @@ -17,62 +17,48 @@ * 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 { connect } from 'react-redux'; import { getOrganizationByKey, areThereCustomOrganizations } from '../../store/rootReducer'; import OrganizationLink from '../ui/OrganizationLink'; -/*:: -type OwnProps = { - organizationKey: string -}; -*/ - -/*:: -type Props = { - link?: boolean, - linkClassName?: string, - organizationKey: string, - organization: { key: string, name: string } | null, - shouldBeDisplayed: boolean -}; -*/ - -class Organization extends React.PureComponent { - /*:: props: Props; */ - - static defaultProps = { - link: true - }; +interface OwnProps { + organizationKey: string; +} - render() { - const { organization, shouldBeDisplayed } = this.props; +interface Props { + link?: boolean; + linkClassName?: string; + organization: { key: string; name: string } | null; + shouldBeDisplayed: boolean; +} - if (!shouldBeDisplayed || !organization) { - return null; - } +function Organization(props: Props) { + const { link = true, organization, shouldBeDisplayed } = props; - return ( - <span> - {this.props.link ? ( - <OrganizationLink className={this.props.linkClassName} organization={organization}> - {organization.name} - </OrganizationLink> - ) : ( - organization.name - )} - <span className="slash-separator" /> - </span> - ); + if (!shouldBeDisplayed || !organization) { + return null; } + + return ( + <span> + {link ? ( + <OrganizationLink className={props.linkClassName} organization={organization}> + {organization.name} + </OrganizationLink> + ) : ( + organization.name + )} + <span className="slash-separator" /> + </span> + ); } -const mapStateToProps = (state, ownProps /*: OwnProps */) => ({ +const mapStateToProps = (state: any, ownProps: OwnProps) => ({ organization: getOrganizationByKey(state, ownProps.organizationKey), shouldBeDisplayed: areThereCustomOrganizations(state) }); -export default connect(mapStateToProps)(Organization); +export default connect<any, any, any>(mapStateToProps)(Organization); export const UnconnectedOrganization = Organization; diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.js b/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx index 7bb6ae80476..34f6ace01b2 100644 --- a/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.js +++ b/server/sonar-web/src/main/js/components/shared/__tests__/Organization-test.tsx @@ -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 { UnconnectedOrganization } from '../Organization'; diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.js.snap b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap index 72ffd1b6d84..72ffd1b6d84 100644 --- a/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.js.snap +++ b/server/sonar-web/src/main/js/components/shared/__tests__/__snapshots__/Organization-test.tsx.snap diff --git a/server/sonar-web/src/main/js/components/tags/TagsList.js b/server/sonar-web/src/main/js/components/tags/TagsList.tsx index c85ad16c00a..a35b0465358 100644 --- a/server/sonar-web/src/main/js/components/tags/TagsList.js +++ b/server/sonar-web/src/main/js/components/tags/TagsList.tsx @@ -17,37 +17,25 @@ * 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 classNames from 'classnames'; +import * as React from 'react'; +import * as classNames from 'classnames'; import './TagsList.css'; -/*:: -type Props = { - tags: Array<string>, - allowUpdate: boolean, - customClass?: string -}; -*/ - -export default class TagsList extends React.PureComponent { - /*:: props: Props; */ - - static defaultProps = { - allowUpdate: false - }; +interface Props { + allowUpdate?: boolean; + customClass?: string; + tags: string[]; +} - render() { - const { tags, allowUpdate } = this.props; - const spanClass = classNames('text-ellipsis', { note: !allowUpdate }); - const tagListClass = classNames('tags-list', this.props.customClass); +export default function TagsList({ allowUpdate = false, customClass, tags }: Props) { + const spanClass = classNames('text-ellipsis', { note: !allowUpdate }); + const tagListClass = classNames('tags-list', customClass); - return ( - <span className={tagListClass} title={tags.join(', ')}> - <i className="icon-tags icon-half-transparent" /> - <span className={spanClass}>{tags.join(', ')}</span> - {allowUpdate && <i className="icon-dropdown" />} - </span> - ); - } + return ( + <span className={tagListClass} title={tags.join(', ')}> + <i className="icon-tags icon-half-transparent" /> + <span className={spanClass}>{tags.join(', ')}</span> + {allowUpdate && <i className="icon-dropdown" />} + </span> + ); } diff --git a/server/sonar-web/src/main/js/components/tags/__tests__/TagsList-test.js b/server/sonar-web/src/main/js/components/tags/__tests__/TagsList-test.tsx index 438730aff86..d093e16e7fa 100644 --- a/server/sonar-web/src/main/js/components/tags/__tests__/TagsList-test.js +++ b/server/sonar-web/src/main/js/components/tags/__tests__/TagsList-test.tsx @@ -17,8 +17,8 @@ * 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 React from 'react'; import TagsList from '../TagsList'; const tags = ['foo', 'bar']; @@ -30,14 +30,10 @@ it('should render with a list of tag', () => { expect(taglist.find('span.note').hasClass('text-ellipsis')).toBe(true); }); -it('should FAIL to render without tags', () => { - expect(() => shallow(<TagsList />)).toThrow(); -}); - it('should correctly handle a lot of tags', () => { const lotOfTags = []; for (let i = 0; i < 20; i++) { - lotOfTags.push(tags); + lotOfTags.push(String(tags)); } const taglist = shallow(<TagsList tags={lotOfTags} />); expect(taglist.text()).toBe(lotOfTags.join(', ')); diff --git a/server/sonar-web/src/main/js/components/ui/CoverageRating.js b/server/sonar-web/src/main/js/components/ui/CoverageRating.js deleted file mode 100644 index 6fe1c7cc09e..00000000000 --- a/server/sonar-web/src/main/js/components/ui/CoverageRating.js +++ /dev/null @@ -1,70 +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 { DonutChart } from '../charts/donut-chart'; - -const SIZE_TO_WIDTH_MAPPING = { - small: 16, - normal: 24, - big: 40, - huge: 60 -}; - -const SIZE_TO_THICKNESS_MAPPING = { - small: 2, - normal: 3, - big: 3, - huge: 4 -}; - -export default class CoverageRating extends React.PureComponent { - /*:: props: { - value: number | string, - size?: 'small' | 'normal' | 'big' | 'huge', - muted?: boolean - }; -*/ - - static defaultProps = { - size: 'normal', - muted: false - }; - - render() { - let data = [{ value: 100, fill: '#ccc ' }]; - - if (this.props.value != null) { - const value = Number(this.props.value); - data = [ - { value, fill: this.props.muted ? '#bdbdbd' : '#00aa00' }, - { value: 100 - value, fill: this.props.muted ? '#f3f3f3' : '#d4333f' } - ]; - } - - // $FlowFixMe - const size = SIZE_TO_WIDTH_MAPPING[this.props.size]; - - // $FlowFixMe - const thickness = SIZE_TO_THICKNESS_MAPPING[this.props.size]; - - return <DonutChart data={data} width={size} height={size} thickness={thickness} />; - } -} diff --git a/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx new file mode 100644 index 00000000000..e7eda495d7f --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx @@ -0,0 +1,48 @@ +/* + * 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 { DonutChart } from '../charts/donut-chart'; + +const SIZE_TO_WIDTH_MAPPING = { small: 16, normal: 24, big: 40, huge: 60 }; + +const SIZE_TO_THICKNESS_MAPPING = { small: 2, normal: 3, big: 3, huge: 4 }; + +interface Props { + muted?: boolean; + size?: 'small' | 'normal' | 'big' | 'huge'; + value: number | string | null | undefined; +} + +export default function CoverageRating({ muted = false, size = 'normal', value }: Props) { + let data = [{ value: 100, fill: '#ccc ' }]; + + if (value != null) { + const numberValue = Number(value); + data = [ + { value: numberValue, fill: muted ? '#bdbdbd' : '#00aa00' }, + { value: 100 - numberValue, fill: muted ? '#f3f3f3' : '#d4333f' } + ]; + } + + const width = SIZE_TO_WIDTH_MAPPING[size]; + const thickness = SIZE_TO_THICKNESS_MAPPING[size]; + + return <DonutChart data={data} width={width} height={width} thickness={thickness} />; +} diff --git a/server/sonar-web/src/main/js/components/ui/DuplicationsRating.js b/server/sonar-web/src/main/js/components/ui/DuplicationsRating.js deleted file mode 100644 index 628adac1d1b..00000000000 --- a/server/sonar-web/src/main/js/components/ui/DuplicationsRating.js +++ /dev/null @@ -1,55 +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 classNames from 'classnames'; -import { inRange } from 'lodash'; -import './DuplicationsRating.css'; - -export default class DuplicationsRating extends React.PureComponent { - /*:: props: { - value: number, - size?: 'small' | 'normal' | 'big' | 'huge', - muted?: boolean - }; -*/ - - static defaultProps = { - small: false, - muted: false - }; - - render() { - const { value, size, muted } = this.props; - const className = classNames('duplications-rating', { - 'duplications-rating-small': size === 'small', - 'duplications-rating-big': size === 'big', - 'duplications-rating-huge': size === 'huge', - 'duplications-rating-muted': muted, - 'duplications-rating-A': inRange(value, 0, 3), - 'duplications-rating-B': inRange(value, 3, 5), - 'duplications-rating-C': inRange(value, 5, 10), - 'duplications-rating-D': inRange(value, 10, 20), - 'duplications-rating-E': value >= 20 - }); - - return <div className={className} />; - } -} diff --git a/server/sonar-web/src/main/js/components/ui/DuplicationsRating.tsx b/server/sonar-web/src/main/js/components/ui/DuplicationsRating.tsx new file mode 100644 index 00000000000..01703bafa31 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/DuplicationsRating.tsx @@ -0,0 +1,45 @@ +/* + * 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 * as classNames from 'classnames'; +import { inRange } from 'lodash'; +import './DuplicationsRating.css'; + +interface Props { + muted?: boolean; + size?: 'small' | 'normal' | 'big' | 'huge'; + value: number; +} + +export default function DuplicationsRating({ muted = false, size = 'normal', value }: Props) { + const className = classNames('duplications-rating', { + 'duplications-rating-small': size === 'small', + 'duplications-rating-big': size === 'big', + 'duplications-rating-huge': size === 'huge', + 'duplications-rating-muted': muted, + 'duplications-rating-A': inRange(value, 0, 3), + 'duplications-rating-B': inRange(value, 3, 5), + 'duplications-rating-C': inRange(value, 5, 10), + 'duplications-rating-D': inRange(value, 10, 20), + 'duplications-rating-E': value >= 20 + }); + + return <div className={className} />; +} diff --git a/server/sonar-web/src/main/js/components/ui/OrganizationLink.js b/server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx index 9251d1ae863..a5cc9d56804 100644 --- a/server/sonar-web/src/main/js/components/ui/OrganizationLink.js +++ b/server/sonar-web/src/main/js/components/ui/OrganizationLink.tsx @@ -17,18 +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. */ -// @flow -import React from 'react'; +import * as React from 'react'; import { Link } from 'react-router'; -export default function OrganizationLink( - props /*: { - children?: React.Element<*>, - organization: { - key: string - } -} */ -) { +interface Props { + children?: React.ReactNode; + organization: { key: string }; + [x: string]: any; +} + +export default function OrganizationLink(props: Props) { const { children, organization, ...other } = props; return ( diff --git a/server/sonar-web/src/main/js/components/ui/Rating.js b/server/sonar-web/src/main/js/components/ui/Rating.js deleted file mode 100644 index 0ec18df9e7c..00000000000 --- a/server/sonar-web/src/main/js/components/ui/Rating.js +++ /dev/null @@ -1,58 +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 PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { formatMeasure } from '../../helpers/measures'; -import './Rating.css'; - -export default class Rating extends React.PureComponent { - static propTypes = { - className: PropTypes.string, - value: (props, propName, componentName) => { - // allow both numbers and strings - const numberValue = Number(props[propName]); - if (numberValue < 1 || numberValue > 5) { - throw new Error(`Invalid prop "${propName}" passed to "${componentName}".`); - } - }, - small: PropTypes.bool, - muted: PropTypes.bool - }; - - static defaultProps = { - small: false, - muted: false - }; - - render() { - const formatted = formatMeasure(this.props.value, 'RATING'); - const className = classNames( - 'rating', - 'rating-' + formatted, - { - 'rating-small': this.props.small, - 'rating-muted': this.props.muted - }, - this.props.className - ); - return <span className={className}>{formatted}</span>; - } -} diff --git a/server/sonar-web/src/main/js/components/ui/Rating.tsx b/server/sonar-web/src/main/js/components/ui/Rating.tsx new file mode 100644 index 00000000000..67abfe61782 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/Rating.tsx @@ -0,0 +1,45 @@ +/* + * 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 * as classNames from 'classnames'; +import { formatMeasure } from '../../helpers/measures'; +import './Rating.css'; + +interface Props { + className?: string; + muted?: boolean; + small?: boolean; + value: string | number; +} + +export default function Rating({ className, muted = false, small = false, value }: Props) { + const formatted = formatMeasure(value, 'RATING'); + return ( + <span + className={classNames( + 'rating', + 'rating-' + formatted, + { 'rating-small': small, 'rating-muted': muted }, + className + )}> + {formatted} + </span> + ); +} diff --git a/server/sonar-web/src/main/js/components/ui/SizeRating.js b/server/sonar-web/src/main/js/components/ui/SizeRating.js deleted file mode 100644 index 3518c901225..00000000000 --- a/server/sonar-web/src/main/js/components/ui/SizeRating.js +++ /dev/null @@ -1,66 +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 classNames from 'classnames'; -import { inRange } from 'lodash'; -import './SizeRating.css'; - -export default class SizeRating extends React.PureComponent { - /*:: props: { - value: number, - small?: boolean, - muted?: boolean - }; -*/ - - static defaultProps = { - small: false, - muted: false - }; - - render() { - const { value } = this.props; - - if (value == null) { - return <div className="size-rating size-rating-muted"> </div>; - } - - let letter; - if (inRange(value, 0, 1000)) { - letter = 'XS'; - } else if (inRange(value, 1000, 10000)) { - letter = 'S'; - } else if (inRange(value, 10000, 100000)) { - letter = 'M'; - } else if (inRange(value, 100000, 500000)) { - letter = 'L'; - } else if (value >= 500000) { - letter = 'XL'; - } - - const className = classNames('size-rating', { - 'size-rating-small': this.props.small, - 'size-rating-muted': this.props.muted - }); - - return <div className={className}>{letter}</div>; - } -} diff --git a/server/sonar-web/src/main/js/components/ui/SizeRating.tsx b/server/sonar-web/src/main/js/components/ui/SizeRating.tsx new file mode 100644 index 00000000000..d4a657676c0 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/SizeRating.tsx @@ -0,0 +1,55 @@ +/* + * 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 * as classNames from 'classnames'; +import { inRange } from 'lodash'; +import './SizeRating.css'; + +interface Props { + muted?: boolean; + small?: boolean; + value: number | null | undefined; +} + +export default function SizeRating({ small = false, muted = false, value }: Props) { + if (value == null) { + return <div className="size-rating size-rating-muted"> </div>; + } + + let letter; + if (inRange(value, 0, 1000)) { + letter = 'XS'; + } else if (inRange(value, 1000, 10000)) { + letter = 'S'; + } else if (inRange(value, 10000, 100000)) { + letter = 'M'; + } else if (inRange(value, 100000, 500000)) { + letter = 'L'; + } else if (value >= 500000) { + letter = 'XL'; + } + + const className = classNames('size-rating', { + 'size-rating-small': small, + 'size-rating-muted': muted + }); + + return <div className={className}>{letter}</div>; +} diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx new file mode 100644 index 00000000000..feffbe8c87f --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/__tests__/OrganizationLink-test.tsx @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 OrganizationLink from '../OrganizationLink'; + +it('renders', () => { + expect(shallow(<OrganizationLink organization={{ key: 'org' }} />)).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap new file mode 100644 index 00000000000..147ffccb64f --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/OrganizationLink-test.tsx.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<Link + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/org" +/> +`; |