import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import ActionLink from 'sentry/components/actions/actionLink'; import IgnoreActions from 'sentry/components/actions/ignore'; import {openConfirmModal} from 'sentry/components/confirm'; import DropdownMenuControlV2 from 'sentry/components/dropdownMenuControlV2'; import {MenuItemProps} from 'sentry/components/dropdownMenuItemV2'; import {IconEllipsis} from 'sentry/icons'; import {t} from 'sentry/locale'; import GroupStore from 'sentry/stores/groupStore'; import space from 'sentry/styles/space'; import {Organization, Project, ResolutionStatus} from 'sentry/types'; import Projects from 'sentry/utils/projects'; import useMedia from 'sentry/utils/useMedia'; import ResolveActions from './resolveActions'; import ReviewAction from './reviewAction'; import IssueListSortOptions from './sortOptions'; import {ConfirmAction, getConfirm, getLabel} from './utils'; type Props = { allInQuerySelected: boolean; anySelected: boolean; issues: Set; multiSelected: boolean; onDelete: () => void; onMerge: () => void; onShouldConfirm: (action: ConfirmAction) => boolean; onSortChange: (sort: string) => void; onUpdate: (data?: any) => void; orgSlug: Organization['slug']; query: string; queryCount: number; sort: string; selectedProjectSlug?: string; }; function ActionSet({ orgSlug, queryCount, query, allInQuerySelected, anySelected, multiSelected, issues, onUpdate, onShouldConfirm, onDelete, onMerge, selectedProjectSlug, sort, onSortChange, }: Props) { const numIssues = issues.size; const confirm = getConfirm(numIssues, allInQuerySelected, query, queryCount); const label = getLabel(numIssues, allInQuerySelected); // merges require a single project to be active in an org context // selectedProjectSlug is null when 0 or >1 projects are selected. const mergeDisabled = !(multiSelected && selectedProjectSlug); const selectedIssues = [...issues].map(GroupStore.get); const canMarkReviewed = anySelected && (allInQuerySelected || selectedIssues.some(issue => !!issue?.inbox)); // determine which ... dropdown options to show based on issue(s) selected const canAddBookmark = allInQuerySelected || selectedIssues.some(issue => !issue?.isBookmarked); const canRemoveBookmark = allInQuerySelected || selectedIssues.some(issue => issue?.isBookmarked); const canSetUnresolved = allInQuerySelected || selectedIssues.some(issue => issue?.status === 'resolved'); // Determine whether to nest "Merge" and "Mark as Reviewed" buttons inside // the dropdown menu based on the current screen size const theme = useTheme(); const nestMergeAndReview = useMedia(`(max-width: ${theme.breakpoints.xlarge})`); const menuItems: MenuItemProps[] = [ { key: 'merge', label: t('Merge'), hidden: !nestMergeAndReview, onAction: () => { openConfirmModal({ bypass: !onShouldConfirm(ConfirmAction.MERGE), onConfirm: onMerge, message: confirm(ConfirmAction.MERGE, false), confirmText: label('merge'), }); }, }, { key: 'mark-reviewed', label: t('Mark Reviewed'), hidden: !nestMergeAndReview, onAction: () => onUpdate({inbox: false}), }, { key: 'bookmark', label: t('Add to Bookmarks'), hidden: !canAddBookmark, onAction: () => { openConfirmModal({ bypass: !onShouldConfirm(ConfirmAction.BOOKMARK), onConfirm: () => onUpdate({isBookmarked: true}), message: confirm(ConfirmAction.BOOKMARK, false), confirmText: label('bookmark'), }); }, }, { key: 'remove-bookmark', label: t('Remove from Bookmarks'), hidden: !canRemoveBookmark, onAction: () => { openConfirmModal({ bypass: !onShouldConfirm(ConfirmAction.UNBOOKMARK), onConfirm: () => onUpdate({isBookmarked: false}), message: confirm('remove', false, ' from your bookmarks'), confirmText: label('remove', ' from your bookmarks'), }); }, }, { key: 'unresolve', label: t('Set status to: Unresolved'), hidden: !canSetUnresolved, onAction: () => { openConfirmModal({ bypass: !onShouldConfirm(ConfirmAction.UNRESOLVE), onConfirm: () => onUpdate({status: ResolutionStatus.UNRESOLVED}), message: confirm(ConfirmAction.UNRESOLVE, true), confirmText: label('unresolve'), }); }, }, { key: 'delete', label: t('Delete'), priority: 'danger', onAction: () => { openConfirmModal({ bypass: !onShouldConfirm(ConfirmAction.DELETE), onConfirm: onDelete, priority: 'danger', message: confirm(ConfirmAction.DELETE, false), confirmText: label('delete'), }); }, }, ]; const disabledMenuItems = [ ...(mergeDisabled ? ['merge'] : []), ...(canMarkReviewed ? [] : ['mark-reviewed']), ]; return ( {selectedProjectSlug ? ( {({projects, initiallyLoaded, fetchError}) => { const selectedProject = projects[0]; return ( ); }} ) : ( )} {!nestMergeAndReview && ( )} {!nestMergeAndReview && ( {t('Merge')} )} , showChevron: false, size: 'xs', }} disabledKeys={disabledMenuItems} isDisabled={!anySelected} /> ); } export default ActionSet; const Wrapper = styled('div')` @media (min-width: ${p => p.theme.breakpoints.small}) { width: 66.66%; } @media (min-width: ${p => p.theme.breakpoints.large}) { width: 50%; } flex: 1; margin: 0 ${space(1)}; display: grid; gap: ${space(0.5)}; grid-auto-flow: column; justify-content: flex-start; white-space: nowrap; `;