@@ -37,6 +37,10 @@ export interface License { | |||
type: string; | |||
} | |||
export function isValidLicense(): Promise<{ isValidLicense: boolean }> { | |||
return getJSON('/api/editions/is_valid_license'); | |||
} | |||
export function showLicense(): Promise<License> { | |||
return getJSON('/api/editions/show_license').catch((e: { response: Response }) => { | |||
if (e.response && e.response.status === 404) { |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import { Link } from 'react-router'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import * as PropTypes from 'prop-types'; | |||
import ComponentNavLicenseNotif from './ComponentNavLicenseNotif'; | |||
import NavBarNotif from '../../../../components/nav/NavBarNotif'; | |||
import PendingIcon from '../../../../components/icons-components/PendingIcon'; | |||
import { Component } from '../../../types'; | |||
@@ -37,10 +37,6 @@ interface Props { | |||
} | |||
export default class ComponentNavBgTaskNotif extends React.PureComponent<Props> { | |||
static contextTypes = { | |||
canAdmin: PropTypes.bool.isRequired | |||
}; | |||
renderMessage(messageKey: string, status?: string) { | |||
const { component } = this.props; | |||
const canSeeBackgroundTasks = | |||
@@ -82,21 +78,9 @@ export default class ComponentNavBgTaskNotif extends React.PureComponent<Props> | |||
} else if (currentTask && currentTask.status === STATUSES.FAILED) { | |||
if ( | |||
currentTask.errorType && | |||
currentTask.errorType.includes('LICENSING') && | |||
hasMessage('license.component_navigation.button', currentTask.errorType) | |||
) { | |||
return ( | |||
<NavBarNotif className="alert alert-danger"> | |||
<span className="little-spacer-right">{currentTask.errorMessage}</span> | |||
{this.context.canAdmin ? ( | |||
<Link to="/admin/extension/license/app"> | |||
{translate('license.component_navigation.button', currentTask.errorType)}. | |||
</Link> | |||
) : ( | |||
translate('please_contact_administrator') | |||
)} | |||
</NavBarNotif> | |||
); | |||
return <ComponentNavLicenseNotif currentTask={currentTask} />; | |||
} | |||
return ( |
@@ -0,0 +1,102 @@ | |||
/* | |||
* 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 { Link } from 'react-router'; | |||
import * as PropTypes from 'prop-types'; | |||
import NavBarNotif from '../../../../components/nav/NavBarNotif'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { Task } from '../../../../api/ce'; | |||
import { isValidLicense } from '../../../../api/marketplace'; | |||
interface Props { | |||
currentTask?: Task; | |||
} | |||
interface State { | |||
isValidLicense?: boolean; | |||
loading: boolean; | |||
} | |||
export default class ComponentNavLicenseNotif extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
static contextTypes = { | |||
canAdmin: PropTypes.bool.isRequired | |||
}; | |||
state: State = { loading: false }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchIsValidLicense(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchIsValidLicense = () => { | |||
this.setState({ loading: true }); | |||
isValidLicense().then( | |||
({ isValidLicense }) => { | |||
if (this.mounted) { | |||
this.setState({ isValidLicense, loading: false }); | |||
} | |||
}, | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ loading: false }); | |||
} | |||
} | |||
); | |||
}; | |||
render() { | |||
const { currentTask } = this.props; | |||
const { isValidLicense, loading } = this.state; | |||
if (loading || !currentTask || !currentTask.errorType) { | |||
return null; | |||
} | |||
if (isValidLicense && currentTask.errorType !== 'LICENSING_LOC') { | |||
return ( | |||
<NavBarNotif className="alert alert-danger"> | |||
<span className="little-spacer-right"> | |||
{translate('component_navigation.status.last_blocked_due_to_bad_license')} | |||
</span> | |||
</NavBarNotif> | |||
); | |||
} | |||
return ( | |||
<NavBarNotif className="alert alert-danger"> | |||
<span className="little-spacer-right">{currentTask.errorMessage}</span> | |||
{this.context.canAdmin ? ( | |||
<Link to="/admin/extension/license/app"> | |||
{translate('license.component_navigation.button', currentTask.errorType)}. | |||
</Link> | |||
) : ( | |||
translate('please_contact_administrator') | |||
)} | |||
</NavBarNotif> | |||
); | |||
} | |||
} |
@@ -64,21 +64,14 @@ it('renders background task license info correctly', () => { | |||
expect( | |||
getWrapper({ currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } }) | |||
).toMatchSnapshot(); | |||
expect( | |||
getWrapper( | |||
{ currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } }, | |||
{ canAdmin: false } | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
function getWrapper(props = {}, context = {}) { | |||
function getWrapper(props = {}) { | |||
return shallow( | |||
<ComponentNavBgTaskNotif | |||
component={component} | |||
currentTask={{ status: 'FAILED' } as Task} | |||
{...props} | |||
/>, | |||
{ context: { canAdmin: true, ...context } } | |||
/> | |||
); | |||
} |
@@ -0,0 +1,82 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import ComponentNavLicenseNotif from '../ComponentNavLicenseNotif'; | |||
import { Task } from '../../../../../api/ce'; | |||
import { isValidLicense } from '../../../../../api/marketplace'; | |||
import { waitAndUpdate } from '../../../../../helpers/testUtils'; | |||
jest.mock('../../../../../helpers/l10n', () => { | |||
const l10n = require.requireActual('../../../../../helpers/l10n'); | |||
l10n.hasMessage = jest.fn(() => true); | |||
return l10n; | |||
}); | |||
jest.mock('../../../../../api/marketplace', () => ({ | |||
isValidLicense: jest.fn().mockResolvedValue({ isValidLicense: false }) | |||
})); | |||
beforeEach(() => { | |||
(isValidLicense as jest.Mock<any>).mockClear(); | |||
}); | |||
it('renders background task license info correctly', async () => { | |||
let wrapper = getWrapper({ | |||
currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
wrapper = getWrapper( | |||
{ currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } }, | |||
{ canAdmin: false } | |||
); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('renders a different message if the license is valid', async () => { | |||
(isValidLicense as jest.Mock<any>).mockResolvedValueOnce({ isValidLicense: true }); | |||
const wrapper = getWrapper({ | |||
currentTask: { status: 'FAILED', errorType: 'LICENSING', errorMessage: 'Foo' } | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('renders correctly for LICENSING_LOC error', async () => { | |||
(isValidLicense as jest.Mock<any>).mockResolvedValueOnce({ isValidLicense: true }); | |||
const wrapper = getWrapper({ | |||
currentTask: { status: 'FAILED', errorType: 'LICENSING_LOC', errorMessage: 'Foo' } | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
function getWrapper(props = {}, context = {}) { | |||
return shallow( | |||
<ComponentNavLicenseNotif | |||
currentTask={{ errorMessage: 'Foo', errorType: 'LICENSING' } as Task} | |||
{...props} | |||
/>, | |||
{ context: { canAdmin: true, ...context } } | |||
); | |||
} |
@@ -24,36 +24,15 @@ exports[`renders background task in progress info correctly 1`] = ` | |||
`; | |||
exports[`renders background task license info correctly 1`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
Foo | |||
</span> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/admin/extension/license/app" | |||
> | |||
license.component_navigation.button.LICENSING | |||
. | |||
</Link> | |||
</NavBarNotif> | |||
`; | |||
exports[`renders background task license info correctly 2`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
Foo | |||
</span> | |||
please_contact_administrator | |||
</NavBarNotif> | |||
<ComponentNavLicenseNotif | |||
currentTask={ | |||
Object { | |||
"errorMessage": "Foo", | |||
"errorType": "LICENSING", | |||
"status": "FAILED", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`renders background task pending info correctly 1`] = ` |
@@ -0,0 +1,66 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`renders a different message if the license is valid 1`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
component_navigation.status.last_blocked_due_to_bad_license | |||
</span> | |||
</NavBarNotif> | |||
`; | |||
exports[`renders background task license info correctly 1`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
Foo | |||
</span> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/admin/extension/license/app" | |||
> | |||
license.component_navigation.button.LICENSING | |||
. | |||
</Link> | |||
</NavBarNotif> | |||
`; | |||
exports[`renders background task license info correctly 2`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
Foo | |||
</span> | |||
please_contact_administrator | |||
</NavBarNotif> | |||
`; | |||
exports[`renders correctly for LICENSING_LOC error 1`] = ` | |||
<NavBarNotif | |||
className="alert alert-danger" | |||
> | |||
<span | |||
className="little-spacer-right" | |||
> | |||
Foo | |||
</span> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/admin/extension/license/app" | |||
> | |||
license.component_navigation.button.LICENSING_LOC | |||
. | |||
</Link> | |||
</NavBarNotif> | |||
`; |
@@ -2222,6 +2222,7 @@ component_navigation.status.pending=There is a pending analysis. | |||
component_navigation.status.pending.admin=There is a pending analysis. More details available on the {url} page. | |||
component_navigation.status.in_progress=The analysis is in progress. | |||
component_navigation.status.in_progress.admin=The analysis is in progress. More details available on the {url} page. | |||
component_navigation.status.last_blocked_due_to_bad_license=Last analysis blocked due to an invalid license, which has since been corrected. Please reanalyze this project. | |||
background_task.status.ALL=All | |||
background_task.status.PENDING=Pending |