aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
authorPascal Mugnier <pascal.mugnier@sonarsource.com>2018-04-10 13:47:42 +0200
committerSonarTech <sonartech@sonarsource.com>2018-04-10 20:20:54 +0200
commit50766c5a770d31733a4f5f0f29a3cbf663473d77 (patch)
tree6aa335d1afd44ba45e43e6ccc254f192ad69d4d0 /server/sonar-web/src/main/js/apps
parentf239ffffd3818fec2aa2d74b12875355324df73e (diff)
downloadsonarqube-50766c5a770d31733a4f5f0f29a3cbf663473d77.tar.gz
sonarqube-50766c5a770d31733a4f5f0f29a3cbf663473d77.zip
SONAR-10133 Full-width banner to prompt restart after plugin change (#102)
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/App.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx108
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/__tests__/PendingActions-test.tsx95
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap61
5 files changed, 17 insertions, 301 deletions
diff --git a/server/sonar-web/src/main/js/apps/marketplace/App.tsx b/server/sonar-web/src/main/js/apps/marketplace/App.tsx
index 2dcf58ab2e0..9446bfe471c 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/App.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/App.tsx
@@ -24,17 +24,15 @@ import Helmet from 'react-helmet';
import Header from './Header';
import EditionBoxes from './EditionBoxes';
import Footer from './Footer';
-import PendingActions from './PendingActions';
import PluginsList from './PluginsList';
import Search from './Search';
import { filterPlugins, parseQuery, Query, serializeQuery } from './utils';
import {
getAvailablePlugins,
getInstalledPluginsWithUpdates,
- getPendingPlugins,
getPluginUpdates,
Plugin,
- PluginPending,
+ PluginPendingResult,
getInstalledPlugins
} from '../../api/plugins';
import { Edition, EditionStatus } from '../../api/marketplace';
@@ -46,20 +44,17 @@ export interface Props {
editions?: Edition[];
editionsReadOnly: boolean;
editionStatus?: EditionStatus;
+ fetchPendingPlugins: () => void;
loadingEditions: boolean;
location: { pathname: string; query: RawQuery };
+ pendingPlugins: PluginPendingResult;
standaloneMode: boolean;
- updateCenterActive: boolean;
setEditionStatus: (editionStatus: EditionStatus) => void;
+ updateCenterActive: boolean;
}
interface State {
loadingPlugins: boolean;
- pending: {
- installing: PluginPending[];
- updating: PluginPending[];
- removing: PluginPending[];
- };
plugins: Plugin[];
}
@@ -74,18 +69,13 @@ export default class App extends React.PureComponent<Props, State> {
super(props);
this.state = {
loadingPlugins: true,
- pending: {
- installing: [],
- updating: [],
- removing: []
- },
plugins: []
};
}
componentDidMount() {
this.mounted = true;
- this.fetchPendingPlugins();
+ this.props.fetchPendingPlugins();
this.fetchQueryPlugins();
}
@@ -127,16 +117,6 @@ export default class App extends React.PureComponent<Props, State> {
);
};
- fetchPendingPlugins = () =>
- getPendingPlugins().then(
- pending => {
- if (this.mounted) {
- this.setState({ pending });
- }
- },
- () => {}
- );
-
updateQuery = (newQuery: Partial<Query>) => {
const query = serializeQuery({ ...parseQuery(this.props.location.query), ...newQuery });
this.context.router.push({ pathname: this.props.location.pathname, query });
@@ -149,19 +129,14 @@ export default class App extends React.PureComponent<Props, State> {
};
render() {
- const { editions, editionStatus, standaloneMode } = this.props;
- const { loadingPlugins, plugins, pending } = this.state;
+ const { editions, editionStatus, 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;
return (
<div className="page page-limited" id="marketplace-page">
<Helmet title={translate('marketplace.page')} />
- <div className="page-notifs">
- {standaloneMode && (
- <PendingActions pending={pending} refreshPending={this.fetchPendingPlugins} />
- )}
- </div>
<Header />
<EditionBoxes
canInstall={standaloneMode && !this.props.editionsReadOnly}
@@ -180,10 +155,10 @@ export default class App extends React.PureComponent<Props, State> {
{loadingPlugins && <i className="spinner" />}
{!loadingPlugins && (
<PluginsList
- pending={pending}
+ pending={pendingPlugins}
plugins={filteredPlugins}
readOnly={!standaloneMode}
- refreshPending={this.fetchPendingPlugins}
+ refreshPending={this.props.fetchPendingPlugins}
/>
)}
{!loadingPlugins && <Footer total={filteredPlugins.length} />}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
index 4f7676767ba..73611432c0b 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
@@ -24,11 +24,13 @@ import {
getGlobalSettingValue,
getMarketplaceState,
getMarketplaceEditions,
- getMarketplaceEditionStatus
+ getMarketplaceEditionStatus,
+ getMarketplacePendingPlugins
} from '../../store/rootReducer';
import { Edition, EditionStatus } from '../../api/marketplace';
-import { setEditionStatus } from '../../store/marketplace/actions';
+import { setEditionStatus, fetchPendingPlugins } from '../../store/marketplace/actions';
import { RawQuery } from '../../helpers/query';
+import { PluginPendingResult } from '../../api/plugins';
interface OwnProps {
location: { pathname: string; query: RawQuery };
@@ -39,12 +41,14 @@ interface StateToProps {
editionsReadOnly: boolean;
editionStatus?: EditionStatus;
loadingEditions: boolean;
+ pendingPlugins: PluginPendingResult;
standaloneMode: boolean;
updateCenterActive: boolean;
}
interface DispatchToProps {
setEditionStatus: (editionStatus: EditionStatus) => void;
+ fetchPendingPlugins: () => void;
}
const mapStateToProps = (state: any) => ({
@@ -52,12 +56,13 @@ const mapStateToProps = (state: any) => ({
editionsReadOnly: getMarketplaceState(state).readOnly,
editionStatus: getMarketplaceEditionStatus(state),
loadingEditions: getMarketplaceState(state).loading,
+ pendingPlugins: getMarketplacePendingPlugins(state),
standaloneMode: getAppState(state).standalone,
updateCenterActive:
(getGlobalSettingValue(state, 'sonar.updatecenter.activate') || {}).value === 'true'
});
-const mapDispatchToProps = { setEditionStatus };
+const mapDispatchToProps = { setEditionStatus, fetchPendingPlugins };
export default connect<StateToProps, DispatchToProps, OwnProps>(
mapStateToProps,
diff --git a/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx b/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx
deleted file mode 100644
index d392d5efcc3..00000000000
--- a/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx
+++ /dev/null
@@ -1,108 +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 { FormattedMessage } from 'react-intl';
-import RestartForm from '../../components/common/RestartForm';
-import { cancelPendingPlugins, PluginPending } from '../../api/plugins';
-import { Button } from '../../components/ui/buttons';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- pending: {
- installing: PluginPending[];
- updating: PluginPending[];
- removing: PluginPending[];
- };
- refreshPending: () => void;
-}
-
-interface State {
- openRestart: boolean;
-}
-
-export default class PendingActions extends React.PureComponent<Props, State> {
- state: State = { openRestart: false };
-
- handleOpenRestart = () => {
- this.setState({ openRestart: true });
- };
-
- hanleCloseRestart = () => {
- this.setState({ openRestart: false });
- };
-
- handleRevert = () => {
- cancelPendingPlugins().then(this.props.refreshPending, () => {});
- };
-
- render() {
- const { installing, updating, removing } = this.props.pending;
- const hasPendingActions = installing.length || updating.length || removing.length;
- if (!hasPendingActions) {
- return null;
- }
-
- return (
- <div className="js-pending alert alert-warning">
- <div className="display-inline-block">
- <p>{translate('marketplace.sonarqube_needs_to_be_restarted_to')}</p>
- <ul className="list-styled spacer-top">
- {installing.length > 0 && (
- <li>
- <FormattedMessage
- defaultMessage={translate('marketplace.install_x_plugins')}
- id="marketplace.install_x_plugins"
- values={{ nb: <strong>{installing.length}</strong> }}
- />
- </li>
- )}
- {updating.length > 0 && (
- <li>
- <FormattedMessage
- defaultMessage={translate('marketplace.update_x_plugins')}
- id="marketplace.update_x_plugins"
- values={{ nb: <strong>{updating.length}</strong> }}
- />
- </li>
- )}
- {removing.length > 0 && (
- <li>
- <FormattedMessage
- defaultMessage={translate('marketplace.uninstall_x_plugins')}
- id="marketplace.uninstall_x_plugins"
- values={{ nb: <strong>{removing.length}</strong> }}
- />
- </li>
- )}
- </ul>
- </div>
- <div className="pull-right">
- <Button className="js-restart little-spacer-right" onClick={this.handleOpenRestart}>
- {translate('marketplace.restart')}
- </Button>
- <Button className="js-cancel-all button-red" onClick={this.handleRevert}>
- {translate('marketplace.revert')}
- </Button>
- </div>
- {this.state.openRestart && <RestartForm onClose={this.hanleCloseRestart} />}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PendingActions-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/PendingActions-test.tsx
deleted file mode 100644
index ff023270fac..00000000000
--- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PendingActions-test.tsx
+++ /dev/null
@@ -1,95 +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.
- */
-/* eslint-disable import/order */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import { click } from '../../../helpers/testUtils';
-import PendingActions from '../PendingActions';
-
-jest.mock('../../../api/plugins', () => ({
- cancelPendingPlugins: jest.fn(() => Promise.resolve())
-}));
-
-const cancelPendingPlugins = require('../../../api/plugins').cancelPendingPlugins as jest.Mock<any>;
-
-beforeEach(() => {
- cancelPendingPlugins.mockClear();
-});
-
-it('should display pending actions', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should not display anything', () => {
- expect(getWrapper({ pending: { installing: [], updating: [], removing: [] } }).type()).toBeNull();
-});
-
-it('should open the restart form', () => {
- const wrapper = getWrapper();
- click(wrapper.find('.js-restart'));
- expect(wrapper.find('RestartForm').exists()).toBeTruthy();
-});
-
-it('should cancel all pending and refresh them', async () => {
- const refreshPending = jest.fn();
- const wrapper = getWrapper({ refreshPending });
- click(wrapper.find('.js-cancel-all'));
- expect(cancelPendingPlugins).toHaveBeenCalled();
- await new Promise(setImmediate);
-
- expect(refreshPending).toHaveBeenCalled();
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <PendingActions
- pending={{
- installing: [
- {
- key: 'foo',
- name: 'Foo',
- description: 'foo description',
- version: 'fooversion',
- implementationBuild: 'foobuild'
- },
- {
- key: 'bar',
- name: 'Bar',
- description: 'bar description',
- version: 'barversion',
- implementationBuild: 'barbuild'
- }
- ],
- updating: [],
- removing: [
- {
- key: 'baz',
- name: 'Baz',
- description: 'baz description',
- version: 'bazversion',
- implementationBuild: 'bazbuild'
- }
- ]
- }}
- refreshPending={() => {}}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap
deleted file mode 100644
index c8688596746..00000000000
--- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display pending actions 1`] = `
-<div
- className="js-pending alert alert-warning"
->
- <div
- className="display-inline-block"
- >
- <p>
- marketplace.sonarqube_needs_to_be_restarted_to
- </p>
- <ul
- className="list-styled spacer-top"
- >
- <li>
- <FormattedMessage
- defaultMessage="marketplace.install_x_plugins"
- id="marketplace.install_x_plugins"
- values={
- Object {
- "nb": <strong>
- 2
- </strong>,
- }
- }
- />
- </li>
- <li>
- <FormattedMessage
- defaultMessage="marketplace.uninstall_x_plugins"
- id="marketplace.uninstall_x_plugins"
- values={
- Object {
- "nb": <strong>
- 1
- </strong>,
- }
- }
- />
- </li>
- </ul>
- </div>
- <div
- className="pull-right"
- >
- <Button
- className="js-restart little-spacer-right"
- onClick={[Function]}
- >
- marketplace.restart
- </Button>
- <Button
- className="js-cancel-all button-red"
- onClick={[Function]}
- >
- marketplace.revert
- </Button>
- </div>
-</div>
-`;