import { throwGlobalError } from '../helpers/error';
import { getJSON, post, postJSON, RequestData } from '../helpers/request';
import { BranchParameters } from '../types/branch-like';
-import { Analysis, Paging } from '../types/types';
+import { Analysis } from '../types/project-activity';
+import { Paging } from '../types/types';
export enum ProjectActivityStatuses {
STATUS_PROCESSED = 'P',
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { localizeMetric } from '../../../helpers/measures';
import { BranchLike } from '../../../types/branch-like';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
-import { Analysis as AnalysisType, Component, Metric } from '../../../types/types';
+import {
+ Analysis as AnalysisType,
+ GraphType,
+ MeasureHistory
+} from '../../../types/project-activity';
+import { Component, Metric } from '../../../types/types';
import Analysis from './Analysis';
export interface ActivityPanelProps {
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import { translate } from '../../../helpers/l10n';
import { ComponentQualifier } from '../../../types/component';
-import { Analysis as TypeAnalysis } from '../../../types/types';
+import { Analysis as TypeAnalysis } from '../../../types/project-activity';
import Event from './Event';
export interface AnalysisProps {
import { Branch, BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { MetricKey } from '../../../types/metrics';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { Analysis, GraphType, MeasureHistory } from '../../../types/project-activity';
import { QualityGateStatus, QualityGateStatusCondition } from '../../../types/quality-gates';
-import { Analysis, Component, MeasureEnhanced, Metric, Period } from '../../../types/types';
+import { Component, MeasureEnhanced, Metric, Period } from '../../../types/types';
import '../styles.css';
import { HISTORY_METRICS_LIST, METRICS } from '../utils';
import BranchOverviewRenderer from './BranchOverviewRenderer';
import { ApplicationPeriod } from '../../../types/application';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { Analysis, GraphType, MeasureHistory } from '../../../types/project-activity';
import { QualityGateStatus } from '../../../types/quality-gates';
-import { Analysis, Component, MeasureEnhanced, Metric, Period } from '../../../types/types';
+import { Component, MeasureEnhanced, Metric, Period } from '../../../types/types';
import ActivityPanel from './ActivityPanel';
import FirstAnalysisNextStepsNotif from './FirstAnalysisNextStepsNotif';
import MeasuresPanel from './MeasuresPanel';
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { isDefinitionChangeEvent } from '../../../components/activity-graph/DefinitionChangeEventInner';
+import { isRichQualityGateEvent } from '../../../components/activity-graph/RichQualityGateEventInner';
import Level from '../../../components/ui/Level';
import { translate } from '../../../helpers/l10n';
-import { AnalysisEvent } from '../../../types/types';
-import { isDefinitionChangeEvent } from '../../projectActivity/components/DefinitionChangeEventInner';
-import { isRichQualityGateEvent } from '../../projectActivity/components/RichQualityGateEventInner';
+import { AnalysisEvent } from '../../../types/project-activity';
interface Props {
event: AnalysisEvent;
import { parseDate } from '../../../../helpers/dates';
import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
-import {
- mockAnalysis,
- mockAnalysisEvent,
- mockMeasure,
- mockMetric
-} from '../../../../helpers/testMocks';
+import { mockAnalysis, mockAnalysisEvent } from '../../../../helpers/mocks/project-activity';
+import { mockMeasure, mockMetric } from '../../../../helpers/testMocks';
import { GraphType } from '../../../../types/project-activity';
import { ActivityPanel, ActivityPanelProps } from '../ActivityPanel';
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockAnalysis } from '../../../../helpers/testMocks';
+import { mockAnalysis } from '../../../../helpers/mocks/project-activity';
import { ComponentQualifier } from '../../../../types/component';
import { Analysis, AnalysisProps } from '../Analysis';
import { isDiffMetric } from '../../../../helpers/measures';
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockAnalysis } from '../../../../helpers/testMocks';
+import { mockAnalysis } from '../../../../helpers/mocks/project-activity';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { ComponentQualifier } from '../../../../types/component';
import { MetricKey } from '../../../../types/metrics';
});
jest.mock('../../../../api/projectActivity', () => {
- const { mockAnalysis } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockAnalysis } = jest.requireActual('../../../../helpers/mocks/project-activity');
return {
getProjectActivity: jest.fn().mockResolvedValue({
analyses: [
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { AnalysisEvent } from '../../../../types/types';
+import { AnalysisEvent } from '../../../../types/project-activity';
import { Event } from '../Event';
it('should render an event correctly', () => {
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { AnalysisEvent } from '../../types/types';
+import { AnalysisEvent } from '../../types/project-activity';
import { State } from './components/ProjectActivityApp';
export function addCustomEvent(analysis: string, event: AnalysisEvent) {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 '../../../components/common/Link';
-import { ButtonLink } from '../../../components/controls/buttons';
-import BranchIcon from '../../../components/icons/BranchIcon';
-import DropdownIcon from '../../../components/icons/DropdownIcon';
-import { isMainBranch } from '../../../helpers/branch-like';
-import { translate } from '../../../helpers/l10n';
-import { limitComponentName } from '../../../helpers/path';
-import { getProjectUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { AnalysisEvent } from '../../../types/types';
-
-export type DefinitionChangeEvent = AnalysisEvent &
- Required<Pick<AnalysisEvent, 'definitionChange'>>;
-
-export function isDefinitionChangeEvent(event: AnalysisEvent): event is DefinitionChangeEvent {
- return event.category === 'DEFINITION_CHANGE' && event.definitionChange !== undefined;
-}
-
-interface Props {
- branchLike: BranchLike | undefined;
- event: DefinitionChangeEvent;
- readonly?: boolean;
-}
-
-interface State {
- expanded: boolean;
-}
-
-export class DefinitionChangeEventInner extends React.PureComponent<Props, State> {
- state: State = { expanded: false };
-
- stopPropagation = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.stopPropagation();
- };
-
- toggleProjectsList = () => {
- this.setState(state => ({ expanded: !state.expanded }));
- };
-
- renderProjectLink = (project: { key: string; name: string }, branch: string | undefined) => (
- <Link
- onClick={this.stopPropagation}
- title={project.name}
- to={getProjectUrl(project.key, branch)}>
- {limitComponentName(project.name, 28)}
- </Link>
- );
-
- renderBranch = (branch = translate('branches.main_branch')) => (
- <span className="nowrap" title={branch}>
- <BranchIcon className="little-spacer-left text-text-top" />
- {branch}
- </span>
- );
-
- renderProjectChange(project: {
- changeType: string;
- key: string;
- name: string;
- branch?: string;
- newBranch?: string;
- oldBranch?: string;
- }) {
- const mainBranch = !this.props.branchLike || isMainBranch(this.props.branchLike);
-
- if (project.changeType === 'ADDED') {
- const message = mainBranch
- ? 'event.definition_change.added'
- : 'event.definition_change.branch_added';
- return (
- <div className="text-ellipsis">
- <FormattedMessage
- defaultMessage={translate(message)}
- id={message}
- values={{
- project: this.renderProjectLink(project, project.branch),
- branch: this.renderBranch(project.branch)
- }}
- />
- </div>
- );
- } else if (project.changeType === 'REMOVED') {
- const message = mainBranch
- ? 'event.definition_change.removed'
- : 'event.definition_change.branch_removed';
- return (
- <div className="text-ellipsis">
- <FormattedMessage
- defaultMessage={translate(message)}
- id={message}
- values={{
- project: this.renderProjectLink(project, project.branch),
- branch: this.renderBranch(project.branch)
- }}
- />
- </div>
- );
- } else if (project.changeType === 'BRANCH_CHANGED') {
- return (
- <FormattedMessage
- defaultMessage={translate('event.definition_change.branch_replaced')}
- id="event.definition_change.branch_replaced"
- values={{
- project: this.renderProjectLink(project, project.newBranch),
- oldBranch: this.renderBranch(project.oldBranch),
- newBranch: this.renderBranch(project.newBranch)
- }}
- />
- );
- }
- return null;
- }
-
- render() {
- const { event, readonly } = this.props;
- const { expanded } = this.state;
- return (
- <>
- <span className="note">
- {translate('event.category', event.category)}
- {!readonly && ':'}
- </span>
-
- {!readonly && (
- <div>
- <ButtonLink
- className="project-activity-event-inner-more-link"
- onClick={this.toggleProjectsList}
- stopPropagation={true}>
- {expanded ? translate('hide') : translate('more')}
- <DropdownIcon className="little-spacer-left" turned={expanded} />
- </ButtonLink>
- </div>
- )}
-
- {expanded && (
- <ul className="spacer-left spacer-top">
- {event.definitionChange.projects.map(project => (
- <li className="display-flex-center spacer-top" key={project.key}>
- {this.renderProjectChange(project)}
- </li>
- ))}
- </ul>
- )}
- </>
- );
- }
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import EventInner from '../../../components/activity-graph/EventInner';
import { DeleteButton, EditButton } from '../../../components/controls/buttons';
import { translate } from '../../../helpers/l10n';
-import { AnalysisEvent } from '../../../types/types';
-import EventInner from './EventInner';
+import { AnalysisEvent } from '../../../types/project-activity';
import ChangeEventForm from './forms/ChangeEventForm';
import RemoveEventForm from './forms/RemoveEventForm';
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { ComponentContext } from '../../../app/components/componentContext/ComponentContext';
-import Tooltip from '../../../components/controls/Tooltip';
-import { translate } from '../../../helpers/l10n';
-import { AnalysisEvent } from '../../../types/types';
-import { DefinitionChangeEventInner, isDefinitionChangeEvent } from './DefinitionChangeEventInner';
-import { isRichQualityGateEvent, RichQualityGateEventInner } from './RichQualityGateEventInner';
-
-export interface EventInnerProps {
- event: AnalysisEvent;
- readonly?: boolean;
-}
-
-export default function EventInner({ event, readonly }: EventInnerProps) {
- if (isRichQualityGateEvent(event)) {
- return <RichQualityGateEventInner event={event} readonly={readonly} />;
- } else if (isDefinitionChangeEvent(event)) {
- return (
- <ComponentContext.Consumer>
- {({ branchLike }) => (
- <DefinitionChangeEventInner branchLike={branchLike} event={event} readonly={readonly} />
- )}
- </ComponentContext.Consumer>
- );
- }
-
- return (
- <Tooltip overlay={event.description || null}>
- <span className="text-middle">
- <span className="note little-spacer-right">
- {translate('event.category', event.category)}:
- </span>
- <strong className="spacer-right">{event.name}</strong>
- </span>
- </Tooltip>
- );
-}
*/
import { sortBy } from 'lodash';
import * as React from 'react';
-import { AnalysisEvent } from '../../../types/types';
+import { AnalysisEvent } from '../../../types/project-activity';
import Event from './Event';
export interface EventsProps {
import { toShortNotSoISOString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import { ComponentQualifier } from '../../../types/component';
-import { ParsedAnalysis } from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
import { activityQueryChanged, getAnalysesByVersionByDay, Query } from '../utils';
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
import { parseDate } from '../../../helpers/dates';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { scrollToElement } from '../../../helpers/scrolling';
-import { ParsedAnalysis } from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
import Events from './Events';
import AddEventForm from './forms/AddEventForm';
import RemoveAnalysisForm from './forms/RemoveAnalysisForm';
import { serializeStringArray } from '../../../helpers/query';
import { BranchLike } from '../../../types/branch-like';
import { MetricKey } from '../../../types/metrics';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
-import { Component, Metric, Paging, ParsedAnalysis, RawQuery } from '../../../types/types';
+import { GraphType, MeasureHistory, ParsedAnalysis } from '../../../types/project-activity';
+import { Component, Metric, Paging, RawQuery } from '../../../types/types';
import * as actions from '../actions';
import {
customMetricsChanged,
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import { parseDate } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
-import { MeasureHistory } from '../../../types/project-activity';
-import { Component, Metric, ParsedAnalysis } from '../../../types/types';
+import { MeasureHistory, ParsedAnalysis } from '../../../types/project-activity';
+import { Component, Metric } from '../../../types/types';
import { Query } from '../utils';
import './projectActivity.css';
import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
saveActivityGraph,
splitSeriesInGraphs
} from '../../../components/activity-graph/utils';
-import { GraphType, MeasureHistory, Point, Serie } from '../../../types/project-activity';
-import { Metric, ParsedAnalysis } from '../../../types/types';
+import {
+ GraphType,
+ MeasureHistory,
+ ParsedAnalysis,
+ Point,
+ Serie
+} from '../../../types/project-activity';
+import { Metric } from '../../../types/types';
import { datesQueryChanged, historyQueryChanged, Query } from '../utils';
import { PROJECT_ACTIVITY_GRAPH } from './ProjectActivityApp';
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 '../../../components/common/Link';
-import { ResetButtonLink } from '../../../components/controls/buttons';
-import DropdownIcon from '../../../components/icons/DropdownIcon';
-import Level from '../../../components/ui/Level';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { getProjectUrl } from '../../../helpers/urls';
-import { AnalysisEvent } from '../../../types/types';
-
-export type RichQualityGateEvent = AnalysisEvent & Required<Pick<AnalysisEvent, 'qualityGate'>>;
-
-export function isRichQualityGateEvent(event: AnalysisEvent): event is RichQualityGateEvent {
- return event.category === 'QUALITY_GATE' && event.qualityGate !== undefined;
-}
-
-interface Props {
- event: RichQualityGateEvent;
- readonly?: boolean;
-}
-
-interface State {
- expanded: boolean;
-}
-
-export class RichQualityGateEventInner extends React.PureComponent<Props, State> {
- state: State = { expanded: false };
-
- stopPropagation = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.stopPropagation();
- };
-
- toggleProjectsList = () => {
- this.setState(state => ({ expanded: !state.expanded }));
- };
-
- render() {
- const { event, readonly } = this.props;
- const { expanded } = this.state;
- return (
- <>
- <span className="note 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>
- {!readonly && 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 className="spacer-left spacer-top">
- {event.qualityGate.failing.map(project => (
- <li className="display-flex-center spacer-top" key={project.key}>
- <Level
- aria-label={translate('quality_gates.status')}
- className="spacer-right"
- level={event.qualityGate.status}
- small={true}
- />
- <div className="flex-1 text-ellipsis">
- <Link
- onClick={this.stopPropagation}
- title={project.name}
- to={getProjectUrl(project.key, project.branch)}>
- <span aria-label={translateWithParameters('project_x', project.name)}>
- {project.name}
- </span>
- </Link>
- </div>
- </li>
- ))}
- </ul>
- )}
- </>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockBranch } from '../../../../helpers/mocks/branch-like';
-import { click } from '../../../../helpers/testUtils';
-import { DefinitionChangeEvent, DefinitionChangeEventInner } from '../DefinitionChangeEventInner';
-
-it('should render', () => {
- const event: DefinitionChangeEvent = {
- category: 'DEFINITION_CHANGE',
- key: 'foo1234',
- name: '',
- definitionChange: {
- projects: [
- { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' },
- { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }
- ]
- }
- };
- const wrapper = shallow(<DefinitionChangeEventInner branchLike={undefined} event={event} />);
- expect(wrapper).toMatchSnapshot();
-
- click(wrapper.find('.project-activity-event-inner-more-link'));
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render for a branch', () => {
- const branch = mockBranch({ name: 'feature-x' });
- const event: DefinitionChangeEvent = {
- category: 'DEFINITION_CHANGE',
- key: 'foo1234',
- name: '',
- definitionChange: {
- projects: [
- { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'feature-x' },
- {
- changeType: 'BRANCH_CHANGED',
- key: 'bar',
- name: 'Bar',
- oldBranch: 'master',
- newBranch: 'feature-y'
- }
- ]
- }
- };
- const wrapper = shallow(<DefinitionChangeEventInner branchLike={branch} event={event} />);
- click(wrapper.find('.project-activity-event-inner-more-link'));
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render when readonly', () => {
- const event: DefinitionChangeEvent = {
- category: 'DEFINITION_CHANGE',
- key: 'foo1234',
- name: '',
- definitionChange: {
- projects: [
- { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' },
- { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }
- ]
- }
- };
- const wrapper = shallow(
- <DefinitionChangeEventInner branchLike={undefined} event={event} readonly={true} />
- );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false);
-});
import { shallow } from 'enzyme';
import * as React from 'react';
import { DeleteButton, EditButton } from '../../../../components/controls/buttons';
-import { mockAnalysisEvent } from '../../../../helpers/testMocks';
+import { mockAnalysisEvent } from '../../../../helpers/mocks/project-activity';
import { click } from '../../../../helpers/testUtils';
import { Event, EventProps } from '../Event';
import ChangeEventForm from '../forms/ChangeEventForm';
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockAnalysisEvent } from '../../../../helpers/testMocks';
-import { BranchLike } from '../../../../types/branch-like';
-import EventInner, { EventInnerProps } from '../EventInner';
-
-jest.mock('../../../../app/components/componentContext/ComponentContext', () => {
- const { mockBranch } = jest.requireActual('../../../../helpers/mocks/branch-like');
- return {
- ComponentContext: {
- Consumer: ({
- children
- }: {
- children: (props: { branchLike: BranchLike }) => React.ReactNode;
- }) => {
- return children({ branchLike: mockBranch() });
- }
- }
- };
-});
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot('default');
- expect(
- shallowRender({
- event: mockAnalysisEvent({
- category: 'VERSION',
- description: undefined,
- qualityGate: undefined
- })
- })
- ).toMatchSnapshot('no description');
- expect(shallowRender({ event: mockAnalysisEvent() })).toMatchSnapshot('rich quality gate');
- expect(
- shallowRender({
- event: mockAnalysisEvent({
- category: 'DEFINITION_CHANGE',
- definitionChange: {
- projects: [{ changeType: 'ADDED', key: 'foo', name: 'Foo' }]
- },
- qualityGate: undefined
- })
- })
- .find('Consumer')
- .dive()
- ).toMatchSnapshot('definition change');
-});
-
-function shallowRender(props: Partial<EventInnerProps> = {}) {
- return shallow(
- <EventInner
- event={mockAnalysisEvent({ category: 'VERSION', qualityGate: undefined })}
- {...props}
- />
- );
-}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockAnalysisEvent } from '../../../../helpers/testMocks';
+import { mockAnalysisEvent } from '../../../../helpers/mocks/project-activity';
import { Events, EventsProps } from '../Events';
it('should render correctly', () => {
import * as React from 'react';
import { DEFAULT_GRAPH } from '../../../../components/activity-graph/utils';
import { parseDate } from '../../../../helpers/dates';
-import { mockParsedAnalysis } from '../../../../helpers/testMocks';
+import { mockParsedAnalysis } from '../../../../helpers/mocks/project-activity';
import { ComponentQualifier } from '../../../../types/component';
import ProjectActivityAnalysesList from '../ProjectActivityAnalysesList';
import * as React from 'react';
import { IntlProvider } from 'react-intl';
import TimeFormatter from '../../../../components/intl/TimeFormatter';
+import { mockAnalysisEvent, mockParsedAnalysis } from '../../../../helpers/mocks/project-activity';
import { scrollToElement } from '../../../../helpers/scrolling';
-import { mockAnalysisEvent, mockParsedAnalysis } from '../../../../helpers/testMocks';
import { click } from '../../../../helpers/testUtils';
import AddEventForm from '../forms/AddEventForm';
import RemoveAnalysisForm from '../forms/RemoveAnalysisForm';
});
jest.mock('../../../../api/projectActivity', () => {
- const { mockAnalysis, mockPaging } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockPaging } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockAnalysis } = jest.requireActual('../../../../helpers/mocks/project-activity');
return {
...jest.requireActual('../../../../api/projectActivity'),
createEvent: jest.fn(),
import * as React from 'react';
import { changeEvent, createEvent } from '../../../../api/projectActivity';
import { mockComponent } from '../../../../helpers/mocks/component';
-import {
- mockAnalysisEvent,
- mockLocation,
- mockMetric,
- mockRouter
-} from '../../../../helpers/testMocks';
+import { mockAnalysisEvent } from '../../../../helpers/mocks/project-activity';
+import { mockLocation, mockMetric, mockRouter } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { ComponentQualifier } from '../../../../types/component';
import { MetricKey } from '../../../../types/metrics';
});
jest.mock('../../../../api/projectActivity', () => {
- const { mockAnalysis, mockPaging } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockPaging } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockAnalysis } = jest.requireActual('../../../../helpers/mocks/project-activity');
return {
...jest.requireActual('../../../../api/projectActivity'),
createEvent: jest.fn(),
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../../helpers/testUtils';
-import { RichQualityGateEvent, RichQualityGateEventInner } from '../RichQualityGateEventInner';
-
-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);
-});
-
-it('should not expand when readonly', () => {
- const wrapper = shallow(<RichQualityGateEventInner event={event} readonly={true} />);
- expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false);
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Fragment>
- <span
- className="note"
- >
- event.category.DEFINITION_CHANGE
- :
- </span>
- <div>
- <ButtonLink
- className="project-activity-event-inner-more-link"
- onClick={[Function]}
- stopPropagation={true}
- >
- more
- <DropdownIcon
- className="little-spacer-left"
- turned={false}
- />
- </ButtonLink>
- </div>
-</Fragment>
-`;
-
-exports[`should render 2`] = `
-<Fragment>
- <span
- className="note"
- >
- event.category.DEFINITION_CHANGE
- :
- </span>
- <div>
- <ButtonLink
- className="project-activity-event-inner-more-link"
- onClick={[Function]}
- stopPropagation={true}
- >
- hide
- <DropdownIcon
- className="little-spacer-left"
- turned={true}
- />
- </ButtonLink>
- </div>
- <ul
- className="spacer-left spacer-top"
- >
- <li
- className="display-flex-center spacer-top"
- key="foo"
- >
- <div
- className="text-ellipsis"
- >
- <FormattedMessage
- defaultMessage="event.definition_change.added"
- id="event.definition_change.added"
- values={
- Object {
- "branch": <span
- className="nowrap"
- title="master"
- >
- <BranchIcon
- className="little-spacer-left text-text-top"
- />
- master
- </span>,
- "project": <ForwardRef(Link)
- onClick={[Function]}
- title="Foo"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=foo&branch=master",
- }
- }
- >
- Foo
- </ForwardRef(Link)>,
- }
- }
- />
- </div>
- </li>
- <li
- className="display-flex-center spacer-top"
- key="bar"
- >
- <div
- className="text-ellipsis"
- >
- <FormattedMessage
- defaultMessage="event.definition_change.removed"
- id="event.definition_change.removed"
- values={
- Object {
- "branch": <span
- className="nowrap"
- title="master"
- >
- <BranchIcon
- className="little-spacer-left text-text-top"
- />
- master
- </span>,
- "project": <ForwardRef(Link)
- onClick={[Function]}
- title="Bar"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=bar&branch=master",
- }
- }
- >
- Bar
- </ForwardRef(Link)>,
- }
- }
- />
- </div>
- </li>
- </ul>
-</Fragment>
-`;
-
-exports[`should render for a branch 1`] = `
-<Fragment>
- <span
- className="note"
- >
- event.category.DEFINITION_CHANGE
- :
- </span>
- <div>
- <ButtonLink
- className="project-activity-event-inner-more-link"
- onClick={[Function]}
- stopPropagation={true}
- >
- hide
- <DropdownIcon
- className="little-spacer-left"
- turned={true}
- />
- </ButtonLink>
- </div>
- <ul
- className="spacer-left spacer-top"
- >
- <li
- className="display-flex-center spacer-top"
- key="foo"
- >
- <div
- className="text-ellipsis"
- >
- <FormattedMessage
- defaultMessage="event.definition_change.branch_added"
- id="event.definition_change.branch_added"
- values={
- Object {
- "branch": <span
- className="nowrap"
- title="feature-x"
- >
- <BranchIcon
- className="little-spacer-left text-text-top"
- />
- feature-x
- </span>,
- "project": <ForwardRef(Link)
- onClick={[Function]}
- title="Foo"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=foo&branch=feature-x",
- }
- }
- >
- Foo
- </ForwardRef(Link)>,
- }
- }
- />
- </div>
- </li>
- <li
- className="display-flex-center spacer-top"
- key="bar"
- >
- <FormattedMessage
- defaultMessage="event.definition_change.branch_replaced"
- id="event.definition_change.branch_replaced"
- values={
- Object {
- "newBranch": <span
- className="nowrap"
- title="feature-y"
- >
- <BranchIcon
- className="little-spacer-left text-text-top"
- />
- feature-y
- </span>,
- "oldBranch": <span
- className="nowrap"
- title="master"
- >
- <BranchIcon
- className="little-spacer-left text-text-top"
- />
- master
- </span>,
- "project": <ForwardRef(Link)
- onClick={[Function]}
- title="Bar"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=bar&branch=feature-y",
- }
- }
- >
- Bar
- </ForwardRef(Link)>,
- }
- }
- />
- </li>
- </ul>
-</Fragment>
-`;
-
-exports[`should render when readonly 1`] = `
-<Fragment>
- <span
- className="note"
- >
- event.category.DEFINITION_CHANGE
- </span>
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<Tooltip
- overlay="Lorem ipsum dolor sit amet"
->
- <span
- className="text-middle"
- >
- <span
- className="note little-spacer-right"
- >
- event.category.VERSION
- :
- </span>
- <strong
- className="spacer-right"
- >
- Lorem ipsum
- </strong>
- </span>
-</Tooltip>
-`;
-
-exports[`should render correctly: definition change 1`] = `
-<DefinitionChangeEventInner
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": false,
- "name": "branch-6.7",
- }
- }
- event={
- Object {
- "category": "DEFINITION_CHANGE",
- "definitionChange": Object {
- "projects": Array [
- Object {
- "changeType": "ADDED",
- "key": "foo",
- "name": "Foo",
- },
- ],
- },
- "description": "Lorem ipsum dolor sit amet",
- "key": "E11",
- "name": "Lorem ipsum",
- "qualityGate": undefined,
- }
- }
-/>
-`;
-
-exports[`should render correctly: no description 1`] = `
-<Tooltip
- overlay={null}
->
- <span
- className="text-middle"
- >
- <span
- className="note little-spacer-right"
- >
- event.category.VERSION
- :
- </span>
- <strong
- className="spacer-right"
- >
- Lorem ipsum
- </strong>
- </span>
-</Tooltip>
-`;
-
-exports[`should render correctly: rich quality gate 1`] = `
-<RichQualityGateEventInner
- event={
- Object {
- "category": "QUALITY_GATE",
- "description": "Lorem ipsum dolor sit amet",
- "key": "E11",
- "name": "Lorem ipsum",
- "qualityGate": Object {
- "failing": Array [
- Object {
- "branch": "master",
- "key": "foo",
- "name": "Foo",
- },
- Object {
- "branch": "feature/bar",
- "key": "bar",
- "name": "Bar",
- },
- ],
- "status": "ERROR",
- "stillFailing": true,
- },
- }
- }
-/>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Fragment>
- <span
- className="note 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>
-</Fragment>
-`;
-
-exports[`should render 2`] = `
-<Fragment>
- <span
- className="note 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
- className="spacer-left spacer-top"
- >
- <li
- className="display-flex-center spacer-top"
- key="foo"
- >
- <Level
- aria-label="quality_gates.status"
- className="spacer-right"
- level="ERROR"
- small={true}
- />
- <div
- className="flex-1 text-ellipsis"
- >
- <ForwardRef(Link)
- onClick={[Function]}
- title="Foo"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=foo&branch=master",
- }
- }
- >
- <span
- aria-label="project_x.Foo"
- >
- Foo
- </span>
- </ForwardRef(Link)>
- </div>
- </li>
- <li
- className="display-flex-center spacer-top"
- key="bar"
- >
- <Level
- aria-label="quality_gates.status"
- className="spacer-right"
- level="ERROR"
- small={true}
- />
- <div
- className="flex-1 text-ellipsis"
- >
- <ForwardRef(Link)
- onClick={[Function]}
- title="Bar"
- to={
- Object {
- "pathname": "/dashboard",
- "search": "?id=bar&branch=master",
- }
- }
- >
- <span
- aria-label="project_x.Bar"
- >
- Bar
- </span>
- </ForwardRef(Link)>
- </div>
- </li>
- </ul>
-</Fragment>
-`;
import * as React from 'react';
import ConfirmModal from '../../../../components/controls/ConfirmModal';
import { translate } from '../../../../helpers/l10n';
-import { ParsedAnalysis } from '../../../../types/types';
+import { ParsedAnalysis } from '../../../../types/project-activity';
interface Props {
addEvent: (analysis: string, name: string, category?: string) => Promise<void>;
import * as React from 'react';
import ConfirmModal from '../../../../components/controls/ConfirmModal';
import { translate } from '../../../../helpers/l10n';
-import { AnalysisEvent } from '../../../../types/types';
+import { AnalysisEvent } from '../../../../types/project-activity';
interface Props {
changeEvent: (event: string, name: string) => Promise<void>;
import * as React from 'react';
import ConfirmModal from '../../../../components/controls/ConfirmModal';
import { translate } from '../../../../helpers/l10n';
-import { ParsedAnalysis } from '../../../../types/types';
+import { ParsedAnalysis } from '../../../../types/project-activity';
interface Props {
analysis: ParsedAnalysis;
import * as React from 'react';
import ConfirmModal from '../../../../components/controls/ConfirmModal';
import { translate } from '../../../../helpers/l10n';
-import { AnalysisEvent } from '../../../../types/types';
+import { AnalysisEvent } from '../../../../types/project-activity';
export interface RemoveEventFormProps {
analysisKey: string;
import { shallow } from 'enzyme';
import * as React from 'react';
import ConfirmModal from '../../../../../components/controls/ConfirmModal';
-import { mockAnalysisEvent } from '../../../../../helpers/testMocks';
+import { mockAnalysisEvent } from '../../../../../helpers/mocks/project-activity';
import RemoveEventForm, { RemoveEventFormProps } from '../RemoveEventForm';
it('should render correctly', () => {
serializeString,
serializeStringArray
} from '../../helpers/query';
-import { GraphType } from '../../types/project-activity';
-import { Dict, ParsedAnalysis, RawQuery } from '../../types/types';
+import { GraphType, ParsedAnalysis } from '../../types/project-activity';
+import { Dict, RawQuery } from '../../types/types';
export interface Query {
category: string;
import { AppState } from '../../../types/appstate';
import { Branch, BranchLike } from '../../../types/branch-like';
import { Feature } from '../../../types/features';
-import {
- Component,
- NewCodePeriod,
- NewCodePeriodSettingType,
- ParsedAnalysis
-} from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
+import { Component, NewCodePeriod, NewCodePeriodSettingType } from '../../../types/types';
import '../styles.css';
import { getSettingValue } from '../utils';
import AppHeader from './AppHeader';
import { getProjectActivity } from '../../../api/projectActivity';
import { parseDate, toShortNotSoISOString } from '../../../helpers/dates';
import { scrollToElement } from '../../../helpers/scrolling';
-import { Analysis, Dict, ParsedAnalysis } from '../../../types/types';
+import { Analysis, ParsedAnalysis } from '../../../types/project-activity';
+import { Dict } from '../../../types/types';
import BranchAnalysisListRenderer from './BranchAnalysisListRenderer';
interface Props {
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
import { parseDate, toShortNotSoISOString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
-import { ParsedAnalysis } from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
import Events from '../../projectActivity/components/Events';
import { getAnalysesByVersionByDay } from '../../projectActivity/utils';
import { toNotSoISOString } from '../../../helpers/dates';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Branch, BranchWithNewCodePeriod } from '../../../types/branch-like';
-import { NewCodePeriod, NewCodePeriodSettingType, ParsedAnalysis } from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
+import { NewCodePeriod, NewCodePeriodSettingType } from '../../../types/types';
import { getSettingValue, validateSetting } from '../utils';
import BaselineSettingAnalysis from './BaselineSettingAnalysis';
import BaselineSettingDays from './BaselineSettingDays';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Branch } from '../../../types/branch-like';
-import { NewCodePeriod, NewCodePeriodSettingType, ParsedAnalysis } from '../../../types/types';
+import { ParsedAnalysis } from '../../../types/project-activity';
+import { NewCodePeriod, NewCodePeriodSettingType } from '../../../types/types';
import { validateSetting } from '../utils';
import BaselineSettingAnalysis from './BaselineSettingAnalysis';
import BaselineSettingDays from './BaselineSettingDays';
import * as React from 'react';
import { getProjectActivity } from '../../../../api/projectActivity';
import { toShortNotSoISOString } from '../../../../helpers/dates';
-import { mockAnalysis, mockAnalysisEvent } from '../../../../helpers/testMocks';
+import { mockAnalysis, mockAnalysisEvent } from '../../../../helpers/mocks/project-activity';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import BranchAnalysisList from '../BranchAnalysisList';
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockAnalysisEvent, mockParsedAnalysis } from '../../../../helpers/testMocks';
+import { mockAnalysisEvent, mockParsedAnalysis } from '../../../../helpers/mocks/project-activity';
import BranchAnalysisListRenderer, {
BranchAnalysisListRendererProps
} from '../BranchAnalysisListRenderer';
import { filter, slice, sortBy } from 'lodash';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import EventInner from '../../apps/projectActivity/components/EventInner';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { formatMeasure } from '../../helpers/measures';
import { ParsedAnalysis, Serie } from '../../types/project-activity';
import DateFormatter from '../intl/DateFormatter';
import TimeFormatter from '../intl/TimeFormatter';
import { Alert } from '../ui/Alert';
+import EventInner from './EventInner';
import { getAnalysisEventsForDate } from './utils';
export interface DataTableModalProps {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { isMainBranch } from '../../helpers/branch-like';
+import { translate } from '../../helpers/l10n';
+import { limitComponentName } from '../../helpers/path';
+import { getProjectUrl } from '../../helpers/urls';
+import { BranchLike } from '../../types/branch-like';
+import { AnalysisEvent } from '../../types/project-activity';
+import Link from '../common/Link';
+import { ButtonLink } from '../controls/buttons';
+import BranchIcon from '../icons/BranchIcon';
+import DropdownIcon from '../icons/DropdownIcon';
+
+export type DefinitionChangeEvent = AnalysisEvent &
+ Required<Pick<AnalysisEvent, 'definitionChange'>>;
+
+export function isDefinitionChangeEvent(event: AnalysisEvent): event is DefinitionChangeEvent {
+ return event.category === 'DEFINITION_CHANGE' && event.definitionChange !== undefined;
+}
+
+interface Props {
+ branchLike: BranchLike | undefined;
+ event: DefinitionChangeEvent;
+ readonly?: boolean;
+}
+
+interface State {
+ expanded: boolean;
+}
+
+export class DefinitionChangeEventInner extends React.PureComponent<Props, State> {
+ state: State = { expanded: false };
+
+ stopPropagation = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.stopPropagation();
+ };
+
+ toggleProjectsList = () => {
+ this.setState(state => ({ expanded: !state.expanded }));
+ };
+
+ renderProjectLink = (project: { key: string; name: string }, branch: string | undefined) => (
+ <Link
+ onClick={this.stopPropagation}
+ title={project.name}
+ to={getProjectUrl(project.key, branch)}>
+ {limitComponentName(project.name, 28)}
+ </Link>
+ );
+
+ renderBranch = (branch = translate('branches.main_branch')) => (
+ <span className="nowrap" title={branch}>
+ <BranchIcon className="little-spacer-left text-text-top" />
+ {branch}
+ </span>
+ );
+
+ renderProjectChange(project: {
+ changeType: string;
+ key: string;
+ name: string;
+ branch?: string;
+ newBranch?: string;
+ oldBranch?: string;
+ }) {
+ const mainBranch = !this.props.branchLike || isMainBranch(this.props.branchLike);
+
+ if (project.changeType === 'ADDED') {
+ const message = mainBranch
+ ? 'event.definition_change.added'
+ : 'event.definition_change.branch_added';
+ return (
+ <div className="text-ellipsis">
+ <FormattedMessage
+ defaultMessage={translate(message)}
+ id={message}
+ values={{
+ project: this.renderProjectLink(project, project.branch),
+ branch: this.renderBranch(project.branch)
+ }}
+ />
+ </div>
+ );
+ } else if (project.changeType === 'REMOVED') {
+ const message = mainBranch
+ ? 'event.definition_change.removed'
+ : 'event.definition_change.branch_removed';
+ return (
+ <div className="text-ellipsis">
+ <FormattedMessage
+ defaultMessage={translate(message)}
+ id={message}
+ values={{
+ project: this.renderProjectLink(project, project.branch),
+ branch: this.renderBranch(project.branch)
+ }}
+ />
+ </div>
+ );
+ } else if (project.changeType === 'BRANCH_CHANGED') {
+ return (
+ <FormattedMessage
+ defaultMessage={translate('event.definition_change.branch_replaced')}
+ id="event.definition_change.branch_replaced"
+ values={{
+ project: this.renderProjectLink(project, project.newBranch),
+ oldBranch: this.renderBranch(project.oldBranch),
+ newBranch: this.renderBranch(project.newBranch)
+ }}
+ />
+ );
+ }
+ return null;
+ }
+
+ render() {
+ const { event, readonly } = this.props;
+ const { expanded } = this.state;
+ return (
+ <>
+ <span className="note">
+ {translate('event.category', event.category)}
+ {!readonly && ':'}
+ </span>
+
+ {!readonly && (
+ <div>
+ <ButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={this.toggleProjectsList}
+ stopPropagation={true}>
+ {expanded ? translate('hide') : translate('more')}
+ <DropdownIcon className="little-spacer-left" turned={expanded} />
+ </ButtonLink>
+ </div>
+ )}
+
+ {expanded && (
+ <ul className="spacer-left spacer-top">
+ {event.definitionChange.projects.map(project => (
+ <li className="display-flex-center spacer-top" key={project.key}>
+ {this.renderProjectChange(project)}
+ </li>
+ ))}
+ </ul>
+ )}
+ </>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { ComponentContext } from '../../app/components/componentContext/ComponentContext';
+import { translate } from '../../helpers/l10n';
+import { AnalysisEvent } from '../../types/project-activity';
+import Tooltip from '../controls/Tooltip';
+import { DefinitionChangeEventInner, isDefinitionChangeEvent } from './DefinitionChangeEventInner';
+import { isRichQualityGateEvent, RichQualityGateEventInner } from './RichQualityGateEventInner';
+
+export interface EventInnerProps {
+ event: AnalysisEvent;
+ readonly?: boolean;
+}
+
+export default function EventInner({ event, readonly }: EventInnerProps) {
+ if (isRichQualityGateEvent(event)) {
+ return <RichQualityGateEventInner event={event} readonly={readonly} />;
+ } else if (isDefinitionChangeEvent(event)) {
+ return (
+ <ComponentContext.Consumer>
+ {({ branchLike }) => (
+ <DefinitionChangeEventInner branchLike={branchLike} event={event} readonly={readonly} />
+ )}
+ </ComponentContext.Consumer>
+ );
+ }
+
+ return (
+ <Tooltip overlay={event.description || null}>
+ <span className="text-middle">
+ <span className="note little-spacer-right">
+ {translate('event.category', event.category)}:
+ </span>
+ <strong className="spacer-right">{event.name}</strong>
+ </span>
+ </Tooltip>
+ );
+}
import AdvancedTimeline from '../../components/charts/AdvancedTimeline';
import { translate } from '../../helpers/l10n';
import { formatMeasure, getShortType } from '../../helpers/measures';
-import { MeasureHistory, Serie } from '../../types/project-activity';
-import { ParsedAnalysis } from '../../types/types';
+import { MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
import { Button } from '../controls/buttons';
import ModalButton from '../controls/ModalButton';
import DataTableModal from './DataTableModal';
import DeferredSpinner from '../../components/ui/DeferredSpinner';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { getBaseUrl } from '../../helpers/system';
-import { GraphType, MeasureHistory, Serie } from '../../types/project-activity';
-import { ParsedAnalysis } from '../../types/types';
+import { GraphType, MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
import GraphHistory from './GraphHistory';
import './styles.css';
import { getSeriesMetricType, hasHistoryData, isCustomGraph } from './utils';
import * as React from 'react';
import { Popup, PopupPlacement } from '../../components/ui/popups';
import { isDefined } from '../../helpers/types';
-import { MeasureHistory, Serie } from '../../types/project-activity';
-import { AnalysisEvent } from '../../types/types';
+import { AnalysisEvent, MeasureHistory, Serie } from '../../types/project-activity';
import DateTimeFormatter from '../intl/DateTimeFormatter';
import GraphsTooltipsContent from './GraphsTooltipsContent';
import GraphsTooltipsContentCoverage from './GraphsTooltipsContentCoverage';
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import EventInner from '../../apps/projectActivity/components/EventInner';
-import { AnalysisEvent } from '../../types/types';
+import { AnalysisEvent } from '../../types/project-activity';
+import EventInner from './EventInner';
interface Props {
addSeparator: boolean;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { translate, translateWithParameters } from '../../helpers/l10n';
+import { getProjectUrl } from '../../helpers/urls';
+import { AnalysisEvent } from '../../types/project-activity';
+import Link from '../common/Link';
+import { ResetButtonLink } from '../controls/buttons';
+import DropdownIcon from '../icons/DropdownIcon';
+import Level from '../ui/Level';
+
+export type RichQualityGateEvent = AnalysisEvent & Required<Pick<AnalysisEvent, 'qualityGate'>>;
+
+export function isRichQualityGateEvent(event: AnalysisEvent): event is RichQualityGateEvent {
+ return event.category === 'QUALITY_GATE' && event.qualityGate !== undefined;
+}
+
+interface Props {
+ event: RichQualityGateEvent;
+ readonly?: boolean;
+}
+
+interface State {
+ expanded: boolean;
+}
+
+export class RichQualityGateEventInner extends React.PureComponent<Props, State> {
+ state: State = { expanded: false };
+
+ stopPropagation = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.stopPropagation();
+ };
+
+ toggleProjectsList = () => {
+ this.setState(state => ({ expanded: !state.expanded }));
+ };
+
+ render() {
+ const { event, readonly } = this.props;
+ const { expanded } = this.state;
+ return (
+ <>
+ <span className="note 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>
+ {!readonly && 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 className="spacer-left spacer-top">
+ {event.qualityGate.failing.map(project => (
+ <li className="display-flex-center spacer-top" key={project.key}>
+ <Level
+ aria-label={translate('quality_gates.status')}
+ className="spacer-right"
+ level={event.qualityGate.status}
+ small={true}
+ />
+ <div className="flex-1 text-ellipsis">
+ <Link
+ onClick={this.stopPropagation}
+ title={project.name}
+ to={getProjectUrl(project.key, project.branch)}>
+ <span aria-label={translateWithParameters('project_x', project.name)}>
+ {project.name}
+ </span>
+ </Link>
+ </div>
+ </li>
+ ))}
+ </ul>
+ )}
+ </>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockBranch } from '../../../helpers/mocks/branch-like';
+import { click } from '../../../helpers/testUtils';
+import { DefinitionChangeEvent, DefinitionChangeEventInner } from '../DefinitionChangeEventInner';
+
+it('should render', () => {
+ const event: DefinitionChangeEvent = {
+ category: 'DEFINITION_CHANGE',
+ key: 'foo1234',
+ name: '',
+ definitionChange: {
+ projects: [
+ { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' },
+ { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }
+ ]
+ }
+ };
+ const wrapper = shallow(<DefinitionChangeEventInner branchLike={undefined} event={event} />);
+ expect(wrapper).toMatchSnapshot();
+
+ click(wrapper.find('.project-activity-event-inner-more-link'));
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render for a branch', () => {
+ const branch = mockBranch({ name: 'feature-x' });
+ const event: DefinitionChangeEvent = {
+ category: 'DEFINITION_CHANGE',
+ key: 'foo1234',
+ name: '',
+ definitionChange: {
+ projects: [
+ { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'feature-x' },
+ {
+ changeType: 'BRANCH_CHANGED',
+ key: 'bar',
+ name: 'Bar',
+ oldBranch: 'master',
+ newBranch: 'feature-y'
+ }
+ ]
+ }
+ };
+ const wrapper = shallow(<DefinitionChangeEventInner branchLike={branch} event={event} />);
+ click(wrapper.find('.project-activity-event-inner-more-link'));
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render when readonly', () => {
+ const event: DefinitionChangeEvent = {
+ category: 'DEFINITION_CHANGE',
+ key: 'foo1234',
+ name: '',
+ definitionChange: {
+ projects: [
+ { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' },
+ { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }
+ ]
+ }
+ };
+ const wrapper = shallow(
+ <DefinitionChangeEventInner branchLike={undefined} event={event} readonly={true} />
+ );
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false);
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockAnalysisEvent } from '../../../helpers/mocks/project-activity';
+import { BranchLike } from '../../../types/branch-like';
+import EventInner, { EventInnerProps } from '../EventInner';
+
+jest.mock('../../../app/components/componentContext/ComponentContext', () => {
+ const { mockBranch } = jest.requireActual('../../../helpers/mocks/branch-like');
+ return {
+ ComponentContext: {
+ Consumer: ({
+ children
+ }: {
+ children: (props: { branchLike: BranchLike }) => React.ReactNode;
+ }) => {
+ return children({ branchLike: mockBranch() });
+ }
+ }
+ };
+});
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(
+ shallowRender({
+ event: mockAnalysisEvent({
+ category: 'VERSION',
+ description: undefined,
+ qualityGate: undefined
+ })
+ })
+ ).toMatchSnapshot('no description');
+ expect(shallowRender({ event: mockAnalysisEvent() })).toMatchSnapshot('rich quality gate');
+ expect(
+ shallowRender({
+ event: mockAnalysisEvent({
+ category: 'DEFINITION_CHANGE',
+ definitionChange: {
+ projects: [{ changeType: 'ADDED', key: 'foo', name: 'Foo' }]
+ },
+ qualityGate: undefined
+ })
+ })
+ .find('Consumer')
+ .dive()
+ ).toMatchSnapshot('definition change');
+});
+
+function shallowRender(props: Partial<EventInnerProps> = {}) {
+ return shallow(
+ <EventInner
+ event={mockAnalysisEvent({ category: 'VERSION', qualityGate: undefined })}
+ {...props}
+ />
+ );
+}
function shallowRender(overrides: Partial<GraphHistory['props']> = {}) {
return shallow(
<GraphHistory
- events={[]}
+ analyses={[]}
+ ariaLabel="foo"
graph={DEFAULT_GRAPH}
leakPeriodDate={parseDate('2017-05-16T13:50:02+0200')}
isCustom={false}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { click } from '../../../helpers/testUtils';
+import { RichQualityGateEvent, RichQualityGateEventInner } from '../RichQualityGateEventInner';
+
+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);
+});
+
+it('should not expand when readonly', () => {
+ const wrapper = shallow(<RichQualityGateEventInner event={event} readonly={true} />);
+ expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false);
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<Fragment>
+ <span
+ className="note"
+ >
+ event.category.DEFINITION_CHANGE
+ :
+ </span>
+ <div>
+ <ButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={[Function]}
+ stopPropagation={true}
+ >
+ more
+ <DropdownIcon
+ className="little-spacer-left"
+ turned={false}
+ />
+ </ButtonLink>
+ </div>
+</Fragment>
+`;
+
+exports[`should render 2`] = `
+<Fragment>
+ <span
+ className="note"
+ >
+ event.category.DEFINITION_CHANGE
+ :
+ </span>
+ <div>
+ <ButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={[Function]}
+ stopPropagation={true}
+ >
+ hide
+ <DropdownIcon
+ className="little-spacer-left"
+ turned={true}
+ />
+ </ButtonLink>
+ </div>
+ <ul
+ className="spacer-left spacer-top"
+ >
+ <li
+ className="display-flex-center spacer-top"
+ key="foo"
+ >
+ <div
+ className="text-ellipsis"
+ >
+ <FormattedMessage
+ defaultMessage="event.definition_change.added"
+ id="event.definition_change.added"
+ values={
+ Object {
+ "branch": <span
+ className="nowrap"
+ title="master"
+ >
+ <BranchIcon
+ className="little-spacer-left text-text-top"
+ />
+ master
+ </span>,
+ "project": <ForwardRef(Link)
+ onClick={[Function]}
+ title="Foo"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=foo&branch=master",
+ }
+ }
+ >
+ Foo
+ </ForwardRef(Link)>,
+ }
+ }
+ />
+ </div>
+ </li>
+ <li
+ className="display-flex-center spacer-top"
+ key="bar"
+ >
+ <div
+ className="text-ellipsis"
+ >
+ <FormattedMessage
+ defaultMessage="event.definition_change.removed"
+ id="event.definition_change.removed"
+ values={
+ Object {
+ "branch": <span
+ className="nowrap"
+ title="master"
+ >
+ <BranchIcon
+ className="little-spacer-left text-text-top"
+ />
+ master
+ </span>,
+ "project": <ForwardRef(Link)
+ onClick={[Function]}
+ title="Bar"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=bar&branch=master",
+ }
+ }
+ >
+ Bar
+ </ForwardRef(Link)>,
+ }
+ }
+ />
+ </div>
+ </li>
+ </ul>
+</Fragment>
+`;
+
+exports[`should render for a branch 1`] = `
+<Fragment>
+ <span
+ className="note"
+ >
+ event.category.DEFINITION_CHANGE
+ :
+ </span>
+ <div>
+ <ButtonLink
+ className="project-activity-event-inner-more-link"
+ onClick={[Function]}
+ stopPropagation={true}
+ >
+ hide
+ <DropdownIcon
+ className="little-spacer-left"
+ turned={true}
+ />
+ </ButtonLink>
+ </div>
+ <ul
+ className="spacer-left spacer-top"
+ >
+ <li
+ className="display-flex-center spacer-top"
+ key="foo"
+ >
+ <div
+ className="text-ellipsis"
+ >
+ <FormattedMessage
+ defaultMessage="event.definition_change.branch_added"
+ id="event.definition_change.branch_added"
+ values={
+ Object {
+ "branch": <span
+ className="nowrap"
+ title="feature-x"
+ >
+ <BranchIcon
+ className="little-spacer-left text-text-top"
+ />
+ feature-x
+ </span>,
+ "project": <ForwardRef(Link)
+ onClick={[Function]}
+ title="Foo"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=foo&branch=feature-x",
+ }
+ }
+ >
+ Foo
+ </ForwardRef(Link)>,
+ }
+ }
+ />
+ </div>
+ </li>
+ <li
+ className="display-flex-center spacer-top"
+ key="bar"
+ >
+ <FormattedMessage
+ defaultMessage="event.definition_change.branch_replaced"
+ id="event.definition_change.branch_replaced"
+ values={
+ Object {
+ "newBranch": <span
+ className="nowrap"
+ title="feature-y"
+ >
+ <BranchIcon
+ className="little-spacer-left text-text-top"
+ />
+ feature-y
+ </span>,
+ "oldBranch": <span
+ className="nowrap"
+ title="master"
+ >
+ <BranchIcon
+ className="little-spacer-left text-text-top"
+ />
+ master
+ </span>,
+ "project": <ForwardRef(Link)
+ onClick={[Function]}
+ title="Bar"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=bar&branch=feature-y",
+ }
+ }
+ >
+ Bar
+ </ForwardRef(Link)>,
+ }
+ }
+ />
+ </li>
+ </ul>
+</Fragment>
+`;
+
+exports[`should render when readonly 1`] = `
+<Fragment>
+ <span
+ className="note"
+ >
+ event.category.DEFINITION_CHANGE
+ </span>
+</Fragment>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<Tooltip
+ overlay="Lorem ipsum dolor sit amet"
+>
+ <span
+ className="text-middle"
+ >
+ <span
+ className="note little-spacer-right"
+ >
+ event.category.VERSION
+ :
+ </span>
+ <strong
+ className="spacer-right"
+ >
+ Lorem ipsum
+ </strong>
+ </span>
+</Tooltip>
+`;
+
+exports[`should render correctly: definition change 1`] = `
+<DefinitionChangeEventInner
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": false,
+ "name": "branch-6.7",
+ }
+ }
+ event={
+ Object {
+ "category": "DEFINITION_CHANGE",
+ "definitionChange": Object {
+ "projects": Array [
+ Object {
+ "changeType": "ADDED",
+ "key": "foo",
+ "name": "Foo",
+ },
+ ],
+ },
+ "description": "Lorem ipsum dolor sit amet",
+ "key": "E11",
+ "name": "Lorem ipsum",
+ "qualityGate": undefined,
+ }
+ }
+/>
+`;
+
+exports[`should render correctly: no description 1`] = `
+<Tooltip
+ overlay={null}
+>
+ <span
+ className="text-middle"
+ >
+ <span
+ className="note little-spacer-right"
+ >
+ event.category.VERSION
+ :
+ </span>
+ <strong
+ className="spacer-right"
+ >
+ Lorem ipsum
+ </strong>
+ </span>
+</Tooltip>
+`;
+
+exports[`should render correctly: rich quality gate 1`] = `
+<RichQualityGateEventInner
+ event={
+ Object {
+ "category": "QUALITY_GATE",
+ "description": "Lorem ipsum dolor sit amet",
+ "key": "E11",
+ "name": "Lorem ipsum",
+ "qualityGate": Object {
+ "failing": Array [
+ Object {
+ "branch": "master",
+ "key": "foo",
+ "name": "Foo",
+ },
+ Object {
+ "branch": "feature/bar",
+ "key": "bar",
+ "name": "Bar",
+ },
+ ],
+ "status": "ERROR",
+ "stillFailing": true,
+ },
+ }
+ }
+/>
+`;
</AutoSizer>
</div>
<div
- className="spacer-top big-spacer-bottom small"
+ className="little-spacer-top big-spacer-bottom"
>
<div
- className="display-flex-justify-center"
+ className="display-flex-justify-end little-padded-right"
>
<ModalButton
modal={[Function]}
</AutoSizer>
</div>
<div
- className="spacer-top big-spacer-bottom small"
+ className="little-spacer-top big-spacer-bottom"
>
<div
- className="display-flex-justify-center"
+ className="display-flex-justify-end little-padded-right"
>
<ModalButton
modal={[Function]}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<Fragment>
+ <span
+ className="note 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>
+</Fragment>
+`;
+
+exports[`should render 2`] = `
+<Fragment>
+ <span
+ className="note 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
+ className="spacer-left spacer-top"
+ >
+ <li
+ className="display-flex-center spacer-top"
+ key="foo"
+ >
+ <Level
+ aria-label="quality_gates.status"
+ className="spacer-right"
+ level="ERROR"
+ small={true}
+ />
+ <div
+ className="flex-1 text-ellipsis"
+ >
+ <ForwardRef(Link)
+ onClick={[Function]}
+ title="Foo"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=foo&branch=master",
+ }
+ }
+ >
+ <span
+ aria-label="project_x.Foo"
+ >
+ Foo
+ </span>
+ </ForwardRef(Link)>
+ </div>
+ </li>
+ <li
+ className="display-flex-center spacer-top"
+ key="bar"
+ >
+ <Level
+ aria-label="quality_gates.status"
+ className="spacer-right"
+ level="ERROR"
+ small={true}
+ />
+ <div
+ className="flex-1 text-ellipsis"
+ >
+ <ForwardRef(Link)
+ onClick={[Function]}
+ title="Bar"
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "search": "?id=bar&branch=master",
+ }
+ }
+ >
+ <span
+ aria-label="project_x.Bar"
+ >
+ Bar
+ </span>
+ </ForwardRef(Link)>
+ </div>
+ </li>
+ </ul>
+</Fragment>
+`;
import { localizeMetric } from '../../helpers/measures';
import { get, save } from '../../helpers/storage';
import { MetricKey } from '../../types/metrics';
-import { GraphType, MeasureHistory, Serie } from '../../types/project-activity';
-import { Dict, Metric, ParsedAnalysis } from '../../types/types';
+import { GraphType, MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
+import { Dict, Metric } from '../../types/types';
export const DEFAULT_GRAPH = GraphType.issues;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { Analysis, AnalysisEvent, ParsedAnalysis } from '../../types/project-activity';
+
+export function mockAnalysis(overrides: Partial<Analysis> = {}): Analysis {
+ return {
+ date: '2017-03-01T09:36:01+0100',
+ events: [],
+ key: 'foo',
+ projectVersion: '1.0',
+ ...overrides
+ };
+}
+
+export function mockParsedAnalysis(overrides: Partial<ParsedAnalysis> = {}): ParsedAnalysis {
+ return {
+ date: new Date('2017-03-01T09:37:01+0100'),
+ events: [],
+ key: 'foo',
+ projectVersion: '1.0',
+ ...overrides
+ };
+}
+
+export function mockAnalysisEvent(overrides: Partial<AnalysisEvent> = {}): AnalysisEvent {
+ return {
+ category: 'QUALITY_GATE',
+ key: 'E11',
+ description: 'Lorem ipsum dolor sit amet',
+ name: 'Lorem ipsum',
+ qualityGate: {
+ status: 'ERROR',
+ stillFailing: true,
+ failing: [
+ {
+ key: 'foo',
+ name: 'Foo',
+ branch: 'master'
+ },
+ {
+ key: 'bar',
+ name: 'Bar',
+ branch: 'feature/bar'
+ }
+ ]
+ },
+ ...overrides
+ };
+}
import { TaskStatuses } from '../types/tasks';
import {
AlmApplication,
- Analysis,
- AnalysisEvent,
Condition,
FlowLocation,
Group,
MeasureEnhanced,
Metric,
Paging,
- ParsedAnalysis,
Period,
ProfileInheritanceDetails,
Rule,
};
}
-export function mockAnalysis(overrides: Partial<Analysis> = {}): Analysis {
- return {
- date: '2017-03-01T09:36:01+0100',
- events: [],
- key: 'foo',
- projectVersion: '1.0',
- ...overrides
- };
-}
-
-export function mockParsedAnalysis(overrides: Partial<ParsedAnalysis> = {}): ParsedAnalysis {
- return {
- date: new Date('2017-03-01T09:37:01+0100'),
- events: [],
- key: 'foo',
- projectVersion: '1.0',
- ...overrides
- };
-}
-
-export function mockAnalysisEvent(overrides: Partial<AnalysisEvent> = {}): AnalysisEvent {
- return {
- category: 'QUALITY_GATE',
- key: 'E11',
- description: 'Lorem ipsum dolor sit amet',
- name: 'Lorem ipsum',
- qualityGate: {
- status: 'ERROR',
- stillFailing: true,
- failing: [
- {
- key: 'foo',
- name: 'Foo',
- branch: 'master'
- },
- {
- key: 'bar',
- name: 'Bar',
- branch: 'feature/bar'
- }
- ]
- },
- ...overrides
- };
-}
-
export function mockAppState(overrides: Partial<AppState> = {}): AppState {
return {
edition: EditionKey.community,
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+interface BaseAnalysis {
+ buildString?: string;
+ detectedCI?: string;
+ events: AnalysisEvent[];
+ key: string;
+ manualNewCodePeriodBaseline?: boolean;
+ projectVersion?: string;
+}
+
+export interface Analysis extends BaseAnalysis {
+ date: string;
+}
+
+export interface ParsedAnalysis extends BaseAnalysis {
+ date: Date;
+}
+
+export interface AnalysisEvent {
+ category: string;
+ description?: string;
+ key: string;
+ name: string;
+ qualityGate?: {
+ failing: Array<{ branch: string; key: string; name: string }>;
+ status: string;
+ stillFailing: boolean;
+ };
+ definitionChange?: {
+ projects: Array<{
+ branch?: string;
+ changeType: string;
+ key: string;
+ name: string;
+ newBranch?: string;
+ oldBranch?: string;
+ }>;
+ };
+}
+
export enum GraphType {
issues = 'issues',
coverage = 'coverage',
name: string;
}
-interface BaseAnalysis {
- buildString?: string;
- detectedCI?: string;
- events: AnalysisEvent[];
- key: string;
- manualNewCodePeriodBaseline?: boolean;
- projectVersion?: string;
-}
-
-export interface Analysis extends BaseAnalysis {
- date: string;
-}
-
-export interface ParsedAnalysis extends BaseAnalysis {
- date: Date;
-}
-
-export interface AnalysisEvent {
- category: string;
- description?: string;
- key: string;
- name: string;
- qualityGate?: {
- failing: Array<{ branch: string; key: string; name: string }>;
- status: string;
- stillFailing: boolean;
- };
- definitionChange?: {
- projects: Array<{
- branch?: string;
- changeType: string;
- key: string;
- name: string;
- newBranch?: string;
- oldBranch?: string;
- }>;
- };
-}
-
export interface Breadcrumb {
key: string;
name: string;