Browse Source

SONAR-11734 Guard against missing language plugins

tags/7.8
Wouter Admiraal 5 years ago
parent
commit
497c52c32e

+ 1
- 0
server/sonar-web/src/main/js/app/styles/components/page.css View File

@@ -109,6 +109,7 @@
margin-bottom: 10px;
margin-left: 10px;
line-height: var(--controlHeight);
text-align: right;
}

.page-actions .badge {

+ 17
- 7
server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx View File

@@ -24,6 +24,7 @@ import RestoreProfileForm from './RestoreProfileForm';
import { Profile } from '../types';
import { getProfilePath } from '../utils';
import { Actions } from '../../../api/quality-profiles';
import { Alert } from '../../../components/ui/Alert';
import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
import { withRouter, Router } from '../../../components/hoc/withRouter';
@@ -42,7 +43,7 @@ interface State {
restoreFormOpen: boolean;
}

class PageHeader extends React.PureComponent<Props, State> {
export class PageHeader extends React.PureComponent<Props, State> {
state: State = {
createFormOpen: false,
restoreFormOpen: false
@@ -76,13 +77,17 @@ class PageHeader extends React.PureComponent<Props, State> {
};

render() {
const { actions, languages, organization, profiles } = this.props;
return (
<header className="page-header">
<h1 className="page-title">{translate('quality_profiles.page')}</h1>

{this.props.actions.create && (
{actions.create && (
<div className="page-actions">
<Button id="quality-profiles-create" onClick={this.handleCreateClick}>
<Button
disabled={languages.length === 0}
id="quality-profiles-create"
onClick={this.handleCreateClick}>
{translate('create')}
</Button>
<Button
@@ -91,6 +96,11 @@ class PageHeader extends React.PureComponent<Props, State> {
onClick={this.handleRestoreClick}>
{translate('restore')}
</Button>
{languages.length === 0 && (
<Alert className="spacer-top" variant="warning">
{translate('quality_profiles.no_languages_available')}
</Alert>
)}
</div>
)}

@@ -112,17 +122,17 @@ class PageHeader extends React.PureComponent<Props, State> {
<RestoreProfileForm
onClose={this.closeRestoreForm}
onRestore={this.props.updateProfiles}
organization={this.props.organization}
organization={organization}
/>
)}

{this.state.createFormOpen && (
<CreateProfileForm
languages={this.props.languages}
languages={languages}
onClose={this.closeCreateForm}
onCreate={this.handleCreate}
organization={this.props.organization}
profiles={this.props.profiles}
organization={organization}
profiles={profiles}
/>
)}
</header>

+ 56
- 0
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx View File

@@ -0,0 +1,56 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { PageHeader } from '../PageHeader';
import { mockLanguage, mockQualityProfile, mockRouter } from '../../../../helpers/testMocks';
import { click } from '../../../../helpers/testUtils';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ actions: { create: true } })).toMatchSnapshot();
expect(shallowRender({ actions: { create: true }, languages: [] })).toMatchSnapshot();
});

it('should show a create form', () => {
const wrapper = shallowRender({ actions: { create: true } });
click(wrapper.find('#quality-profiles-create'));
expect(wrapper).toMatchSnapshot();
});

it('should show a restore form', () => {
const wrapper = shallowRender({ actions: { create: true } });
click(wrapper.find('#quality-profiles-restore'));
expect(wrapper).toMatchSnapshot();
});

function shallowRender(props: Partial<PageHeader['props']> = {}) {
return shallow(
<PageHeader
actions={{ create: false }}
languages={[mockLanguage()]}
organization="foo"
profiles={[mockQualityProfile()]}
router={mockRouter()}
updateProfiles={jest.fn()}
{...props}
/>
);
}

+ 276
- 0
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap View File

@@ -0,0 +1,276 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<header
className="page-header"
>
<h1
className="page-title"
>
quality_profiles.page
</h1>
<div
className="page-description markdown"
>
quality_profiles.intro1
<br />
quality_profiles.intro2
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/instance-administration/quality-profiles/",
}
}
>
learn_more
</Link>
</div>
</header>
`;

exports[`should render correctly 2`] = `
<header
className="page-header"
>
<h1
className="page-title"
>
quality_profiles.page
</h1>
<div
className="page-actions"
>
<Button
disabled={false}
id="quality-profiles-create"
onClick={[Function]}
>
create
</Button>
<Button
className="little-spacer-left"
id="quality-profiles-restore"
onClick={[Function]}
>
restore
</Button>
</div>
<div
className="page-description markdown"
>
quality_profiles.intro1
<br />
quality_profiles.intro2
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/instance-administration/quality-profiles/",
}
}
>
learn_more
</Link>
</div>
</header>
`;

exports[`should render correctly 3`] = `
<header
className="page-header"
>
<h1
className="page-title"
>
quality_profiles.page
</h1>
<div
className="page-actions"
>
<Button
disabled={true}
id="quality-profiles-create"
onClick={[Function]}
>
create
</Button>
<Button
className="little-spacer-left"
id="quality-profiles-restore"
onClick={[Function]}
>
restore
</Button>
<Alert
className="spacer-top"
variant="warning"
>
quality_profiles.no_languages_available
</Alert>
</div>
<div
className="page-description markdown"
>
quality_profiles.intro1
<br />
quality_profiles.intro2
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/instance-administration/quality-profiles/",
}
}
>
learn_more
</Link>
</div>
</header>
`;

exports[`should show a create form 1`] = `
<header
className="page-header"
>
<h1
className="page-title"
>
quality_profiles.page
</h1>
<div
className="page-actions"
>
<Button
disabled={false}
id="quality-profiles-create"
onClick={[Function]}
>
create
</Button>
<Button
className="little-spacer-left"
id="quality-profiles-restore"
onClick={[Function]}
>
restore
</Button>
</div>
<div
className="page-description markdown"
>
quality_profiles.intro1
<br />
quality_profiles.intro2
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/instance-administration/quality-profiles/",
}
}
>
learn_more
</Link>
</div>
<CreateProfileForm
languages={
Array [
Object {
"key": "css",
"name": "CSS",
},
]
}
onClose={[Function]}
onCreate={[Function]}
organization="foo"
profiles={
Array [
Object {
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "key",
"language": "js",
"languageName": "JavaScript",
"name": "name",
"organization": "foo",
"projectCount": 3,
},
]
}
/>
</header>
`;

exports[`should show a restore form 1`] = `
<header
className="page-header"
>
<h1
className="page-title"
>
quality_profiles.page
</h1>
<div
className="page-actions"
>
<Button
disabled={false}
id="quality-profiles-create"
onClick={[Function]}
>
create
</Button>
<Button
className="little-spacer-left"
id="quality-profiles-restore"
onClick={[Function]}
>
restore
</Button>
</div>
<div
className="page-description markdown"
>
quality_profiles.intro1
<br />
quality_profiles.intro2
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to={
Object {
"pathname": "/documentation/instance-administration/quality-profiles/",
}
}
>
learn_more
</Link>
</div>
<RestoreProfileForm
onClose={[Function]}
onRestore={[MockFunction]}
organization="foo"
/>
</header>
`;

+ 1
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -1141,6 +1141,7 @@ quality_profiles.restore_profile.success={1} rule(s) restored in profile "{0}"
quality_profiles.restore_profile.warning={1} rule(s) restored, {2} rule(s) ignored in profile "{0}"
quality_profiles.optional_configuration_file=Optional configuration file
quality_profiles.new_name=New name
quality_profiles.no_languages_available=There are no languages available. You cannot create a new profile.
quality_profiles.delete_confirm_title=Delete Profile
quality_profiles.are_you_sure_want_delete_profile_x=Are you sure that you want to delete the profile "{0}"?
quality_profiles.are_you_sure_want_delete_profile_x_and_descendants=Are you sure that you want to delete the profile "{0}" and all its descendants?

Loading…
Cancel
Save