diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-02-14 10:51:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-14 10:51:22 +0100 |
commit | 8053754d961994e78ed973d37005bb6b5e8ceeae (patch) | |
tree | 42dce69c3ca726158e88e95544846449c84f4469 /server/sonar-web/src/main/js/apps/maintenance | |
parent | 94a57989f8160badd5c1e7cbb66fdbceaa3bb38d (diff) | |
download | sonarqube-8053754d961994e78ed973d37005bb6b5e8ceeae.tar.gz sonarqube-8053754d961994e78ed973d37005bb6b5e8ceeae.zip |
rewrite maintenance app in react (#3055)
Diffstat (limited to 'server/sonar-web/src/main/js/apps/maintenance')
20 files changed, 833 insertions, 238 deletions
diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx new file mode 100644 index 00000000000..3bc5e06b616 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx @@ -0,0 +1,285 @@ +/* + * 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 { getMigrationStatus, getSystemStatus, migrateDatabase } from '../../../api/system'; +import DateFromNow from '../../../components/intl/DateFromNow'; +import TimeFormatter from '../../../components/intl/TimeFormatter'; +import { translate } from '../../../helpers/l10n'; +import { getBaseUrl } from '../../../helpers/urls'; +import '../styles.css'; + +interface Props { + // eslint-disable-next-line camelcase + location: { query: { return_to?: string } }; + setup: boolean; +} + +interface State { + message?: string; + startedAt?: string; + state?: string; + status?: string; + wasStarting?: boolean; +} + +export default class App extends React.PureComponent<Props, State> { + interval?: number; + mounted = false; + state: State = {}; + + componentDidMount() { + this.mounted = true; + this.fetchStatus(); + } + + componentWillUnmount() { + this.mounted = false; + if (this.interval) { + window.clearInterval(this.interval); + } + } + + fetchStatus = () => { + const request = this.props.setup ? this.fetchMigrationState() : this.fetchSystemStatus(); + request.catch(() => { + if (this.mounted) { + this.setState({ + message: undefined, + startedAt: undefined, + state: undefined, + status: 'OFFLINE' + }); + } + }); + }; + + fetchSystemStatus = () => { + return getSystemStatus().then(({ status }) => { + if (this.mounted) { + this.setState({ status }); + + if (status === 'STARTING') { + this.setState({ wasStarting: true }); + this.scheduleRefresh(); + } else if (status === 'UP') { + if (this.state.wasStarting) { + this.loadPreviousPage(); + } + } else { + this.scheduleRefresh(); + } + } + }); + }; + + fetchMigrationState = () => { + return getMigrationStatus().then(({ message, startedAt, state }) => { + if (this.mounted) { + this.setState({ message, startedAt, state }); + if (state === 'MIGRATION_SUCCEEDED') { + this.loadPreviousPage(); + } else if (state !== 'NO_MIGRATION') { + this.scheduleRefresh(); + } + } + }); + }; + + scheduleRefresh = () => { + this.interval = window.setTimeout(this.fetchStatus, 5000); + }; + + loadPreviousPage = () => { + setInterval(() => { + window.location.href = this.props.location.query['return_to'] || getBaseUrl() + '/'; + }, 2500); + }; + + handleMigrateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => { + event.preventDefault(); + event.currentTarget.blur(); + migrateDatabase().then( + ({ message, startedAt, state }) => { + if (this.mounted) { + this.setState({ message, startedAt, state }); + } + }, + () => {} + ); + }; + + render() { + const { state, status } = this.state; + + return ( + <div className="page-wrapper-simple" id="bd"> + <div + className={classNames('page-simple', { 'panel-warning': state === 'MIGRATION_REQUIRED' })} + id="nonav"> + {status === 'OFFLINE' && ( + <> + <h1 className="maintenance-title text-danger"> + {translate('maintenance.sonarqube_is_offline')} + </h1> + <p className="maintenance-text"> + {translate('maintenance.sonarqube_is_offline.text')} + </p> + <p className="maintenance-text text-center"> + <a href={getBaseUrl() + '/'}>{translate('maintenance.try_again')}</a> + </p> + </> + )} + + {status === 'UP' && ( + <> + <h1 className="maintenance-title">{translate('maintenance.sonarqube_is_up')}</h1> + <p className="maintenance-text text-center"> + {translate('maintenance.all_systems_opetational')} + </p> + <p className="maintenance-text text-center"> + <a href={getBaseUrl() + '/'}>{translate('layout.home')}</a> + </p> + </> + )} + + {status === 'STARTING' && ( + <> + <h1 className="maintenance-title"> + {translate('maintenance.sonarqube_is_starting')} + </h1> + <p className="maintenance-spinner"> + <i className="spinner" /> + </p> + </> + )} + + {status === 'DOWN' && ( + <> + <h1 className="maintenance-title text-danger"> + {translate('maintenance.sonarqube_is_down')} + </h1> + <p className="maintenance-text">{translate('maintenance.sonarqube_is_down.text')}</p> + <p className="maintenance-text text-center"> + <a href={getBaseUrl() + '/'}>{translate('maintenance.try_again')}</a> + </p> + </> + )} + + {(status === 'DB_MIGRATION_NEEDED' || status === 'DB_MIGRATION_RUNNING') && ( + <> + <h1 className="maintenance-title"> + {translate('maintenance.sonarqube_is_under_maintenance')} + </h1> + <p + className="maintenance-text" + dangerouslySetInnerHTML={{ + __html: translate('maintenance.sonarqube_is_under_maintenance.1') + }} + /> + <p + className="maintenance-text" + dangerouslySetInnerHTML={{ + __html: translate('maintenance.sonarqube_is_under_maintenance.2') + }} + /> + </> + )} + + {state === 'NO_MIGRATION' && ( + <> + <h1 className="maintenance-title"> + {translate('maintenance.database_is_up_to_date')} + </h1> + <p className="maintenance-text text-center"> + <a href={getBaseUrl() + '/'}>{translate('layout.home')}</a> + </p> + </> + )} + + {state === 'MIGRATION_REQUIRED' && ( + <> + <h1 className="maintenance-title">{translate('maintenance.upgrade_database')}</h1> + <p className="maintenance-text">{translate('maintenance.upgrade_database.1')}</p> + <p className="maintenance-text">{translate('maintenance.upgrade_database.2')}</p> + <p className="maintenance-text">{translate('maintenance.upgrade_database.3')}</p> + <div className="maintenance-spinner"> + <button id="start-migration" onClick={this.handleMigrateClick} type="button"> + {translate('maintenance.upgrade')} + </button> + </div> + </> + )} + + {state === 'NOT_SUPPORTED' && ( + <> + <h1 className="maintenance-title text-danger"> + {translate('maintenance.migration_not_supported')} + </h1> + <p>{translate('maintenance.migration_not_supported.text')}</p> + </> + )} + + {state === 'MIGRATION_RUNNING' && ( + <> + <h1 className="maintenance-title">{translate('maintenance.database_migration')}</h1> + {this.state.message && ( + <p className="maintenance-text text-center">{this.state.message}</p> + )} + {this.state.startedAt && ( + <p className="maintenance-text text-center"> + {translate('background_tasks.table.started')}{' '} + <DateFromNow date={this.state.startedAt} /> + <br /> + <small className="text-muted"> + <TimeFormatter date={this.state.startedAt} long={true} /> + </small> + </p> + )} + <p className="maintenance-spinner"> + <i className="spinner" /> + </p> + </> + )} + + {state === 'MIGRATION_SUCCEEDED' && ( + <> + <h1 className="maintenance-title text-success"> + {translate('maintenance.database_is_up_to_date')} + </h1> + <p className="maintenance-text text-center"> + <a href={getBaseUrl() + '/'}>{translate('layout.home')}</a> + </p> + </> + )} + + {state === 'MIGRATION_FAILED' && ( + <> + <h1 className="maintenance-title text-danger"> + {translate('maintenance.upgrade_failed')} + </h1> + <p className="maintenance-text">{translate('maintenance.upgrade_failed.text')}</p> + </> + )} + </div> + </div> + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.tsx index 38be383b830..1a84ccdcd6d 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.tsx @@ -18,19 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import init from '../init'; -import '../styles.css'; +import App from './App'; interface Props { + // eslint-disable-next-line camelcase location: { query: { return_to: string } }; } -export default class MaintenanceAppContainer extends React.PureComponent<Props> { - componentDidMount() { - init(this.refs.container, false, this.props.location.query['return_to']); - } - - render() { - return <div ref="container" />; - } +export default function MaintenanceAppContainer(props: Props) { + return <App setup={false} {...props} />; } diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.tsx index 46d68176189..4cd1e8fe5b5 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.tsx @@ -18,19 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import init from '../init'; -import '../styles.css'; +import App from './App'; interface Props { + // eslint-disable-next-line camelcase location: { query: { return_to: string } }; } -export default class SetupAppContainer extends React.PureComponent<Props> { - componentDidMount() { - init(this.refs.container, true, this.props.location.query['return_to']); - } - - render() { - return <div ref="container" />; - } +export default function MaintenanceAppContainer(props: Props) { + return <App setup={true} {...props} />; } diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx new file mode 100644 index 00000000000..8d4511d09e7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx @@ -0,0 +1,134 @@ +/* + * 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 App from '../App'; +import { click, waitAndUpdate } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/system', () => ({ + getMigrationStatus: jest.fn(), + getSystemStatus: jest.fn(), + migrateDatabase: jest.fn() +})); + +jest.useFakeTimers(); + +const getMigrationStatus = require('../../../../api/system').getMigrationStatus as jest.Mock; +const getSystemStatus = require('../../../../api/system').getSystemStatus as jest.Mock; +const migrateDatabase = require('../../../../api/system').migrateDatabase as jest.Mock; + +const location = { query: {} }; + +beforeEach(() => { + getMigrationStatus.mockClear(); + getSystemStatus.mockClear(); + migrateDatabase.mockClear(); +}); + +afterEach(() => { + jest.clearAllTimers(); +}); + +describe('Maintenance Page', () => { + ['UP', 'DOWN', 'STARTING', 'DB_MIGRATION_NEEDED', 'DB_MIGRATION_RUNNING'].forEach(status => { + it(`should render ${status} status`, async () => { + getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status })); + await checkApp(false); + }); + }); + + it('should render OFFLINE status', async () => { + getSystemStatus.mockImplementationOnce(() => Promise.reject(undefined)); + await checkApp(false); + }); + + it('should poll status', async () => { + getSystemStatus.mockImplementationOnce(() => + Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) + ); + const wrapper = shallow(<App location={location} setup={false} />); + await waitAndUpdate(wrapper); + expect(getSystemStatus).toBeCalled(); + + getSystemStatus.mockClear(); + getSystemStatus.mockImplementationOnce(() => + Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) + ); + jest.runOnlyPendingTimers(); + await waitAndUpdate(wrapper); + expect(getSystemStatus).toBeCalled(); + + getSystemStatus.mockClear(); + getSystemStatus.mockImplementationOnce(() => + Promise.resolve({ status: 'DB_MIGRATION_RUNNING' }) + ); + jest.runOnlyPendingTimers(); + await waitAndUpdate(wrapper); + expect(getSystemStatus).toBeCalled(); + }); + + it('should open previous page', async () => { + getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status: 'STARTING' })); + const wrapper = shallow(<App location={location} setup={false} />); + const loadPreviousPage = jest.fn(); + (wrapper.instance() as App).loadPreviousPage = loadPreviousPage; + await waitAndUpdate(wrapper); + + getSystemStatus.mockImplementationOnce(() => Promise.resolve({ status: 'UP' })); + jest.runOnlyPendingTimers(); + await waitAndUpdate(wrapper); + expect(loadPreviousPage).toBeCalled(); + }); +}); + +describe('Setup Page', () => { + ['NO_MIGRATION', 'NOT_SUPPORTED', 'MIGRATION_SUCCEEDED', 'MIGRATION_FAILED'].forEach(state => { + it(`should render ${state} state`, async () => { + getMigrationStatus.mockImplementationOnce(() => + Promise.resolve({ message: 'message', startedAt: '2017-01-02T00:00:00.000Z', state }) + ); + await checkApp(true); + }); + }); + + it('should start migration', async () => { + getMigrationStatus.mockImplementationOnce(() => + Promise.resolve({ state: 'MIGRATION_REQUIRED' }) + ); + migrateDatabase.mockImplementationOnce(() => + Promise.resolve({ startedAt: '2017-01-02T00:00:00.000Z', state: 'MIGRATION_RUNNING' }) + ); + const wrapper = shallow(<App location={location} setup={true} />); + await waitAndUpdate(wrapper); + expect(wrapper).toMatchSnapshot(); + + click(wrapper.find('button')); + expect(migrateDatabase).toBeCalled(); + await waitAndUpdate(wrapper); + expect(wrapper).toMatchSnapshot(); + }); +}); + +async function checkApp(setup: boolean) { + const wrapper = shallow(<App location={location} setup={setup} />); + await waitAndUpdate(wrapper); + expect(wrapper).toMatchSnapshot(); +} diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap new file mode 100644 index 00000000000..784a8eb1969 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap @@ -0,0 +1,399 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Maintenance Page should render DB_MIGRATION_NEEDED status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.sonarqube_is_under_maintenance + </h1> + <p + className="maintenance-text" + dangerouslySetInnerHTML={ + Object { + "__html": "maintenance.sonarqube_is_under_maintenance.1", + } + } + /> + <p + className="maintenance-text" + dangerouslySetInnerHTML={ + Object { + "__html": "maintenance.sonarqube_is_under_maintenance.2", + } + } + /> + </React.Fragment> + </div> +</div> +`; + +exports[`Maintenance Page should render DB_MIGRATION_RUNNING status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.sonarqube_is_under_maintenance + </h1> + <p + className="maintenance-text" + dangerouslySetInnerHTML={ + Object { + "__html": "maintenance.sonarqube_is_under_maintenance.1", + } + } + /> + <p + className="maintenance-text" + dangerouslySetInnerHTML={ + Object { + "__html": "maintenance.sonarqube_is_under_maintenance.2", + } + } + /> + </React.Fragment> + </div> +</div> +`; + +exports[`Maintenance Page should render DOWN status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title text-danger" + > + maintenance.sonarqube_is_down + </h1> + <p + className="maintenance-text" + > + maintenance.sonarqube_is_down.text + </p> + <p + className="maintenance-text text-center" + > + <a + href="/" + > + maintenance.try_again + </a> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Maintenance Page should render OFFLINE status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title text-danger" + > + maintenance.sonarqube_is_offline + </h1> + <p + className="maintenance-text" + > + maintenance.sonarqube_is_offline.text + </p> + <p + className="maintenance-text text-center" + > + <a + href="/" + > + maintenance.try_again + </a> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Maintenance Page should render STARTING status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.sonarqube_is_starting + </h1> + <p + className="maintenance-spinner" + > + <i + className="spinner" + /> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Maintenance Page should render UP status 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.sonarqube_is_up + </h1> + <p + className="maintenance-text text-center" + > + maintenance.all_systems_opetational + </p> + <p + className="maintenance-text text-center" + > + <a + href="/" + > + layout.home + </a> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should render MIGRATION_FAILED state 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title text-danger" + > + maintenance.upgrade_failed + </h1> + <p + className="maintenance-text" + > + maintenance.upgrade_failed.text + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should render MIGRATION_SUCCEEDED state 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title text-success" + > + maintenance.database_is_up_to_date + </h1> + <p + className="maintenance-text text-center" + > + <a + href="/" + > + layout.home + </a> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should render NO_MIGRATION state 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.database_is_up_to_date + </h1> + <p + className="maintenance-text text-center" + > + <a + href="/" + > + layout.home + </a> + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should render NOT_SUPPORTED state 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title text-danger" + > + maintenance.migration_not_supported + </h1> + <p> + maintenance.migration_not_supported.text + </p> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should start migration 1`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple panel-warning" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.upgrade_database + </h1> + <p + className="maintenance-text" + > + maintenance.upgrade_database.1 + </p> + <p + className="maintenance-text" + > + maintenance.upgrade_database.2 + </p> + <p + className="maintenance-text" + > + maintenance.upgrade_database.3 + </p> + <div + className="maintenance-spinner" + > + <button + id="start-migration" + onClick={[Function]} + type="button" + > + maintenance.upgrade + </button> + </div> + </React.Fragment> + </div> +</div> +`; + +exports[`Setup Page should start migration 2`] = ` +<div + className="page-wrapper-simple" + id="bd" +> + <div + className="page-simple" + id="nonav" + > + <React.Fragment> + <h1 + className="maintenance-title" + > + maintenance.database_migration + </h1> + <p + className="maintenance-text text-center" + > + background_tasks.table.started + + <DateFromNow + date="2017-01-02T00:00:00.000Z" + /> + <br /> + <small + className="text-muted" + > + <TimeFormatter + date="2017-01-02T00:00:00.000Z" + long={true} + /> + </small> + </p> + <p + className="maintenance-spinner" + > + <i + className="spinner" + /> + </p> + </React.Fragment> + </div> +</div> +`; diff --git a/server/sonar-web/src/main/js/apps/maintenance/init.js b/server/sonar-web/src/main/js/apps/maintenance/init.js deleted file mode 100644 index 15c84c25ed9..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/init.js +++ /dev/null @@ -1,37 +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 Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import MainView from './main-view'; - -const App = new Marionette.Application(); - -App.on('start', options => { - const viewOptions = { - ...options, - model: new Backbone.Model() - }; - const mainView = new MainView(viewOptions); - mainView.render().refresh(); -}); - -export default function(el, setup, returnTo) { - App.start({ el, setup, returnTo }); -} diff --git a/server/sonar-web/src/main/js/apps/maintenance/main-view.js b/server/sonar-web/src/main/js/apps/maintenance/main-view.js deleted file mode 100644 index da558206ba2..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/main-view.js +++ /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. - */ -import Marionette from 'backbone.marionette'; -import Template from './templates/maintenance-main.hbs'; -import { getSystemStatus, getMigrationStatus, migrateDatabase } from '../../api/system'; -import { getBaseUrl } from '../../helpers/urls'; - -export default Marionette.ItemView.extend({ - template: Template, - - events: { - 'click #start-migration': 'startMigration' - }, - - initialize() { - this.pollingInternal = setInterval(() => { - this.refresh(); - }, 5000); - this.wasStarting = false; - }, - - getStatus() { - return this.options.setup ? getMigrationStatus() : getSystemStatus(); - }, - - refresh() { - return this.getStatus().then( - r => { - if (r.status === 'STARTING') { - this.wasStarting = true; - } - // unset `status` in case if was `OFFLINE` previously - this.model.set({ status: undefined, ...r }); - this.render(); - if (this.model.get('status') === 'UP' || this.model.get('state') === 'NO_MIGRATION') { - this.stopPolling(); - } - if (this.model.get('status') === 'UP' && this.wasStarting) { - this.loadPreviousPage(); - } - if (this.model.get('state') === 'MIGRATION_SUCCEEDED') { - this.loadPreviousPage(); - } - }, - () => { - this.model.set({ status: 'OFFLINE' }); - this.render(); - } - ); - }, - - stopPolling() { - clearInterval(this.pollingInternal); - }, - - startMigration() { - migrateDatabase().then( - r => { - this.model.set(r); - this.render(); - }, - () => {} - ); - }, - - loadPreviousPage() { - setInterval(() => { - window.location = this.options.returnTo || getBaseUrl(); - }, 2500); - }, - - serializeData() { - return { - ...Marionette.ItemView.prototype.serializeData.apply(this, arguments), - setup: this.options.setup - }; - } -}); diff --git a/server/sonar-web/src/main/js/apps/maintenance/routes.tsx b/server/sonar-web/src/main/js/apps/maintenance/routes.tsx index 7ef353bbe4a..ac4c46ec21c 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/routes.tsx +++ b/server/sonar-web/src/main/js/apps/maintenance/routes.tsx @@ -19,9 +19,12 @@ */ import * as React from 'react'; import { IndexRoute } from 'react-router'; -import MaintenanceAppContainer from './components/MaintenanceAppContainer'; -import SetupAppContainer from './components/SetupAppContainer'; +import { lazyLoad } from '../../components/lazyLoad'; -export const maintenanceRoutes = <IndexRoute component={MaintenanceAppContainer} />; +export const maintenanceRoutes = ( + <IndexRoute component={lazyLoad(() => import('./components/MaintenanceAppContainer'))} /> +); -export const setupRoutes = <IndexRoute component={SetupAppContainer} />; +export const setupRoutes = ( + <IndexRoute component={lazyLoad(() => import('./components/SetupAppContainer'))} /> +); diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-failed.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-failed.hbs deleted file mode 100644 index ab1421b6b7e..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-failed.hbs +++ /dev/null @@ -1,2 +0,0 @@ -<h1 class="maintenance-title text-danger">{{t 'maintenance.upgrade_failed'}}</h1> -<p class="maintenance-text">{{t 'maintenance.upgrade_failed.text'}}</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-not-supported.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-not-supported.hbs deleted file mode 100644 index 6d023044313..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-not-supported.hbs +++ /dev/null @@ -1,2 +0,0 @@ -<h1 class="maintenance-title text-danger">{{t 'maintenance.migration_not_supported'}}</h1> -<p>{{t 'maintenance.migration_not_supported.text'}}</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-required.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-required.hbs deleted file mode 100644 index 3236ff5a80f..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-required.hbs +++ /dev/null @@ -1,7 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.upgrade_database'}}</h1> -<p class="maintenance-text">{{t 'maintenance.upgrade_database.1'}}</p> -<p class="maintenance-text">{{t 'maintenance.upgrade_database.2'}}</p> -<p class="maintenance-text">{{t 'maintenance.upgrade_database.3'}}</p> -<div class="maintenance-spinner"> - <button id="start-migration">{{t 'maintenance.upgrade'}}</button> -</div> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-running.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-running.hbs deleted file mode 100644 index c69baef7434..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-running.hbs +++ /dev/null @@ -1,11 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.database_migration'}}</h1> -{{#if message}} - <p class="maintenance-text text-center">{{message}}</p> -{{/if}} -{{#if startedAt}} - <p class="maintenance-text text-center"> - {{t 'background_tasks.table.started'}} {{fromNow startedAt}}<br> - <small class="text-muted">{{dt startedAt}}</small> - </p> -{{/if}} -<p class="maintenance-spinner"><i class="spinner"></i></p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-succeeded.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-succeeded.hbs deleted file mode 100644 index 7e70e68cf30..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-migration-succeeded.hbs +++ /dev/null @@ -1,4 +0,0 @@ -<h1 class="maintenance-title text-success">{{t 'maintenance.database_is_up_to_date'}}</h1> -<p class="maintenance-text text-center"> - <a href="{{link '/'}}">{{t 'layout.home'}}</a> -</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-no-migration.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-no-migration.hbs deleted file mode 100644 index 6c30631c9a5..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-state-no-migration.hbs +++ /dev/null @@ -1,4 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.database_is_up_to_date'}}</h1> -<p class="maintenance-text text-center"> - <a href="{{link '/'}}">{{t 'layout.home'}}</a> -</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-down.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-down.hbs deleted file mode 100644 index 811aa16ef5b..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-down.hbs +++ /dev/null @@ -1,5 +0,0 @@ -<h1 class="maintenance-title text-danger">{{t 'maintenance.sonarqube_is_down'}}</h1> -<p class="maintenance-text">{{t 'maintenance.sonarqube_is_down.text'}}</p> -<p class="maintenance-text text-center"> - <a href="{{link '/'}}">{{t 'maintenance.try_again'}}</a> -</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-migration.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-migration.hbs deleted file mode 100644 index f51f4c72475..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-migration.hbs +++ /dev/null @@ -1,3 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.sonarqube_is_under_maintenance'}}</h1> -<p class="maintenance-text">{{{t 'maintenance.sonarqube_is_under_maintenance.1'}}}</p> -<p class="maintenance-text">{{{t 'maintenance.sonarqube_is_under_maintenance.2'}}}</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-offline.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-offline.hbs deleted file mode 100644 index 6e7bac35c3f..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-offline.hbs +++ /dev/null @@ -1,5 +0,0 @@ -<h1 class="maintenance-title text-danger">{{t 'maintenance.sonarqube_is_offline'}}</h1> -<p class="maintenance-text">{{t 'maintenance.sonarqube_is_offline.text'}}</p> -<p class="maintenance-text text-center"> - <a href="{{link '/'}}">{{t 'maintenance.try_again'}}</a> -</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-starting.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-starting.hbs deleted file mode 100644 index 96f7d89f122..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-starting.hbs +++ /dev/null @@ -1,2 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.sonarqube_is_starting'}}</h1> -<p class="maintenance-spinner"><i class="spinner"></i></p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-up.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-up.hbs deleted file mode 100644 index e97b550f342..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/_maintenance-status-up.hbs +++ /dev/null @@ -1,5 +0,0 @@ -<h1 class="maintenance-title">{{t 'maintenance.sonarqube_is_up'}}</h1> -<p class="maintenance-text text-center">{{t 'maintenance.all_systems_opetational'}}</p> -<p class="maintenance-text text-center"> - <a href="{{link '/'}}">{{t 'layout.home'}}</a> -</p> diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs deleted file mode 100644 index 44a4bc8798d..00000000000 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs +++ /dev/null @@ -1,32 +0,0 @@ -<div id="bd" class="page-wrapper-simple"> - <div id="nonav" class="page-simple {{#eq state 'MIGRATION_REQUIRED'}}panel-warning{{/eq}}"> - - {{#eq status 'OFFLINE'}} - - {{> '_maintenance-status-offline'}} - - {{else}} - - {{#unless setup}} - - {{#eq status 'UP'}}{{> '_maintenance-status-up'}}{{/eq}} - {{#eq status 'STARTING'}}{{> '_maintenance-status-starting'}}{{/eq}} - {{#eq status 'DOWN'}}{{> '_maintenance-status-down'}}{{/eq}} - {{#eq status 'DB_MIGRATION_NEEDED'}}{{> '_maintenance-status-migration'}}{{/eq}} - {{#eq status 'DB_MIGRATION_RUNNING'}}{{> '_maintenance-status-migration'}}{{/eq}} - - {{else}} - - {{#eq state 'NO_MIGRATION'}}{{> '_maintenance-state-no-migration'}}{{/eq}} - {{#eq state 'MIGRATION_REQUIRED'}}{{> '_maintenance-state-migration-required'}}{{/eq}} - {{#eq state 'NOT_SUPPORTED'}}{{> '_maintenance-state-migration-not-supported'}}{{/eq}} - {{#eq state 'MIGRATION_RUNNING'}}{{> '_maintenance-state-migration-running'}}{{/eq}} - {{#eq state 'MIGRATION_SUCCEEDED'}}{{> '_maintenance-state-migration-succeeded'}}{{/eq}} - {{#eq state 'MIGRATION_FAILED'}}{{> '_maintenance-state-migration-failed'}}{{/eq}} - - {{/unless}} - - {{/eq}} - - </div> -</div> |