Skip to content

Commit 89b8ee9

Browse files
committed
优化
1 parent 9ed139c commit 89b8ee9

File tree

3 files changed

+55
-36
lines changed

3 files changed

+55
-36
lines changed

src/components/features/context/ContextView.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ const Row = memo(function Row({ index, style, data }: RowProps) {
6969
export function ContextView() {
7070
const { t } = useTranslation();
7171
const {
72-
projectRoot, fileTree, isScanning,
72+
fileTree, isScanning,
7373
projectIgnore, updateProjectIgnore,
7474
refreshTreeStatus,
75-
setProjectRoot, setFileTree, setIsScanning, toggleSelect,
75+
setFileTree, setIsScanning, toggleSelect,
7676
removeComments, detectSecrets, invertSelection,
7777
expandedIds, toggleExpand,
7878
hasProjectIgnoreFiles, isIgnoreSyncActive, toggleIgnoreSync, checkIgnoreFiles
@@ -82,7 +82,9 @@ export function ContextView() {
8282
isContextSidebarOpen, setContextSidebarOpen,
8383
contextSidebarWidth, setContextSidebarWidth,
8484
globalIgnore,
85-
models
85+
models,
86+
projectRoot: globalProjectRoot,
87+
setProjectRoot: setGlobalProjectRoot
8688
} = useAppStore();
8789

8890
const { openPreview } = usePreviewStore();
@@ -114,14 +116,15 @@ export function ContextView() {
114116
const activeModels = (models && models.length > 0) ? models : DEFAULT_MODELS;
115117

116118
useEffect(() => {
117-
if (projectRoot) setPathInput(projectRoot);
118-
}, [projectRoot]);
119+
// Sync global project root to local input
120+
if (globalProjectRoot) setPathInput(globalProjectRoot);
121+
}, [globalProjectRoot]);
119122

120123
useEffect(() => {
121-
if (projectRoot) {
124+
if (globalProjectRoot) {
122125
checkIgnoreFiles();
123126
}
124-
}, [projectRoot]);
127+
}, [globalProjectRoot]);
125128

126129
useEffect(() => {
127130
if (fileTree.length > 0) {
@@ -159,13 +162,13 @@ export function ContextView() {
159162
const getDefaultSavePath = async () => {
160163
let namePart = 'context';
161164

162-
if (projectRoot) {
165+
if (globalProjectRoot) {
163166
try {
164-
const base = await basename(projectRoot);
167+
const base = await basename(globalProjectRoot);
165168
if (base) namePart = base;
166169
} catch (e) {
167-
const separator = projectRoot.includes('\\') ? '\\' : '/';
168-
const cleanRoot = projectRoot.endsWith(separator) ? projectRoot.slice(0, -1) : projectRoot;
170+
const separator = globalProjectRoot.includes('\\') ? '\\' : '/';
171+
const cleanRoot = globalProjectRoot.endsWith(separator) ? globalProjectRoot.slice(0, -1) : globalProjectRoot;
169172
namePart = cleanRoot.split(separator).pop() || 'context';
170173
}
171174
}
@@ -339,7 +342,8 @@ export function ContextView() {
339342

340343
const tree = await scanProject(path, effectiveConfig);
341344
setFileTree(tree);
342-
await setProjectRoot(path);
345+
// setGlobalProjectRoot will automatically sync to useContextStore
346+
setGlobalProjectRoot(path);
343347
await checkIgnoreFiles();
344348

345349
const idealWidth = calculateIdealTreeWidth(tree);
@@ -357,6 +361,8 @@ export function ContextView() {
357361
const selected = await open({ directory: true, multiple: false, recursive: false });
358362
if (selected && typeof selected === 'string') {
359363
setPathInput(selected);
364+
// Update global project root - all components will receive this
365+
setGlobalProjectRoot(selected);
360366
await performScan(selected);
361367
}
362368
} catch (err) { }
@@ -404,15 +410,15 @@ export function ContextView() {
404410
onChange={(e) => setPathInput(e.target.value)}
405411
onKeyDown={handleKeyDown}
406412
/>
407-
{pathInput && pathInput !== projectRoot && (
413+
{pathInput && pathInput !== globalProjectRoot && (
408414
<button onClick={() => performScan(pathInput)} className="p-1 hover:bg-primary hover:text-primary-foreground rounded-sm transition-colors"><ArrowRight size={14} /></button>
409415
)}
410416
</div>
411417

412418
<button onClick={handleBrowse} className="flex items-center gap-2 px-3 py-1.5 bg-secondary hover:bg-secondary/80 border border-border rounded-md text-sm font-medium transition-colors whitespace-nowrap">
413419
<FolderOpen size={16} /><span>{t('context.browse')}</span>
414420
</button>
415-
<button onClick={() => performScan(projectRoot || '')} disabled={!projectRoot || isScanning} className="p-2 text-muted-foreground hover:text-foreground hover:bg-secondary rounded-md transition-colors disabled:opacity-50">
421+
<button onClick={() => performScan(globalProjectRoot || '')} disabled={!globalProjectRoot || isScanning} className="p-2 text-muted-foreground hover:text-foreground hover:bg-secondary rounded-md transition-colors disabled:opacity-50">
416422
<RefreshCw size={16} className={cn(isScanning && "animate-spin")} />
417423
</button>
418424
</div>
@@ -454,7 +460,7 @@ export function ContextView() {
454460
</div>
455461

456462
<div className="flex-1 overflow-hidden relative">
457-
{!projectRoot ? (
463+
{!globalProjectRoot ? (
458464
<div className="absolute inset-0 flex flex-col items-center justify-center text-muted-foreground opacity-50 gap-2 text-center px-4"><p className="text-sm">{t('context.enterPath')}</p></div>
459465
) : isScanning ? (
460466
<div className="absolute inset-0 flex flex-col items-center justify-center gap-3 text-sm text-muted-foreground animate-pulse"><Loader2 size={20} className="animate-spin text-primary" /><span>{t('context.scanning')}</span></div>

src/components/features/patch/PatchView.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,12 @@ interface GitDiffFile {
3636
}
3737

3838
export function PatchView() {
39-
const { aiConfig } = useAppStore();
39+
const { aiConfig, projectRoot: globalProjectRoot, setProjectRoot } = useAppStore();
4040
const { t } = useTranslation();
4141
const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
4242
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
4343
const [mode, setMode] = useState<PatchMode>('diff');
4444

45-
const [patchProjectRoot, setPatchProjectRoot] = useState<string | null>(null);
4645
const [yamlInput, setYamlInput] = useState('');
4746

4847
const [files, setFiles] = useState<PatchFileItem[]>([]);
@@ -62,7 +61,6 @@ export function PatchView() {
6261
file: null
6362
});
6463

65-
const [gitProjectRoot, setGitProjectRoot] = useState<string | null>(null);
6664
const [commits, setCommits] = useState<GitCommit[]>([]);
6765
const [baseHash, setBaseHash] = useState<string>('');
6866
const [compareHash, setCompareHash] = useState<string>('');
@@ -81,7 +79,7 @@ export function PatchView() {
8179
if (!files.some(f => f.id === MANUAL_DIFF_ID)) {
8280
const manualItem: PatchFileItem = { id: MANUAL_DIFF_ID, path: 'Manual Comparison', original: '', modified: '', status: 'success', isManual: true };
8381
setFiles(prev => [manualItem, ...prev]);
84-
if (!selectedFileId && !gitProjectRoot) {
82+
if (!selectedFileId && !globalProjectRoot) {
8583
setSelectedFileId(MANUAL_DIFF_ID);
8684
}
8785
}
@@ -98,7 +96,8 @@ export function PatchView() {
9896
try {
9997
const selected = await openDialog({ directory: true, multiple: false });
10098
if (typeof selected === 'string') {
101-
setPatchProjectRoot(selected);
99+
// Update global project root - shared across all features
100+
setProjectRoot(selected);
102101
showNotification(t('patch.projectLoaded'));
103102
}
104103
} catch (e) {
@@ -121,15 +120,15 @@ export function PatchView() {
121120
};
122121

123122
useEffect(() => {
124-
if (mode !== 'patch' || !patchProjectRoot || !yamlInput.trim()) {
123+
if (mode !== 'patch' || !globalProjectRoot || !yamlInput.trim()) {
125124
if(mode === 'patch') setFiles([]);
126125
return;
127126
}
128127

129128
const timer = setTimeout(async () => {
130129
const filePatches = parseMultiFilePatch(yamlInput);
131130
const newFiles: PatchFileItem[] = await Promise.all(filePatches.map(async (fp) => {
132-
const fullPath = `${patchProjectRoot}/${fp.filePath}`;
131+
const fullPath = `${globalProjectRoot}/${fp.filePath}`;
133132
try {
134133
const original = await readTextFile(fullPath);
135134
const result = applyPatches(original, fp.operations);
@@ -165,7 +164,7 @@ export function PatchView() {
165164
}, 300);
166165

167166
return () => clearTimeout(timer);
168-
}, [mode, patchProjectRoot, yamlInput, t]);
167+
}, [mode, globalProjectRoot, yamlInput, t]);
169168

170169
const handleAiFix = async (file: PatchFileItem) => {
171170
if (isFixing || !file.original) return;
@@ -219,7 +218,8 @@ export function PatchView() {
219218
try {
220219
const selected = await openDialog({ directory: true, multiple: false });
221220
if (typeof selected === 'string') {
222-
setGitProjectRoot(selected);
221+
// Update global project root - shared across all features
222+
setProjectRoot(selected);
223223
setIsGitLoading(true);
224224
try {
225225
const result = await invoke<GitCommit[]>(`${GIT_PLUGIN_PREFIX}get_git_commits`, { projectPath: selected });
@@ -241,13 +241,13 @@ export function PatchView() {
241241
};
242242

243243
const handleGenerateDiff = async () => {
244-
if (!gitProjectRoot || !baseHash || !compareHash) return;
244+
if (!globalProjectRoot || !baseHash || !compareHash) return;
245245
setIsGitLoading(true);
246-
setFiles(prev => prev.filter(p => p.isManual));
246+
setFiles(prev => prev.filter(p => p.isManual));
247247
setSelectedFileId(null);
248248
try {
249249
const result = await invoke<GitDiffFile[]>(`${GIT_PLUGIN_PREFIX}get_git_diff`, {
250-
projectPath: gitProjectRoot,
250+
projectPath: globalProjectRoot,
251251
oldHash: baseHash,
252252
newHash: compareHash,
253253
});
@@ -298,7 +298,7 @@ export function PatchView() {
298298
};
299299

300300
const handleExportTrigger = () => {
301-
if (!gitProjectRoot || !baseHash || !compareHash) return;
301+
if (!globalProjectRoot || !baseHash || !compareHash) return;
302302
if (selectedExportIds.size === 0) {
303303
showNotification(t('patch.selectOne'), "warning");
304304
return;
@@ -307,9 +307,9 @@ export function PatchView() {
307307
};
308308

309309
const performExport = async (format: ExportFormat, layout: ExportLayout) => {
310-
setIsExportDialogOpen(false);
310+
setIsExportDialogOpen(false);
311311
setIsExporting(true);
312-
312+
313313
try {
314314
const extMap: Record<ExportFormat, string> = {
315315
'Markdown': 'md',
@@ -328,7 +328,7 @@ export function PatchView() {
328328
const selectedList = Array.from(selectedExportIds);
329329

330330
await invoke(`${GIT_PLUGIN_PREFIX}export_git_diff`, {
331-
projectPath: gitProjectRoot,
331+
projectPath: globalProjectRoot,
332332
oldHash: baseHash,
333333
newHash: compareHash,
334334
format: format,
@@ -351,12 +351,12 @@ export function PatchView() {
351351
<div className="h-full flex overflow-hidden bg-background relative">
352352
<div className={cn("shrink-0 transition-all duration-300 ease-in-out overflow-hidden border-r border-border", isSidebarOpen ? "w-[350px] opacity-100" : "w-0 opacity-0 border-none")}>
353353
<div className="w-[350px] h-full">
354-
<PatchSidebar
354+
<PatchSidebar
355355
mode={mode} setMode={setMode}
356-
projectRoot={patchProjectRoot} onLoadProject={handleLoadPatchProject}
356+
projectRoot={globalProjectRoot} onLoadProject={handleLoadPatchProject}
357357
yamlInput={yamlInput} onYamlChange={setYamlInput} onClearYaml={handleClear}
358358
files={files} selectedFileId={selectedFileId} onSelectFile={setSelectedFileId}
359-
gitProjectRoot={gitProjectRoot} onBrowseGitProject={handleBrowseGitProject}
359+
gitProjectRoot={globalProjectRoot} onBrowseGitProject={handleBrowseGitProject}
360360
commits={commits} baseHash={baseHash} setBaseHash={setBaseHash}
361361
compareHash={compareHash} setCompareHash={setCompareHash}
362362
onCompare={handleGenerateDiff} isGitLoading={isGitLoading}
@@ -376,15 +376,15 @@ export function PatchView() {
376376
</div>
377377
)}
378378

379-
<DiffWorkspace
379+
<DiffWorkspace
380380
selectedFile={currentFile || null}
381381
onSave={handleSaveClick}
382382
onCopy={async (txt) => { await writeClipboard(txt); showNotification(t('patch.copied')); }}
383383
onManualUpdate={handleManualUpdate}
384384
isSidebarOpen={isSidebarOpen}
385385
onToggleSidebar={() => setIsSidebarOpen(!isSidebarOpen)}
386386
isReadOnly={currentFile?.isManual !== true}
387-
onExport={mode === 'diff' && gitProjectRoot ? handleExportTrigger : undefined}
387+
onExport={mode === 'diff' && globalProjectRoot ? handleExportTrigger : undefined}
388388
/>
389389
</div>
390390
<ExportDialog

src/store/useAppStore.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { invoke } from '@tauri-apps/api/core';
77
import { AIModelConfig, AIProviderConfig, AIProviderSetting, DEFAULT_AI_CONFIG, DEFAULT_PROVIDER_SETTINGS } from '@/types/model';
88
import { fetchFromMirrors, MODEL_MIRROR_BASES } from '@/lib/network';
99
import i18n from '@/i18n/config';
10+
import { useContextStore } from './useContextStore';
1011

1112
export type AppView = 'prompts' | 'context' | 'patch' | 'refinery' | 'automator';
1213
export type AppTheme = 'dark' | 'light' | 'black';
@@ -94,6 +95,9 @@ interface AppState {
9495
restReminder: RestReminderConfig;
9596
windowDestroyDelay: WindowDestroyDelay;
9697

98+
// Global project root - shared across all features (Context, Patch, Git Diff)
99+
projectRoot: string | null;
100+
97101
models: AIModelConfig[];
98102
lastUpdated: number;
99103

@@ -108,6 +112,7 @@ interface AppState {
108112
refinerySettings: RefinerySettings;
109113

110114
setView: (view: AppView) => void;
115+
setProjectRoot: (path: string | null) => void;
111116
toggleSidebar: () => void;
112117
setSettingsOpen: (open: boolean) => void;
113118
setMonitorOpen: (open: boolean) => void;
@@ -152,6 +157,7 @@ export const useAppStore = create<AppState>()(
152157
intervalMinutes: 45
153158
},
154159
windowDestroyDelay: 0,
160+
projectRoot: null,
155161

156162
models: DEFAULT_MODELS,
157163
lastUpdated: 0,
@@ -166,6 +172,13 @@ export const useAppStore = create<AppState>()(
166172
spotlightAppearance: { ...state.spotlightAppearance, ...config }
167173
})),
168174
setView: (view) => set({ currentView: view }),
175+
setProjectRoot: (path) => {
176+
set({ projectRoot: path });
177+
// Sync with context store to keep states consistent
178+
if (path) {
179+
useContextStore.getState().setProjectRoot(path);
180+
}
181+
},
169182
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
170183
setSettingsOpen: (open) => set({ isSettingsOpen: open }),
171184
setMonitorOpen: (open) => set({ isMonitorOpen: open }),

0 commit comments

Comments
 (0)