]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9508 Display worker counter in background tasks page
authorStas Vilchik <stas.vilchik@sonarsource.com>
Thu, 6 Jul 2017 12:37:46 +0000 (14:37 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 17 Jul 2017 08:52:47 +0000 (10:52 +0200)
12 files changed:
server/sonar-web/src/main/js/api/ce.js
server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css
server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
server/sonar-web/src/main/js/apps/background-tasks/components/Header.js
server/sonar-web/src/main/js/apps/background-tasks/components/Workers.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Workers-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/WorkersForm-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/less/init/forms.less
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index bc4eb2283e25246d44ee8395bc57a19152966eac..4fa75478b1db4133e5d3b17a590742a64e51d5c3 100644 (file)
@@ -19,6 +19,7 @@
  */
 // @flow
 import { getJSON, post } from '../helpers/request';
+import throwGlobalError from '../app/utils/throwGlobalError';
 
 export const getActivity = (data?: Object): Promise<*> => getJSON('/api/ce/activity', data);
 
@@ -42,3 +43,9 @@ export const getTasksForComponent = (componentKey: string): Promise<*> =>
   getJSON('/api/ce/component', { componentKey });
 
 export const getTypes = (): Promise<*> => getJSON('/api/ce/task_types').then(r => r.taskTypes);
+
+export const getWorkers = (): Promise<{ canSetWorkerCount: boolean, value: number }> =>
+  getJSON('/api/ce/worker_count').catch(throwGlobalError);
+
+export const setWorkerCount = (count: number): Promise<void> =>
+  post('/api/ce/set_worker_count', { count }).catch(throwGlobalError);
index 2bad2aba5a0761e51c47d4ad39fffa4ea6e36394..a957b5f0250b6170d241d0e999bc9fa6afffcc05 100644 (file)
 .bt-search-form-right {
   margin-left: auto !important;
 }
+
+.bt-workers-warning-icon {
+  position: relative;
+  top: -1px;
+}
+
+.bt-workers-warning-icon::before {
+  color: #d3d3d3;
+}
index 4062eaea41a0443aef017cb6be3a00c12f7ac230..a26112033ff33dd6ad9dc0ebacdbda9a228869ca 100644 (file)
@@ -214,7 +214,7 @@ class BackgroundTasksApp extends React.PureComponent {
     return (
       <div className="page page-limited">
         <Helmet title={translate('background_tasks.page')} />
-        <Header />
+        <Header component={component} />
 
         <Stats
           component={component}
index c775e76f17a4b3ed496134197e2417bd479c5025..e91b1b1188b5cd775397ce0ac37fe6aff9067669 100644 (file)
  */
 /* @flow */
 import React from 'react';
+import Workers from './Workers';
 import { translate } from '../../../helpers/l10n';
 
-const Header = () => {
+type Props = {
+  component?: Object
+};
+
+export default function Header(props: Props) {
   return (
     <header className="page-header">
       <h1 className="page-title">
         {translate('background_tasks.page')}
       </h1>
+      {!props.component &&
+        <div className="page-actions">
+          <Workers />
+        </div>}
       <p className="page-description">
         {translate('background_tasks.page.description')}
       </p>
     </header>
   );
-};
-
-export default Header;
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.js
new file mode 100644 (file)
index 0000000..b37622a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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 WorkersForm from './WorkersForm';
+import Tooltip from '../../../components/controls/Tooltip';
+import { getWorkers } from '../../../api/ce';
+import { translate } from '../../../helpers/l10n';
+
+type State = {
+  canSetWorkerCount: boolean,
+  formOpen: boolean,
+  loading: boolean,
+  workerCount: number
+};
+
+export default class Workers extends React.PureComponent {
+  mounted: boolean;
+  state: State = {
+    canSetWorkerCount: false,
+    formOpen: false,
+    loading: true,
+    workerCount: 1
+  };
+
+  componentDidMount() {
+    this.mounted = true;
+    this.loadWorkers();
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  loadWorkers = () => {
+    this.setState({ loading: true });
+    getWorkers().then(({ canSetWorkerCount, value }) => {
+      if (this.mounted) {
+        this.setState({
+          canSetWorkerCount,
+          loading: false,
+          workerCount: value
+        });
+      }
+    });
+  };
+
+  closeForm = (newWorkerCount?: number) =>
+    (newWorkerCount
+      ? this.setState({ formOpen: false, workerCount: newWorkerCount })
+      : this.setState({ formOpen: false }));
+
+  handleChangeClick = (event: Event) => {
+    event.preventDefault();
+    this.setState({ formOpen: true });
+  };
+
+  render() {
+    const { canSetWorkerCount, formOpen, loading, workerCount } = this.state;
+
+    return (
+      <div>
+        {!loading &&
+          workerCount > 1 &&
+          <Tooltip overlay={translate('background_tasks.number_of_workers.warning')}>
+            <i className="icon-alert-warn little-spacer-right bt-workers-warning-icon" />
+          </Tooltip>}
+
+        {translate('background_tasks.number_of_workers')}
+
+        {loading
+          ? <i className="spinner little-spacer-left" />
+          : <strong className="little-spacer-left">{workerCount}</strong>}
+
+        {!loading &&
+          (canSetWorkerCount
+            ? <Tooltip overlay={translate('background_tasks.change_number_of_workers')}>
+                <a className="icon-edit spacer-left" href="#" onClick={this.handleChangeClick} />
+              </Tooltip>
+            : <a
+                className="button button-promote spacer-left"
+                href="https://redirect.sonarsource.com/plugins/governance.html"
+                target="_blank">
+                {translate('background_tasks.add_more_with_governance')}
+              </a>)}
+
+        {formOpen && <WorkersForm onClose={this.closeForm} workerCount={this.state.workerCount} />}
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.js b/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.js
new file mode 100644 (file)
index 0000000..2f66fe8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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 Modal from 'react-modal';
+import Select from 'react-select';
+import { times } from 'lodash';
+import { setWorkerCount } from '../../../api/ce';
+import { translate } from '../../../helpers/l10n';
+
+const MAX_WORKERS = 10;
+
+type Props = {
+  onClose: (newWorkerCount?: number) => void,
+  workerCount: number
+};
+
+type State = {
+  newWorkerCount: number,
+  submitting: boolean
+};
+
+export default class WorkersForm extends React.PureComponent {
+  mounted: boolean;
+  props: Props;
+  state: State;
+
+  constructor(props: Props) {
+    super(props);
+    this.state = {
+      newWorkerCount: props.workerCount,
+      submitting: false
+    };
+  }
+
+  componentDidMount() {
+    this.mounted = true;
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  handleClose = () => this.props.onClose();
+
+  handleWorkerCountChange = (option: { value: number }) =>
+    this.setState({ newWorkerCount: option.value });
+
+  handleSubmit = (event: Event) => {
+    event.preventDefault();
+    this.setState({ submitting: true });
+    const { newWorkerCount } = this.state;
+    setWorkerCount(newWorkerCount).then(
+      () => {
+        if (this.mounted) {
+          this.props.onClose(newWorkerCount);
+        }
+      },
+      () => {
+        if (this.mounted) {
+          this.setState({ submitting: false });
+        }
+      }
+    );
+  };
+
+  render() {
+    const options = times(MAX_WORKERS).map((_, i) => ({ label: i + 1, value: i + 1 }));
+
+    return (
+      <Modal
+        isOpen={true}
+        contentLabel={translate('background_tasks.change_number_of_workers')}
+        className="modal"
+        overlayClassName="modal-overlay"
+        onRequestClose={this.handleClose}>
+        <header className="modal-head">
+          <h2>{translate('background_tasks.change_number_of_workers')}</h2>
+        </header>
+        <form onSubmit={this.handleSubmit}>
+          <div className="modal-body">
+            <Select
+              className="input-tiny spacer-top"
+              clearable={false}
+              onChange={this.handleWorkerCountChange}
+              options={options}
+              searchable={false}
+              value={this.state.newWorkerCount}
+            />
+            <div className="big-spacer-top alert alert-success markdown">
+              {translate('background_tasks.change_number_of_workers.hint')}
+            </div>
+          </div>
+          <footer className="modal-foot">
+            <div>
+              {this.state.submitting && <i className="spinner spacer-right" />}
+              <button disabled={this.state.submitting} type="submit">
+                {translate('save')}
+              </button>
+              <button type="reset" className="button-link" onClick={this.handleClose}>
+                {translate('cancel')}
+              </button>
+            </div>
+          </footer>
+        </form>
+      </Modal>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Workers-test.js b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Workers-test.js
new file mode 100644 (file)
index 0000000..5ad0643
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 { shallow } from 'enzyme';
+import Workers from '../Workers';
+import { click } from '../../../../helpers/testUtils';
+
+it('renders', () => {
+  const wrapper = shallow(<Workers />);
+  expect(wrapper).toMatchSnapshot();
+
+  wrapper.setState({
+    canSetWorkerCount: true,
+    loading: false,
+    workerCount: 1
+  });
+  expect(wrapper).toMatchSnapshot();
+
+  wrapper.setState({ canSetWorkerCount: false });
+  expect(wrapper).toMatchSnapshot();
+
+  wrapper.setState({ workerCount: 2 });
+  expect(wrapper).toMatchSnapshot();
+});
+
+it('opens form', () => {
+  const wrapper = shallow(<Workers />);
+
+  wrapper.setState({
+    canSetWorkerCount: true,
+    loading: false,
+    workerCount: 1
+  });
+  expect(wrapper).toMatchSnapshot();
+
+  click(wrapper.find('.icon-edit'));
+  expect(wrapper).toMatchSnapshot();
+});
+
+it('updates worker count', () => {
+  const wrapper = shallow(<Workers />);
+
+  wrapper.setState({
+    canSetWorkerCount: true,
+    formOpen: true,
+    loading: false,
+    workerCount: 1
+  });
+  expect(wrapper).toMatchSnapshot();
+
+  wrapper.find('WorkersForm').prop('onClose')(7);
+  wrapper.update();
+  expect(wrapper).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/WorkersForm-test.js b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/WorkersForm-test.js
new file mode 100644 (file)
index 0000000..f821ba6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 { shallow } from 'enzyme';
+import WorkersForm from '../WorkersForm';
+import { submit, doAsync } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/ce', () => ({
+  setWorkerCount: () => Promise.resolve()
+}));
+
+it('changes select', () => {
+  const wrapper = shallow(<WorkersForm onClose={jest.fn()} workerCount={1} />);
+  expect(wrapper).toMatchSnapshot();
+
+  wrapper.find('Select').prop('onChange')({ value: 7 });
+  wrapper.update();
+  expect(wrapper).toMatchSnapshot();
+});
+
+it('returns new worker count', () => {
+  const onClose = jest.fn();
+  const wrapper = shallow(<WorkersForm onClose={onClose} workerCount={1} />);
+  // $FlowFixMe
+  wrapper.instance().mounted = true;
+  wrapper.find('Select').prop('onChange')({ value: 7 });
+
+  wrapper.update();
+  submit(wrapper.find('form'));
+
+  return doAsync(() => {
+    expect(onClose).toBeCalled();
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.js.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.js.snap
new file mode 100644 (file)
index 0000000..7951ffa
--- /dev/null
@@ -0,0 +1,175 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`opens form 1`] = `
+<div>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    1
+  </strong>
+  <Tooltip
+    overlay="background_tasks.change_number_of_workers"
+    placement="bottom"
+  >
+    <a
+      className="icon-edit spacer-left"
+      href="#"
+      onClick={[Function]}
+    />
+  </Tooltip>
+</div>
+`;
+
+exports[`opens form 2`] = `
+<div>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    1
+  </strong>
+  <Tooltip
+    overlay="background_tasks.change_number_of_workers"
+    placement="bottom"
+  >
+    <a
+      className="icon-edit spacer-left"
+      href="#"
+      onClick={[Function]}
+    />
+  </Tooltip>
+  <WorkersForm
+    onClose={[Function]}
+    workerCount={1}
+  />
+</div>
+`;
+
+exports[`renders 1`] = `
+<div>
+  background_tasks.number_of_workers
+  <i
+    className="spinner little-spacer-left"
+  />
+</div>
+`;
+
+exports[`renders 2`] = `
+<div>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    1
+  </strong>
+  <Tooltip
+    overlay="background_tasks.change_number_of_workers"
+    placement="bottom"
+  >
+    <a
+      className="icon-edit spacer-left"
+      href="#"
+      onClick={[Function]}
+    />
+  </Tooltip>
+</div>
+`;
+
+exports[`renders 3`] = `
+<div>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    1
+  </strong>
+  <a
+    className="button button-promote spacer-left"
+    href="https://redirect.sonarsource.com/plugins/governance.html"
+    target="_blank"
+  >
+    background_tasks.add_more_with_governance
+  </a>
+</div>
+`;
+
+exports[`renders 4`] = `
+<div>
+  <Tooltip
+    overlay="background_tasks.number_of_workers.warning"
+    placement="bottom"
+  >
+    <i
+      className="icon-alert-warn little-spacer-right bt-workers-warning-icon"
+    />
+  </Tooltip>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    2
+  </strong>
+  <a
+    className="button button-promote spacer-left"
+    href="https://redirect.sonarsource.com/plugins/governance.html"
+    target="_blank"
+  >
+    background_tasks.add_more_with_governance
+  </a>
+</div>
+`;
+
+exports[`updates worker count 1`] = `
+<div>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    1
+  </strong>
+  <Tooltip
+    overlay="background_tasks.change_number_of_workers"
+    placement="bottom"
+  >
+    <a
+      className="icon-edit spacer-left"
+      href="#"
+      onClick={[Function]}
+    />
+  </Tooltip>
+  <WorkersForm
+    onClose={[Function]}
+    workerCount={1}
+  />
+</div>
+`;
+
+exports[`updates worker count 2`] = `
+<div>
+  <Tooltip
+    overlay="background_tasks.number_of_workers.warning"
+    placement="bottom"
+  >
+    <i
+      className="icon-alert-warn little-spacer-right bt-workers-warning-icon"
+    />
+  </Tooltip>
+  background_tasks.number_of_workers
+  <strong
+    className="little-spacer-left"
+  >
+    7
+  </strong>
+  <Tooltip
+    overlay="background_tasks.change_number_of_workers"
+    placement="bottom"
+  >
+    <a
+      className="icon-edit spacer-left"
+      href="#"
+      onClick={[Function]}
+    />
+  </Tooltip>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.js.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.js.snap
new file mode 100644 (file)
index 0000000..35ba8f8
--- /dev/null
@@ -0,0 +1,283 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`changes select 1`] = `
+<Modal
+  ariaHideApp={true}
+  className="modal"
+  closeTimeoutMS={0}
+  contentLabel="background_tasks.change_number_of_workers"
+  isOpen={true}
+  onRequestClose={[Function]}
+  overlayClassName="modal-overlay"
+  parentSelector={[Function]}
+  portalClassName="ReactModalPortal"
+  shouldCloseOnOverlayClick={true}
+>
+  <header
+    className="modal-head"
+  >
+    <h2>
+      background_tasks.change_number_of_workers
+    </h2>
+  </header>
+  <form
+    onSubmit={[Function]}
+  >
+    <div
+      className="modal-body"
+    >
+      <Select
+        addLabelText="Add \\"{label}\\"?"
+        arrowRenderer={[Function]}
+        autosize={true}
+        backspaceRemoves={true}
+        backspaceToRemoveMessage="Press backspace to remove {label}"
+        className="input-tiny spacer-top"
+        clearAllText="Clear all"
+        clearValueText="Clear value"
+        clearable={false}
+        delimiter=","
+        disabled={false}
+        escapeClearsValue={true}
+        filterOptions={[Function]}
+        ignoreAccents={true}
+        ignoreCase={true}
+        inputProps={Object {}}
+        isLoading={false}
+        joinValues={false}
+        labelKey="label"
+        matchPos="any"
+        matchProp="any"
+        menuBuffer={0}
+        menuRenderer={[Function]}
+        multi={false}
+        noResultsText="No results found"
+        onBlurResetsInput={true}
+        onChange={[Function]}
+        onCloseResetsInput={true}
+        openAfterFocus={false}
+        optionComponent={[Function]}
+        options={
+          Array [
+            Object {
+              "label": 1,
+              "value": 1,
+            },
+            Object {
+              "label": 2,
+              "value": 2,
+            },
+            Object {
+              "label": 3,
+              "value": 3,
+            },
+            Object {
+              "label": 4,
+              "value": 4,
+            },
+            Object {
+              "label": 5,
+              "value": 5,
+            },
+            Object {
+              "label": 6,
+              "value": 6,
+            },
+            Object {
+              "label": 7,
+              "value": 7,
+            },
+            Object {
+              "label": 8,
+              "value": 8,
+            },
+            Object {
+              "label": 9,
+              "value": 9,
+            },
+            Object {
+              "label": 10,
+              "value": 10,
+            },
+          ]
+        }
+        pageSize={5}
+        placeholder="Select..."
+        required={false}
+        scrollMenuIntoView={true}
+        searchable={false}
+        simpleValue={false}
+        tabSelectsValue={true}
+        value={1}
+        valueComponent={[Function]}
+        valueKey="value"
+      />
+      <div
+        className="big-spacer-top alert alert-success markdown"
+      >
+        background_tasks.change_number_of_workers.hint
+      </div>
+    </div>
+    <footer
+      className="modal-foot"
+    >
+      <div>
+        <button
+          disabled={false}
+          type="submit"
+        >
+          save
+        </button>
+        <button
+          className="button-link"
+          onClick={[Function]}
+          type="reset"
+        >
+          cancel
+        </button>
+      </div>
+    </footer>
+  </form>
+</Modal>
+`;
+
+exports[`changes select 2`] = `
+<Modal
+  ariaHideApp={true}
+  className="modal"
+  closeTimeoutMS={0}
+  contentLabel="background_tasks.change_number_of_workers"
+  isOpen={true}
+  onRequestClose={[Function]}
+  overlayClassName="modal-overlay"
+  parentSelector={[Function]}
+  portalClassName="ReactModalPortal"
+  shouldCloseOnOverlayClick={true}
+>
+  <header
+    className="modal-head"
+  >
+    <h2>
+      background_tasks.change_number_of_workers
+    </h2>
+  </header>
+  <form
+    onSubmit={[Function]}
+  >
+    <div
+      className="modal-body"
+    >
+      <Select
+        addLabelText="Add \\"{label}\\"?"
+        arrowRenderer={[Function]}
+        autosize={true}
+        backspaceRemoves={true}
+        backspaceToRemoveMessage="Press backspace to remove {label}"
+        className="input-tiny spacer-top"
+        clearAllText="Clear all"
+        clearValueText="Clear value"
+        clearable={false}
+        delimiter=","
+        disabled={false}
+        escapeClearsValue={true}
+        filterOptions={[Function]}
+        ignoreAccents={true}
+        ignoreCase={true}
+        inputProps={Object {}}
+        isLoading={false}
+        joinValues={false}
+        labelKey="label"
+        matchPos="any"
+        matchProp="any"
+        menuBuffer={0}
+        menuRenderer={[Function]}
+        multi={false}
+        noResultsText="No results found"
+        onBlurResetsInput={true}
+        onChange={[Function]}
+        onCloseResetsInput={true}
+        openAfterFocus={false}
+        optionComponent={[Function]}
+        options={
+          Array [
+            Object {
+              "label": 1,
+              "value": 1,
+            },
+            Object {
+              "label": 2,
+              "value": 2,
+            },
+            Object {
+              "label": 3,
+              "value": 3,
+            },
+            Object {
+              "label": 4,
+              "value": 4,
+            },
+            Object {
+              "label": 5,
+              "value": 5,
+            },
+            Object {
+              "label": 6,
+              "value": 6,
+            },
+            Object {
+              "label": 7,
+              "value": 7,
+            },
+            Object {
+              "label": 8,
+              "value": 8,
+            },
+            Object {
+              "label": 9,
+              "value": 9,
+            },
+            Object {
+              "label": 10,
+              "value": 10,
+            },
+          ]
+        }
+        pageSize={5}
+        placeholder="Select..."
+        required={false}
+        scrollMenuIntoView={true}
+        searchable={false}
+        simpleValue={false}
+        tabSelectsValue={true}
+        value={7}
+        valueComponent={[Function]}
+        valueKey="value"
+      />
+      <div
+        className="big-spacer-top alert alert-success markdown"
+      >
+        background_tasks.change_number_of_workers.hint
+      </div>
+    </div>
+    <footer
+      className="modal-foot"
+    >
+      <div>
+        <button
+          disabled={false}
+          type="submit"
+        >
+          save
+        </button>
+        <button
+          className="button-link"
+          onClick={[Function]}
+          type="reset"
+        >
+          cancel
+        </button>
+      </div>
+    </footer>
+  </form>
+</Modal>
+`;
index 7852cb8b2c755a960d05d2e0b13731c459c42e78..1a0a37e5e321e7f8e34f7cc9f11359ac7c40c485 100644 (file)
@@ -254,6 +254,18 @@ input[type="submit"].button-grey {
   padding: 0 6px;
 }
 
+.button-promote,
+input[type="submit"].button-promote {
+  border-color: #5041d2;
+  background-color: #5041d2;
+  color: #fff;
+  transition: background-color 0.3s ease;
+
+  &:hover, &:focus, &.active {
+    background-color: darken(#5041d2, 10%);
+  }
+}
+
 .button-group {
   display: inline-block;
   vertical-align: middle;
index 6b132ffad972839103bb3de66823a86f07d40ccb..d4dcf80001eb1f46296c26949242b7fcf118d8c9 100644 (file)
@@ -2759,6 +2759,12 @@ background_tasks.pending=pending
 background_tasks.failures=still failing
 background_tasks.in_progress_duration=Duration of the current task in progress.
 
+background_tasks.number_of_workers=Number of Workers:
+background_tasks.number_of_workers.warning=Configuring additional workers without first vertically scaling your server could have negative performance impacts.
+background_tasks.change_number_of_workers=Edit CE Workers
+background_tasks.change_number_of_workers.hint=If your queue backs up behind the analysis reports from large projects, increasing the number of Compute Engine workers will allow you to take full advantage of having configured increased Compute Engine memory on a multi-core server (vertical scaling).
+background_tasks.add_more_with_governance=Add more with Governance
+
 
 
 #------------------------------------------------------------------------------