Make commit history easier to scan and review (#2146)

* feat(app): improve commit history and diff review

* fix(app): keep commit timestamps current

* fix(app): pause hidden commit clocks

* fix(app): reopen commit diff in persistence test
This commit is contained in:
Mohamed Boudra
2026-07-17 04:15:04 +08:00
committed by GitHub
parent 60855a0f3a
commit 737f30c339
6 changed files with 210 additions and 22 deletions
+71 -12
View File
@@ -1,10 +1,11 @@
import { useMemo } from "react";
import { useCallback, useMemo, type ReactNode } from "react";
import { Text, View } from "react-native";
import { useTranslation } from "react-i18next";
import { GitCommitHorizontal } from "lucide-react-native";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import invariant from "tiny-invariant";
import { useIsCompactFormFactor } from "@/constants/layout";
import { SegmentedControl } from "@/components/ui/segmented-control";
import { useIsCompactFormFactor, WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
import { isWeb } from "@/constants/platform";
import { useChangesPreferences } from "@/hooks/use-changes-preferences";
import { useAppSettings } from "@/hooks/use-settings";
@@ -22,7 +23,7 @@ function CommitDiffPanel() {
const { serverId, workspaceId, target } = usePaneContext();
const cwd = useWorkspaceDirectory(serverId, workspaceId);
const { settings } = useAppSettings();
const { preferences } = useChangesPreferences();
const { preferences, updatePreferences } = useChangesPreferences();
const isCompact = useIsCompactFormFactor();
invariant(target.kind === "commit_diff", "CommitDiffPanel requires commit_diff target");
@@ -32,7 +33,29 @@ function CommitDiffPanel() {
sha: target.sha,
enabled: Boolean(cwd),
});
const effectiveLayout = isWeb && !isCompact ? preferences.layout : "unified";
const canUseSplitLayout = isWeb && !isCompact;
const effectiveLayout = canUseSplitLayout ? preferences.layout : "unified";
const layoutOptions = useMemo(
() => [
{
value: "unified" as const,
label: t("workspace.git.diff.unified"),
testID: "commit-diff-layout-unified",
},
{
value: "split" as const,
label: t("workspace.git.diff.split"),
testID: "commit-diff-layout-split",
},
],
[t],
);
const handleLayoutChange = useCallback(
(layout: "unified" | "split") => {
void updatePreferences({ layout });
},
[updatePreferences],
);
const displayPreferences = useMemo(
() => ({
layout: effectiveLayout,
@@ -59,29 +82,47 @@ function CommitDiffPanel() {
</View>
);
}
let bodyContent: ReactNode;
if (error) {
return (
bodyContent = (
<View style={styles.centerState} testID="commit-diff-error">
<Text style={styles.errorText}>{t("panels.diff.loadError")}</Text>
</View>
);
}
if (isLoading && files.length === 0) {
return (
} else if (isLoading && files.length === 0) {
bodyContent = (
<View style={styles.centerState} testID="commit-diff-loading">
<Text style={styles.mutedText}>{t("workspace.tabs.loading")}</Text>
</View>
);
}
if (files.length === 0) {
return (
} else if (files.length === 0) {
bodyContent = (
<View style={styles.centerState} testID="commit-diff-empty">
<Text style={styles.mutedText}>{t("panels.diff.empty")}</Text>
</View>
);
} else {
bodyContent = (
<SharedDiffView files={files} displayPreferences={displayPreferences} mode={commitMode} />
);
}
return <SharedDiffView files={files} displayPreferences={displayPreferences} mode={commitMode} />;
return (
<View style={styles.container} testID="commit-diff-panel">
{canUseSplitLayout ? (
<View style={styles.toolbar} testID="commit-diff-toolbar">
<SegmentedControl
options={layoutOptions}
value={preferences.layout}
onValueChange={handleLayoutChange}
size="sm"
testID="commit-diff-layout-control"
/>
</View>
) : null}
<View style={styles.body}>{bodyContent}</View>
</View>
);
}
function useCommitDiffPanelDescriptor(
@@ -104,6 +145,24 @@ export const commitDiffPanelRegistration: PanelRegistration<"commit_diff"> = {
};
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
minHeight: 0,
},
toolbar: {
height: WORKSPACE_SECONDARY_HEADER_HEIGHT,
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-end",
paddingHorizontal: theme.spacing[3],
borderBottomWidth: theme.borderWidth[1],
borderBottomColor: theme.colors.border,
flexShrink: 0,
},
body: {
flex: 1,
minHeight: 0,
},
centerState: {
flex: 1,
alignItems: "center",