@@ -58,6 +58,15 @@ export interface ClusterSysInfo extends SysInfo { | |||
'Search Nodes': NodeInfo[]; | |||
} | |||
export interface SystemUpgrade { | |||
version: string; | |||
description: string; | |||
releaseDate: string; | |||
changeLogUrl: string; | |||
downloadUrl: string; | |||
plugins: any; | |||
} | |||
export function setLogLevel(level: string): Promise<void | Response> { | |||
return post('/api/system/change_log_level', { level }).catch(throwGlobalError); | |||
} | |||
@@ -70,6 +79,13 @@ export function getSystemStatus(): Promise<any> { | |||
return getJSON('/api/system/status'); | |||
} | |||
export function getSystemUpgrades(): Promise<{ | |||
upgrades: SystemUpgrade[]; | |||
updateCenterRefresh: string; | |||
}> { | |||
return getJSON('/api/system/upgrades'); | |||
} | |||
export function getMigrationStatus(): Promise<any> { | |||
return getJSON('/api/system/db_migration_status'); | |||
} |
@@ -185,7 +185,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
}; | |||
updateEditionStatus = (editionStatus: EditionStatus) => { | |||
this.setState({ editionStatus: editionStatus }); | |||
this.setState({ editionStatus }); | |||
if (this.timer) { | |||
global.clearTimeout(this.timer); | |||
this.timer = undefined; | |||
@@ -211,7 +211,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
return ( | |||
<div className="page page-limited" id="marketplace-page"> | |||
<Helmet title={translate('marketplace.page')} /> | |||
<div className="marketplace-notifs"> | |||
<div className="page-notifs"> | |||
{editionStatus && ( | |||
<EditionsStatusNotif | |||
editions={editions} |
@@ -30,11 +30,3 @@ | |||
align-items: baseline; | |||
justify-content: space-between; | |||
} | |||
.marketplace-notifs .alert { | |||
padding: 8px; | |||
} | |||
.marketplace-notifs .alert:last-child { | |||
margin-bottom: 16px; | |||
} |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as u from '../utils'; | |||
import { ClusterSysInfo, SysInfo } from '../../../api/system'; | |||
import { ClusterSysInfo, SysInfo, SystemUpgrade } from '../../../api/system'; | |||
describe('parseQuery', () => { | |||
it('should correctly parse the expand array', () => { | |||
@@ -84,3 +84,51 @@ describe('getSystemLogsLevel', () => { | |||
expect(u.getSystemLogsLevel({ System: {} } as SysInfo)).toBe('INFO'); | |||
}); | |||
}); | |||
describe('sortUpgrades', () => { | |||
it('should sort correctly versions', () => { | |||
expect( | |||
u.sortUpgrades([ | |||
{ version: '5.4.2' }, | |||
{ version: '5.10' }, | |||
{ version: '5.1' }, | |||
{ version: '5.4' } | |||
] as SystemUpgrade[]) | |||
).toEqual([{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }]); | |||
expect( | |||
u.sortUpgrades([ | |||
{ version: '5.10' }, | |||
{ version: '5.1.2' }, | |||
{ version: '6.0' }, | |||
{ version: '6.9' } | |||
] as SystemUpgrade[]) | |||
).toEqual([{ version: '6.9' }, { version: '6.0' }, { version: '5.10' }, { version: '5.1.2' }]); | |||
}); | |||
}); | |||
describe('groupUpgrades', () => { | |||
it('should group correctly', () => { | |||
expect( | |||
u.groupUpgrades([ | |||
{ version: '5.10' }, | |||
{ version: '5.4.2' }, | |||
{ version: '5.4' }, | |||
{ version: '5.1' } | |||
] as SystemUpgrade[]) | |||
).toEqual([ | |||
[{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }] | |||
]); | |||
expect( | |||
u.groupUpgrades([ | |||
{ version: '6.9' }, | |||
{ version: '6.7' }, | |||
{ version: '6.0' }, | |||
{ version: '5.10' }, | |||
{ version: '5.4.2' } | |||
] as SystemUpgrade[]) | |||
).toEqual([ | |||
[{ version: '6.9' }, { version: '6.7' }, { version: '6.0' }], | |||
[{ version: '5.10' }, { version: '5.4.2' }] | |||
]); | |||
}); | |||
}); |
@@ -23,6 +23,7 @@ import Helmet from 'react-helmet'; | |||
import ClusterSysInfos from './ClusterSysInfos'; | |||
import PageHeader from './PageHeader'; | |||
import StandaloneSysInfos from './StandaloneSysInfos'; | |||
import SystemUpgradeNotif from './system-upgrade/SystemUpgradeNotif'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { ClusterSysInfo, getSystemInfo, SysInfo } from '../../../api/system'; | |||
import { getSystemLogsLevel, isCluster, parseQuery, Query, serializeQuery } from '../utils'; | |||
@@ -117,6 +118,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
return ( | |||
<div className="page page-limited"> | |||
<Helmet title={translate('system_info.page')} /> | |||
<SystemUpgradeNotif /> | |||
<PageHeader | |||
loading={loading} | |||
isCluster={isCluster(sysInfoData)} |
@@ -0,0 +1,71 @@ | |||
/* | |||
* 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 { getSystemUpgrades, SystemUpgrade } from '../../../api/system'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface State { | |||
systemUpgrades?: SystemUpgrade[]; | |||
} | |||
export default class SystemUpgradeNotif extends React.PureComponent<{}, State> { | |||
mounted: boolean; | |||
state: State = {}; | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchSystemUpgrades(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchSystemUpgrades = () => | |||
getSystemUpgrades().then( | |||
({ upgrades }) => { | |||
if (this.mounted) { | |||
this.setState({ systemUpgrades: upgrades }); | |||
} | |||
}, | |||
() => {} | |||
); | |||
handleLearnMore = () => {}; | |||
render() { | |||
const { systemUpgrades } = this.state; | |||
if (!systemUpgrades || systemUpgrades.length <= 0) { | |||
return null; | |||
} | |||
return ( | |||
<div className="page-notifs"> | |||
<div className="alert alert-info"> | |||
{translate('system.new_version_available')} | |||
<button className="spacer-left" onClick={this.handleLearnMore}> | |||
{translate('learn_more')} | |||
</button> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* 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 Modal from 'react-modal'; | |||
import SystemUpgradeItem from './SystemUpgradeItem'; | |||
import { SystemUpgrade } from '../../../../api/system'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
interface Props { | |||
systemUpgrades: SystemUpgrade[][]; | |||
onClose: () => void; | |||
} | |||
interface State { | |||
upgrading: boolean; | |||
} | |||
export default class SystemUpgradeForm extends React.PureComponent<Props, State> { | |||
state: State = { upgrading: false }; | |||
getBadge = (idx: number) => { | |||
if (this.props.systemUpgrades.length <= 1) { | |||
return undefined; | |||
} | |||
if (idx === 0) { | |||
return translate('system.latest_version'); | |||
} | |||
return translate('system.latest_lts_version'); | |||
}; | |||
handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
this.props.onClose(); | |||
}; | |||
render() { | |||
const { upgrading } = this.state; | |||
const { systemUpgrades } = this.props; | |||
const header = translate('system.system_upgrade'); | |||
return ( | |||
<Modal | |||
isOpen={true} | |||
contentLabel={header} | |||
className="modal" | |||
overlayClassName="modal-overlay" | |||
onRequestClose={this.props.onClose}> | |||
<div className="modal-head"> | |||
<h2>{header}</h2> | |||
</div> | |||
<div className="modal-body"> | |||
{systemUpgrades.map((upgrades, idx) => ( | |||
<SystemUpgradeItem | |||
key={upgrades[upgrades.length - 1].version} | |||
badge={this.getBadge(idx)} | |||
systemUpgrades={upgrades} | |||
/> | |||
))} | |||
</div> | |||
<div className="modal-foot"> | |||
{upgrading && <i className="spinner spacer-right" />} | |||
<a className="pull-left" href="https://www.sonarqube.org/downloads/" target="_blank"> | |||
{translate('system.see_sonarqube_downloads')} | |||
</a> | |||
<a href="#" onClick={this.handleCancelClick}> | |||
{translate('cancel')} | |||
</a> | |||
</div> | |||
</Modal> | |||
); | |||
} | |||
} |
@@ -0,0 +1,86 @@ | |||
/* | |||
* 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'; | |||
import DateFormatter from '../../../../components/intl/DateFormatter'; | |||
import { SystemUpgrade } from '../../../../api/system'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
interface Props { | |||
className?: string; | |||
upgrades: SystemUpgrade[]; | |||
} | |||
interface State { | |||
showMore: boolean; | |||
} | |||
export default class SystemUpgradeIntermediate extends React.PureComponent<Props, State> { | |||
state: State = { showMore: false }; | |||
toggleIntermediatVersions = (event: React.SyntheticEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
this.setState(state => ({ showMore: !state.showMore })); | |||
}; | |||
render() { | |||
const { showMore } = this.state; | |||
const { upgrades } = this.props; | |||
if (upgrades.length <= 0) { | |||
return null; | |||
} | |||
return ( | |||
<div className={this.props.className}> | |||
<a | |||
className="button-link little-spacer-bottom" | |||
href="#" | |||
onClick={this.toggleIntermediatVersions}> | |||
{showMore ? ( | |||
translate('system.hide_intermediate_versions') | |||
) : ( | |||
translate('system.show_intermediate_versions') | |||
)} | |||
<i | |||
className={classNames('little-spacer-left', { | |||
'icon-arrow-down': !showMore, | |||
'icon-arrow-up': showMore | |||
})} | |||
/> | |||
</a> | |||
{showMore && | |||
upgrades.map(upgrade => ( | |||
<div key={upgrade.version} className="note system-upgrade-intermediate"> | |||
<DateFormatter date={upgrade.releaseDate} long={true}> | |||
{formattedDate => ( | |||
<p> | |||
<b className="little-spacer-right">SonarQube {upgrade.version}</b> | |||
{formattedDate} | |||
</p> | |||
)} | |||
</DateFormatter> | |||
<p className="little-spacer-top">{upgrade.description}</p> | |||
</div> | |||
))} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
/* | |||
* 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 { FormattedMessage } from 'react-intl'; | |||
import DateFormatter from '../../../../components/intl/DateFormatter'; | |||
import SystemUpgradeIntermediate from './SystemUpgradeIntermediate'; | |||
import { SystemUpgrade } from '../../../../api/system'; | |||
import { translate, translateWithParameters } from '../../../../helpers/l10n'; | |||
interface Props { | |||
badge?: string; | |||
systemUpgrades: SystemUpgrade[]; | |||
} | |||
export default function SystemUpgradeItem({ badge, systemUpgrades }: Props) { | |||
const lastUpgrade = systemUpgrades[0]; | |||
return ( | |||
<div className="system-upgrade-version"> | |||
{badge && <span className="spacer-bottom badge badge-secondary">{badge}</span>} | |||
<p> | |||
<FormattedMessage | |||
defaultMessage={translate('system.version_is_availble')} | |||
id="system.version_is_availble" | |||
values={{ version: <b>SonarQube {lastUpgrade.version}</b> }} | |||
/> | |||
</p> | |||
<p className="spacer-top">{lastUpgrade.description}</p> | |||
<div className="big-spacer-top"> | |||
<DateFormatter date={lastUpgrade.releaseDate} long={true}> | |||
{formattedDate => ( | |||
<span>{translateWithParameters('system.released_x', formattedDate)}</span> | |||
)} | |||
</DateFormatter> | |||
<a className="spacer-left" href={lastUpgrade.changeLogUrl} target="_blank"> | |||
{translate('system.release_notes')} | |||
</a> | |||
</div> | |||
<SystemUpgradeIntermediate className="spacer-top" upgrades={systemUpgrades.slice(1)} /> | |||
<div className="big-spacer-top"> | |||
<a | |||
className="button" | |||
download={`sonarqube-${lastUpgrade.version}.zip`} | |||
href={lastUpgrade.downloadUrl} | |||
target="blank"> | |||
{translateWithParameters('system.download_x', lastUpgrade.version)} | |||
</a> | |||
<a | |||
className="spacer-left" | |||
href="https://redirect.sonarsource.com/doc/upgrading.html" | |||
target="_blank"> | |||
{translate('system.how_to_upgrade')} | |||
</a> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,81 @@ | |||
/* | |||
* 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 SystemUpgradeForm from './SystemUpgradeForm'; | |||
import { getSystemUpgrades, SystemUpgrade } from '../../../../api/system'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { sortUpgrades, groupUpgrades } from '../../utils'; | |||
interface State { | |||
systemUpgrades: SystemUpgrade[][]; | |||
openSystemUpgradeForm: boolean; | |||
} | |||
export default class SystemUpgradeNotif extends React.PureComponent<{}, State> { | |||
mounted: boolean; | |||
state: State = { openSystemUpgradeForm: false, systemUpgrades: [] }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchSystemUpgrade(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchSystemUpgrade = () => | |||
getSystemUpgrades().then( | |||
({ upgrades }) => { | |||
if (this.mounted) { | |||
this.setState({ systemUpgrades: groupUpgrades(sortUpgrades(upgrades)) }); | |||
} | |||
}, | |||
() => {} | |||
); | |||
handleOpenSystemUpgradeForm = () => this.setState({ openSystemUpgradeForm: true }); | |||
handleCloseSystemUpgradeForm = () => this.setState({ openSystemUpgradeForm: false }); | |||
render() { | |||
const { systemUpgrades } = this.state; | |||
if (systemUpgrades.length <= 0) { | |||
return null; | |||
} | |||
return ( | |||
<div className="page-notifs"> | |||
<div className="alert alert-info"> | |||
{translate('system.new_version_available')} | |||
<button className="spacer-left" onClick={this.handleOpenSystemUpgradeForm}> | |||
{translate('learn_more')} | |||
</button> | |||
</div> | |||
{this.state.openSystemUpgradeForm && ( | |||
<SystemUpgradeForm | |||
systemUpgrades={systemUpgrades} | |||
onClose={this.handleCloseSystemUpgradeForm} | |||
/> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import SystemUpgradeForm from '../SystemUpgradeForm'; | |||
const UPGRADES = [ | |||
[ | |||
{ | |||
version: '6.4', | |||
description: 'Version 6.4 description', | |||
releaseDate: '2017-06-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '6.3', | |||
description: 'Version 6.3 description', | |||
releaseDate: '2017-05-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
} | |||
], | |||
[ | |||
{ | |||
version: '5.6.7', | |||
description: 'Version 5.6.7 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.6', | |||
description: 'Version 5.6.6 description', | |||
releaseDate: '2017-04-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.5', | |||
description: 'Version 5.6.5 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
} | |||
] | |||
]; | |||
it('should display correctly', () => { | |||
expect( | |||
shallow(<SystemUpgradeForm onClose={jest.fn()} systemUpgrades={UPGRADES} />) | |||
).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,58 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import { click } from '../../../../../helpers/testUtils'; | |||
import SystemUpgradeIntermediate from '../SystemUpgradeIntermediate'; | |||
const UPGRADES = [ | |||
{ | |||
version: '5.6.6', | |||
description: 'Version 5.6.6 description', | |||
releaseDate: '2017-04-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.5', | |||
description: 'Version 5.6.5 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
} | |||
]; | |||
it('should display correctly', () => { | |||
const wrapper = shallow(<SystemUpgradeIntermediate upgrades={UPGRADES} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
wrapper.setState({ showMore: true }); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should allow to show and hide intermediates', () => { | |||
const wrapper = shallow(<SystemUpgradeIntermediate upgrades={UPGRADES} />); | |||
expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeFalsy(); | |||
click(wrapper.find('a')); | |||
expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeTruthy(); | |||
click(wrapper.find('a')); | |||
expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeFalsy(); | |||
}); |
@@ -0,0 +1,59 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import SystemUpgradeItem from '../SystemUpgradeItem'; | |||
const UPGRADES = [ | |||
{ | |||
version: '5.6.7', | |||
description: 'Version 5.6.7 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.6', | |||
description: 'Version 5.6.6 description', | |||
releaseDate: '2017-04-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.5', | |||
description: 'Version 5.6.5 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
} | |||
]; | |||
it('should display correctly', () => { | |||
const wrapper = shallow(<SystemUpgradeItem systemUpgrades={UPGRADES} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should display a badge', () => { | |||
const wrapper = shallow(<SystemUpgradeItem badge="test badge" systemUpgrades={UPGRADES} />); | |||
expect(wrapper.find('.badge').exists()).toBeTruthy(); | |||
}); |
@@ -0,0 +1,123 @@ | |||
/* | |||
* 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 { mount, shallow } from 'enzyme'; | |||
import { click } from '../../../../../helpers/testUtils'; | |||
import SystemUpgradeNotif from '../SystemUpgradeNotif'; | |||
jest.mock('../../../../../api/system', () => ({ | |||
getSystemUpgrades: jest.fn(() => | |||
Promise.resolve({ | |||
updateCenterRefresh: '', | |||
upgrades: [ | |||
{ | |||
version: '5.6.7', | |||
description: 'Version 5.6.7 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.5', | |||
description: 'Version 5.6.5 description', | |||
releaseDate: '2017-03-01', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '6.3', | |||
description: 'Version 6.3 description', | |||
releaseDate: '2017-05-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '5.6.6', | |||
description: 'Version 5.6.6 description', | |||
releaseDate: '2017-04-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
}, | |||
{ | |||
version: '6.4', | |||
description: 'Version 6.4 description', | |||
releaseDate: '2017-06-02', | |||
changeLogUrl: 'changelogurl', | |||
downloadUrl: 'downloadurl', | |||
plugins: {} | |||
} | |||
] | |||
}) | |||
) | |||
})); | |||
const getSystemUpgrades = require('../../../../../api/system').getSystemUpgrades as jest.Mock<any>; | |||
beforeEach(() => { | |||
getSystemUpgrades.mockClear(); | |||
}); | |||
it('should display correctly', async () => { | |||
const wrapper = shallow(<SystemUpgradeNotif />); | |||
expect(wrapper).toMatchSnapshot(); | |||
const instance = wrapper.instance() as SystemUpgradeNotif; | |||
instance.mounted = true; | |||
instance.fetchSystemUpgrade(); | |||
await new Promise(setImmediate); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should display nothing', async () => { | |||
getSystemUpgrades.mockImplementationOnce(() => | |||
Promise.resolve({ updateCenterRefresh: '', upgrades: [] }) | |||
); | |||
const wrapper = shallow(<SystemUpgradeNotif />); | |||
const instance = wrapper.instance() as SystemUpgradeNotif; | |||
instance.mounted = true; | |||
instance.fetchSystemUpgrade(); | |||
await new Promise(setImmediate); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should fetch upgrade when mounting', () => { | |||
mount(<SystemUpgradeNotif />); | |||
expect(getSystemUpgrades).toHaveBeenCalled(); | |||
}); | |||
it('should open the upgrade form', async () => { | |||
const wrapper = shallow(<SystemUpgradeNotif />); | |||
const instance = wrapper.instance() as SystemUpgradeNotif; | |||
instance.mounted = true; | |||
instance.fetchSystemUpgrade(); | |||
await new Promise(setImmediate); | |||
wrapper.update(); | |||
click(wrapper.find('button')); | |||
expect(wrapper.find('SystemUpgradeForm').exists()).toBeTruthy(); | |||
}); |
@@ -0,0 +1,100 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should display correctly 1`] = ` | |||
<Modal | |||
ariaHideApp={true} | |||
bodyOpenClassName="ReactModal__Body--open" | |||
className="modal" | |||
closeTimeoutMS={0} | |||
contentLabel="system.system_upgrade" | |||
isOpen={true} | |||
onRequestClose={[Function]} | |||
overlayClassName="modal-overlay" | |||
parentSelector={[Function]} | |||
portalClassName="ReactModalPortal" | |||
shouldCloseOnOverlayClick={true} | |||
> | |||
<div | |||
className="modal-head" | |||
> | |||
<h2> | |||
system.system_upgrade | |||
</h2> | |||
</div> | |||
<div | |||
className="modal-body" | |||
> | |||
<SystemUpgradeItem | |||
badge="system.latest_version" | |||
systemUpgrades={ | |||
Array [ | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 6.4 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-06-02", | |||
"version": "6.4", | |||
}, | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 6.3 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-05-02", | |||
"version": "6.3", | |||
}, | |||
] | |||
} | |||
/> | |||
<SystemUpgradeItem | |||
badge="system.latest_lts_version" | |||
systemUpgrades={ | |||
Array [ | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 5.6.7 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-03-01", | |||
"version": "5.6.7", | |||
}, | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 5.6.6 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-04-02", | |||
"version": "5.6.6", | |||
}, | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 5.6.5 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-03-01", | |||
"version": "5.6.5", | |||
}, | |||
] | |||
} | |||
/> | |||
</div> | |||
<div | |||
className="modal-foot" | |||
> | |||
<a | |||
className="pull-left" | |||
href="https://www.sonarqube.org/downloads/" | |||
target="_blank" | |||
> | |||
system.see_sonarqube_downloads | |||
</a> | |||
<a | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
cancel | |||
</a> | |||
</div> | |||
</Modal> | |||
`; |
@@ -0,0 +1,57 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should display correctly 1`] = ` | |||
<div> | |||
<a | |||
className="button-link little-spacer-bottom" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
system.show_intermediate_versions | |||
<i | |||
className="little-spacer-left icon-arrow-down" | |||
/> | |||
</a> | |||
</div> | |||
`; | |||
exports[`should display correctly 2`] = ` | |||
<div> | |||
<a | |||
className="button-link little-spacer-bottom" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
system.hide_intermediate_versions | |||
<i | |||
className="little-spacer-left icon-arrow-up" | |||
/> | |||
</a> | |||
<div | |||
className="note system-upgrade-intermediate" | |||
> | |||
<DateFormatter | |||
date="2017-04-02" | |||
long={true} | |||
/> | |||
<p | |||
className="little-spacer-top" | |||
> | |||
Version 5.6.6 description | |||
</p> | |||
</div> | |||
<div | |||
className="note system-upgrade-intermediate" | |||
> | |||
<DateFormatter | |||
date="2017-03-01" | |||
long={true} | |||
/> | |||
<p | |||
className="little-spacer-top" | |||
> | |||
Version 5.6.5 description | |||
</p> | |||
</div> | |||
</div> | |||
`; |
@@ -0,0 +1,84 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should display correctly 1`] = ` | |||
<div | |||
className="system-upgrade-version" | |||
> | |||
<p> | |||
<FormattedMessage | |||
defaultMessage="system.version_is_availble" | |||
id="system.version_is_availble" | |||
values={ | |||
Object { | |||
"version": <b> | |||
SonarQube | |||
5.6.7 | |||
</b>, | |||
} | |||
} | |||
/> | |||
</p> | |||
<p | |||
className="spacer-top" | |||
> | |||
Version 5.6.7 description | |||
</p> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<DateFormatter | |||
date="2017-03-01" | |||
long={true} | |||
/> | |||
<a | |||
className="spacer-left" | |||
href="changelogurl" | |||
target="_blank" | |||
> | |||
system.release_notes | |||
</a> | |||
</div> | |||
<SystemUpgradeIntermediate | |||
className="spacer-top" | |||
upgrades={ | |||
Array [ | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 5.6.6 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-04-02", | |||
"version": "5.6.6", | |||
}, | |||
Object { | |||
"changeLogUrl": "changelogurl", | |||
"description": "Version 5.6.5 description", | |||
"downloadUrl": "downloadurl", | |||
"plugins": Object {}, | |||
"releaseDate": "2017-03-01", | |||
"version": "5.6.5", | |||
}, | |||
] | |||
} | |||
/> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<a | |||
className="button" | |||
download="sonarqube-5.6.7.zip" | |||
href="downloadurl" | |||
target="blank" | |||
> | |||
system.download_x.5.6.7 | |||
</a> | |||
<a | |||
className="spacer-left" | |||
href="https://redirect.sonarsource.com/doc/upgrading.html" | |||
target="_blank" | |||
> | |||
system.how_to_upgrade | |||
</a> | |||
</div> | |||
</div> | |||
`; |
@@ -0,0 +1,23 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should display correctly 1`] = `null`; | |||
exports[`should display correctly 2`] = ` | |||
<div | |||
className="page-notifs" | |||
> | |||
<div | |||
className="alert alert-info" | |||
> | |||
system.new_version_available | |||
<button | |||
className="spacer-left" | |||
onClick={[Function]} | |||
> | |||
learn_more | |||
</button> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should display nothing 1`] = `null`; |
@@ -61,3 +61,17 @@ | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.system-upgrade-version { | |||
padding: 8px; | |||
} | |||
.system-upgrade-version ~ .system-upgrade-version { | |||
margin-top: 10px; | |||
padding-top: 18px; | |||
border-top: solid 1px #e6e6e6; | |||
} | |||
.system-upgrade-intermediate { | |||
padding: 6px 10px; | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { each, memoize, omit, omitBy, pickBy, sortBy } from 'lodash'; | |||
import { each, groupBy, memoize, omit, omitBy, pickBy, sortBy } from 'lodash'; | |||
import { | |||
cleanQuery, | |||
parseAsArray, | |||
@@ -31,7 +31,8 @@ import { | |||
NodeInfo, | |||
SysInfo, | |||
SysInfoSection, | |||
SysValueObject | |||
SysValueObject, | |||
SystemUpgrade | |||
} from '../../api/system'; | |||
import { formatMeasure } from '../../helpers/measures'; | |||
@@ -185,3 +186,17 @@ export const serializeQuery = memoize((query: Query): RawQuery => | |||
expand: serializeStringArray(query.expandedCards) | |||
}) | |||
); | |||
export function sortUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[] { | |||
return sortBy(upgrades, [ | |||
(upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[0]), | |||
(upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[1] || 0), | |||
(upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[2] || 0) | |||
]); | |||
} | |||
export function groupUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[][] { | |||
const groupedVersions = groupBy(upgrades, upgrade => upgrade.version.split('.')[0]); | |||
const sortedMajor = sortBy(Object.keys(groupedVersions), key => -Number(key)); | |||
return sortedMajor.map(key => groupedVersions[key]); | |||
} |
@@ -65,3 +65,13 @@ | |||
.alert-success { | |||
.alert-emphasis-variant(#3c763d, #dff0d8, #d6e9c6); | |||
} | |||
.page-notifs .alert { | |||
display: flex; | |||
justify-content: space-between; | |||
padding: 8px 10px; | |||
} | |||
.page-notifs .alert:last-child { | |||
margin-bottom: 16px; | |||
} |
@@ -2066,7 +2066,6 @@ marketplace.all=All | |||
marketplace.updates_only=Updates Only | |||
marketplace.restart=Restart | |||
marketplace.revert=Revert | |||
marketplace.system_upgrades=System Upgrades | |||
marketplace.install=Install | |||
marketplace.install_x=Install {0} | |||
marketplace.installed=Installed | |||
@@ -2224,7 +2223,6 @@ background_tasks.search_by_task_or_component=Search by Task or Component | |||
background_tasks.failing_count=Count of projects where processing of most recent analysis report failed | |||
#------------------------------------------------------------------------------ | |||
# | |||
# SYSTEM | |||
@@ -2236,14 +2234,26 @@ system.cluster_log_level.info=Changes apply to all Application nodes but not to | |||
system.current_health_of_x=Current health status of {0} | |||
system.download_logs=Download Logs | |||
system.download_system_info=Download System Info | |||
system.download_x=Download {0} | |||
system.hide_intermediate_versions=Hide intermediate versions | |||
system.how_to_upgrade=How to upgrade? | |||
system.is_restarting=Server is restarting. This page will be automatically refreshed. | |||
system.latest_version=Latest Version | |||
system.latest_lts_version=Latest LTS Version | |||
system.log_level.warning=This level has performance impacts, please make sure to get back to INFO level once your investigation is done. Please note that when the server is restarted, logging will revert to the level configured in sonar.properties. | |||
system.log_level.warning.short=Current logs level has performance impacts, get back to INFO level. | |||
system.log_level.info=Changes don't apply to Search. | |||
system.logs_level=Logs level | |||
system.new_version_available=A new version of SonarQube is available. | |||
system.release_notes=Release Notes | |||
system.released_x=Released {0} | |||
system.restart_server=Restart Server | |||
system.search_nodes_title=Search Nodes | |||
system.see_sonarqube_downloads=See All SonarQube Downloads | |||
system.set_log_level=Set logs level | |||
system.show_intermediate_versions=Show intermediate versions | |||
system.system_upgrade=System Upgrade | |||
system.version_is_availble={version} is available | |||
#------------------------------------------------------------------------------ |