]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9954 Add serverId and nloc query to the request license url
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 19 Oct 2017 08:26:51 +0000 (10:26 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 23 Oct 2017 15:01:13 +0000 (08:01 -0700)
server/sonar-web/src/main/js/api/marketplace.ts
server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx
server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap
server/sonar-web/src/main/js/components/common/DeferredSpinner.js [deleted file]
server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx [new file with mode: 0644]

index 30c801ae0f214f889fbb6765a1919031fed1c8d7..57ee91288832de96ff877937694422260bea7cea 100644 (file)
@@ -65,6 +65,10 @@ export function getLicensePreview(data: {
   return postJSON('/api/editions/preview', data).catch(throwGlobalError);
 }
 
+export function getFormData(): Promise<{ serverId: string; ncloc: number }> {
+  return getJSON('/api/editions/form_data').catch(throwGlobalError);
+}
+
 export function applyLicense(data: { license: string }): Promise<EditionStatus> {
   return postJSON('/api/editions/apply_license', data).catch(throwGlobalError);
 }
index 857a40e40581ea0c34e8d8dcda17801292b571ec..6971889135c8620daf738f0209bf99da9f3614d1 100644 (file)
@@ -32,13 +32,13 @@ export interface Props {
 
 interface State {
   license: string;
-  loading: boolean;
   status?: string;
+  submitting: boolean;
 }
 
 export default class LicenseEditionForm extends React.PureComponent<Props, State> {
   mounted: boolean;
-  state: State = { license: '', loading: false };
+  state: State = { license: '', submitting: false };
 
   componentDidMount() {
     this.mounted = true;
@@ -63,7 +63,7 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
     event.preventDefault();
     const { license, status } = this.state;
     if (license && status && ['AUTOMATIC_INSTALL', 'NO_INSTALL'].includes(status)) {
-      this.setState({ loading: true });
+      this.setState({ submitting: true });
       applyLicense({ license }).then(
         editionStatus => {
           this.props.updateEditionStatus(editionStatus);
@@ -71,7 +71,7 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
         },
         () => {
           if (this.mounted) {
-            this.setState({ loading: false });
+            this.setState({ submitting: false });
           }
         }
       );
@@ -80,7 +80,7 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
 
   render() {
     const { edition } = this.props;
-    const { loading, status } = this.state;
+    const { submitting, status } = this.state;
     const header = translateWithParameters('marketplace.install_x', edition.name);
     return (
       <Modal
@@ -101,10 +101,10 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
         />
 
         <footer className="modal-foot">
-          {loading && <i className="spinner spacer-right" />}
+          {submitting && <i className="spinner spacer-right" />}
           {status &&
           ['NO_INSTALL', 'AUTOMATIC_INSTALL'].includes(status) && (
-            <button className="js-confirm" onClick={this.handleConfirmClick} disabled={loading}>
+            <button className="js-confirm" onClick={this.handleConfirmClick} disabled={submitting}>
               {status === 'NO_INSTALL' ? translate('save') : translate('marketplace.install')}
             </button>
           )}
index 76cbc297483fa8b218206c553ce896e7c9dd5607..86c29fc65e967e910d6f549baaae448489bf9693 100644 (file)
  */
 import * as React from 'react';
 import * as classNames from 'classnames';
+import { stringify } from 'querystring';
 import { debounce } from 'lodash';
-import { Edition, getLicensePreview } from '../../../api/marketplace';
+import { omitNil } from '../../../helpers/request';
+import { Edition, getFormData, getLicensePreview } from '../../../api/marketplace';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 
 export interface Props {
@@ -33,8 +35,11 @@ export interface Props {
 interface State {
   license: string;
   licenseEdition?: Edition;
-  loading: boolean;
   previewStatus?: string;
+  formData?: {
+    serverId?: string;
+    ncloc?: number;
+  };
 }
 
 export default class LicenseEditionSet extends React.PureComponent<Props, State> {
@@ -42,12 +47,13 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
 
   constructor(props: Props) {
     super(props);
-    this.state = { license: '', loading: false };
+    this.state = { license: '' };
     this.fetchLicensePreview = debounce(this.fetchLicensePreview, 100);
   }
 
   componentDidMount() {
     this.mounted = true;
+    this.fetchFormData();
   }
 
   componentWillUnmount() {
@@ -72,6 +78,28 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
       }
     );
 
+  fetchFormData = () => {
+    getFormData().then(
+      formData => {
+        if (this.mounted) {
+          this.setState({ formData });
+        }
+      },
+      () => {}
+    );
+  };
+
+  getLicenseFormUrl = (edition: Edition) => {
+    let url = edition.request_license_link;
+    if (this.state.formData) {
+      const query = stringify(omitNil(this.state.formData));
+      if (query) {
+        url += '?' + query;
+      }
+    }
+    return url;
+  };
+
   handleLicenseChange = (event: React.SyntheticEvent<HTMLTextAreaElement>) => {
     const license = event.currentTarget.value;
     if (license) {
@@ -94,7 +122,7 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
     return (
       <div className={className}>
         {edition && (
-          <label className="spacer-bottom" htmlFor="set-license">
+          <label className="display-inline-block spacer-bottom" htmlFor="set-license">
             {translateWithParameters('marketplace.enter_license_for_x', edition.name)}
             <em className="mandatory">*</em>
           </label>
@@ -143,7 +171,7 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
         {edition && (
           <a
             className="display-inline-block spacer-top"
-            href={edition.request_license_link}
+            href={this.getLicenseFormUrl(edition)}
             target="_blank">
             {translate('marketplace.i_need_a_license')}
           </a>
index 6ba3dd639b29ff83922594e389544337d590965e..48c4cdecbf9e68702d84639c2b30e216e7a0b724 100644 (file)
@@ -46,7 +46,7 @@ exports[`should correctly display status message after checking license 3`] = `
 exports[`should display correctly 1`] = `
 <div>
   <label
-    className="spacer-bottom"
+    className="display-inline-block spacer-bottom"
     htmlFor="set-license"
   >
     marketplace.enter_license_for_x.Foo
diff --git a/server/sonar-web/src/main/js/components/common/DeferredSpinner.js b/server/sonar-web/src/main/js/components/common/DeferredSpinner.js
deleted file mode 100644 (file)
index f638257..0000000
+++ /dev/null
@@ -1,89 +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';
-
-/*::
-type Props = {
-  children?: React.Element<*>,
-  className?: string,
-  loading?: boolean,
-  timeout: number
-};
-*/
-
-/*::
-type State = {
-  showSpinner: boolean
-};
-*/
-
-export default class DeferredSpinner extends React.PureComponent {
-  /*:: props: Props; */
-  /*:: state: State; */
-  /*:: timer: number; */
-
-  static defaultProps = {
-    timeout: 100
-  };
-
-  constructor(props /*: Props */) {
-    super(props);
-    this.state = { showSpinner: false };
-  }
-
-  componentDidMount() {
-    if (this.props.loading == null || this.props.loading === true) {
-      this.startTimer();
-    }
-  }
-
-  componentWillReceiveProps(nextProps /*: Props */) {
-    if (this.props.loading === false && nextProps.loading === true) {
-      this.stopTimer();
-      this.startTimer();
-    }
-    if (this.props.loading === true && nextProps.loading === false) {
-      this.stopTimer();
-      this.setState({ showSpinner: false });
-    }
-  }
-
-  componentWillUnmount() {
-    this.stopTimer();
-  }
-
-  startTimer = () => {
-    this.timer = setTimeout(() => this.setState({ showSpinner: true }), this.props.timeout);
-  };
-
-  stopTimer = () => {
-    clearTimeout(this.timer);
-  };
-
-  render() {
-    return this.state.showSpinner ? (
-      <i className={classNames('spinner', this.props.className)} />
-    ) : (
-      this.props.children || null
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx b/server/sonar-web/src/main/js/components/common/DeferredSpinner.tsx
new file mode 100644 (file)
index 0000000..a840e2e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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';
+
+interface Props {
+  children?: JSX.Element;
+  className?: string;
+  loading?: boolean;
+  timeout: number;
+}
+
+interface State {
+  showSpinner: boolean;
+}
+
+export default class DeferredSpinner extends React.PureComponent<Props, State> {
+  timer: any;
+
+  static defaultProps = {
+    timeout: 100
+  };
+
+  state: State = { showSpinner: false };
+
+  componentDidMount() {
+    if (this.props.loading == null || this.props.loading === true) {
+      this.startTimer();
+    }
+  }
+
+  componentWillReceiveProps(nextProps: Props) {
+    if (this.props.loading === false && nextProps.loading === true) {
+      this.stopTimer();
+      this.startTimer();
+    }
+    if (this.props.loading === true && nextProps.loading === false) {
+      this.stopTimer();
+      this.setState({ showSpinner: false });
+    }
+  }
+
+  componentWillUnmount() {
+    this.stopTimer();
+  }
+
+  startTimer = () => {
+    this.timer = setTimeout(() => this.setState({ showSpinner: true }), this.props.timeout);
+  };
+
+  stopTimer = () => {
+    clearTimeout(this.timer);
+  };
+
+  render() {
+    if (this.state.showSpinner) {
+      return <i className={classNames('spinner', this.props.className)} />;
+    }
+    return (this.props.children as JSX.Element) || null;
+  }
+}