aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2019-04-02 12:35:38 +0200
committerSonarTech <sonartech@sonarsource.com>2019-04-08 20:21:06 +0200
commit497c52c32eec22b058284e3d51ff775f3be2cbcc (patch)
tree79ce2eec0550735d91b88e6bbfd27ca7cfd1b6a4 /server/sonar-web/src/main
parent99af758e84e5cc84f304e84e714ee0613fc32e59 (diff)
downloadsonarqube-497c52c32eec22b058284e3d51ff775f3be2cbcc.tar.gz
sonarqube-497c52c32eec22b058284e3d51ff775f3be2cbcc.zip
SONAR-11734 Guard against missing language plugins
Diffstat (limited to 'server/sonar-web/src/main')
-rw-r--r--server/sonar-web/src/main/js/app/styles/components/page.css1
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx24
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap276
4 files changed, 350 insertions, 7 deletions
diff --git a/server/sonar-web/src/main/js/app/styles/components/page.css b/server/sonar-web/src/main/js/app/styles/components/page.css
index 3f2e5960d57..633ad610da9 100644
--- a/server/sonar-web/src/main/js/app/styles/components/page.css
+++ b/server/sonar-web/src/main/js/app/styles/components/page.css
@@ -109,6 +109,7 @@
margin-bottom: 10px;
margin-left: 10px;
line-height: var(--controlHeight);
+ text-align: right;
}
.page-actions .badge {
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
index 8258c8fdab5..10f8debfa0e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
@@ -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>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx
new file mode 100644
index 00000000000..e271851d301
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx
@@ -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}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
new file mode 100644
index 00000000000..380a24788b4
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
@@ -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>
+`;