From: Stas Vilchik Date: Thu, 8 Feb 2018 11:05:28 +0000 (+0100) Subject: SONAR-10375 Project's homepage sidebar improvements (#3032) X-Git-Tag: 7.5~1710 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e497662d7c337fcc7c5293e2a38fd63cf8783bfd;p=sonarqube.git SONAR-10375 Project's homepage sidebar improvements (#3032) --- diff --git a/server/sonar-web/src/main/js/app/theme.js b/server/sonar-web/src/main/js/app/theme.js index b5ebfb7b796..04f518b8060 100644 --- a/server/sonar-web/src/main/js/app/theme.js +++ b/server/sonar-web/src/main/js/app/theme.js @@ -70,6 +70,8 @@ module.exports = { contextNavHeightRaw: 9 * grid, + pagePadding: '20px', + // different defaultShadow: '0 6px 12px rgba(0, 0, 0, 0.175)', diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx index b86c74027f4..4a4e572f7c3 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx +++ b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx @@ -65,7 +65,7 @@ export default class BadgesModal extends React.PureComponent { const header = translate('overview.badges.title'); const fullBadgeOptions = { branch, project, ...badgeOptions }; return ( - <> +
@@ -106,7 +106,7 @@ export default class BadgesModal extends React.PureComponent { )} - +
); } } diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap index f43e19a5715..e813fd772bd 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap @@ -1,14 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should display the modal after click 1`] = ` - +
- +
`; exports[`should display the modal after click 2`] = ` diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx index 44285fe03da..4e7dd8c57b5 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx @@ -191,7 +191,7 @@ export class OverviewApp extends React.PureComponent { -
+
{ return (
-

{translate('project_activity.page')}

+

+ {translate('overview.project_activity', this.props.component.qualifier)} +

{ const isProject = qualifier === 'TRK'; const isPrivate = visibility === Visibility.Private; - const hasDescription = !!description; - const hasQualityProfiles = Array.isArray(qualityProfiles) && qualityProfiles.length > 0; - const hasQualityGate = !!qualityGate; - - const shouldShowQualityProfiles = isProject && hasQualityProfiles; - const shouldShowQualityGate = isProject && hasQualityGate; - const hasOrganization = component.organization != null && organizationsEnabled; - return (
- {hasDescription && ( -
{description}
- )} - - - - {isProject && ( - - )} +
+

+ {translate('overview.about_this_project', qualifier)} +

+ {description !== undefined &&

{description}

} + {isProject && ( + + )} + +
{ qualifier={component.qualifier} /> - {shouldShowQualityGate && ( - - )} - - {shouldShowQualityProfiles && ( - + {isProject && ( +
+ {qualityGate && ( + + )} + + {qualityProfiles && + qualityProfiles.length > 0 && ( + + )} +
)} {isProject && } - - - {hasOrganization && } +
+ + {organizationsEnabled && } +
{onSonarCloud && isProject && diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.js deleted file mode 100644 index cfb43f2d58e..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import React from 'react'; -import { translate } from '../../../helpers/l10n'; - -const MetaKey = ({ component }) => { - return ( -
-

{translate('key')}

- e.target.select()} - /> -
- ); -}; - -export default MetaKey; diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.tsx new file mode 100644 index 00000000000..4d6c5748748 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaKey.tsx @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import ClipboardButton from '../../../components/controls/ClipboardButton'; +import { translate } from '../../../helpers/l10n'; + +interface Props { + componentKey: string; + qualifier: string; +} + +export default function MetaKey({ componentKey, qualifier }: Props) { + return ( + <> +

{translate('overview.project_key', qualifier)}

+
+ + +
+ + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx index 66980dda926..907d76a3877 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx @@ -22,6 +22,7 @@ import MetaLink from './MetaLink'; import { getProjectLinks, ProjectLink } from '../../../api/projectLinks'; import { orderLinks } from '../../project-admin/links/utils'; import { LightComponent } from '../../../app/types'; +import { translate } from '../../../helpers/l10n'; interface Props { component: LightComponent; @@ -71,6 +72,7 @@ export default class MetaLinks extends React.PureComponent { return (
+

{translate('overview.external_links')}

    {orderedLinks.map(link => )}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.js deleted file mode 100644 index 30bd9aa417b..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import React from 'react'; -import { translate } from '../../../helpers/l10n'; - -const MetaOrganizationKey = ({ component }) => { - return ( -
-

{translate('organization_key')}

- e.target.select()} - /> -
- ); -}; - -export default MetaOrganizationKey; diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.tsx new file mode 100644 index 00000000000..9d8ca5a8000 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaOrganizationKey.tsx @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { translate } from '../../../helpers/l10n'; +import ClipboardButton from '../../../components/controls/ClipboardButton'; + +interface Props { + organization: string; +} + +export default function MetaOrganizationKey({ organization }: Props) { + return ( + <> +

{translate('organization_key')}

+
+ + +
+ + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.js deleted file mode 100644 index 2181137c139..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import React from 'react'; -import { Link } from 'react-router'; -import { translate } from '../../../helpers/l10n'; -import { getQualityGateUrl } from '../../../helpers/urls'; - -const MetaQualityGate = ({ gate, organization }) => { - return ( -
-

{translate('overview.quality_gate')}

- -
    -
  • - {gate.isDefault && ( - {'(' + translate('default') + ')'} - )} - {gate.name} -
  • -
-
- ); -}; - -export default MetaQualityGate; diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.tsx new file mode 100644 index 00000000000..bd713048330 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityGate.tsx @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { Link } from 'react-router'; +import { translate } from '../../../helpers/l10n'; +import { getQualityGateUrl } from '../../../helpers/urls'; + +interface Props { + organization?: string; + qualityGate: { isDefault?: boolean; key: string; name: string }; +} + +export default function MetaQualityGate({ qualityGate, organization }: Props) { + return ( + <> +

{translate('overview.quality_gate')}

+ +
    +
  • + {qualityGate.isDefault && ( + {'(' + translate('default') + ')'} + )} + {qualityGate.name} +
  • +
+ + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.js deleted file mode 100644 index c39bcf3846d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.js +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -// @flow -import React from 'react'; -import { connect } from 'react-redux'; -import { Link } from 'react-router'; -import Tooltip from '../../../components/controls/Tooltip'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { getQualityProfileUrl } from '../../../helpers/urls'; -import { searchRules } from '../../../api/rules'; -import { getLanguages } from '../../../store/rootReducer'; - -class MetaQualityProfiles extends React.PureComponent { - /*:: mounted: boolean; */ - - /*:: props: { - component: { organization: string }, - customOrganizations: boolean, - languages: { [string]: { name: string } }, - organization: string | void; - profiles: Array<{ key: string, language: string, name: string }> - }; -*/ - - state = { - deprecatedByKey: {} - }; - - componentDidMount() { - this.mounted = true; - this.loadDeprecatedRules(); - } - - componentWillUnmount() { - this.mounted = false; - } - - loadDeprecatedRules() { - const requests = this.props.profiles.map(profile => - this.loadDeprecatedRulesForProfile(profile.key) - ); - Promise.all(requests).then( - responses => { - if (this.mounted) { - const deprecatedByKey = {}; - responses.forEach((count, i) => { - const profileKey = this.props.profiles[i].key; - deprecatedByKey[profileKey] = count; - }); - this.setState({ deprecatedByKey }); - } - }, - () => {} - ); - } - - loadDeprecatedRulesForProfile(profileKey) { - const data = { - activation: 'true', - organization: this.props.organization, - ps: 1, - qprofile: profileKey, - statuses: 'DEPRECATED' - }; - return searchRules(data).then(r => r.total); - } - - getDeprecatedRulesCount(profile) { - const count = this.state.deprecatedByKey[profile.key]; - return count || 0; - } - - renderProfile(profile) { - const languageFromStore = this.props.languages[profile.language]; - const languageName = languageFromStore ? languageFromStore.name : profile.language; - - const path = this.props.customOrganizations - ? getQualityProfileUrl(profile.name, profile.language, this.props.component.organization) - : getQualityProfileUrl(profile.name, profile.language); - - const inner = ( -
- {'(' + languageName + ')'} - {profile.name} -
- ); - - const count = this.getDeprecatedRulesCount(profile); - - if (count > 0) { - const tooltip = translateWithParameters('overview.deprecated_profile', count); - return ( - -
  • {inner}
  • -
    - ); - } - - return
  • {inner}
  • ; - } - - render() { - const { profiles } = this.props; - - return ( -
    -

    {translate('overview.quality_profiles')}

    - -
      - {profiles.map(profile => this.renderProfile(profile))} -
    -
    - ); - } -} - -const mapStateToProps = state => ({ - languages: getLanguages(state) -}); - -export default connect(mapStateToProps)(MetaQualityProfiles); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx new file mode 100644 index 00000000000..c9648810b85 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.tsx @@ -0,0 +1,140 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; +import * as classNames from 'classnames'; +import Tooltip from '../../../components/controls/Tooltip'; +import { translate, translateWithParameters } from '../../../helpers/l10n'; +import { getQualityProfileUrl } from '../../../helpers/urls'; +import { searchRules } from '../../../api/rules'; +import { getLanguages } from '../../../store/rootReducer'; + +interface StateProps { + languages: { [key: string]: { name: string } }; +} + +interface OwnProps { + headerClassName?: string; + organization?: string; + profiles: { key: string; language: string; name: string }[]; +} + +interface State { + deprecatedByKey: { [key: string]: number }; +} + +class MetaQualityProfiles extends React.PureComponent { + mounted: boolean; + state: State = { deprecatedByKey: {} }; + + componentDidMount() { + this.mounted = true; + this.loadDeprecatedRules(); + } + + componentWillUnmount() { + this.mounted = false; + } + + loadDeprecatedRules() { + const requests = this.props.profiles.map(profile => + this.loadDeprecatedRulesForProfile(profile.key) + ); + Promise.all(requests).then( + responses => { + if (this.mounted) { + const deprecatedByKey: { [key: string]: number } = {}; + responses.forEach((count, i) => { + const profileKey = this.props.profiles[i].key; + deprecatedByKey[profileKey] = count; + }); + this.setState({ deprecatedByKey }); + } + }, + () => {} + ); + } + + loadDeprecatedRulesForProfile(profileKey: string) { + const data = { + activation: 'true', + organization: this.props.organization, + ps: 1, + qprofile: profileKey, + statuses: 'DEPRECATED' + }; + return searchRules(data).then(r => r.total); + } + + getDeprecatedRulesCount(profile: { key: string }) { + const count = this.state.deprecatedByKey[profile.key]; + return count || 0; + } + + renderProfile(profile: { key: string; language: string; name: string }) { + const languageFromStore = this.props.languages[profile.language]; + const languageName = languageFromStore ? languageFromStore.name : profile.language; + + const path = getQualityProfileUrl(profile.name, profile.language, this.props.organization); + + const inner = ( +
    + {'(' + languageName + ')'} + {profile.name} +
    + ); + + const count = this.getDeprecatedRulesCount(profile); + + if (count > 0) { + const tooltip = translateWithParameters('overview.deprecated_profile', count); + return ( + +
  • {inner}
  • +
    + ); + } + + return
  • {inner}
  • ; + } + + render() { + const { headerClassName, profiles } = this.props; + + return ( + <> +

    + {translate('overview.quality_profiles')} +

    + +
      + {profiles.map(profile => this.renderProfile(profile))} +
    + + ); + } +} + +const mapStateToProps = (state: any) => ({ + languages: getLanguages(state) +}); + +export default connect(mapStateToProps)(MetaQualityProfiles); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx index 6465c861817..335d0b48795 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx @@ -89,7 +89,7 @@ export default class MetaSize extends React.PureComponent { } return ( -
    +
    {this.props.component.qualifier === 'APP' && this.renderProjects()} {this.renderLoC(ncloc)} {this.renderLoCDistribution()} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx index e0caea4f6fb..209b8a97880 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx @@ -99,7 +99,7 @@ export default class MetaTags extends React.PureComponent { if (this.canUpdateTags()) { return ( -
    (this.card = card)}> +
    (this.card = card)}>