@@ -32,7 +32,7 @@ import { Spinner } from "~/components/primitives/Spinner";
3232import { Paragraph } from "~/components/primitives/Paragraph" ;
3333import { Callout } from "~/components/primitives/Callout" ;
3434import { Header1 , Header2 , Header3 } from "~/components/primitives/Headers" ;
35- import { formatDistanceToNow } from "date-fns" ;
35+ import { formatDistanceToNow , isPast } from "date-fns" ;
3636import { formatNumberCompact } from "~/utils/numberFormatter" ;
3737import * as Property from "~/components/primitives/PropertyTable" ;
3838import { TaskRunsTable } from "~/components/runs/v3/TaskRunsTable" ;
@@ -463,6 +463,8 @@ function ErrorGroupDetail({
463463 ) }
464464 </ Property . Table >
465465 </ div >
466+
467+ < IgnoredDetails state = { errorGroup . state } totalOccurrences = { errorGroup . count } />
466468 </ div >
467469
468470 { /* Activity chart */ }
@@ -563,6 +565,89 @@ function StatusBadge({ status }: { status: ErrorGroupState["status"] }) {
563565 ) ;
564566}
565567
568+ function IgnoredDetails ( {
569+ state,
570+ totalOccurrences,
571+ } : {
572+ state : ErrorGroupState ;
573+ totalOccurrences : number ;
574+ } ) {
575+ if ( state . status !== "IGNORED" ) {
576+ return null ;
577+ }
578+
579+ const hasConditions =
580+ state . ignoredUntil || state . ignoredUntilOccurrenceRate || state . ignoredUntilTotalOccurrences ;
581+
582+ const ignoredForever = ! hasConditions ;
583+
584+ const occurrencesSinceIgnore =
585+ state . ignoredUntilTotalOccurrences && state . ignoredAtOccurrenceCount !== null
586+ ? totalOccurrences - state . ignoredAtOccurrenceCount
587+ : null ;
588+
589+ return (
590+ < div className = "flex flex-col gap-1.5 rounded border border-text-dimmed/20 bg-text-dimmed/5 px-3 py-2.5 text-sm" >
591+ < div className = "flex items-center gap-2" >
592+ < span className = "font-medium text-text-bright" >
593+ { ignoredForever ? "Ignored permanently" : "Ignored with conditions" }
594+ </ span >
595+ { state . ignoredByUserDisplayName && (
596+ < span className = "text-text-dimmed" > by { state . ignoredByUserDisplayName } </ span >
597+ ) }
598+ { state . ignoredAt && (
599+ < span className = "text-text-dimmed" >
600+ < RelativeDateTime date = { state . ignoredAt } />
601+ </ span >
602+ ) }
603+ </ div >
604+
605+ { state . ignoredReason && (
606+ < div className = "text-text-dimmed" >
607+ Reason: < span className = "text-text-bright" > { state . ignoredReason } </ span >
608+ </ div >
609+ ) }
610+
611+ { hasConditions && (
612+ < div className = "flex flex-col gap-0.5 text-xs text-text-dimmed" >
613+ < span className = "font-medium text-text-bright/80" > Will unignore when:</ span >
614+ < ul className = "list-inside list-disc space-y-0.5 pl-1" >
615+ { state . ignoredUntil && (
616+ < li >
617+ Time expires:{ " " }
618+ < span className = "text-text-bright" >
619+ < DateTime date = { state . ignoredUntil } />
620+ </ span >
621+ { isPast ( state . ignoredUntil ) && < span className = "ml-1 text-warning" > (expired)</ span > }
622+ </ li >
623+ ) }
624+ { state . ignoredUntilOccurrenceRate !== null && state . ignoredUntilOccurrenceRate > 0 && (
625+ < li >
626+ Occurrence rate exceeds{ " " }
627+ < span className = "text-text-bright" > { state . ignoredUntilOccurrenceRate } /min</ span >
628+ </ li >
629+ ) }
630+ { state . ignoredUntilTotalOccurrences !== null &&
631+ state . ignoredUntilTotalOccurrences > 0 && (
632+ < li >
633+ Total occurrences exceed{ " " }
634+ < span className = "text-text-bright" >
635+ { state . ignoredUntilTotalOccurrences . toLocaleString ( ) }
636+ </ span >
637+ { occurrencesSinceIgnore !== null && (
638+ < span className = "ml-1 text-text-dimmed" >
639+ ({ occurrencesSinceIgnore . toLocaleString ( ) } since ignored)
640+ </ span >
641+ ) }
642+ </ li >
643+ ) }
644+ </ ul >
645+ </ div >
646+ ) }
647+ </ div >
648+ ) ;
649+ }
650+
566651function ErrorGroupActionButtons ( {
567652 state,
568653 taskIdentifier,
0 commit comments