mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
MAESTRO: Migrate file click handler to open tabs instead of overlay
Updated handleFileClick in useAppHandlers.ts to use the new tab-based file preview system. When onOpenFileTab callback is provided, file clicks now open tabs instead of using the legacy setPreviewFile overlay. Changes: - Added FileTabInfo interface and onOpenFileTab optional callback to UseAppHandlersDeps - Modified handleFileClick to fetch file stat for lastModified timestamp - handleFileClick now calls onOpenFileTab when provided, falling back to legacy setPreviewFile behavior otherwise - Moved handleOpenFileTab definition in App.tsx to before useAppHandlers call and wired it as the onOpenFileTab callback
This commit is contained in:
@@ -3881,6 +3881,83 @@ function MaestroConsoleInner() {
|
||||
[activeSessionId]
|
||||
);
|
||||
|
||||
/**
|
||||
* Open a file preview tab. If a tab with the same path already exists, select it.
|
||||
* Otherwise, create a new FilePreviewTab, add it to filePreviewTabs and unifiedTabOrder,
|
||||
* and set it as the active file tab (deselecting any active AI tab).
|
||||
*
|
||||
* For SSH remote files, pass sshRemoteId so content can be re-fetched if needed.
|
||||
*/
|
||||
const handleOpenFileTab = useCallback(
|
||||
(file: { path: string; name: string; content: string; sshRemoteId?: string; lastModified?: number }) => {
|
||||
setSessions((prev) =>
|
||||
prev.map((s) => {
|
||||
if (s.id !== activeSessionIdRef.current) return s;
|
||||
|
||||
// Check if a tab with this path already exists
|
||||
const existingTab = s.filePreviewTabs.find((tab) => tab.path === file.path);
|
||||
if (existingTab) {
|
||||
// Tab exists - update content and lastModified if provided (e.g., after re-fetch) and select it
|
||||
const updatedTabs = s.filePreviewTabs.map((tab) =>
|
||||
tab.id === existingTab.id
|
||||
? {
|
||||
...tab,
|
||||
content: file.content,
|
||||
lastModified: file.lastModified ?? tab.lastModified,
|
||||
isLoading: false,
|
||||
}
|
||||
: tab
|
||||
);
|
||||
return {
|
||||
...s,
|
||||
filePreviewTabs: updatedTabs,
|
||||
activeFileTabId: existingTab.id,
|
||||
activeTabId: s.activeTabId, // Keep AI tab reference but it's not visually active
|
||||
};
|
||||
}
|
||||
|
||||
// Create a new file preview tab
|
||||
const newTabId = generateId();
|
||||
const extension = file.name.includes('.')
|
||||
? '.' + file.name.split('.').pop()
|
||||
: '';
|
||||
const nameWithoutExtension = extension
|
||||
? file.name.slice(0, -extension.length)
|
||||
: file.name;
|
||||
|
||||
const newFileTab: FilePreviewTab = {
|
||||
id: newTabId,
|
||||
path: file.path,
|
||||
name: nameWithoutExtension,
|
||||
extension,
|
||||
content: file.content,
|
||||
scrollTop: 0,
|
||||
searchQuery: '',
|
||||
editMode: false,
|
||||
editContent: undefined,
|
||||
createdAt: Date.now(),
|
||||
lastModified: file.lastModified ?? Date.now(), // Use file mtime or current time as fallback
|
||||
sshRemoteId: file.sshRemoteId,
|
||||
isLoading: false, // Content is already loaded when this is called
|
||||
};
|
||||
|
||||
// Create the unified tab reference
|
||||
const newTabRef: UnifiedTabRef = { type: 'file', id: newTabId };
|
||||
|
||||
return {
|
||||
...s,
|
||||
filePreviewTabs: [...s.filePreviewTabs, newFileTab],
|
||||
unifiedTabOrder: [...s.unifiedTabOrder, newTabRef],
|
||||
activeFileTabId: newTabId,
|
||||
// Deselect AI tab when file tab becomes active
|
||||
// Note: activeTabId stays as is - it tracks the last active AI tab for when user switches back
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
// --- APP HANDLERS (drag, file, folder operations) ---
|
||||
const {
|
||||
handleImageDragEnter,
|
||||
@@ -3908,6 +3985,7 @@ function MaestroConsoleInner() {
|
||||
setConfirmModalMessage,
|
||||
setConfirmModalOnConfirm,
|
||||
setConfirmModalOpen,
|
||||
onOpenFileTab: handleOpenFileTab,
|
||||
});
|
||||
|
||||
// Use custom colors when custom theme is selected, otherwise use the standard theme
|
||||
@@ -5167,83 +5245,6 @@ You are taking over this conversation. Based on the context above, provide a bri
|
||||
);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Open a file preview tab. If a tab with the same path already exists, select it.
|
||||
* Otherwise, create a new FilePreviewTab, add it to filePreviewTabs and unifiedTabOrder,
|
||||
* and set it as the active file tab (deselecting any active AI tab).
|
||||
*
|
||||
* For SSH remote files, pass sshRemoteId so content can be re-fetched if needed.
|
||||
*/
|
||||
const handleOpenFileTab = useCallback(
|
||||
(file: { path: string; name: string; content: string; sshRemoteId?: string; lastModified?: number }) => {
|
||||
setSessions((prev) =>
|
||||
prev.map((s) => {
|
||||
if (s.id !== activeSessionIdRef.current) return s;
|
||||
|
||||
// Check if a tab with this path already exists
|
||||
const existingTab = s.filePreviewTabs.find((tab) => tab.path === file.path);
|
||||
if (existingTab) {
|
||||
// Tab exists - update content and lastModified if provided (e.g., after re-fetch) and select it
|
||||
const updatedTabs = s.filePreviewTabs.map((tab) =>
|
||||
tab.id === existingTab.id
|
||||
? {
|
||||
...tab,
|
||||
content: file.content,
|
||||
lastModified: file.lastModified ?? tab.lastModified,
|
||||
isLoading: false,
|
||||
}
|
||||
: tab
|
||||
);
|
||||
return {
|
||||
...s,
|
||||
filePreviewTabs: updatedTabs,
|
||||
activeFileTabId: existingTab.id,
|
||||
activeTabId: s.activeTabId, // Keep AI tab reference but it's not visually active
|
||||
};
|
||||
}
|
||||
|
||||
// Create a new file preview tab
|
||||
const newTabId = generateId();
|
||||
const extension = file.name.includes('.')
|
||||
? '.' + file.name.split('.').pop()
|
||||
: '';
|
||||
const nameWithoutExtension = extension
|
||||
? file.name.slice(0, -extension.length)
|
||||
: file.name;
|
||||
|
||||
const newFileTab: FilePreviewTab = {
|
||||
id: newTabId,
|
||||
path: file.path,
|
||||
name: nameWithoutExtension,
|
||||
extension,
|
||||
content: file.content,
|
||||
scrollTop: 0,
|
||||
searchQuery: '',
|
||||
editMode: false,
|
||||
editContent: undefined,
|
||||
createdAt: Date.now(),
|
||||
lastModified: file.lastModified ?? Date.now(), // Use file mtime or current time as fallback
|
||||
sshRemoteId: file.sshRemoteId,
|
||||
isLoading: false, // Content is already loaded when this is called
|
||||
};
|
||||
|
||||
// Create the unified tab reference
|
||||
const newTabRef: UnifiedTabRef = { type: 'file', id: newTabId };
|
||||
|
||||
return {
|
||||
...s,
|
||||
filePreviewTabs: [...s.filePreviewTabs, newFileTab],
|
||||
unifiedTabOrder: [...s.unifiedTabOrder, newTabRef],
|
||||
activeFileTabId: newTabId,
|
||||
// Deselect AI tab when file tab becomes active
|
||||
// Note: activeTabId stays as is - it tracks the last active AI tab for when user switches back
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Open a file tab with async content loading (for SSH remote files).
|
||||
* Creates the tab immediately with loading state, fetches content, then updates the tab.
|
||||
|
||||
Reference in New Issue
Block a user