Skip to content

Commit 4e3e10a

Browse files
authored
feat(dynamic-grouping): Allow disabling of filters in top group demo, add tags (#104037)
allows disabling sorting / filters brings back tags
1 parent 2d2754b commit 4e3e10a

File tree

1 file changed

+119
-91
lines changed

1 file changed

+119
-91
lines changed

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

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

4+
import {Tag} from '@sentry/scraps/badge';
45
import {Container, Flex} from '@sentry/scraps/layout';
56
import {Heading, Text} from '@sentry/scraps/text';
67

@@ -243,6 +244,13 @@ function ClusterCard({
243244
)}
244245
</Fragment>
245246
)}
247+
{cluster.tags && cluster.tags.length > 0 && (
248+
<Flex wrap="wrap" gap="xs">
249+
{cluster.tags.map(tag => (
250+
<Tag key={tag}>{tag}</Tag>
251+
))}
252+
</Flex>
253+
)}
246254
</Flex>
247255
<IssueCountBadge>
248256
<IssueCountNumber>{issueCount}</IssueCountNumber>
@@ -346,6 +354,7 @@ function DynamicGrouping() {
346354
null
347355
);
348356
const [jsonError, setJsonError] = useState<string | null>(null);
357+
const [disableFilters, setDisableFilters] = useState(false);
349358

350359
// Fetch cluster data from API
351360
const {data: topIssuesResponse, isPending} = useApiQuery<TopIssuesResponse>(
@@ -377,6 +386,7 @@ function DynamicGrouping() {
377386
setCustomClusterData(null);
378387
setJsonInputValue('');
379388
setJsonError(null);
389+
setDisableFilters(false);
380390
}, []);
381391

382392
const clusterData = customClusterData ?? topIssuesResponse?.data ?? [];
@@ -419,32 +429,36 @@ function DynamicGrouping() {
419429
setRemovedClusterIds(prev => new Set([...prev, clusterId]));
420430
};
421431

422-
const filteredAndSortedClusters = clusterData
423-
.filter(cluster => {
424-
if (removedClusterIds.has(cluster.cluster_id)) return false;
425-
426-
const fixabilityScore = (cluster.fixability_score ?? 0) * 100;
427-
if (fixabilityScore < minFixabilityScore) return false;
428-
429-
if (filterByAssignedToMe) {
430-
if (!cluster.assignedTo?.length) return false;
431-
return cluster.assignedTo.some(
432-
entity =>
433-
(entity.type === 'user' && entity.id === user.id) ||
434-
(entity.type === 'team' && userTeams.some(team => team.id === entity.id))
435-
);
436-
}
437-
438-
if (isTeamFilterActive) {
439-
if (!cluster.assignedTo?.length) return false;
440-
return cluster.assignedTo.some(
441-
entity => entity.type === 'team' && selectedTeamIds.has(entity.id)
442-
);
443-
}
444-
445-
return true;
446-
})
447-
.sort((a, b) => (b.fixability_score ?? 0) - (a.fixability_score ?? 0));
432+
// When using custom JSON data with filters disabled, skip all filtering and sorting
433+
const shouldSkipFilters = isUsingCustomData && disableFilters;
434+
const filteredAndSortedClusters = shouldSkipFilters
435+
? clusterData.filter(cluster => !removedClusterIds.has(cluster.cluster_id))
436+
: clusterData
437+
.filter(cluster => {
438+
if (removedClusterIds.has(cluster.cluster_id)) return false;
439+
440+
const fixabilityScore = (cluster.fixability_score ?? 0) * 100;
441+
if (fixabilityScore < minFixabilityScore) return false;
442+
443+
if (filterByAssignedToMe) {
444+
if (!cluster.assignedTo?.length) return false;
445+
return cluster.assignedTo.some(
446+
entity =>
447+
(entity.type === 'user' && entity.id === user.id) ||
448+
(entity.type === 'team' && userTeams.some(team => team.id === entity.id))
449+
);
450+
}
451+
452+
if (isTeamFilterActive) {
453+
if (!cluster.assignedTo?.length) return false;
454+
return cluster.assignedTo.some(
455+
entity => entity.type === 'team' && selectedTeamIds.has(entity.id)
456+
);
457+
}
458+
459+
return true;
460+
})
461+
.sort((a, b) => (b.fixability_score ?? 0) - (a.fixability_score ?? 0));
448462

449463
const totalIssues = filteredAndSortedClusters.flatMap(c => c.group_ids).length;
450464

@@ -506,6 +520,17 @@ function DynamicGrouping() {
506520
{jsonError}
507521
</Text>
508522
)}
523+
<Flex gap="sm" align="center" style={{marginTop: space(1.5)}}>
524+
<Checkbox
525+
checked={disableFilters}
526+
onChange={e => setDisableFilters(e.target.checked)}
527+
aria-label={t('Disable filters and sorting')}
528+
size="sm"
529+
/>
530+
<Text size="sm" variant="muted">
531+
{t('Disable filters and sorting')}
532+
</Text>
533+
</Flex>
509534
<Flex gap="sm" style={{marginTop: space(1)}}>
510535
<Button size="sm" priority="primary" onClick={handleParseJson}>
511536
{t('Parse and Load')}
@@ -532,77 +557,80 @@ function DynamicGrouping() {
532557
totalIssues,
533558
filteredAndSortedClusters.length
534559
)}
560+
{shouldSkipFilters && ` ${t('(filters disabled)')}`}
535561
</Text>
536562

537-
<Container
538-
padding="sm"
539-
border="primary"
540-
radius="md"
541-
background="primary"
542-
marginTop="md"
543-
>
544-
<Disclosure>
545-
<Disclosure.Title>
546-
<Text size="sm" bold>
547-
{t('More Filters')}
548-
</Text>
549-
</Disclosure.Title>
550-
<Disclosure.Content>
551-
<Flex direction="column" gap="md" paddingTop="md">
552-
<Flex gap="sm" align="center">
553-
<Checkbox
554-
checked={filterByAssignedToMe}
555-
onChange={e => handleAssignedToMeChange(e.target.checked)}
556-
aria-label={t('Show only issues assigned to me')}
557-
size="sm"
558-
disabled={isTeamFilterActive}
559-
/>
560-
<FilterLabel disabled={isTeamFilterActive}>
561-
{t('Only show issues assigned to me')}
562-
</FilterLabel>
563-
</Flex>
564-
565-
{teamsInData.length > 0 && (
566-
<Flex direction="column" gap="sm">
567-
<FilterLabel disabled={filterByAssignedToMe}>
568-
{t('Filter by teams')}
563+
{!shouldSkipFilters && (
564+
<Container
565+
padding="sm"
566+
border="primary"
567+
radius="md"
568+
background="primary"
569+
marginTop="md"
570+
>
571+
<Disclosure>
572+
<Disclosure.Title>
573+
<Text size="sm" bold>
574+
{t('More Filters')}
575+
</Text>
576+
</Disclosure.Title>
577+
<Disclosure.Content>
578+
<Flex direction="column" gap="md" paddingTop="md">
579+
<Flex gap="sm" align="center">
580+
<Checkbox
581+
checked={filterByAssignedToMe}
582+
onChange={e => handleAssignedToMeChange(e.target.checked)}
583+
aria-label={t('Show only issues assigned to me')}
584+
size="sm"
585+
disabled={isTeamFilterActive}
586+
/>
587+
<FilterLabel disabled={isTeamFilterActive}>
588+
{t('Only show issues assigned to me')}
569589
</FilterLabel>
570-
<Flex direction="column" gap="xs" style={{paddingLeft: 8}}>
571-
{teamsInData.map(team => (
572-
<Flex key={team.id} gap="sm" align="center">
573-
<Checkbox
574-
checked={selectedTeamIds.has(team.id)}
575-
onChange={() => handleTeamToggle(team.id)}
576-
aria-label={t('Filter by team %s', team.name)}
577-
size="sm"
578-
disabled={filterByAssignedToMe}
579-
/>
580-
<FilterLabel disabled={filterByAssignedToMe}>
581-
#{team.name}
582-
</FilterLabel>
583-
</Flex>
584-
))}
590+
</Flex>
591+
592+
{teamsInData.length > 0 && (
593+
<Flex direction="column" gap="sm">
594+
<FilterLabel disabled={filterByAssignedToMe}>
595+
{t('Filter by teams')}
596+
</FilterLabel>
597+
<Flex direction="column" gap="xs" style={{paddingLeft: 8}}>
598+
{teamsInData.map(team => (
599+
<Flex key={team.id} gap="sm" align="center">
600+
<Checkbox
601+
checked={selectedTeamIds.has(team.id)}
602+
onChange={() => handleTeamToggle(team.id)}
603+
aria-label={t('Filter by team %s', team.name)}
604+
size="sm"
605+
disabled={filterByAssignedToMe}
606+
/>
607+
<FilterLabel disabled={filterByAssignedToMe}>
608+
#{team.name}
609+
</FilterLabel>
610+
</Flex>
611+
))}
612+
</Flex>
585613
</Flex>
614+
)}
615+
616+
<Flex gap="sm" align="center">
617+
<Text size="sm" variant="muted">
618+
{t('Minimum fixability score (%)')}
619+
</Text>
620+
<NumberInput
621+
min={0}
622+
max={100}
623+
value={minFixabilityScore}
624+
onChange={value => setMinFixabilityScore(value ?? 0)}
625+
aria-label={t('Minimum fixability score')}
626+
size="sm"
627+
/>
586628
</Flex>
587-
)}
588-
589-
<Flex gap="sm" align="center">
590-
<Text size="sm" variant="muted">
591-
{t('Minimum fixability score (%)')}
592-
</Text>
593-
<NumberInput
594-
min={0}
595-
max={100}
596-
value={minFixabilityScore}
597-
onChange={value => setMinFixabilityScore(value ?? 0)}
598-
aria-label={t('Minimum fixability score')}
599-
size="sm"
600-
/>
601629
</Flex>
602-
</Flex>
603-
</Disclosure.Content>
604-
</Disclosure>
605-
</Container>
630+
</Disclosure.Content>
631+
</Disclosure>
632+
</Container>
633+
)}
606634
</Fragment>
607635
)}
608636
</HeaderSection>

0 commit comments

Comments
 (0)