]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10811 Update editions boxes for marketing needs
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 30 May 2018 09:58:36 +0000 (11:58 +0200)
committerSonarTech <sonartech@sonarsource.com>
Tue, 12 Jun 2018 18:21:00 +0000 (20:21 +0200)
18 files changed:
server/sonar-docs/src/images/sonarsource-icon.png [new file with mode: 0644]
server/sonar-docs/src/tooltips/editions/community.md [deleted file]
server/sonar-docs/src/tooltips/editions/datacenter.md
server/sonar-docs/src/tooltips/editions/developer.md
server/sonar-docs/src/tooltips/editions/enterprise.md
server/sonar-web/src/main/js/apps/marketplace/App.tsx
server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx
server/sonar-web/src/main/js/apps/marketplace/Header.tsx
server/sonar-web/src/main/js/apps/marketplace/__tests__/EditionBoxes-test.tsx
server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/EditionBoxes-test.tsx.snap
server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
server/sonar-web/src/main/js/apps/marketplace/components/__tests__/EditionBox-test.tsx
server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
server/sonar-web/src/main/js/apps/marketplace/style.css
server/sonar-web/src/main/js/apps/marketplace/utils.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

diff --git a/server/sonar-docs/src/images/sonarsource-icon.png b/server/sonar-docs/src/images/sonarsource-icon.png
new file mode 100644 (file)
index 0000000..430eb1f
Binary files /dev/null and b/server/sonar-docs/src/images/sonarsource-icon.png differ
diff --git a/server/sonar-docs/src/tooltips/editions/community.md b/server/sonar-docs/src/tooltips/editions/community.md
deleted file mode 100644 (file)
index 61ca7e8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-### Community Edition
-
-Comes with support for 9 programming languages, numerous plugins, integration with DevOps tool chains, and ability to connect to SonarLint in the IDE.
index 228f816a02337a3a02c68f753efe8fbd4eed90e6..4976256eb493ea19e98f94d3c6acc3620ab677b1 100644 (file)
@@ -1,3 +1,3 @@
-### Data Center Edition
+### ![SonarSource logo](/images/sonarsource-icon.png) Data Center Edition
 
-Enterprise Edition + component redundancy and data integrity
+Support for High-Availability. Allow every node of SonarQube to be redundant, in order to keep the service up at all times without worrying about downtime or interruption.
index 6c1bf7f04616e4254a1352d957023bbbbd096dd1..d2fafe1afb1b7b39edcafac2d7a34b9b1c2864ee 100644 (file)
@@ -1,3 +1,7 @@
-### Developer Edition
+### ![SonarSource logo](/images/sonarsource-icon.png) Developer Edition
+
+* Branch and Pull Requests analysis
+* Analysis of additional languages: C/C++, Objective-C, PL/SQL, ABAP , VB.NET, TSQL , Swift
+* Detection of security vulnerabilities
+* SonarLint notifications
 
-Community Edition + branch analysis, SonarLint push notifications, and 16 languages.
index 918dddbf05bd2bd8898956f5f98aa3a11f979363..34f709880df0e1b5cc1a7aaf9db2619d0789fee7 100644 (file)
@@ -1,3 +1,7 @@
-### Enterprise Edition
+### ![SonarSource logo](/images/sonarsource-icon.png) Enterprise Edition
+
+* Portfolio management
+* Executive reporting
+* Analysis of additional languages: COBOL, PL/I, RPG & VB6
+* Parallel processing of analysis reports
 
-Developer Edition + portfolio management, executive reporting, parallel processing of analysis reports and 20 languages.
index 966ab400de039bf390f02c4371ab9f06ca8e8553..486f4e2bd1703874201c8eb6e35763257be4e35a 100644 (file)
@@ -119,7 +119,7 @@ export default class App extends React.PureComponent<Props, State> {
   };
 
   render() {
-    const { currentEdition, standaloneMode, pendingPlugins } = this.props;
+    const { currentEdition = 'community', standaloneMode, pendingPlugins } = this.props;
     const { loadingPlugins, plugins } = this.state;
     const query = parseQuery(this.props.location.query);
     const filteredPlugins = query.search ? filterPlugins(plugins, query.search) : plugins;
@@ -128,8 +128,11 @@ export default class App extends React.PureComponent<Props, State> {
       <div className="page page-limited" id="marketplace-page">
         <Suggestions suggestions="marketplace" />
         <Helmet title={translate('marketplace.page')} />
-        <Header />
+        <Header currentEdition={currentEdition} />
         <EditionBoxes currentEdition={currentEdition} />
+        <header className="page-header">
+          <h1 className="page-title">{translate('marketplace.page.open_source_plugins')}</h1>
+        </header>
         <Search
           query={query}
           updateCenterActive={this.props.updateCenterActive}
index 0b762d28f7ef4f8ef595e10a33fce9dd7fd1878d..f79b349ec69aab354c7048173b964e473113654f 100644 (file)
@@ -24,7 +24,7 @@ import { EDITIONS } from './utils';
 import { getFormData } from '../../api/marketplace';
 
 export interface Props {
-  currentEdition?: string;
+  currentEdition: string;
 }
 
 interface State {
@@ -59,11 +59,18 @@ export default class EditionBoxes extends React.PureComponent<Props, State> {
   render() {
     const { currentEdition } = this.props;
     const { serverId, ncloc } = this.state;
+    const currentEditionIdx = EDITIONS.findIndex(edition => edition.key === currentEdition);
+    const visibleEditions = EDITIONS.slice(currentEditionIdx + 1);
+
+    if (visibleEditions.length <= 0) {
+      return null;
+    }
+
     return (
       <div className="spacer-bottom marketplace-editions">
-        {EDITIONS.map(edition => (
+        {visibleEditions.map(edition => (
           <EditionBox
-            currentEdition={currentEdition || 'community'}
+            currentEdition={currentEdition}
             edition={edition}
             key={edition.key}
             ncloc={ncloc}
index 6e63ce4d401e70eb0d0302ae3c069b19a38b1879..2c17f03f8e7e10c034234d05ef31b0b9d1439db8 100644 (file)
 import * as React from 'react';
 import { translate } from '../../helpers/l10n';
 
-export default function Header() {
+interface Props {
+  currentEdition: string;
+}
+
+export default function Header({ currentEdition }: Props) {
   return (
-    <header id="marketplace-header" className="page-header">
+    <header className="page-header" id="marketplace-header">
       <h1 className="page-title">{translate('marketplace.page')}</h1>
-      <p className="page-description">{translate('marketplace.page.description')}</p>
+      <h3 className="page-description">
+        {translate('marketplace.page.you_are_running', currentEdition)}
+      </h3>
+      <p className="page-description">
+        {currentEdition === 'datacenter'
+          ? translate('marketplace.page.description_best_edition')
+          : translate('marketplace.page.description')}
+      </p>
     </header>
   );
 }
index dd49bb10079b3922d9614b3f5b3eb70ea996c428..9c35ee382d6d45f3a46d602f03c5dd342999abd8 100644 (file)
@@ -23,19 +23,41 @@ import EditionBoxes from '../EditionBoxes';
 
 jest.mock('../utils', () => ({
   EDITIONS: [
-    { key: 'comunity', homeUrl: 'more_url' },
-    { key: 'developer', downloadUrl: 'download_url', homeUrl: 'more_url' }
+    { key: 'community', name: 'Community Edition', homeUrl: 'more_url' },
+    {
+      key: 'developer',
+      name: 'Developer Edition',
+      homeUrl: 'more_url'
+    },
+    {
+      key: 'enterprise',
+      name: 'Enterprise Edition',
+      homeUrl: 'more_url'
+    },
+    {
+      key: 'datacenter',
+      name: 'Data Center Edition',
+      homeUrl: 'more_url'
+    }
   ]
 }));
 
-it('should display the edition boxes correctly', () => {
+it('should display the available edition boxes correctly', () => {
   expect(getWrapper()).toMatchSnapshot();
 });
 
-it('should display the developer edition as installed', () => {
+it('should display the enterprise and datacenter edition boxes', () => {
   expect(getWrapper({ currentEdition: 'developer' })).toMatchSnapshot();
 });
 
+it('should display the datacenter edition box only', () => {
+  expect(getWrapper({ currentEdition: 'enterprise' })).toMatchSnapshot();
+});
+
+it('should not display any edition box', () => {
+  expect(getWrapper({ currentEdition: 'datacenter' }).type()).toBeNull();
+});
+
 function getWrapper(props = {}) {
-  return shallow(<EditionBoxes currentEdition={undefined} {...props} />);
+  return shallow(<EditionBoxes currentEdition={'community'} {...props} />);
 }
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/Header-test.tsx
new file mode 100644 (file)
index 0000000..3e0a609
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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 { shallow } from 'enzyme';
+import Header from '../Header';
+
+it('should render with installed editions', () => {
+  expect(shallow(<Header currentEdition="community" />)).toMatchSnapshot();
+  expect(shallow(<Header currentEdition="datacenter" />)).toMatchSnapshot();
+});
index 687a2cde364bf4bed371032f95fc9c9a8e2155c7..d8abf481899cbd80093628bcf453a747c8d48356 100644 (file)
@@ -1,57 +1,88 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`should display the developer edition as installed 1`] = `
+exports[`should display the available edition boxes correctly 1`] = `
 <div
   className="spacer-bottom marketplace-editions"
 >
   <EditionBox
-    currentEdition="developer"
+    currentEdition="community"
     edition={
       Object {
         "homeUrl": "more_url",
-        "key": "comunity",
+        "key": "developer",
+        "name": "Developer Edition",
       }
     }
-    key="comunity"
+    key="developer"
   />
   <EditionBox
-    currentEdition="developer"
+    currentEdition="community"
     edition={
       Object {
-        "downloadUrl": "download_url",
         "homeUrl": "more_url",
-        "key": "developer",
+        "key": "enterprise",
+        "name": "Enterprise Edition",
       }
     }
-    key="developer"
+    key="enterprise"
+  />
+  <EditionBox
+    currentEdition="community"
+    edition={
+      Object {
+        "homeUrl": "more_url",
+        "key": "datacenter",
+        "name": "Data Center Edition",
+      }
+    }
+    key="datacenter"
   />
 </div>
 `;
 
-exports[`should display the edition boxes correctly 1`] = `
+exports[`should display the datacenter edition box only 1`] = `
 <div
   className="spacer-bottom marketplace-editions"
 >
   <EditionBox
-    currentEdition="community"
+    currentEdition="enterprise"
     edition={
       Object {
         "homeUrl": "more_url",
-        "key": "comunity",
+        "key": "datacenter",
+        "name": "Data Center Edition",
       }
     }
-    key="comunity"
+    key="datacenter"
   />
+</div>
+`;
+
+exports[`should display the enterprise and datacenter edition boxes 1`] = `
+<div
+  className="spacer-bottom marketplace-editions"
+>
   <EditionBox
-    currentEdition="community"
+    currentEdition="developer"
     edition={
       Object {
-        "downloadUrl": "download_url",
         "homeUrl": "more_url",
-        "key": "developer",
+        "key": "enterprise",
+        "name": "Enterprise Edition",
       }
     }
-    key="developer"
+    key="enterprise"
+  />
+  <EditionBox
+    currentEdition="developer"
+    edition={
+      Object {
+        "homeUrl": "more_url",
+        "key": "datacenter",
+        "name": "Data Center Edition",
+      }
+    }
+    key="datacenter"
   />
 </div>
 `;
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/Header-test.tsx.snap
new file mode 100644 (file)
index 0000000..4b6c283
--- /dev/null
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render with installed editions 1`] = `
+<header
+  className="page-header"
+  id="marketplace-header"
+>
+  <h1
+    className="page-title"
+  >
+    marketplace.page
+  </h1>
+  <h3
+    className="page-description"
+  >
+    marketplace.page.you_are_running.community
+  </h3>
+  <p
+    className="page-description"
+  >
+    marketplace.page.description
+  </p>
+</header>
+`;
+
+exports[`should render with installed editions 2`] = `
+<header
+  className="page-header"
+  id="marketplace-header"
+>
+  <h1
+    className="page-title"
+  >
+    marketplace.page
+  </h1>
+  <h3
+    className="page-description"
+  >
+    marketplace.page.you_are_running.datacenter
+  </h3>
+  <p
+    className="page-description"
+  >
+    marketplace.page.description_best_edition
+  </p>
+</header>
+`;
index 968aa5660209e5ec9f3836e8b3ba5e814d65ec71..55309126c7e031a535e5ccae76a868d8ef5892a9 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import CheckIcon from '../../../components/icons-components/CheckIcon';
-import { translate } from '../../../helpers/l10n';
-import DocInclude from '../../../components/docs/DocInclude';
 import { Edition, getEditionUrl } from '../utils';
+import DocInclude from '../../../components/docs/DocInclude';
+import { translate } from '../../../helpers/l10n';
 
 interface Props {
   currentEdition: string;
@@ -30,23 +29,16 @@ interface Props {
   serverId?: string;
 }
 
-export default function EditionBox({ currentEdition, edition, ncloc, serverId }: Props) {
-  const isInstalled = currentEdition === edition.key;
-  const url = getEditionUrl(edition, { ncloc, serverId, sourceEdition: currentEdition });
+export default function EditionBox({ edition, ncloc, serverId, currentEdition }: Props) {
   return (
     <div className="boxed-group boxed-group-inner marketplace-edition">
-      {isInstalled && (
-        <span className="marketplace-edition-badge badge badge-normal-size display-flex-center">
-          <CheckIcon className="little-spacer-right" size={14} />
-          {translate('marketplace.installed')}
-        </span>
-      )}
-      <div>
-        <DocInclude path={'/tooltips/editions/' + edition.key} />
-      </div>
+      <DocInclude path={'/tooltips/editions/' + edition.key} />
       <div className="marketplace-edition-action spacer-top">
-        <a href={url} target="_blank">
-          {translate('marketplace.learn_more')}
+        <a
+          href={getEditionUrl(edition, { ncloc, serverId, sourceEdition: currentEdition })}
+          rel="noopener noreferrer"
+          target="_blank">
+          {translate('marketplace.ask_for_information')}
         </a>
       </div>
     </div>
index 4142b022e589b07f5b35eb45847f64d0ed49e24b..f4398076daf29516a46d3342c91fe021484e57a6 100644 (file)
@@ -29,13 +29,14 @@ const DEFAULT_EDITION = {
 };
 
 it('should display the edition', () => {
-  expect(getWrapper({ ncloc: 1000, serverId: 'serverId' })).toMatchSnapshot();
+  expect(
+    shallow(
+      <EditionBox
+        currentEdition="community"
+        edition={DEFAULT_EDITION}
+        ncloc={1000}
+        serverId="serverId"
+      />
+    )
+  ).toMatchSnapshot();
 });
-
-it('should show insalled badge', () => {
-  expect(getWrapper({ currentEdition: 'foo' })).toMatchSnapshot();
-});
-
-function getWrapper(props = {}) {
-  return shallow(<EditionBox currentEdition="community" edition={DEFAULT_EDITION} {...props} />);
-}
index 39c71155bc692cd59b5d4f3ce81ca89d6e0050c2..69af9d6c1dba376b009ad5c4182d15011b57453c 100644 (file)
@@ -4,50 +4,18 @@ exports[`should display the edition 1`] = `
 <div
   className="boxed-group boxed-group-inner marketplace-edition"
 >
-  <div>
-    <DocInclude
-      path="/tooltips/editions/foo"
-    />
-  </div>
+  <DocInclude
+    path="/tooltips/editions/foo"
+  />
   <div
     className="marketplace-edition-action spacer-top"
   >
     <a
       href="more_url?ncloc=1000&serverId=serverId&sourceEdition=community"
+      rel="noopener noreferrer"
       target="_blank"
     >
-      marketplace.learn_more
-    </a>
-  </div>
-</div>
-`;
-
-exports[`should show insalled badge 1`] = `
-<div
-  className="boxed-group boxed-group-inner marketplace-edition"
->
-  <span
-    className="marketplace-edition-badge badge badge-normal-size display-flex-center"
-  >
-    <CheckIcon
-      className="little-spacer-right"
-      size={14}
-    />
-    marketplace.installed
-  </span>
-  <div>
-    <DocInclude
-      path="/tooltips/editions/foo"
-    />
-  </div>
-  <div
-    className="marketplace-edition-action spacer-top"
-  >
-    <a
-      href="more_url?sourceEdition=foo"
-      target="_blank"
-    >
-      marketplace.learn_more
+      marketplace.ask_for_information
     </a>
   </div>
 </div>
index 0e2ef2a2831226145ae52638c0a0b5e86d5cb3da..5016e1db61b0993ff7c5203c079ddb82c2306d82 100644 (file)
@@ -20,7 +20,6 @@
 .marketplace-editions {
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
   margin-left: -8px;
   margin-right: -8px;
 }
   justify-content: space-between;
   margin-left: 8px;
   margin-right: 8px;
+  max-width: 50%;
+}
+
+.marketplace-edition .markdown img {
+  width: 16px;
 }
 
 .marketplace-edition .markdown h3 {
index 0c93eb22f17a1623bd541691b094ec3f72b921bc..29ea02d891f9b4c1f9456c0156705352e421f8ff 100644 (file)
@@ -66,7 +66,7 @@ export const EDITIONS: Edition[] = [
 
 export function getEditionUrl(
   edition: Edition,
-  data: { serverId?: string; ncloc?: number; sourceEdition: string }
+  data: { serverId?: string; ncloc?: number; sourceEdition?: string }
 ) {
   let url = edition.homeUrl;
   const query = stringify(omitNil(data));
index 546935e89ba50972c6995e48cc825090b21c4a75..f35e01ce87c49b4df1f1e0f4c341f585ecdb7290 100644 (file)
@@ -190,6 +190,7 @@ visibility=Visibility
 with=With
 worst=Worst
 yes=Yes
+no=No
 
 
 
@@ -2132,7 +2133,13 @@ workspace.no_rule=The rule has been removed or never existed.
 #
 #------------------------------------------------------------------------------
 marketplace.page=Marketplace
-marketplace.page.description=Discover and install new features
+marketplace.page.description=Discover more features with the SonarSource Editions:
+marketplace.page.description_best_edition=This Edition gives you access to all features of the SonarQube-SonarLint ecosystem, including all SonarSource code analyzers !
+marketplace.page.you_are_running.community=You are currently running a Community Edition.
+marketplace.page.you_are_running.developer=You are currently running a Developer Edition.
+marketplace.page.you_are_running.enterprise=You are currently running an Enterprise Edition.
+marketplace.page.you_are_running.datacenter=You are currently running a Data Center Edition.
+marketplace.page.open_source_plugins=Community plugins
 marketplace.instance_needs_to_be_restarted_to={instance} needs to be restarted in order to
 marketplace.install_x_plugins=install {nb} plugins
 marketplace.update_x_plugins=update {nb} plugins
@@ -2154,6 +2161,7 @@ marketplace.checking_license=Checking your license...
 marketplace._installed=installed
 marketplace.available_under_commercial_license=Available under our commercial editions
 marketplace.learn_more=Learn more
+marketplace.ask_for_information=Ask for more information
 marketplace.homepage=Homepage
 marketplace.issue_tracker=Issue Tracker
 marketplace.licensed_under_x=Licensed under {license}