aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/src/main/js/app/types.ts5
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/Event.tsx22
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap26
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/RichQualityGateEventInner.tsx117
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/RichQualityGateEventInner-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap157
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css202
-rw-r--r--server/sonar-web/src/main/js/components/ui/Level.css4
-rw-r--r--server/sonar-web/src/main/js/components/ui/Level.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.css2
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties1
15 files changed, 529 insertions, 124 deletions
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index bcca9babe86..8774f66a0ec 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -57,6 +57,11 @@ export interface AnalysisEvent {
description?: string;
key: string;
name: string;
+ qualityGate?: {
+ failing: Array<{ branch: string; key: string; name: string }>;
+ status: string;
+ stillFailing: boolean;
+ };
}
export interface AppState {
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Event.tsx b/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
index 9090864acca..bd1498eb292 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
@@ -18,8 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { translate } from '../../../helpers/l10n';
+import { FormattedMessage } from 'react-intl';
import { AnalysisEvent } from '../../../app/types';
+import { isRichQualityGateEvent } from '../../projectActivity/components/RichQualityGateEventInner';
+import Level from '../../../components/ui/Level';
+import { translate } from '../../../helpers/l10n';
interface Props {
event: AnalysisEvent;
@@ -36,6 +39,23 @@ export default function Event({ event }: Props) {
);
}
+ if (isRichQualityGateEvent(event)) {
+ return (
+ <div className="overview-analysis-event">
+ <span className="note">{translate('event.category', event.category)}:</span>{' '}
+ {event.qualityGate.stillFailing ? (
+ <FormattedMessage
+ defaultMessage={translate('event.quality_gate.still_x')}
+ id="event.quality_gate.still_x"
+ values={{ status: <Level level={event.qualityGate.status} small={true} /> }}
+ />
+ ) : (
+ <Level level={event.qualityGate.status} small={true} />
+ )}
+ </div>
+ );
+ }
+
return (
<div className="overview-analysis-event">
<span className="note">{translate('event.category', event.category)}:</span>{' '}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
index e15be764817..05b9bcc6693 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Event from '../Event';
+import { RichQualityGateEvent } from '../../../projectActivity/components/RichQualityGateEventInner';
const EVENT = { key: '1', category: 'OTHER', name: 'test' };
const VERSION = { key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' };
@@ -31,3 +32,17 @@ it('should render an event correctly', () => {
it('should render a version correctly', () => {
expect(shallow(<Event event={VERSION} />)).toMatchSnapshot();
});
+
+it('should render rich quality gate event', () => {
+ const event: RichQualityGateEvent = {
+ category: 'QUALITY_GATE',
+ key: 'foo1234',
+ name: '',
+ qualityGate: {
+ failing: [{ branch: 'master', key: 'foo', name: 'Foo' }],
+ status: 'ERROR',
+ stillFailing: true
+ }
+ };
+ expect(shallow(<Event event={event} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
index 5af2a4e8b9b..eb026e1a3e7 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
@@ -25,3 +25,29 @@ exports[`should render an event correctly 1`] = `
</strong>
</div>
`;
+
+exports[`should render rich quality gate event 1`] = `
+<div
+ className="overview-analysis-event"
+>
+ <span
+ className="note"
+ >
+ event.category.QUALITY_GATE
+ :
+ </span>
+
+ <FormattedMessage
+ defaultMessage="event.quality_gate.still_x"
+ id="event.quality_gate.still_x"
+ values={
+ Object {
+ "status": <Level
+ level="ERROR"
+ small={true}
+ />,
+ }
+ }
+ />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
index 53455dd8439..80fe882f3d9 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
@@ -86,7 +86,7 @@ export class Meta extends React.PureComponent<Props> {
}
return (
- <div className="overview-meta-card">
+ <div className="overview-meta-card" id="overview-meta-quality-gate">
{qualityGate && (
<MetaQualityGate
organization={organizationsEnabled ? component.organization : undefined}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.tsx
index fa50f913600..4d66330e64e 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.tsx
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.tsx
@@ -18,6 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import * as classNames from 'classnames';
+import { isRichQualityGateEvent, RichQualityGateEventInner } from './RichQualityGateEventInner';
import { AnalysisEvent } from '../../../app/types';
import ProjectEventIcon from '../../../components/icons-components/ProjectEventIcon';
import { translate } from '../../../helpers/l10n';
@@ -27,17 +29,28 @@ interface Props {
}
export default function EventInner({ event }: Props) {
- return (
- <div className="project-activity-event-inner">
- <div className="project-activity-event-inner-icon little-spacer-right">
- <ProjectEventIcon
- className={'project-activity-event-icon margin-align ' + event.category}
- />
+ if (isRichQualityGateEvent(event)) {
+ return <RichQualityGateEventInner event={event} />;
+ } else {
+ return (
+ <div className="project-activity-event-inner">
+ <div className="project-activity-event-inner-main">
+ <ProjectEventIcon
+ className={classNames(
+ 'project-activity-event-icon',
+ 'little-spacer-right',
+ event.category
+ )}
+ />
+
+ <span className="project-activity-event-inner-text">
+ <span className="note little-spacer-right">
+ {translate('event.category', event.category)}:
+ </span>
+ <strong title={event.description}>{event.name}</strong>
+ </span>
+ </div>
</div>
- <span className="project-activity-event-inner-text">
- <span className="note">{translate('event.category', event.category)}:</span>{' '}
- <strong title={event.description}>{event.name}</strong>
- </span>
- </div>
- );
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.tsx
index e98701a25cb..7db07883772 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.tsx
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.tsx
@@ -108,7 +108,6 @@ export default class ProjectActivityAnalysis extends React.PureComponent<Props,
render() {
const { analysis, isFirst, canAdmin } = this.props;
const { date, events } = analysis;
- const analysisTitle = translate('project_activity.analysis');
const hasVersion = events.find(event => event.category === 'VERSION') != null;
const canAddVersion = canAdmin && !hasVersion && this.props.canCreateVersion;
@@ -117,16 +116,13 @@ export default class ProjectActivityAnalysis extends React.PureComponent<Props,
return (
<li
- className={classNames('project-activity-analysis clearfix', {
- selected: this.props.selected
- })}
+ className={classNames('project-activity-analysis', { selected: this.props.selected })}
data-date={date.valueOf()}
onClick={this.handleClick}
tabIndex={0}>
<div className="project-activity-time spacer-right">
<TimeTooltipFormatter className="text-middle" date={date} />
</div>
- <div className="project-activity-analysis-icon spacer-right" title={analysisTitle} />
{(canAddVersion || canAddEvent || canDeleteAnalyses) && (
<div className="project-activity-analysis-actions big-spacer-right">
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/RichQualityGateEventInner.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/RichQualityGateEventInner.tsx
new file mode 100644
index 00000000000..780668cf39d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/RichQualityGateEventInner.tsx
@@ -0,0 +1,117 @@
+/*
+ * 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 { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router';
+import * as classNames from 'classnames';
+import { AnalysisEvent } from '../../../app/types';
+import DropdownIcon from '../../../components/icons-components/DropdownIcon';
+import ProjectEventIcon from '../../../components/icons-components/ProjectEventIcon';
+import { ResetButtonLink } from '../../../components/ui/buttons';
+import Level from '../../../components/ui/Level';
+import { translate } from '../../../helpers/l10n';
+import { getProjectUrl } from '../../../helpers/urls';
+
+export type RichQualityGateEvent = Exclude<AnalysisEvent, 'qualityGate'> &
+ Required<Pick<AnalysisEvent, 'qualityGate'>>;
+
+export function isRichQualityGateEvent(event: AnalysisEvent): event is RichQualityGateEvent {
+ return event.category === 'QUALITY_GATE' && event.qualityGate !== undefined;
+}
+
+interface Props {
+ event: RichQualityGateEvent;
+}
+
+interface State {
+ expanded: boolean;
+}
+
+export class RichQualityGateEventInner extends React.PureComponent<Props, State> {
+ state: State = { expanded: false };
+
+ toggleProjectsList = () => {
+ this.setState(state => ({ expanded: !state.expanded }));
+ };
+
+ render() {
+ const { event } = this.props;
+ const { expanded } = this.state;
+ return (
+ <div className="project-activity-event-inner">
+ <div className="project-activity-event-inner-main">
+ <ProjectEventIcon
+ className={classNames(
+ 'project-activity-event-icon',
+ 'little-spacer-right',
+ event.category
+ )}
+ />
+
+ <div className="project-activity-event-inner-text flex-1">
+ <span className="note little-spacer-right">
+ {translate('event.category', event.category)}:
+ </span>
+ {event.qualityGate.stillFailing ? (
+ <FormattedMessage
+ defaultMessage={translate('event.quality_gate.still_x')}
+ id="event.quality_gate.still_x"
+ values={{ status: <Level level={event.qualityGate.status} small={true} /> }}
+ />
+ ) : (
+ <Level level={event.qualityGate.status} small={true} />
+ )}
+ </div>
+
+ {event.qualityGate.failing.length > 0 && (
+ <ResetButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={this.toggleProjectsList}
+ stopPropagation={true}>
+ {expanded ? translate('hide') : translate('more')}
+ <DropdownIcon className="little-spacer-left" turned={expanded} />
+ </ResetButtonLink>
+ )}
+ </div>
+
+ {expanded && (
+ <ul>
+ {event.qualityGate.failing.map(project => (
+ <li className="display-flex-center little-spacer-top" key={project.key}>
+ <Level
+ className="little-spacer-right"
+ level={event.qualityGate.status}
+ small={true}
+ />
+ <div className="flex-1 text-ellipsis">
+ <Link
+ onClick={e => e.stopPropagation()}
+ to={getProjectUrl(project.key, project.branch)}>
+ {project.name}
+ </Link>
+ </div>
+ </li>
+ ))}
+ </ul>
+ )}
+ </div>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/RichQualityGateEventInner-test.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/RichQualityGateEventInner-test.tsx
new file mode 100644
index 00000000000..1bccc563006
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/RichQualityGateEventInner-test.tsx
@@ -0,0 +1,55 @@
+/*
+ * 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 { RichQualityGateEventInner, RichQualityGateEvent } from '../RichQualityGateEventInner';
+import { click } from '../../../../helpers/testUtils';
+
+const event: RichQualityGateEvent = {
+ category: 'QUALITY_GATE',
+ key: 'foo1234',
+ name: '',
+ qualityGate: {
+ failing: [
+ { branch: 'master', key: 'foo', name: 'Foo' },
+ { branch: 'master', key: 'bar', name: 'Bar' }
+ ],
+ status: 'ERROR',
+ stillFailing: true
+ }
+};
+
+it('should render', () => {
+ const wrapper = shallow(<RichQualityGateEventInner event={event} />);
+ expect(wrapper).toMatchSnapshot();
+
+ click(wrapper.find('.project-activity-event-inner-more-link'));
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should not expand', () => {
+ const wrapper = shallow(
+ <RichQualityGateEventInner
+ event={{ ...event, qualityGate: { ...event.qualityGate, failing: [] } }}
+ />
+ );
+ expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false);
+});
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap
new file mode 100644
index 00000000000..1127c310212
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap
@@ -0,0 +1,157 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<div
+ className="project-activity-event-inner"
+>
+ <div
+ className="project-activity-event-inner-main"
+ >
+ <ProjectEventIcon
+ className="project-activity-event-icon little-spacer-right QUALITY_GATE"
+ />
+ <div
+ className="project-activity-event-inner-text flex-1"
+ >
+ <span
+ className="note little-spacer-right"
+ >
+ event.category.QUALITY_GATE
+ :
+ </span>
+ <FormattedMessage
+ defaultMessage="event.quality_gate.still_x"
+ id="event.quality_gate.still_x"
+ values={
+ Object {
+ "status": <Level
+ level="ERROR"
+ small={true}
+ />,
+ }
+ }
+ />
+ </div>
+ <ResetButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={[Function]}
+ stopPropagation={true}
+ >
+ more
+ <DropdownIcon
+ className="little-spacer-left"
+ turned={false}
+ />
+ </ResetButtonLink>
+ </div>
+</div>
+`;
+
+exports[`should render 2`] = `
+<div
+ className="project-activity-event-inner"
+>
+ <div
+ className="project-activity-event-inner-main"
+ >
+ <ProjectEventIcon
+ className="project-activity-event-icon little-spacer-right QUALITY_GATE"
+ />
+ <div
+ className="project-activity-event-inner-text flex-1"
+ >
+ <span
+ className="note little-spacer-right"
+ >
+ event.category.QUALITY_GATE
+ :
+ </span>
+ <FormattedMessage
+ defaultMessage="event.quality_gate.still_x"
+ id="event.quality_gate.still_x"
+ values={
+ Object {
+ "status": <Level
+ level="ERROR"
+ small={true}
+ />,
+ }
+ }
+ />
+ </div>
+ <ResetButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={[Function]}
+ stopPropagation={true}
+ >
+ hide
+ <DropdownIcon
+ className="little-spacer-left"
+ turned={true}
+ />
+ </ResetButtonLink>
+ </div>
+ <ul>
+ <li
+ className="display-flex-center little-spacer-top"
+ key="foo"
+ >
+ <Level
+ className="little-spacer-right"
+ level="ERROR"
+ small={true}
+ />
+ <div
+ className="flex-1 text-ellipsis"
+ >
+ <Link
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": "master",
+ "id": "foo",
+ },
+ }
+ }
+ >
+ Foo
+ </Link>
+ </div>
+ </li>
+ <li
+ className="display-flex-center little-spacer-top"
+ key="bar"
+ >
+ <Level
+ className="little-spacer-right"
+ level="ERROR"
+ small={true}
+ />
+ <div
+ className="flex-1 text-ellipsis"
+ >
+ <Link
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": "master",
+ "id": "bar",
+ },
+ }
+ }
+ >
+ Bar
+ </Link>
+ </div>
+ </li>
+ </ul>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
index e8953145857..ca57363cb5b 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
@@ -61,78 +61,6 @@
flex-shrink: 0;
}
-.project-activity-graphs {
- flex-grow: 1;
- display: flex;
- flex-direction: column;
- align-items: stretch;
- justify-content: center;
-}
-
-.project-activity-graph-container {
- padding: 10px 0;
- flex-grow: 1;
- display: flex;
- flex-direction: column;
- align-items: stretch;
- justify-content: center;
-}
-
-.project-activity-graph {
- flex: 1;
- overflow: hidden;
-}
-
-.project-activity-graph-legends {
- flex-grow: 0;
- padding-bottom: 16px;
- text-align: center;
-}
-
-.project-activity-graph-legend-actionable {
- display: inline-block;
- padding: 4px 8px 4px 12px;
- border-width: 1px;
- border-style: solid;
- border-radius: 12px;
-}
-
-.project-activity-graph-tooltip {
- padding: 8px;
-}
-
-.project-activity-graph-tooltip-line {
- height: 20px;
-}
-
-.project-activity-graph-tooltip-line + .project-activity-graph-tooltip-line {
- padding-top: 4px;
-}
-
-.project-activity-graph-tooltip-line .project-activity-event-icon {
- margin-top: 1px;
-}
-
-.project-activity-graph-tooltip-issues-line {
- height: 26px;
- padding-bottom: 4px;
-}
-
-.project-activity-graph-tooltip-separator {
- padding-left: 16px;
- padding-right: 16px;
-}
-
-.project-activity-graph-tooltip-separator hr {
- margin-top: 8px;
- margin-bottom: 8px;
-}
-
-.project-activity-graph-tooltip-title,
-.project-activity-graph-tooltip-value {
- font-weight: bold;
-}
-
.project-activity-days-list {
}
@@ -156,8 +84,9 @@
.project-activity-analysis {
position: relative;
- min-height: 20px;
- padding: 4px;
+ display: flex;
+ min-height: var(--smallControlHeight);
+ padding: calc(0.5 * var(--gridSize));
border-top: 1px solid var(--barBorderColor);
border-bottom: 1px solid var(--barBorderColor);
cursor: pointer;
@@ -180,36 +109,30 @@
}
.project-activity-analysis-actions {
- float: left;
+ flex-shrink: 0;
+ flex-grow: 0;
+ height: var(--smallControlHeight);
}
.project-activity-time {
- float: left;
+ flex-shrink: 0;
+ flex-grow: 0;
width: 54px;
- line-height: 20px;
+ height: var(--smallControlHeight);
+ line-height: var(--smallControlHeight);
box-sizing: border-box;
font-size: var(--smallFontSize);
font-weight: bold;
text-align: right;
}
-.project-activity-analysis-icon {
- float: left;
- width: 10px;
- height: 10px;
- margin-top: 5px;
- border: 2px solid var(--blue);
- border-radius: 10px;
- box-sizing: border-box;
- content: '';
-}
-
.project-activity-events {
- overflow: hidden;
+ flex: 1;
+ min-width: 0;
}
.project-activity-event {
- line-height: 18px;
+ line-height: var(--smallControlHeight);
display: flex;
}
@@ -219,28 +142,32 @@
.project-activity-event-inner {
flex: 1;
+ min-width: 0;
+}
+
+.project-activity-event-inner-main {
display: flex;
- flex-direction: row;
- overflow: hidden;
+ align-items: flex-start;
}
-.project-activity-event-inner-icon {
+.project-activity-event-icon {
flex-shrink: 0;
+ flex-grow: 0;
+ margin-top: calc(0.5 * var(--smallControlHeight) - 7px);
}
.project-activity-event-inner-text {
- flex: 1;
- display: inline-block;
- overflow: hidden;
- text-overflow: ellipsis;
+ line-height: var(--smallControlHeight);
}
-.project-activity-event-actions {
- display: inline-block;
+.project-activity-event-inner-more-link {
+ line-height: 16px;
+ margin-top: 2px;
}
-.project-activity-event-inner-icon .project-activity-event-icon {
- margin-top: 3px;
+.project-activity-event-actions {
+ flex-shrink: 0;
+ flex-grow: 0;
}
.project-activity-event-icon.VERSION {
@@ -289,3 +216,76 @@
overflow: hidden;
text-overflow: ellipsis;
}
+
+.project-activity-graphs {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+}
+
+.project-activity-graph-container {
+ padding: 10px 0;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+}
+
+.project-activity-graph {
+ flex: 1;
+ overflow: hidden;
+}
+
+.project-activity-graph-legends {
+ flex-grow: 0;
+ padding-bottom: 16px;
+ text-align: center;
+}
+
+.project-activity-graph-legend-actionable {
+ display: inline-block;
+ padding: 4px 8px 4px 12px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 12px;
+}
+
+.project-activity-graph-tooltip {
+ padding: 8px;
+}
+
+.project-activity-graph-tooltip-line {
+ height: 20px;
+}
+
+.project-activity-graph-tooltip-line + .project-activity-graph-tooltip-line {
+ padding-top: 4px;
+}
+
+.Select .project-activity-event-icon,
+.project-activity-graph-tooltip-line .project-activity-event-icon {
+ margin-top: 1px;
+}
+
+.project-activity-graph-tooltip-issues-line {
+ height: 26px;
+ padding-bottom: 4px;
+}
+
+.project-activity-graph-tooltip-separator {
+ padding-left: 16px;
+ padding-right: 16px;
+}
+
+.project-activity-graph-tooltip-separator hr {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+
+.project-activity-graph-tooltip-title,
+.project-activity-graph-tooltip-value {
+ font-weight: bold;
+}
diff --git a/server/sonar-web/src/main/js/components/ui/Level.css b/server/sonar-web/src/main/js/components/ui/Level.css
index d402b5a4d3d..45bc0a4783b 100644
--- a/server/sonar-web/src/main/js/components/ui/Level.css
+++ b/server/sonar-web/src/main/js/components/ui/Level.css
@@ -42,8 +42,8 @@
padding-right: 9px;
margin-top: -1px;
margin-bottom: -1px;
- height: 18px;
- line-height: 18px;
+ height: var(--smallControlHeight);
+ line-height: var(--smallControlHeight);
font-size: var(--smallFontSize);
}
diff --git a/server/sonar-web/src/main/js/components/ui/Level.tsx b/server/sonar-web/src/main/js/components/ui/Level.tsx
index 684ea75b97a..6f74c198fa1 100644
--- a/server/sonar-web/src/main/js/components/ui/Level.tsx
+++ b/server/sonar-web/src/main/js/components/ui/Level.tsx
@@ -30,7 +30,7 @@ interface Props {
}
export default function Level(props: Props) {
- const formatted = formatMeasure(props.level, 'LEVEL', null);
+ const formatted = formatMeasure(props.level, 'LEVEL');
const className = classNames(props.className, 'level', 'level-' + props.level, {
'level-small': props.small,
'level-muted': props.muted
diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css
index c5e8be870f9..ed7a6499ecb 100644
--- a/server/sonar-web/src/main/js/components/ui/buttons.css
+++ b/server/sonar-web/src/main/js/components/ui/buttons.css
@@ -119,6 +119,7 @@
.button-link {
display: inline;
height: auto; /* Keep this to not inherit the height from .button */
+ line-height: 1;
margin: 0;
padding: 0;
border: none;
@@ -128,7 +129,6 @@
border-bottom: 1px solid var(--lightBlue);
font-weight: 400;
font-size: inherit;
- line-height: inherit;
transition: all 0.2s ease;
}
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 93e061c69ac..eb795a57ec0 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -437,6 +437,7 @@ event.category.VERSION=Version
event.category.QUALITY_GATE=Quality Gate
event.category.QUALITY_PROFILE=Quality Profile
event.category.OTHER=Other
+event.quality_gate.still_x=Still {status}
#------------------------------------------------------------------------------