History

fix(mobile): shimmer active tool rows (#8932)

Julius Marminge committed 2 months agov0.0.38-nightly.20260831.1240

Commit 5ce92c21 parent 35da5813 files · +25 −7Browse files

Unified · Split

3 files
  1. apps/mobile/src/features/threads/thread-work-log.tsx +3 −2
  2. apps/mobile/src/lib/threadActivity.test.ts +20 −1
  3. apps/mobile/src/lib/threadActivity.ts +2 −4
apps/mobile/src/features/threads/thread-work-log.tsx+3−2
@@ -9,6 +9,7 @@ import { · 8 unmodified lines
9 type ColorValue,9 type ColorValue,
10 Pressable,10 Pressable,
11 ScrollView,11 ScrollView,
12 StyleSheet,
12 View,13 View,
13} from "react-native";14} from "react-native";
14import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";15import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";
@@ -143,7 +144,7 @@ function ShimmeringWorkContent(props: { · 128 unmodified lines
143 144
144 return (145 return (
145 <View146 <View
146 className="min-w-0 flex-1"147 className="min-w-0 flex-1 overflow-hidden"
147 onLayout={(event) => setAvailableWidth(event.nativeEvent.layout.width)}148 onLayout={(event) => setAvailableWidth(event.nativeEvent.layout.width)}
148 >149 >
149 <ShimmerWorkContent150 <ShimmerWorkContent
@@ -164,7 +165,7 @@ function ShimmeringWorkContent(props: { · 14 unmodified lines
164 style={[{ width: SHIMMER_WIDTH }, sweepStyle]}165 style={[{ width: SHIMMER_WIDTH }, sweepStyle]}
165 >166 >
166 <MaskedView167 <MaskedView
167 className="absolute inset-0"168 style={StyleSheet.absoluteFill}
168 maskElement={169 maskElement={
169 <Svg width="100%" height="100%">170 <Svg width="100%" height="100%">
170 <Defs>171 <Defs>
apps/mobile/src/lib/threadActivity.test.ts+20−1
@@ -942,8 +942,27 @@ describe("buildThreadFeed", () => { · 941 unmodified lines
942 summary: "Running pnpm",942 summary: "Running pnpm",
943 summaryKind: "command",943 summaryKind: "command",
944 live: true,944 live: true,
945 shimmer: false,945 shimmer: true,
946 });946 });
947 expect(rows[0]).toMatchObject({ live: false, shimmer: false });
948
949 const stoppedRows = deriveThreadFeedPresentation(feed, latestTurn, new Set());
950 expect(stoppedRows.filter((entry) => entry.type === "work-toggle")).toMatchObject([
951 { live: false, shimmer: false },
952 { live: false, shimmer: false },
953 ]);
954
955 const completedRows = deriveThreadFeedPresentation(
956 feed,
957 { ...latestTurn, state: "completed", completedAt: "2026-04-01T00:00:04.000Z" },
958 new Set([turnId]),
959 new Set(),
960 latestTurn.startedAt,
961 );
962 expect(completedRows.filter((entry) => entry.type === "work-toggle")).toMatchObject([
963 { live: false, shimmer: false },
964 { live: false, shimmer: false },
965 ]);
947 });966 });
948 967
949 it("does not revive cached in-progress tools after work stops", () => {968 it("does not revive cached in-progress tools after work stops", () => {
apps/mobile/src/lib/threadActivity.ts+2−4
@@ -1512,10 +1512,8 @@ function appendToolGroupRows( · 1511 unmodified lines
1512 ),1512 ),
1513 hasFailure: activities.findLast((activity) => activity.toolLike)?.status === "failure",1513 hasFailure: activities.findLast((activity) => activity.toolLike)?.status === "failure",
1514 live,1514 live,
1515 shimmer:1515 // Match the live label until the turn or contiguous tool run settles.
1516 isWorking &&1516 shimmer: live,
1517 latestActivity.lifecycleStatus === "inProgress" &&
1518 latestActivity.turnId === unsettledTurnId,
1519 });1517 });
1520 if (!expanded) {1518 if (!expanded) {
1521 return;1519 return;