]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10347 Create a CodeSnippet component and use it in project badges and onboardin...
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 8 Feb 2018 16:43:32 +0000 (17:43 +0100)
committerGuillaume Jambet <guillaume.jambet@gmail.com>
Thu, 1 Mar 2018 14:21:05 +0000 (15:21 +0100)
24 files changed:
server/sonar-web/src/main/js/apps/overview/badges/BadgeSnippet.tsx [deleted file]
server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap
server/sonar-web/src/main/js/apps/overview/badges/styles.css
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/ClangGCC.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js [deleted file]
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/DotNet.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaGradle.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaMaven.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Msvc.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Other.js
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js [deleted file]
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/ClangGCC-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap [deleted file]
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/DotNet-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaGradle-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaMaven-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Msvc-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Other-test.js.snap
server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css
server/sonar-web/src/main/js/components/common/CodeSnippet.css [new file with mode: 0644]
server/sonar-web/src/main/js/components/common/CodeSnippet.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/common/__tests__/CodeSnippet-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/CodeSnippet-test.tsx.snap [new file with mode: 0644]

diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgeSnippet.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgeSnippet.tsx
deleted file mode 100644 (file)
index 5deaf71..0000000
+++ /dev/null
@@ -1,34 +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 * as React from 'react';
-import ClipboardButton from '../../../components/controls/ClipboardButton';
-
-interface Props {
-  snippet: string;
-}
-
-export default function BadgeSnippet({ snippet }: Props) {
-  return (
-    <div className="badge-snippet">
-      <pre>{snippet}</pre>
-      <ClipboardButton copyValue={snippet} tooltipPlacement="top" />
-    </div>
-  );
-}
index fc98e4eb71ab7229ef309d89a664ddb2d729ec48..3592c4daea3cf1dce8fb2eef30cd19dc49b42b19 100644 (file)
  */
 import * as React from 'react';
 import BadgeButton from './BadgeButton';
-import BadgeSnippet from './BadgeSnippet';
 import BadgeParams from './BadgeParams';
 import { BadgeType, BadgeOptions, getBadgeUrl } from './utils';
 import { Metric } from '../../../app/types';
+import CodeSnippet from '../../../components/common/CodeSnippet';
 import Modal from '../../../components/controls/Modal';
 import { translate } from '../../../helpers/l10n';
 import './styles.css';
@@ -101,7 +101,7 @@ export default class BadgesModal extends React.PureComponent<Props, State> {
                 type={selectedType}
                 updateOptions={this.handleUpdateOptions}
               />
-              <BadgeSnippet snippet={getBadgeUrl(selectedType, fullBadgeOptions)} />
+              <CodeSnippet isOneLine={true} snippet={getBadgeUrl(selectedType, fullBadgeOptions)} />
             </div>
             <footer className="modal-foot">
               <ResetButtonLink className="js-modal-close" onClick={this.handleClose}>
index 8366543e432fb0eb82f570f04c676c6610632612..00776343f261329ec470d51602ffd9b3ffa4bcf8 100644 (file)
@@ -75,7 +75,8 @@ exports[`should display the modal after click 2`] = `
       type="measure"
       updateOptions={[Function]}
     />
-    <BadgeSnippet
+    <CodeSnippet
+      isOneLine={true}
       snippet="host/api/project_badges/measure?branch=branch-6.6&project=foo&metric=alert_status"
     />
   </div>
index 3fe0529fe4ca7be11585a222bc3e609e2d258bb1..f3866498378c024d4e21cc31b7e81d2d81fb6a8b 100644 (file)
   background-color: var(--lightBlue);
   border-color: var(--darkBlue);
 }
-
-.badge-snippet {
-  position: relative;
-  margin: var(--gridSize) 0;
-  background: var(--gray40);
-  color: var(--snippetFontColor);
-  border-radius: 3px;
-}
-
-.badge-snippet pre {
-  padding: calc(2 * var(--gridSize));
-  padding-bottom: 40px;
-  overflow: auto;
-}
-
-.badge-snippet button {
-  position: absolute;
-  top: auto;
-  top: 40px;
-  right: calc(2 * var(--gridSize));
-  height: var(--smallControlHeight);
-  line-height: 18px;
-  border: 1px solid #fff;
-  color: #fff;
-  font-size: 11px;
-  font-weight: normal;
-  user-select: none;
-}
-
-.badge-snippet button:hover,
-.badge-snippet button:focus,
-.badge-snippet button:active {
-  background-color: #fff;
-  color: var(--gray40);
-}
index 249c8cc297648c5065db3a82584473009496d197..26d3596d2e967bfff6b825a051e0729eff7fd70d 100644 (file)
@@ -19,9 +19,9 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
 import SQScanner from './SQScanner';
 import BuildWrapper from './BuildWrapper';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -67,8 +67,8 @@ export default function ClangGCC(props /*: Props */) {
           __html: translate('onboarding.analysis.sq_scanner.execute.text')
         }}
       />
-      <Command command={command1} isOneLine={true} />
-      <Command command={command2} isOneLine={props.os === 'win'} />
+      <CodeSnippet isOneLine={true} snippet={command1} />
+      <CodeSnippet isOneLine={props.os === 'win'} snippet={command2} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js
deleted file mode 100644 (file)
index 5e37065..0000000
+++ /dev/null
@@ -1,53 +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 classNames from 'classnames';
-import ClipboardButton from '../../../../components/controls/ClipboardButton';
-import { translate } from '../../../../helpers/l10n';
-
-/*::
-type Props = {
-  command: string | Array<?string>,
-  isOneLine?: boolean
-};
-*/
-
-// keep this "useless" concatentation for the readability reason
-// eslint-disable-next-line no-useless-concat
-const s = ' \\' + '\n  ';
-
-export default class Command extends React.PureComponent {
-  /*:: props: Props; */
-
-  render() {
-    const { command, isOneLine } = this.props;
-    const commandArray = Array.isArray(command) ? command.filter(line => line != null) : [command];
-    const finalCommand = isOneLine ? commandArray.join(' ') : commandArray.join(s);
-
-    return (
-      <div
-        className={classNames('onboarding-command', { 'onboarding-command-oneline': isOneLine })}>
-        <pre>{finalCommand}</pre>
-        <ClipboardButton copyValue={finalCommand} tooltipPlacement="top" />
-      </div>
-    );
-  }
-}
index 493eb4f690b2536daf4707cc6de1978551b6d722..7e5fd4f24e0d77bc18ab9696022577014b6d32fd 100644 (file)
@@ -19,8 +19,8 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
 import MSBuildScanner from './MSBuildScanner';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -58,9 +58,9 @@ export default function DotNet(props /*: Props */) {
           __html: translate('onboarding.analysis.msbuild.execute.text')
         }}
       />
-      <Command command={command1} isOneLine={true} />
-      <Command command={command2} isOneLine={true} />
-      <Command command={command3} isOneLine={true} />
+      <CodeSnippet isOneLine={true} snippet={command1} />
+      <CodeSnippet isOneLine={true} snippet={command2} />
+      <CodeSnippet isOneLine={true} snippet={command3} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
index 83f34e622e3288ad9d729e11d23e87a2e1383946..41913848279c120ac29292919d4de396dafdad41 100644 (file)
@@ -19,7 +19,7 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -47,11 +47,11 @@ export default function JavaGradle(props /*: Props */) {
         className="spacer-bottom markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.gradle.text.1') }}
       />
-      <Command command={config} />
+      <CodeSnippet snippet={config} />
       <p className="spacer-top spacer-bottom markdown">
         {translate('onboarding.analysis.java.gradle.text.2')}
       </p>
-      <Command command={command} />
+      <CodeSnippet snippet={command} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.gradle.docs') }}
index 1c7f56e137df9b42cbb4b5170ae3de0566a2a6c1..a54a97e14435001abed14b4efaf8e3ede722fd06 100644 (file)
@@ -19,7 +19,7 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -42,7 +42,7 @@ export default function JavaMaven(props /*: Props */) {
     <div>
       <h4 className="spacer-bottom">{translate('onboarding.analysis.java.maven.header')}</h4>
       <p className="spacer-bottom markdown">{translate('onboarding.analysis.java.maven.text')}</p>
-      <Command command={command} />
+      <CodeSnippet snippet={command} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.maven.docs') }}
index c8fc810659573b7a1545a9ed7f8176b10523a4ff..756c2daea3131c5496240372e6b3be842adebdb2 100644 (file)
@@ -19,9 +19,9 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
 import MSBuildScanner from './MSBuildScanner';
 import BuildWrapper from './BuildWrapper';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -61,9 +61,9 @@ export default function Msvc(props /*: Props */) {
           __html: translate('onboarding.analysis.msbuild.execute.text')
         }}
       />
-      <Command command={command1} isOneLine={true} />
-      <Command command={command2} isOneLine={true} />
-      <Command command={command3} isOneLine={true} />
+      <CodeSnippet isOneLine={true} snippet={command1} />
+      <CodeSnippet isOneLine={true} snippet={command2} />
+      <CodeSnippet isOneLine={true} snippet={command3} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
index 2698d23cd097cefb2ef4db66632eb8b92b0f15ec..47be65b1952418748671b94a389251150c92cc76 100644 (file)
@@ -19,8 +19,8 @@
  */
 // @flow
 import React from 'react';
-import Command from './Command';
 import SQScanner from './SQScanner';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
 import { translate } from '../../../../helpers/l10n';
 
 /*::
@@ -56,7 +56,7 @@ export default function Other(props /*: Props */) {
           __html: translate('onboarding.analysis.sq_scanner.execute.text')
         }}
       />
-      <Command command={command} isOneLine={props.os === 'win'} />
+      <CodeSnippet isOneLine={props.os === 'win'} snippet={command} />
       <p
         className="big-spacer-top markdown"
         dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js
deleted file mode 100644 (file)
index f4aa51c..0000000
+++ /dev/null
@@ -1,27 +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 { mount } from 'enzyme';
-import Command from '../Command';
-
-it('renders correctly', () => {
-  expect(mount(<Command command={'foo\nbar'} />)).toMatchSnapshot();
-});
index 42680367bee27291a0406856d33b701aff697064..4375df814f3b89e254f45caf32cb1753d8e50a81 100644 (file)
@@ -22,12 +22,13 @@ exports[`renders correctly 1`] = `
       }
     }
   />
-  <Command
-    command="build-wrapper-win-x86-64.exe --out-dir bw-output make clean all"
+  <CodeSnippet
     isOneLine={true}
+    snippet="build-wrapper-win-x86-64.exe --out-dir bw-output make clean all"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "sonar-scanner.bat",
         "-Dsonar.projectKey=projectKey",
@@ -38,7 +39,6 @@ exports[`renders correctly 1`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
@@ -73,12 +73,13 @@ exports[`renders correctly 2`] = `
       }
     }
   />
-  <Command
-    command="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
+  <CodeSnippet
     isOneLine={true}
+    snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={false}
+    snippet={
       Array [
         "sonar-scanner",
         "-Dsonar.projectKey=projectKey",
@@ -89,7 +90,6 @@ exports[`renders correctly 2`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={false}
   />
   <p
     className="big-spacer-top markdown"
@@ -124,12 +124,13 @@ exports[`renders correctly 3`] = `
       }
     }
   />
-  <Command
-    command="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
+  <CodeSnippet
     isOneLine={true}
+    snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={false}
+    snippet={
       Array [
         "sonar-scanner",
         "-Dsonar.projectKey=projectKey",
@@ -140,7 +141,6 @@ exports[`renders correctly 3`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={false}
   />
   <p
     className="big-spacer-top markdown"
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap
deleted file mode 100644 (file)
index a7a6a00..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<Command
-  command="foo
-bar"
->
-  <div
-    className="onboarding-command"
-  >
-    <pre>
-      foo
-bar
-    </pre>
-    <ClipboardButton
-      copyValue="foo
-bar"
-      tooltipPlacement="top"
-    >
-      <Button
-        className="js-copy-to-clipboard no-select"
-        data-clipboard-text="foo
-bar"
-        innerRef={[Function]}
-      >
-        <button
-          className="button js-copy-to-clipboard no-select"
-          data-clipboard-text="foo
-bar"
-          onClick={[Function]}
-          type="button"
-        >
-          copy
-        </button>
-      </Button>
-    </ClipboardButton>
-  </div>
-</Command>
-`;
index 56d2150cae2ffeae8036828f7be52c684b71547b..e21df31e564e0129d9eafead4afd96f56433f8ba 100644 (file)
@@ -16,8 +16,9 @@ exports[`renders correctly 1`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe begin",
         "/k:\\"projectKey\\"",
@@ -26,20 +27,19 @@ exports[`renders correctly 1`] = `
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
-  <Command
-    command="MsBuild.exe /t:Rebuild"
+  <CodeSnippet
     isOneLine={true}
+    snippet="MsBuild.exe /t:Rebuild"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe end",
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
@@ -68,8 +68,9 @@ exports[`renders correctly 2`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe begin",
         "/k:\\"projectKey\\"",
@@ -78,20 +79,19 @@ exports[`renders correctly 2`] = `
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
-  <Command
-    command="MsBuild.exe /t:Rebuild"
+  <CodeSnippet
     isOneLine={true}
+    snippet="MsBuild.exe /t:Rebuild"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe end",
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
index 264de313eac2a68b2a9a6b59963b6eea512972d3..fe46b14fff4ba6465db631667dd3e7fe22db7f1a 100644 (file)
@@ -15,8 +15,8 @@ exports[`renders correctly 1`] = `
       }
     }
   />
-  <Command
-    command="plugins {
+  <CodeSnippet
+    snippet="plugins {
   id \\"org.sonarqube\\" version \\"2.6\\"
 }"
   />
@@ -25,8 +25,8 @@ exports[`renders correctly 1`] = `
   >
     onboarding.analysis.java.gradle.text.2
   </p>
-  <Command
-    command={
+  <CodeSnippet
+    snippet={
       Array [
         "./gradlew sonarqube",
         undefined,
@@ -69,8 +69,8 @@ exports[`renders correctly 2`] = `
       }
     }
   />
-  <Command
-    command="plugins {
+  <CodeSnippet
+    snippet="plugins {
   id \\"org.sonarqube\\" version \\"2.6\\"
 }"
   />
@@ -79,8 +79,8 @@ exports[`renders correctly 2`] = `
   >
     onboarding.analysis.java.gradle.text.2
   </p>
-  <Command
-    command={
+  <CodeSnippet
+    snippet={
       Array [
         "./gradlew sonarqube",
         "-Dsonar.organization=organization",
index 60d6f6c8dfb80c58519dc67868650759b43b068e..00a5d783eb596b5661ed8e504c5352b8e432cbf3 100644 (file)
@@ -12,8 +12,8 @@ exports[`renders correctly 1`] = `
   >
     onboarding.analysis.java.maven.text
   </p>
-  <Command
-    command={
+  <CodeSnippet
+    snippet={
       Array [
         "mvn sonar:sonar",
         undefined,
@@ -53,8 +53,8 @@ exports[`renders correctly 2`] = `
   >
     onboarding.analysis.java.maven.text
   </p>
-  <Command
-    command={
+  <CodeSnippet
+    snippet={
       Array [
         "mvn sonar:sonar",
         "-Dsonar.organization=organization",
index c5260a8f2e7ac04e6da4aaf71985497c5a2bd06b..a5e4f91b4e306aae5dd961636f023484c50c973e 100644 (file)
@@ -20,8 +20,9 @@ exports[`renders correctly 1`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe begin",
         "/k:\\"projectKey\\"",
@@ -31,20 +32,19 @@ exports[`renders correctly 1`] = `
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
-  <Command
-    command="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
+  <CodeSnippet
     isOneLine={true}
+    snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe end",
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
@@ -77,8 +77,9 @@ exports[`renders correctly 2`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe begin",
         "/k:\\"projectKey\\"",
@@ -88,20 +89,19 @@ exports[`renders correctly 2`] = `
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
-  <Command
-    command="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
+  <CodeSnippet
     isOneLine={true}
+    snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "SonarQube.Scanner.MSBuild.exe end",
         "/d:sonar.login=\\"token\\"",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
index ba21667f2f5ddac5bd1608b861e4cb7f2b5f1f20..7c7ae719489ff1b000bb81e1d7bc37155816cbfe 100644 (file)
@@ -18,8 +18,9 @@ exports[`renders correctly 1`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={true}
+    snippet={
       Array [
         "sonar-scanner.bat",
         "-Dsonar.projectKey=projectKey",
@@ -29,7 +30,6 @@ exports[`renders correctly 1`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={true}
   />
   <p
     className="big-spacer-top markdown"
@@ -60,8 +60,9 @@ exports[`renders correctly 2`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={false}
+    snippet={
       Array [
         "sonar-scanner",
         "-Dsonar.projectKey=projectKey",
@@ -71,7 +72,6 @@ exports[`renders correctly 2`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={false}
   />
   <p
     className="big-spacer-top markdown"
@@ -102,8 +102,9 @@ exports[`renders correctly 3`] = `
       }
     }
   />
-  <Command
-    command={
+  <CodeSnippet
+    isOneLine={false}
+    snippet={
       Array [
         "sonar-scanner",
         "-Dsonar.projectKey=projectKey",
@@ -113,7 +114,6 @@ exports[`renders correctly 3`] = `
         "-Dsonar.login=token",
       ]
     }
-    isOneLine={false}
   />
   <p
     className="big-spacer-top markdown"
index e12fb2dde8687749357593821b516edcd6744774..9c8dfc093fcd03fd2704f5393e1b13dc5eeae9cd 100644 (file)
   outline: none;
 }
 
-.onboarding-command {
-  position: relative;
-  margin: 8px 0;
-}
-
-.onboarding-command pre {
-  padding: 15px;
-  border-radius: 2px;
-  background: var(--gray40);
-  color: var(--snippetFontColor);
-  overflow: auto;
-}
-
-.onboarding-command button {
-  position: absolute;
-  top: 15px;
-  right: 15px;
-  height: 20px;
-  line-height: 18px;
-  border: 1px solid #fff;
-  color: #fff;
-  font-size: 11px;
-  font-weight: normal;
-  user-select: none;
-}
-
-.onboarding-command button:hover,
-.onboarding-command button:focus,
-.onboarding-command button:active {
-  background-color: #fff;
-  color: var(--gray40);
-}
-
-.onboarding-command-oneline pre {
-  padding-bottom: 40px;
-}
-
-.onboarding-command-oneline button {
-  top: auto;
-  top: 40px;
-}
-
 .onboarding .page-actions {
   text-align: right;
   margin-bottom: 0;
diff --git a/server/sonar-web/src/main/js/components/common/CodeSnippet.css b/server/sonar-web/src/main/js/components/common/CodeSnippet.css
new file mode 100644 (file)
index 0000000..18232d6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+.code-snippet {
+  position: relative;
+  margin: var(--gridSize) 0;
+  background: var(--gray40);
+  color: var(--snippetFontColor);
+  border-radius: 3px;
+}
+
+.code-snippet pre {
+  padding: calc(2 * var(--gridSize));
+  overflow: auto;
+}
+
+.code-snippet button {
+  position: absolute;
+  top: calc(2 * var(--gridSize));
+  right: calc(2 * var(--gridSize));
+  line-height: 18px;
+  border: 1px solid #fff;
+  color: #fff;
+  font-size: 11px;
+  font-weight: normal;
+  user-select: none;
+}
+
+.code-snippet button:hover,
+.code-snippet button:focus,
+.code-snippet button:active {
+  background-color: #fff;
+  color: var(--gray40);
+}
+
+.code-snippet-oneline pre {
+  padding-bottom: 40px;
+}
+
+.code-snippet-oneline button {
+  top: auto;
+  top: 40px;
+}
diff --git a/server/sonar-web/src/main/js/components/common/CodeSnippet.tsx b/server/sonar-web/src/main/js/components/common/CodeSnippet.tsx
new file mode 100644 (file)
index 0000000..6e24695
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 * as classNames from 'classnames';
+import ClipboardButton from '../controls/ClipboardButton';
+import './CodeSnippet.css';
+
+interface Props {
+  className?: string;
+  isOneLine?: boolean;
+  noCopy?: boolean;
+  snippet: string | (string | undefined)[];
+}
+
+// keep this "useless" concatentation for the readability reason
+// eslint-disable-next-line no-useless-concat
+const s = ' \\' + '\n  ';
+
+export default function CodeSnippet({ className, isOneLine, noCopy, snippet }: Props) {
+  const snippetArray = Array.isArray(snippet)
+    ? snippet.filter(line => line !== undefined)
+    : [snippet];
+  const finalSnippet = isOneLine ? snippetArray.join(' ') : snippetArray.join(s);
+  return (
+    <div className={classNames('code-snippet', { 'code-snippet-oneline': isOneLine }, className)}>
+      <pre>{finalSnippet}</pre>
+      {!noCopy && <ClipboardButton copyValue={finalSnippet} tooltipPlacement="top" />}
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/CodeSnippet-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/CodeSnippet-test.tsx
new file mode 100644 (file)
index 0000000..8956e41
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 { mount } from 'enzyme';
+import CodeSnippet from '../CodeSnippet';
+
+it('renders correctly', () => {
+  expect(mount(<CodeSnippet snippet={'foo\nbar'} />)).toMatchSnapshot();
+  expect(mount(<CodeSnippet snippet={'foo\nbar'} noCopy={true} />)).toMatchSnapshot();
+});
+
+it('renders correctly with array snippet', () => {
+  expect(mount(<CodeSnippet snippet={['foo', 'bar']} />)).toMatchSnapshot();
+  expect(mount(<CodeSnippet snippet={['foo', 'bar']} isOneLine={true} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/CodeSnippet-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
new file mode 100644 (file)
index 0000000..5e330d1
--- /dev/null
@@ -0,0 +1,111 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<CodeSnippet
+  snippet="foo
+bar"
+>
+  <div
+    className="code-snippet"
+  >
+    <pre>
+      foo
+bar
+    </pre>
+    <ClipboardButton
+      copyValue="foo
+bar"
+      tooltipPlacement="top"
+    >
+      <button
+        className="js-copy-to-clipboard no-select"
+        data-clipboard-text="foo
+bar"
+      >
+        copy
+      </button>
+    </ClipboardButton>
+  </div>
+</CodeSnippet>
+`;
+
+exports[`renders correctly 2`] = `
+<CodeSnippet
+  noCopy={true}
+  snippet="foo
+bar"
+>
+  <div
+    className="code-snippet"
+  >
+    <pre>
+      foo
+bar
+    </pre>
+  </div>
+</CodeSnippet>
+`;
+
+exports[`renders correctly with array snippet 1`] = `
+<CodeSnippet
+  snippet={
+    Array [
+      "foo",
+      "bar",
+    ]
+  }
+>
+  <div
+    className="code-snippet"
+  >
+    <pre>
+      foo \\
+  bar
+    </pre>
+    <ClipboardButton
+      copyValue="foo \\\\
+  bar"
+      tooltipPlacement="top"
+    >
+      <button
+        className="js-copy-to-clipboard no-select"
+        data-clipboard-text="foo \\\\
+  bar"
+      >
+        copy
+      </button>
+    </ClipboardButton>
+  </div>
+</CodeSnippet>
+`;
+
+exports[`renders correctly with array snippet 2`] = `
+<CodeSnippet
+  isOneLine={true}
+  snippet={
+    Array [
+      "foo",
+      "bar",
+    ]
+  }
+>
+  <div
+    className="code-snippet code-snippet-oneline"
+  >
+    <pre>
+      foo bar
+    </pre>
+    <ClipboardButton
+      copyValue="foo bar"
+      tooltipPlacement="top"
+    >
+      <button
+        className="js-copy-to-clipboard no-select"
+        data-clipboard-text="foo bar"
+      >
+        copy
+      </button>
+    </ClipboardButton>
+  </div>
+</CodeSnippet>
+`;