/* * SonarQube * Copyright (C) 2009-2024 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 styled from '@emotion/styled'; import classNames from 'classnames'; import { ActionsDropdown, HelperHintIcon, ItemButton, ItemDangerButton, ItemDivider, PopupZLevel, themeBorder, themeColor, } from 'design-system'; import * as React from 'react'; import { WrappedComponentProps, injectIntl } from 'react-intl'; import ClickEventBoundary from '../../../components/controls/ClickEventBoundary'; import Tooltip from '../../../components/controls/Tooltip'; import { formatterOption } from '../../../components/intl/DateTimeFormatter'; import TimeFormatter from '../../../components/intl/TimeFormatter'; import { parseDate } from '../../../helpers/dates'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { ParsedAnalysis, ProjectAnalysisEventCategory } from '../../../types/project-activity'; import Events from './Events'; import AddEventForm from './forms/AddEventForm'; import RemoveAnalysisForm from './forms/RemoveAnalysisForm'; export interface ProjectActivityAnalysisProps extends WrappedComponentProps { analysis: ParsedAnalysis; canAdmin?: boolean; canDeleteAnalyses?: boolean; canCreateVersion: boolean; isBaseline: boolean; isFirst: boolean; selected: boolean; onUpdateSelectedDate: (date: Date) => void; } export enum Dialog { AddEvent = 'add_event', AddVersion = 'add_version', RemoveAnalysis = 'remove_analysis', } function ProjectActivityAnalysis(props: ProjectActivityAnalysisProps) { let node: HTMLLIElement | null = null; const { analysis, isBaseline, isFirst, canAdmin, canCreateVersion, selected, intl: { formatDate }, } = props; React.useEffect(() => { if (node && selected) { node.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }); const [dialog, setDialog] = React.useState(); const closeDialog = () => setDialog(undefined); const parsedDate = parseDate(analysis.date); const hasVersion = analysis.events.find((event) => event.category === 'VERSION') != null; const canAddVersion = canAdmin && !hasVersion && canCreateVersion; const canAddEvent = canAdmin; const canDeleteAnalyses = props.canDeleteAnalyses && !isFirst && !analysis.manualNewCodePeriodBaseline; let tooltipContent = ; if (analysis.buildString) { tooltipContent = ( <> {tooltipContent}{' '} {translateWithParameters('project_activity.analysis_build_string_X', analysis.buildString)} ); } return ( <> { if (!selected) { props.onUpdateSelectedDate(analysis.date); } }} ref={(ref) => (node = ref)} >
{(formattedTime) => ( )}
{(canAddVersion || canAddEvent || canDeleteAnalyses) && (
{canAddVersion && ( setDialog(Dialog.AddVersion)} > {translate('project_activity.add_version')} )} {canAddEvent && ( setDialog(Dialog.AddEvent)}> {translate('project_activity.add_custom_event')} )} {(canAddVersion || canAddEvent) && canDeleteAnalyses && } {canDeleteAnalyses && ( setDialog(Dialog.RemoveAnalysis)} > {translate('project_activity.delete_analysis')} )} {[Dialog.AddEvent, Dialog.AddVersion].includes(dialog as Dialog) && ( )} {dialog === 'remove_analysis' && ( )}
)} {analysis.events.length > 0 && ( )}
{isBaseline && ( {translate('project_activity.new_code_period_start')} )} ); } const ActivityTime = styled.div` box-sizing: border-box; width: 4.5rem; `; const ActivityAnalysisListItem = styled.li` border-bottom: ${themeBorder('default')}; border-left: ${themeBorder('active', 'transparent')}; &:first-of-type { border-top: ${themeBorder('default')}; } &:focus { outline: none; } &:hover, &:focus, &.active { background-color: ${themeColor('subnavigationHover')}; } &.active { border-left: ${themeBorder('active')}; } `; export const BaselineMarker = styled.li` display: flex; align-items: center; border-bottom: ${themeBorder('default', 'newCodeHighlight')}; & span { background-color: ${themeColor('dropdownMenuFocus')}; } `; export default injectIntl(ProjectActivityAnalysis);