import * as React from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import {openModal} from 'app/actionCreators/modal'; import ActionLink from 'app/components/actions/actionLink'; import ButtonBar from 'app/components/buttonBar'; import CustomIgnoreCountModal from 'app/components/customIgnoreCountModal'; import CustomIgnoreDurationModal from 'app/components/customIgnoreDurationModal'; import DropdownLink from 'app/components/dropdownLink'; import Duration from 'app/components/duration'; import Tooltip from 'app/components/tooltip'; import {IconChevron, IconMute} from 'app/icons'; import {t, tn} from 'app/locale'; import space from 'app/styles/space'; import { ResolutionStatus, ResolutionStatusDetails, UpdateResolutionStatus, } from 'app/types'; import ActionButton from './button'; import MenuHeader from './menuHeader'; const IGNORE_DURATIONS = [30, 120, 360, 60 * 24, 60 * 24 * 7]; const IGNORE_COUNTS = [1, 10, 100, 1000, 10000, 100000]; const IGNORE_WINDOWS: [number, string][] = [ [60, t('per hour')], [24 * 60, t('per day')], [24 * 7 * 60, t('per week')], ]; type Props = { onUpdate: (params: UpdateResolutionStatus) => void; disabled?: boolean; shouldConfirm?: boolean; confirmMessage?: React.ReactNode; confirmLabel?: string; isIgnored?: boolean; }; const IgnoreActions = ({ onUpdate, disabled, shouldConfirm, confirmMessage, confirmLabel = t('Ignore'), isIgnored = false, }: Props) => { const onIgnore = (statusDetails: ResolutionStatusDetails) => { return onUpdate({ status: ResolutionStatus.IGNORED, statusDetails: statusDetails || {}, }); }; const onCustomIgnore = (statusDetails: ResolutionStatusDetails) => { onIgnore(statusDetails); }; const actionLinkProps = { shouldConfirm, title: t('Ignore'), message: confirmMessage, confirmLabel, disabled, }; if (isIgnored) { return ( onUpdate({status: ResolutionStatus.UNRESOLVED})} label={t('Unignore')} icon={} /> ); } const openCustomIgnoreDuration = () => openModal(deps => ( onCustomIgnore(details)} /> )); const openCustomIngoreCount = () => openModal(deps => ( onCustomIgnore(details)} label={t('Ignore this issue until it occurs again\u2026')} countLabel={t('Number of times')} countName="ignoreCount" windowName="ignoreWindow" windowChoices={IGNORE_WINDOWS} /> )); const openCustomIgnoreUserCount = () => openModal(deps => ( onCustomIgnore(details)} label={t('Ignore this issue until it affects an additional\u2026')} countLabel={t('Number of users')} countName="ignoreUserCount" windowName="ignoreUserWindow" windowChoices={IGNORE_WINDOWS} /> )); return ( onUpdate({status: ResolutionStatus.IGNORED})} icon={} > {t('Ignore')} } /> } alwaysRenderMenu disabled={disabled} > {t('Ignore')} {t('For\u2026')} } caret={false} isNestedDropdown alwaysRenderMenu > {IGNORE_DURATIONS.map(duration => ( onIgnore({ignoreDuration: duration})} > ))} {t('Custom')} {t('Until this occurs again\u2026')} } caret={false} isNestedDropdown alwaysRenderMenu > {IGNORE_COUNTS.map(count => ( {count === 1 ? t('one time\u2026') // This is intentional as unbalanced string formatters are problematic : tn('%s time\u2026', '%s times\u2026', count)} } caret={false} isNestedDropdown alwaysRenderMenu > onIgnore({ignoreCount: count})} > {t('from now')} {IGNORE_WINDOWS.map(([hours, label]) => ( onIgnore({ ignoreCount: count, ignoreWindow: hours, }) } > {label} ))} ))} {t('Custom')} {t('Until this affects an additional\u2026')} } caret={false} isNestedDropdown alwaysRenderMenu > {IGNORE_COUNTS.map(count => ( {tn('one user\u2026', '%s users\u2026', count)} } caret={false} isNestedDropdown alwaysRenderMenu > onIgnore({ignoreUserCount: count})} > {t('from now')} {IGNORE_WINDOWS.map(([hours, label]) => ( onIgnore({ ignoreUserCount: count, ignoreUserWindow: hours, }) } > {label} ))} ))} {t('Custom')} ); }; export default IgnoreActions; const actionLinkCss = p => css` color: ${p.theme.subText}; &:hover { border-radius: ${p.theme.borderRadius}; background: ${p.theme.bodyBackground} !important; } `; const StyledActionLink = styled(ActionLink)` padding: 7px 10px !important; ${actionLinkCss}; `; const StyledForActionLink = styled(ActionLink)` padding: ${space(0.5)} 0; ${actionLinkCss}; `; const StyledDropdownLink = styled(DropdownLink)` transition: none; border-top-left-radius: 0 !important; border-bottom-left-radius: 0 !important; `; const DropdownMenuItem = styled('li')` :not(:last-child) { border-bottom: 1px solid ${p => p.theme.innerBorder}; } > span { display: block; > ul { border-radius: ${p => p.theme.borderRadius}; top: 5px; left: 100%; margin-top: -5px; margin-left: -1px; &:after, &:before { display: none !important; } } } &:hover > span { background: ${p => p.theme.focus}; } `; const ActionSubMenu = styled('span')` display: grid; grid-template-columns: 200px 1fr; grid-column-start: 1; grid-column-end: 4; gap: ${space(1)}; padding: ${space(0.5)} 0; color: ${p => p.theme.textColor}; a { color: ${p => p.theme.textColor}; } `; const SubMenuChevron = styled('span')` display: grid; align-self: center; color: ${p => p.theme.gray300}; transition: 0.1s color linear; &:hover, &:active { color: ${p => p.theme.subText}; } `;