Files
paseo/packages/app/src/git/commits-section/commit-row.tsx
T
paseo-bot[bot]andMohamed Boudra 05874e289a Keep relative timestamps current in agent, schedule, and import-session rows (#5340)
* Keep relative timestamps current in agent, schedule, and import-session rows

Agent list rows, schedule rows, and import-session rows formatted their
"5m ago" labels once at render, so an idle row kept its first label until
something else re-rendered it. They now use useTimeAgo, which rides the
same shared ticker the sidebar and desktop tabs already use.

Closes #4625

* Say "just now" for the whole first minute so fresh labels stay honest

The shared ticker wakes once a minute, so a seconds label could only go
stale. The prose and compact formatters now share one age description,
and the schedule spec anchors its clock to the schedule's creation time.

* Run every cleanup in the schedule relative-time spec and name its steps

* Keep relative labels current with focused subscriptions

* Update usage card after relative-time hook rename

* Anchor import-session age spec to fixture time

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-09-28 18:00:54 +01:00

108 lines
2.9 KiB
TypeScript

import { memo, useCallback } from "react";
import { Pressable, Text, View, type PressableStateCallbackType } from "react-native";
import { StyleSheet } from "react-native-unistyles";
import { ThemedChevron, chevronColorMapping } from "@/git/themed-chevron";
import type { ClassifiedCheckoutCommit } from "@/git/use-commits-query";
import { CODE_SURFACE_DATASET } from "@/styles/code-surface";
import { useTimeAgo } from "@/hooks/use-time-ago";
import { CommitGraphNode } from "./commit-graph-node";
interface CommitRowProps {
commit: ClassifiedCheckoutCommit;
isFirst: boolean;
isLast: boolean;
onCommitPress: (sha: string) => void;
}
function commitRowPressableStyle({
hovered,
pressed,
}: PressableStateCallbackType & { hovered?: boolean }) {
return [styles.row, (Boolean(hovered) || pressed) && styles.rowActive];
}
export const CommitRow = memo(function CommitRow({
commit,
isFirst,
isLast,
onCommitPress,
}: CommitRowProps) {
const handlePress = useCallback(() => {
onCommitPress(commit.sha);
}, [commit.sha, onCommitPress]);
return (
<Pressable
accessibilityRole="button"
testID={`commit-row-${commit.shortSha}`}
onPress={handlePress}
style={commitRowPressableStyle}
>
<CommitGraphNode commit={commit} isFirst={isFirst} isLast={isLast} />
<View style={styles.commitDetails}>
<Text dataSet={CODE_SURFACE_DATASET} style={styles.shortSha} numberOfLines={1}>
{commit.shortSha}
</Text>
<Text style={styles.subject} numberOfLines={1}>
{commit.subject}
</Text>
</View>
<CommitTimestamp authorDate={commit.authorDate} />
<View style={styles.caret}>
<ThemedChevron size={14} uniProps={chevronColorMapping} />
</View>
</Pressable>
);
});
function CommitTimestamp({ authorDate }: { authorDate: string }) {
const label = useTimeAgo(new Date(authorDate));
return <Text style={styles.timestamp}>{label}</Text>;
}
const styles = StyleSheet.create((theme) => ({
row: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
paddingLeft: theme.spacing[2],
paddingRight: theme.spacing[2],
paddingVertical: theme.spacing[1],
},
rowActive: {
backgroundColor: theme.colors.surfaceSidebarHover,
},
commitDetails: {
flex: 1,
minWidth: 0,
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[1],
},
shortSha: {
fontSize: theme.fontSize.sm,
fontFamily: theme.fontFamily.mono,
color: theme.colors.foregroundMuted,
width: 70,
flexShrink: 0,
},
subject: {
flex: 1,
minWidth: 0,
fontSize: theme.fontSize.base,
color: theme.colors.foreground,
},
timestamp: {
flexShrink: 0,
fontSize: theme.fontSize.sm,
color: theme.colors.foregroundMuted,
},
caret: {
width: 16,
height: 16,
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
},
}));