aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2020-04-06 14:27:19 +0200
committersonartech <sonartech@sonarsource.com>2020-04-15 20:03:38 +0000
commit661873873ffca37fe149bfbf1775cdda8955ea8b (patch)
treea3a64918feafee6a71a86bceb1d190f54d294181 /server
parent613156f73891c1348fe01065ea0b6694e82d3f41 (diff)
downloadsonarqube-661873873ffca37fe149bfbf1775cdda8955ea8b.tar.gz
sonarqube-661873873ffca37fe149bfbf1775cdda8955ea8b.zip
SONAR-13190 Add tags to Applications information sidedrawer
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/components.ts4
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx34
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx5
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap196
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/MetaTags.tsx26
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/MetaTags-test.tsx73
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap2
7 files changed, 292 insertions, 48 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts
index df296aa6181..2b7ddb74492 100644
--- a/server/sonar-web/src/main/js/api/components.ts
+++ b/server/sonar-web/src/main/js/api/components.ts
@@ -86,6 +86,10 @@ export function searchProjectTags(data?: { ps?: number; q?: string }): Promise<a
return getJSON('/api/project_tags/search', data).catch(throwGlobalError);
}
+export function setApplicationTags(data: { application: string; tags: string }): Promise<void> {
+ return post('/api/applications/set_tags', data);
+}
+
export function setProjectTags(data: { project: string; tags: string }): Promise<void> {
return post('/api/project_tags/set', data);
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx
index 1aff0f9cf33..25bab1a9d05 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformationRenderer.tsx
@@ -53,27 +53,23 @@ export function ProjectInformationRenderer(props: ProjectInformationRendererProp
</div>
<div className="overflow-y-auto">
- {(component.description || !isApp) && (
- <div className="big-padded bordered-bottom">
- <div className="display-flex-center">
- <h3 className="spacer-right">{translate('project.info.description')}</h3>
- {component.visibility && (
- <PrivacyBadgeContainer
- organization={undefined}
- qualifier={component.qualifier}
- tooltipProps={{ projectKey: component.key }}
- visibility={component.visibility}
- />
- )}
- </div>
-
- {component.description && <p className="spacer-bottom">{component.description}</p>}
-
- {!isApp && (
- <MetaTags component={component} onComponentChange={props.onComponentChange} />
+ <div className="big-padded bordered-bottom">
+ <div className="display-flex-center">
+ <h3 className="spacer-right">{translate('project.info.description')}</h3>
+ {component.visibility && (
+ <PrivacyBadgeContainer
+ organization={undefined}
+ qualifier={component.qualifier}
+ tooltipProps={{ projectKey: component.key }}
+ visibility={component.visibility}
+ />
)}
</div>
- )}
+
+ {component.description && <p>{component.description}</p>}
+
+ <MetaTags component={component} onComponentChange={props.onComponentChange} />
+ </div>
<div className="big-padded bordered-bottom it__project-loc-value">
<MetaSize component={component} measures={measures} />
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx
index 577b2e387d2..26f2ab9ff25 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/ProjectInformationRenderer-test.tsx
@@ -43,6 +43,11 @@ it('should render an app correctly', () => {
expect(shallowRender({ component })).toMatchSnapshot('default');
});
+it('should render without description', () => {
+ const component = mockComponent({ description: undefined });
+ expect(shallowRender({ component })).toMatchSnapshot();
+});
+
it('should handle missing quality profiles and quality gates', () => {
expect(
shallowRender({
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap
index d071690097a..8819cf6af17 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/__tests__/__snapshots__/ProjectInformationRenderer-test.tsx.snap
@@ -274,6 +274,45 @@ exports[`should render an app correctly: default 1`] = `
className="overflow-y-auto"
>
<div
+ className="big-padded bordered-bottom"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <h3
+ className="spacer-right"
+ >
+ project.info.description
+ </h3>
+ </div>
+ <MetaTags
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ <div
className="big-padded bordered-bottom it__project-loc-value"
>
<MetaSize
@@ -968,3 +1007,160 @@ exports[`should render correctly: with notifications 1`] = `
</div>
</Fragment>
`;
+
+exports[`should render without description 1`] = `
+<Fragment>
+ <div>
+ <h2
+ className="big-padded bordered-bottom"
+ >
+ project.info.title
+ </h2>
+ </div>
+ <div
+ className="overflow-y-auto"
+ >
+ <div
+ className="big-padded bordered-bottom"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <h3
+ className="spacer-right"
+ >
+ project.info.description
+ </h3>
+ </div>
+ <MetaTags
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "description": undefined,
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ <div
+ className="big-padded bordered-bottom it__project-loc-value"
+ >
+ <MetaSize
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "description": undefined,
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={Array []}
+ />
+ </div>
+ <div
+ className="big-padded bordered-bottom"
+ >
+ <MetaQualityGate
+ qualityGate={
+ Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ }
+ }
+ />
+ <Connect(MetaQualityProfiles)
+ headerClassName="big-spacer-top"
+ profiles={
+ Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ]
+ }
+ />
+ </div>
+ <MetaLinks
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "description": undefined,
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <div
+ className="big-padded bordered-bottom"
+ >
+ <MetaKey
+ componentKey="my-project"
+ qualifier="TRK"
+ />
+ </div>
+ <Memo(DrawerLink)
+ label="overview.badges.get_badge.TRK"
+ onPageChange={[MockFunction]}
+ to={1}
+ />
+ <Memo(DrawerLink)
+ label="project.info.to_notifications"
+ onPageChange={[MockFunction]}
+ to={2}
+ />
+ </div>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/MetaTags.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/MetaTags.tsx
index 1e7b3496586..03650b13f67 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/MetaTags.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/MetaTags.tsx
@@ -22,8 +22,9 @@ import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
import { PopupPlacement } from 'sonar-ui-common/components/ui/popups';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { setProjectTags } from '../../../../../../api/components';
+import { setApplicationTags, setProjectTags } from '../../../../../../api/components';
import TagsList from '../../../../../../components/tags/TagsList';
+import { ComponentQualifier } from '../../../../../../types/component';
import MetaTagsSelector from './MetaTagsSelector';
interface Props {
@@ -46,11 +47,24 @@ export default class MetaTags extends React.PureComponent<Props> {
right: containerPos.width - eltPos.width
});
+ setTags = (values: string[]) => {
+ const { component } = this.props;
+
+ if (component.qualifier === ComponentQualifier.Application) {
+ return setApplicationTags({
+ application: component.key,
+ tags: values.join(',')
+ });
+ } else {
+ return setProjectTags({
+ project: component.key,
+ tags: values.join(',')
+ });
+ }
+ };
+
handleSetProjectTags = (values: string[]) => {
- setProjectTags({
- project: this.props.component.key,
- tags: values.join(',')
- }).then(
+ this.setTags(values).then(
() => this.props.onComponentChange({ tags: values }),
() => {}
);
@@ -62,7 +76,7 @@ export default class MetaTags extends React.PureComponent<Props> {
if (this.canUpdateTags()) {
return (
- <div className="project-info-tags" ref={card => (this.card = card)}>
+ <div className="big-spacer-top project-info-tags" ref={card => (this.card = card)}>
<Dropdown
closeOnClick={false}
closeOnClickOutside={true}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/MetaTags-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/MetaTags-test.tsx
index f8464ab66c5..d6df5ed4b7c 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/MetaTags-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/MetaTags-test.tsx
@@ -19,36 +19,65 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { setApplicationTags, setProjectTags } from '../../../../../../../api/components';
import { mockComponent } from '../../../../../../../helpers/testMocks';
+import { ComponentQualifier } from '../../../../../../../types/component';
import MetaTags from '../MetaTags';
-const component = mockComponent({
- configuration: {
- showSettings: false
- }
-});
+jest.mock('../../../../../../../api/components', () => ({
+ setApplicationTags: jest.fn().mockResolvedValue(true),
+ setProjectTags: jest.fn().mockResolvedValue(true)
+}));
-const componentWithTags = mockComponent({
- key: 'my-second-project',
- tags: ['foo', 'bar'],
- configuration: {
- showSettings: true
- },
- name: 'MySecondProject'
+beforeEach(() => {
+ jest.clearAllMocks();
});
it('should render without tags and admin rights', () => {
- expect(
- shallow(<MetaTags component={component} onComponentChange={jest.fn()} />, {
- disableLifecycleMethods: true
- })
- ).toMatchSnapshot();
+ expect(shallowRender()).toMatchSnapshot();
});
it('should render with tags and admin rights', () => {
- expect(
- shallow(<MetaTags component={componentWithTags} onComponentChange={jest.fn()} />, {
- disableLifecycleMethods: true
- })
- ).toMatchSnapshot();
+ const component = mockComponent({
+ key: 'my-second-project',
+ tags: ['foo', 'bar'],
+ configuration: {
+ showSettings: true
+ },
+ name: 'MySecondProject'
+ });
+
+ expect(shallowRender({ component })).toMatchSnapshot();
+});
+
+it('should set tags for a project', () => {
+ const wrapper = shallowRender();
+
+ wrapper.instance().handleSetProjectTags(['tag1', 'tag2']);
+
+ expect(setProjectTags).toHaveBeenCalled();
+ expect(setApplicationTags).not.toHaveBeenCalled();
});
+
+it('should set tags for an app', () => {
+ const wrapper = shallowRender({
+ component: mockComponent({ qualifier: ComponentQualifier.Application })
+ });
+
+ wrapper.instance().handleSetProjectTags(['tag1', 'tag2']);
+
+ expect(setProjectTags).not.toHaveBeenCalled();
+ expect(setApplicationTags).toHaveBeenCalled();
+});
+
+function shallowRender(overrides: Partial<MetaTags['props']> = {}) {
+ const component = mockComponent({
+ configuration: {
+ showSettings: false
+ }
+ });
+
+ return shallow<MetaTags>(
+ <MetaTags component={component} onComponentChange={jest.fn()} {...overrides} />
+ );
+}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
index c415bdfdab7..5e9a5365588 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
@@ -2,7 +2,7 @@
exports[`should render with tags and admin rights 1`] = `
<div
- className="project-info-tags"
+ className="big-spacer-top project-info-tags"
>
<Dropdown
closeOnClick={false}