fix: stabilize history diff loading and comments
Prevents History file loading from getting stuck Disables inline comments in History diffs Keeps review comments available in regular diff views
This commit is contained in:
@@ -610,6 +610,8 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
const [expandedCommitHashes, setExpandedCommitHashes] = React.useState<Set<string>>(new Set());
|
const [expandedCommitHashes, setExpandedCommitHashes] = React.useState<Set<string>>(new Set());
|
||||||
const [commitFilesMap, setCommitFilesMap] = React.useState<Map<string, CommitFileEntry[]>>(new Map());
|
const [commitFilesMap, setCommitFilesMap] = React.useState<Map<string, CommitFileEntry[]>>(new Map());
|
||||||
const [loadingCommitHashes, setLoadingCommitHashes] = React.useState<Set<string>>(new Set());
|
const [loadingCommitHashes, setLoadingCommitHashes] = React.useState<Set<string>>(new Set());
|
||||||
|
const commitFilesMapRef = React.useRef(commitFilesMap);
|
||||||
|
const loadingCommitHashesRef = React.useRef(loadingCommitHashes);
|
||||||
const [historyBranchDivider, setHistoryBranchDivider] = React.useState<HistoryBranchDivider>(null);
|
const [historyBranchDivider, setHistoryBranchDivider] = React.useState<HistoryBranchDivider>(null);
|
||||||
const [remoteUrl, setRemoteUrl] = React.useState<string | null>(null);
|
const [remoteUrl, setRemoteUrl] = React.useState<string | null>(null);
|
||||||
const [gitmojiSearch, setGitmojiSearch] = React.useState('');
|
const [gitmojiSearch, setGitmojiSearch] = React.useState('');
|
||||||
@@ -725,12 +727,20 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
commitFilesMapRef.current = commitFilesMap;
|
||||||
|
}, [commitFilesMap]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
loadingCommitHashesRef.current = loadingCommitHashes;
|
||||||
|
}, [loadingCommitHashes]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!currentDirectory || !git) return;
|
if (!currentDirectory || !git) return;
|
||||||
|
|
||||||
// Find hashes that are expanded but not yet loaded or loading
|
// Find hashes that are expanded but not yet loaded or loading
|
||||||
const hashesToLoad = Array.from(expandedCommitHashes).filter(
|
const hashesToLoad = Array.from(expandedCommitHashes).filter(
|
||||||
(hash) => !commitFilesMap.has(hash) && !loadingCommitHashes.has(hash)
|
(hash) => !commitFilesMapRef.current.has(hash) && !loadingCommitHashesRef.current.has(hash)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hashesToLoad.length === 0) return;
|
if (hashesToLoad.length === 0) return;
|
||||||
@@ -742,6 +752,7 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
for (const hash of hashesToLoad) {
|
for (const hash of hashesToLoad) {
|
||||||
next.add(hash);
|
next.add(hash);
|
||||||
}
|
}
|
||||||
|
loadingCommitHashesRef.current = next;
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -762,6 +773,7 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
for (const { hash, files } of results) {
|
for (const { hash, files } of results) {
|
||||||
next.set(hash, files);
|
next.set(hash, files);
|
||||||
}
|
}
|
||||||
|
commitFilesMapRef.current = next;
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
setLoadingCommitHashes((prev) => {
|
setLoadingCommitHashes((prev) => {
|
||||||
@@ -769,14 +781,29 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
for (const { hash } of results) {
|
for (const { hash } of results) {
|
||||||
next.delete(hash);
|
next.delete(hash);
|
||||||
}
|
}
|
||||||
|
loadingCommitHashesRef.current = next;
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
|
setLoadingCommitHashes((prev) => {
|
||||||
|
let changed = false;
|
||||||
|
const next = new Set(prev);
|
||||||
|
for (const hash of hashesToLoad) {
|
||||||
|
if (next.delete(hash)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!changed) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
loadingCommitHashesRef.current = next;
|
||||||
|
return next;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}, [expandedCommitHashes, currentDirectory, git, commitFilesMap, loadingCommitHashes]);
|
}, [expandedCommitHashes, currentDirectory, git]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!currentDirectory) return;
|
if (!currentDirectory) return;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ interface PierreDiffViewerProps {
|
|||||||
renderSideBySide: boolean;
|
renderSideBySide: boolean;
|
||||||
wrapLines?: boolean;
|
wrapLines?: boolean;
|
||||||
layout?: 'fill' | 'inline';
|
layout?: 'fill' | 'inline';
|
||||||
|
enableComments?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -468,6 +469,7 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
renderSideBySide,
|
renderSideBySide,
|
||||||
wrapLines,
|
wrapLines,
|
||||||
layout = 'fill',
|
layout = 'fill',
|
||||||
|
enableComments = true,
|
||||||
}) => {
|
}) => {
|
||||||
const themeContext = useOptionalThemeSystem();
|
const themeContext = useOptionalThemeSystem();
|
||||||
|
|
||||||
@@ -528,6 +530,10 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
}, [commentText]);
|
}, [commentText]);
|
||||||
|
|
||||||
const handleSelectionChange = useCallback((range: SelectedLineRange | null) => {
|
const handleSelectionChange = useCallback((range: SelectedLineRange | null) => {
|
||||||
|
if (!enableComments) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore callbacks while we're programmatically applying selection
|
// Ignore callbacks while we're programmatically applying selection
|
||||||
if (isApplyingSelectionRef.current) {
|
if (isApplyingSelectionRef.current) {
|
||||||
return;
|
return;
|
||||||
@@ -554,7 +560,7 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
setCommentText('');
|
setCommentText('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isMobile, setCommentText, setSelection]);
|
}, [enableComments, isMobile, setCommentText, setSelection]);
|
||||||
|
|
||||||
const handleCancelComment = useCallback(() => {
|
const handleCancelComment = useCallback(() => {
|
||||||
cancel();
|
cancel();
|
||||||
@@ -751,21 +757,25 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
expansionLineCount: 20,
|
expansionLineCount: 20,
|
||||||
overflow: wrapLines ? ('wrap' as const) : ('scroll' as const),
|
overflow: wrapLines ? ('wrap' as const) : ('scroll' as const),
|
||||||
disableFileHeader: true,
|
disableFileHeader: true,
|
||||||
enableLineSelection: true,
|
enableLineSelection: enableComments,
|
||||||
enableHoverUtility: false,
|
enableHoverUtility: false,
|
||||||
onLineSelected: handleSelectionChange,
|
onLineSelected: enableComments ? handleSelectionChange : undefined,
|
||||||
unsafeCSS: WEBKIT_SCROLL_FIX_CSS,
|
unsafeCSS: WEBKIT_SCROLL_FIX_CSS,
|
||||||
renderAnnotation,
|
renderAnnotation: enableComments ? renderAnnotation : undefined,
|
||||||
}), [darkTheme.metadata.id, isDark, isLargeContent, lightTheme.metadata.id, renderSideBySide, wrapLines, handleSelectionChange, renderAnnotation]);
|
}), [darkTheme.metadata.id, enableComments, isDark, isLargeContent, lightTheme.metadata.id, renderSideBySide, wrapLines, handleSelectionChange, renderAnnotation]);
|
||||||
|
|
||||||
|
|
||||||
const lineAnnotations = useMemo(() => {
|
const lineAnnotations = useMemo(() => {
|
||||||
|
if (!enableComments) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return buildPierreLineAnnotations({
|
return buildPierreLineAnnotations({
|
||||||
drafts: fileDrafts,
|
drafts: fileDrafts,
|
||||||
editingDraftId,
|
editingDraftId,
|
||||||
selection,
|
selection,
|
||||||
});
|
});
|
||||||
}, [editingDraftId, fileDrafts, selection]);
|
}, [editingDraftId, enableComments, fileDrafts, selection]);
|
||||||
|
|
||||||
const lineAnnotationsRef = useRef(lineAnnotations);
|
const lineAnnotationsRef = useRef(lineAnnotations);
|
||||||
|
|
||||||
@@ -958,6 +968,8 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
}, [selection]);
|
}, [selection]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!enableComments) return;
|
||||||
|
|
||||||
const container = diffContainerRef.current;
|
const container = diffContainerRef.current;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
@@ -1009,7 +1021,7 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
}
|
}
|
||||||
cleanup();
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [diffThemeKey, fileName, handleSelectionChange, resolveClickedSide]);
|
}, [diffThemeKey, enableComments, fileName, handleSelectionChange, resolveClickedSide]);
|
||||||
|
|
||||||
// MutationObserver to trigger re-renders when annotation DOM nodes are added/removed
|
// MutationObserver to trigger re-renders when annotation DOM nodes are added/removed
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1052,7 +1064,7 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const commentOverlays = (
|
const commentOverlays = enableComments ? (
|
||||||
<PierreDiffCommentOverlays
|
<PierreDiffCommentOverlays
|
||||||
diffRootRef={diffRootRef}
|
diffRootRef={diffRootRef}
|
||||||
drafts={fileDrafts}
|
drafts={fileDrafts}
|
||||||
@@ -1073,7 +1085,7 @@ export const PierreDiffViewer: React.FC<PierreDiffViewerProps> = ({
|
|||||||
}}
|
}}
|
||||||
onDelete={deleteDraft}
|
onDelete={deleteDraft}
|
||||||
/>
|
/>
|
||||||
);
|
) : null;
|
||||||
|
|
||||||
if (layout === 'fill') {
|
if (layout === 'fill') {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -660,10 +660,11 @@ export const HistoryCommitRow = React.memo(({
|
|||||||
original={cached.original}
|
original={cached.original}
|
||||||
modified={cached.modified}
|
modified={cached.modified}
|
||||||
language={getLanguageFromExtension(file.path) || ''}
|
language={getLanguageFromExtension(file.path) || ''}
|
||||||
fileName={file.path}
|
fileName={file.path}
|
||||||
renderSideBySide={false}
|
renderSideBySide={false}
|
||||||
layout="inline"
|
layout="inline"
|
||||||
/>
|
enableComments={false}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user