Skip to content

Commit 6561cf8

Browse files
authored
chore(top-issues): add more actions (#104467)
Add resolve, archive, and dismiss to clusters. Dismiss intentionally doesn't do anything here yet.
1 parent 4eaa6d1 commit 6561cf8

File tree

1 file changed

+98
-6
lines changed

1 file changed

+98
-6
lines changed

static/app/views/issueList/pages/dynamicGrouping.tsx

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import {Fragment, useMemo, useState} from 'react';
1+
import {Fragment, useCallback, useMemo, useState} from 'react';
22
import styled from '@emotion/styled';
33

44
import {Tag} from '@sentry/scraps/badge';
55
import {Container, Flex} from '@sentry/scraps/layout';
66
import {Heading, Text} from '@sentry/scraps/text';
77

8+
import {bulkUpdate} from 'sentry/actionCreators/group';
9+
import {openConfirmModal} from 'sentry/components/confirm';
810
import {Button} from 'sentry/components/core/button';
911
import {ButtonBar} from 'sentry/components/core/button/buttonBar';
1012
import {Checkbox} from 'sentry/components/core/checkbox';
@@ -31,6 +33,7 @@ import {
3133
IconClock,
3234
IconClose,
3335
IconCopy,
36+
IconEllipsis,
3437
IconFire,
3538
IconFix,
3639
IconSeer,
@@ -40,8 +43,10 @@ import {
4043
import {t, tn} from 'sentry/locale';
4144
import {space} from 'sentry/styles/space';
4245
import type {Group} from 'sentry/types/group';
46+
import {GroupStatus, GroupSubstatus} from 'sentry/types/group';
4347
import {getMessage, getTitle} from 'sentry/utils/events';
4448
import {useApiQuery} from 'sentry/utils/queryClient';
49+
import useApi from 'sentry/utils/useApi';
4550
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
4651
import useOrganization from 'sentry/utils/useOrganization';
4752
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -361,7 +366,9 @@ function ClusterCard({
361366
onTagClick?: (tag: string) => void;
362367
selectedTags?: Set<string>;
363368
}) {
369+
const api = useApi();
364370
const organization = useOrganization();
371+
const {selection} = usePageFilters();
365372
const [showDescription, setShowDescription] = useState(false);
366373
const clusterStats = useClusterStats(cluster.group_ids);
367374
const {copy} = useCopyToClipboard();
@@ -379,9 +386,64 @@ function ClusterCard({
379386
copy(formatClusterInfoForClipboard(cluster));
380387
};
381388

389+
const handleResolve = useCallback(() => {
390+
openConfirmModal({
391+
header: t('Resolve All Issues in Cluster'),
392+
message: t(
393+
'Are you sure you want to resolve all %s issues in this cluster?.',
394+
cluster.group_ids.length
395+
),
396+
confirmText: t('Resolve All'),
397+
onConfirm: () => {
398+
bulkUpdate(
399+
api,
400+
{
401+
orgId: organization.slug,
402+
itemIds: cluster.group_ids.map(String),
403+
data: {status: GroupStatus.RESOLVED},
404+
project: selection.projects,
405+
environment: selection.environments,
406+
...selection.datetime,
407+
},
408+
{}
409+
);
410+
},
411+
});
412+
}, [api, cluster.group_ids, organization.slug, selection]);
413+
414+
const handleArchive = useCallback(() => {
415+
openConfirmModal({
416+
header: t('Archive All Issues in Cluster'),
417+
message: t(
418+
'Are you sure you want to archive all %s issues in this cluster?.',
419+
cluster.group_ids.length
420+
),
421+
confirmText: t('Archive All'),
422+
onConfirm: () => {
423+
bulkUpdate(
424+
api,
425+
{
426+
orgId: organization.slug,
427+
itemIds: cluster.group_ids.map(String),
428+
data: {
429+
status: GroupStatus.IGNORED,
430+
statusDetails: {},
431+
substatus: GroupSubstatus.ARCHIVED_UNTIL_ESCALATING,
432+
},
433+
project: selection.projects,
434+
environment: selection.environments,
435+
...selection.datetime,
436+
},
437+
{}
438+
);
439+
},
440+
});
441+
}, [api, cluster.group_ids, organization.slug, selection]);
442+
443+
const handleDismiss = () => {};
444+
382445
return (
383446
<CardContainer>
384-
{/* Zone 1: Title + Description (Primary Focus) */}
385447
<CardHeader>
386448
<ClusterTitle>{renderWithInlineCode(cluster.title)}</ClusterTitle>
387449
<ClusterTags
@@ -392,7 +454,12 @@ function ClusterCard({
392454
{cluster.description && (
393455
<Fragment>
394456
{showDescription ? (
395-
<DescriptionText>{cluster.description}</DescriptionText>
457+
<Fragment>
458+
<DescriptionText>{cluster.description}</DescriptionText>
459+
<ReadMoreButton onClick={() => setShowDescription(false)}>
460+
{t('Collapse summary')}
461+
</ReadMoreButton>
462+
</Fragment>
396463
) : (
397464
<ReadMoreButton onClick={() => setShowDescription(true)}>
398465
{t('View summary')}
@@ -402,7 +469,6 @@ function ClusterCard({
402469
)}
403470
</CardHeader>
404471

405-
{/* Zone 2: Stats (Secondary Context) */}
406472
<ClusterStatsBar>
407473
{cluster.fixability_score !== null && cluster.fixability_score !== undefined && (
408474
<StatItem>
@@ -469,7 +535,6 @@ function ClusterCard({
469535
)}
470536
</ClusterStatsBar>
471537

472-
{/* Zone 3: Nested Issues (Detail Content) */}
473538
<IssuesSection>
474539
<IssuesSectionHeader>
475540
<Text size="sm" bold uppercase>
@@ -481,7 +546,6 @@ function ClusterCard({
481546
</IssuesList>
482547
</IssuesSection>
483548

484-
{/* Zone 4: Actions (Tertiary) */}
485549
<CardFooter>
486550
<ButtonBar merged gap="0">
487551
<SeerButton
@@ -520,6 +584,34 @@ function ClusterCard({
520584
{t('View All Issues') + ` (${cluster.group_ids.length})`}
521585
</Button>
522586
</Link>
587+
<DropdownMenu
588+
items={[
589+
{
590+
key: 'resolve',
591+
label: t('Resolve All'),
592+
onAction: handleResolve,
593+
},
594+
{
595+
key: 'archive',
596+
label: t('Archive All'),
597+
onAction: handleArchive,
598+
},
599+
{
600+
key: 'dismiss',
601+
label: t('Dismiss'),
602+
onAction: handleDismiss,
603+
},
604+
]}
605+
trigger={triggerProps => (
606+
<Button
607+
{...triggerProps}
608+
size="sm"
609+
icon={<IconEllipsis size="sm" />}
610+
aria-label={t('More actions')}
611+
/>
612+
)}
613+
position="bottom-end"
614+
/>
523615
</CardFooter>
524616
</CardContainer>
525617
);

0 commit comments

Comments
 (0)