feat: optimize file content resolution and enhance loading state handling
- Added a fast path in FileContentResolver to skip history lookup for files created by the agent with empty original content. - Improved loading state in FileSectionDiff to display a loading message and snippet preview when applicable. - Adjusted header content class names in ClaudeLogsSection and button styles in CollapsibleTeamSection for better UI consistency. - Refactored ContinuousScrollView to streamline rendering logic for file sections based on content availability.
This commit is contained in:
parent
05457aca0d
commit
b886b6bf83
5 changed files with 48 additions and 26 deletions
|
|
@ -74,6 +74,19 @@ export class FileContentResolver {
|
|||
logger.debug(`Файл недоступен на диске: ${filePath}`);
|
||||
}
|
||||
|
||||
// Fast path: if the agent created the file and it still exists on disk,
|
||||
// the original content is definitely empty, so skip expensive history lookup.
|
||||
const hasWriteNew = snippets.some((s) => !s.isError && s.type === 'write-new');
|
||||
if (hasWriteNew && currentContent !== null) {
|
||||
const result = {
|
||||
original: '',
|
||||
modified: currentContent,
|
||||
source: 'snippet-reconstruction' as const,
|
||||
};
|
||||
this.cacheResult(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Strategy 1: Try file-history backup
|
||||
const historyResult = await this.tryFileHistoryBackup(teamName, memberName, filePath);
|
||||
if (historyResult) {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export const ClaudeLogsSection = ({
|
|||
</Tooltip>
|
||||
) : undefined
|
||||
}
|
||||
headerContentClassName={isSidebar ? 'flex-wrap items-center gap-y-1 py-1 pr-3' : 'pr-3'}
|
||||
headerContentClassName={isSidebar ? 'flex-wrap items-center gap-y-1 py-1 pr-1' : 'pr-1'}
|
||||
headerExtra={sectionHeaderExtra}
|
||||
defaultOpen={false}
|
||||
contentClassName="pt-0 [overflow-anchor:none]"
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const CollapsibleTeamSection = ({
|
|||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`absolute inset-0 z-0 cursor-pointer transition-colors ${isOpen ? 'rounded-t-md bg-[var(--color-section-bg-open)] hover:bg-[var(--color-section-hover-open)]' : 'rounded-md bg-[var(--color-section-bg)] hover:bg-[var(--color-section-hover)]'}`}
|
||||
className={`absolute inset-0 z-0 cursor-pointer transition-colors ${isOpen ? 'rounded-t-xl bg-[var(--color-section-bg-open)] hover:bg-[var(--color-section-hover-open)]' : 'rounded-xl bg-[var(--color-section-bg)] hover:bg-[var(--color-section-hover)]'}`}
|
||||
onClick={() =>
|
||||
setOpen((prev) => {
|
||||
const next = !prev;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
} from './CodeMirrorDiffUtils';
|
||||
import { FileSectionDiff } from './FileSectionDiff';
|
||||
import { FileSectionHeader } from './FileSectionHeader';
|
||||
import { FileSectionPlaceholder } from './FileSectionPlaceholder';
|
||||
|
||||
import type { EditorView } from '@codemirror/view';
|
||||
import type { FileChangeWithContent, HunkDecision } from '@shared/types';
|
||||
|
|
@ -256,28 +255,25 @@ export const ContinuousScrollView = ({
|
|||
onRestoreMissingFile={onRestoreMissingFile}
|
||||
/>
|
||||
|
||||
{!isCollapsed &&
|
||||
(hasContent ? (
|
||||
<FileSectionDiff
|
||||
file={file}
|
||||
fileContent={content}
|
||||
isLoading={false}
|
||||
collapseUnchanged={collapseUnchanged}
|
||||
onHunkAccepted={onHunkAccepted}
|
||||
onHunkRejected={onHunkRejected}
|
||||
onFullyViewed={onFullyViewed}
|
||||
onContentChanged={onContentChanged}
|
||||
onEditorViewReady={handleEditorViewReady}
|
||||
discardCounter={discardCounters[filePath] ?? 0}
|
||||
autoViewed={autoViewed}
|
||||
isViewed={isViewed}
|
||||
onSelectionChange={onSelectionChange}
|
||||
globalHunkOffset={globalHunkOffsets?.[filePath] ?? 0}
|
||||
totalReviewHunks={totalReviewHunks}
|
||||
/>
|
||||
) : (
|
||||
<FileSectionPlaceholder fileName={file.relativePath} />
|
||||
))}
|
||||
{!isCollapsed && (
|
||||
<FileSectionDiff
|
||||
file={file}
|
||||
fileContent={content}
|
||||
isLoading={!hasContent}
|
||||
collapseUnchanged={collapseUnchanged}
|
||||
onHunkAccepted={onHunkAccepted}
|
||||
onHunkRejected={onHunkRejected}
|
||||
onFullyViewed={onFullyViewed}
|
||||
onContentChanged={onContentChanged}
|
||||
onEditorViewReady={handleEditorViewReady}
|
||||
discardCounter={discardCounters[filePath] ?? 0}
|
||||
autoViewed={autoViewed}
|
||||
isViewed={isViewed}
|
||||
onSelectionChange={onSelectionChange}
|
||||
globalHunkOffset={globalHunkOffsets?.[filePath] ?? 0}
|
||||
totalReviewHunks={totalReviewHunks}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,20 @@ export const FileSectionDiff = ({
|
|||
|
||||
// Loading state
|
||||
if (isLoading) {
|
||||
return <FileSectionPlaceholder fileName={file.relativePath} />;
|
||||
const hasSnippetPreview = file.snippets.some((snippet) => !snippet.isError);
|
||||
if (!hasSnippetPreview) {
|
||||
return <FileSectionPlaceholder fileName={file.relativePath} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-auto">
|
||||
<div className="bg-surface-raised/40 border-b border-border px-4 py-2 text-xs text-text-muted">
|
||||
Loading full diff...
|
||||
</div>
|
||||
<ReviewDiffContent file={file} />
|
||||
<div ref={sentinelRef} className="h-1 shrink-0" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve modified content: prefer full content, fall back to write-type snippet
|
||||
|
|
|
|||
Loading…
Reference in a new issue