@@ -595,34 +595,36 @@ private fun LiveFeedSheet(
595595 BuddyButtonText (" Start Recording" )
596596 }
597597 Text (
598- " Recent useful signals " ,
598+ " Live feed " ,
599599 style = MaterialTheme .typography.titleMedium,
600600 fontWeight = FontWeight .Bold ,
601601 color = BuddyInk ,
602602 )
603603 if (liveFeed.items.isEmpty()) {
604604 EmptyLiveFeedCard ()
605605 } else {
606- LiveFeedRows (liveFeed.items, sentryUiLinks, nowMs)
606+ LiveFeedRows (liveFeed.items.take( LIVE_FEED_VISIBLE_ITEM_LIMIT ) , sentryUiLinks, nowMs)
607607 }
608608}
609609
610610@Composable
611611private fun AttentionCard (liveFeed : BuddyLiveFeed , sentryUiLinks : BuddySentryUiLinks , nowMs : Long ) {
612+ Text (
613+ " Needs attention" ,
614+ style = MaterialTheme .typography.titleMedium,
615+ fontWeight = FontWeight .Bold ,
616+ color = BuddyInk ,
617+ )
618+
612619 val item = liveFeed.latestAdverseItem
613620 if (item == null ) {
614- Card (border = CardDefaults .outlinedCardBorder()) {
615- Row (
616- modifier = Modifier .fillMaxWidth().padding(16 .dp),
617- horizontalArrangement = Arrangement .SpaceBetween ,
618- verticalAlignment = Alignment .CenterVertically ,
619- ) {
620- Column (verticalArrangement = Arrangement .spacedBy(4 .dp)) {
621- Text (" Needs attention" , color = BuddyInk , fontWeight = FontWeight .Bold )
622- Text (" No recent errors or slow spans." , color = BuddyMuted )
623- }
624- Text (" OK" , color = BuddyPurple , fontWeight = FontWeight .Bold )
625- }
621+ Row (
622+ modifier = Modifier .fillMaxWidth().padding(vertical = 6 .dp),
623+ horizontalArrangement = Arrangement .SpaceBetween ,
624+ verticalAlignment = Alignment .CenterVertically ,
625+ ) {
626+ Text (" No recent errors or slow spans." , color = BuddyMuted )
627+ Text (" OK" , color = BuddyPurple , fontWeight = FontWeight .Bold )
626628 }
627629 return
628630 }
@@ -634,34 +636,36 @@ private fun AttentionCard(liveFeed: BuddyLiveFeed, sentryUiLinks: BuddySentryUiL
634636 modifier =
635637 Modifier .clickable(enabled = link != null ) { link?.let { openSentryLink(context, it) } },
636638 colors = CardDefaults .cardColors(containerColor = color.copy(alpha = 0.10f )),
637- border = CardDefaults .outlinedCardBorder(),
638639 ) {
639640 Column (
640641 modifier = Modifier .fillMaxWidth().padding(16 .dp),
641642 verticalArrangement = Arrangement .spacedBy(10 .dp),
642643 ) {
643644 Row (
645+ modifier = Modifier .fillMaxWidth(),
644646 horizontalArrangement = Arrangement .spacedBy(10 .dp),
645647 verticalAlignment = Alignment .CenterVertically ,
646648 ) {
647- Box (modifier = Modifier .size(10 .dp).background(color, CircleShape ))
648- Text (" Needs attention" , color = BuddyInk , fontWeight = FontWeight .Bold )
649- Text (relativeTime(item.timestamp.time, nowMs), color = BuddyMuted )
650- }
651- Text (
652- item.title(),
653- color = BuddyInk ,
654- style = MaterialTheme .typography.titleMedium,
655- fontWeight = FontWeight .Bold ,
656- )
657- item.subtitle()?.let { Text (it, color = BuddyMuted ) }
658- if (link != null ) {
649+ LiveFeedCategoryPill (item.category.label, color)
659650 Text (
660- " Open in Sentry" ,
661- color = BuddyPurple ,
662- style = MaterialTheme .typography.labelMedium,
651+ item.title(),
652+ modifier = Modifier .weight(1f ),
653+ color = BuddyInk ,
654+ style = MaterialTheme .typography.titleMedium,
663655 fontWeight = FontWeight .Bold ,
664656 )
657+ Text (
658+ relativeTime(item.timestamp.time, nowMs),
659+ color = BuddyMuted ,
660+ style = MaterialTheme .typography.labelMedium,
661+ )
662+ }
663+ item.screenContextText()?.let { screenContext ->
664+ Text (
665+ screenContext,
666+ color = BuddyMuted ,
667+ style = MaterialTheme .typography.bodySmall,
668+ )
665669 }
666670 Row (horizontalArrangement = Arrangement .spacedBy(8 .dp)) {
667671 adverseCountChips(liveFeed).forEach { chip ->
@@ -707,29 +711,26 @@ private fun LiveFeedRows(
707711 val color =
708712 if (item.adverse) severityColor(item.severity) else timelineColor(item.timelineItem)
709713 val link = sentryUiLinks.linkFor(item)
710- Card (
714+ Row (
711715 modifier =
712- Modifier .clickable(enabled = link != null ) { link?.let { openSentryLink(context, it) } },
713- border = CardDefaults .outlinedCardBorder(),
716+ Modifier .fillMaxWidth()
717+ .clickable(enabled = link != null ) { link?.let { openSentryLink(context, it) } }
718+ .padding(vertical = 7 .dp),
719+ horizontalArrangement = Arrangement .spacedBy(10 .dp),
720+ verticalAlignment = Alignment .CenterVertically ,
714721 ) {
715- Row (
716- modifier = Modifier .fillMaxWidth().padding(14 .dp),
717- horizontalArrangement = Arrangement .spacedBy(10 .dp),
718- verticalAlignment = Alignment .CenterVertically ,
719- ) {
720- LiveFeedCategoryPill (item.category.label, color)
721- Text (
722- item.title(),
723- modifier = Modifier .weight(1f ),
724- color = BuddyInk ,
725- fontWeight = FontWeight .Bold ,
726- )
727- Text (
728- relativeTime(item.timestamp.time, nowMs),
729- color = BuddyMuted ,
730- style = MaterialTheme .typography.labelMedium,
731- )
732- }
722+ LiveFeedCategoryPill (item.category.label, color)
723+ Text (
724+ item.title(),
725+ modifier = Modifier .weight(1f ),
726+ color = BuddyInk ,
727+ fontWeight = if (item.adverse) FontWeight .Bold else FontWeight .Normal ,
728+ )
729+ Text (
730+ relativeTime(item.timestamp.time, nowMs),
731+ color = BuddyMuted ,
732+ style = MaterialTheme .typography.labelMedium,
733+ )
733734 }
734735 }
735736 }
@@ -1035,45 +1036,21 @@ private fun BuddyLiveFeedItem.title(): String =
10351036 BuddyLiveFeedItem .Category .FAILED_SPAN -> timelineItem.name ? : " Failed span"
10361037 }
10371038
1038- private fun BuddyLiveFeedItem.subtitle (): String? =
1039- when (category) {
1040- BuddyLiveFeedItem .Category .SCREEN -> null
1041- BuddyLiveFeedItem .Category .STEP -> null
1042- BuddyLiveFeedItem .Category .ERROR ->
1043- listOfNotNull(
1044- timelineItem.data.stringValue(" message" ),
1045- timelineItem.data.stringValue(" transaction" )?.let { " in $it " },
1046- )
1047- .joinToString(" • " )
1048- .ifBlank { null }
1049- BuddyLiveFeedItem .Category .FAILED_HTTP -> httpSubtitle()
1050- BuddyLiveFeedItem .Category .SLOW_SPAN ,
1051- BuddyLiveFeedItem .Category .FAILED_SPAN -> spanSubtitle()
1052- }
1053-
10541039private fun BuddyLiveFeedItem.httpTitle (): String {
10551040 val data = timelineItem.data.mapValue(" data" )
10561041 val method = data.stringValue(" method" ) ? : data.stringValue(" http.method" )
10571042 val url = data.stringValue(" url" ) ? : data.stringValue(" http.url" )
10581043 return listOfNotNull(method, url).joinToString(" " ).ifBlank { timelineItem.name ? : " Failed HTTP" }
10591044}
10601045
1061- private fun BuddyLiveFeedItem.httpSubtitle (): String? {
1062- val data = timelineItem.data.mapValue(" data" )
1063- val statusCode = data.longValue(" status_code" ) ? : timelineItem.data.longValue(" status_code" )
1064- return statusCode?.let { " HTTP $it " }
1046+ private fun BuddyLiveFeedItem.screenContextText (): String? {
1047+ if (visibleScreens.isEmpty()) {
1048+ return null
1049+ }
1050+ val label = if (visibleScreens.size == 1 ) " Screen" else " Screens"
1051+ return " $label : ${visibleScreens.joinToString(" -> " )} "
10651052}
10661053
1067- private fun BuddyLiveFeedItem.spanSubtitle (): String? =
1068- listOfNotNull(
1069- timelineItem.data.stringValue(" op" ),
1070- timelineItem.data.stringValue(" status" )?.let { " status $it " },
1071- timelineItem.data.longValue(" duration_ms" )?.let { " ${it} ms" },
1072- timelineItem.data.stringValue(" transaction" )?.let { " in $it " },
1073- )
1074- .joinToString(" • " )
1075- .ifBlank { null }
1076-
10771054private fun relativeTime (timestampMs : Long , nowMs : Long ): String {
10781055 val ageMs = (nowMs - timestampMs).coerceAtLeast(0 )
10791056 if (ageMs < 1000 ) {
@@ -1400,6 +1377,7 @@ private val BuddyBubbleInitialTop = 96.dp
14001377private val BuddyBubbleTouchPadding = 20 .dp
14011378private val BuddyTransientTextWidth = 190 .dp
14021379private val BuddyTransientTextHeight = 28 .dp
1380+ private const val LIVE_FEED_VISIBLE_ITEM_LIMIT = 7
14031381private const val ANALYSIS_POLL_INTERVAL_MS = 1000L
14041382private const val ANALYSIS_TIMEOUT_MS = 30_000L
14051383
0 commit comments