Merge pull request #287 from pedramamini/code-refactor

fix(file-preview): resolve image flickering under heavy parallel agen…
This commit is contained in:
Raza Rauf
2026-02-03 10:58:43 -06:00
committed by GitHub
2 changed files with 1967 additions and 1945 deletions

View File

@@ -2850,7 +2850,9 @@ function MaestroConsoleInner() {
if (groupChatParsed.isGroupChat) {
const groupChatId = groupChatParsed.groupChatId!;
const isModeratorError = groupChatParsed.isModerator ?? false;
const participantOrModerator = isModeratorError ? 'moderator' : groupChatParsed.participantName!;
const participantOrModerator = isModeratorError
? 'moderator'
: groupChatParsed.participantName!;
console.log('[onAgentError] Group chat error received:', {
rawSessionId: sessionId,
@@ -3656,7 +3658,13 @@ function MaestroConsoleInner() {
*/
const handleOpenFileTab = useCallback(
(
file: { path: string; name: string; content: string; sshRemoteId?: string; lastModified?: number },
file: {
path: string;
name: string;
content: string;
sshRemoteId?: string;
lastModified?: number;
},
options?: {
/** If true, create new tab adjacent to current file tab. If false, replace current file tab content. Default: true (create new tab) */
openInNewTab?: boolean;
@@ -3694,9 +3702,7 @@ function MaestroConsoleInner() {
if (!openInNewTab && s.activeFileTabId) {
const currentTabId = s.activeFileTabId;
const currentTab = s.filePreviewTabs.find((tab) => tab.id === currentTabId);
const extension = file.name.includes('.')
? '.' + file.name.split('.').pop()
: '';
const extension = file.name.includes('.') ? '.' + file.name.split('.').pop() : '';
const nameWithoutExtension = extension
? file.name.slice(0, -extension.length)
: file.name;
@@ -3770,9 +3776,7 @@ function MaestroConsoleInner() {
// Create a new file preview tab
const newTabId = generateId();
const extension = file.name.includes('.')
? '.' + file.name.split('.').pop()
: '';
const extension = file.name.includes('.') ? '.' + file.name.split('.').pop() : '';
const nameWithoutExtension = extension
? file.name.slice(0, -extension.length)
: file.name;
@@ -4741,19 +4745,13 @@ You are taking over this conversation. Based on the context above, provide a bri
}
})
.filter((tab): tab is UnifiedTab => tab !== null);
}, [
activeSession?.aiTabs,
activeSession?.filePreviewTabs,
activeSession?.unifiedTabOrder,
]);
}, [activeSession?.aiTabs, activeSession?.filePreviewTabs, activeSession?.unifiedTabOrder]);
// Get the active file preview tab (if a file tab is active)
const activeFileTab = useMemo((): FilePreviewTab | null => {
if (!activeSession?.activeFileTabId) return null;
return (
activeSession.filePreviewTabs.find(
(tab) => tab.id === activeSession.activeFileTabId
) ?? null
activeSession.filePreviewTabs.find((tab) => tab.id === activeSession.activeFileTabId) ?? null
);
}, [activeSession?.activeFileTabId, activeSession?.filePreviewTabs]);
@@ -5172,7 +5170,13 @@ You are taking over this conversation. Based on the context above, provide a bri
forceCloseFileTab(tabId);
}
},
[sessions, forceCloseFileTab, setConfirmModalMessage, setConfirmModalOnConfirm, setConfirmModalOpen]
[
sessions,
forceCloseFileTab,
setConfirmModalMessage,
setConfirmModalOnConfirm,
setConfirmModalOpen,
]
);
/**
@@ -5281,9 +5285,7 @@ You are taking over this conversation. Based on the context above, provide a bri
* If fileTabAutoRefreshEnabled setting is true, checks if file has changed on disk and refreshes content.
*/
const handleSelectFileTab = useCallback(async (tabId: string) => {
const currentSession = sessionsRef.current.find(
(s) => s.id === activeSessionIdRef.current
);
const currentSession = sessionsRef.current.find((s) => s.id === activeSessionIdRef.current);
if (!currentSession) return;
// Verify the file tab exists
@@ -5320,9 +5322,7 @@ You are taking over this conversation. Based on the context above, provide a bri
return {
...s,
filePreviewTabs: s.filePreviewTabs.map((tab) =>
tab.id === tabId
? { ...tab, content, lastModified: currentMtime }
: tab
tab.id === tabId ? { ...tab, content, lastModified: currentMtime } : tab
),
};
})
@@ -5340,34 +5340,31 @@ You are taking over this conversation. Based on the context above, provide a bri
* relative to each other. The fromIndex and toIndex refer to positions in unifiedTabOrder.
* This replaces/supplements handleTabReorder for the unified tab system.
*/
const handleUnifiedTabReorder = useCallback(
(fromIndex: number, toIndex: number) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== activeSessionIdRef.current) return s;
const handleUnifiedTabReorder = useCallback((fromIndex: number, toIndex: number) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== activeSessionIdRef.current) return s;
// Validate indices
if (
fromIndex < 0 ||
fromIndex >= s.unifiedTabOrder.length ||
toIndex < 0 ||
toIndex >= s.unifiedTabOrder.length ||
fromIndex === toIndex
) {
return s;
}
// Validate indices
if (
fromIndex < 0 ||
fromIndex >= s.unifiedTabOrder.length ||
toIndex < 0 ||
toIndex >= s.unifiedTabOrder.length ||
fromIndex === toIndex
) {
return s;
}
// Reorder the unifiedTabOrder array
const newOrder = [...s.unifiedTabOrder];
const [movedRef] = newOrder.splice(fromIndex, 1);
newOrder.splice(toIndex, 0, movedRef);
// Reorder the unifiedTabOrder array
const newOrder = [...s.unifiedTabOrder];
const [movedRef] = newOrder.splice(fromIndex, 1);
newOrder.splice(toIndex, 0, movedRef);
return { ...s, unifiedTabOrder: newOrder };
})
);
},
[]
);
return { ...s, unifiedTabOrder: newOrder };
})
);
}, []);
/**
* Internal tab close handler that performs the actual close.
@@ -5496,9 +5493,7 @@ You are taking over this conversation. Based on the context above, provide a bri
// Close file tab by removing from arrays
updatedSession = {
...updatedSession,
filePreviewTabs: updatedSession.filePreviewTabs.filter(
(t) => t.id !== tabRef.id
),
filePreviewTabs: updatedSession.filePreviewTabs.filter((t) => t.id !== tabRef.id),
unifiedTabOrder: updatedSession.unifiedTabOrder.filter(
(ref) => !(ref.type === 'file' && ref.id === tabRef.id)
),
@@ -5551,9 +5546,7 @@ You are taking over this conversation. Based on the context above, provide a bri
// Close file tab by removing from arrays
updatedSession = {
...updatedSession,
filePreviewTabs: updatedSession.filePreviewTabs.filter(
(t) => t.id !== tabRef.id
),
filePreviewTabs: updatedSession.filePreviewTabs.filter((t) => t.id !== tabRef.id),
unifiedTabOrder: updatedSession.unifiedTabOrder.filter(
(ref) => !(ref.type === 'file' && ref.id === tabRef.id)
),
@@ -5606,9 +5599,7 @@ You are taking over this conversation. Based on the context above, provide a bri
// Close file tab by removing from arrays
updatedSession = {
...updatedSession,
filePreviewTabs: updatedSession.filePreviewTabs.filter(
(t) => t.id !== tabRef.id
),
filePreviewTabs: updatedSession.filePreviewTabs.filter((t) => t.id !== tabRef.id),
unifiedTabOrder: updatedSession.unifiedTabOrder.filter(
(ref) => !(ref.type === 'file' && ref.id === tabRef.id)
),
@@ -7372,9 +7363,7 @@ You are taking over this conversation. Based on the context above, provide a bri
lines.push('|-------|--------|-------------|');
for (const skill of projectSkills) {
const desc =
skill.description && skill.description !== 'No description'
? skill.description
: '—';
skill.description && skill.description !== 'No description' ? skill.description : '—';
lines.push(`| **${skill.name}** | ${formatTokenCount(skill.tokenCount)} | ${desc} |`);
}
lines.push('');
@@ -7387,9 +7376,7 @@ You are taking over this conversation. Based on the context above, provide a bri
lines.push('|-------|--------|-------------|');
for (const skill of userSkills) {
const desc =
skill.description && skill.description !== 'No description'
? skill.description
: '—';
skill.description && skill.description !== 'No description' ? skill.description : '—';
lines.push(`| **${skill.name}** | ${formatTokenCount(skill.tokenCount)} | ${desc} |`);
}
}
@@ -8617,7 +8604,9 @@ You are taking over this conversation. Based on the context above, provide a bri
...s,
aiTabs: s.aiTabs.map((tab) =>
// Clear isGeneratingName to cancel any in-progress automatic naming
tab.id === renameTabId ? { ...tab, name: newName || null, isGeneratingName: false } : tab
tab.id === renameTabId
? { ...tab, name: newName || null, isGeneratingName: false }
: tab
),
};
})
@@ -12289,7 +12278,13 @@ You are taking over this conversation. Based on the context above, provide a bri
} else {
setChatRawTextMode(!chatRawTextMode);
}
}, [activeSession?.activeFileTabId, markdownEditMode, chatRawTextMode, setMarkdownEditMode, setChatRawTextMode]);
}, [
activeSession?.activeFileTabId,
markdownEditMode,
chatRawTextMode,
setMarkdownEditMode,
setChatRawTextMode,
]);
const handleQuickActionsStartTour = useCallback(() => {
setTourFromWizard(false);
setTourOpen(true);
@@ -12833,6 +12828,11 @@ You are taking over this conversation. Based on the context above, provide a bri
// to prevent re-evaluating 50-100+ props on every state change.
// ============================================================================
// Stable fileTree reference - prevents FilePreview re-renders during agent activity.
// Without this, activeSession?.fileTree || [] creates a new empty array on every render
// when fileTree is undefined, and a new reference whenever activeSession updates.
const stableFileTree = useMemo(() => activeSession?.fileTree || [], [activeSession?.fileTree]);
const mainPanelProps = useMainPanelProps({
// Core state
logViewerOpen,
@@ -12885,7 +12885,7 @@ You are taking over this conversation. Based on the context above, provide a bri
currentSessionBatchState: currentSessionBatchState ?? undefined,
// File tree
fileTree: activeSession?.fileTree || [],
fileTree: stableFileTree,
// File preview navigation (per-tab)
canGoBack: fileTabCanGoBack,
@@ -13753,174 +13753,174 @@ You are taking over this conversation. Based on the context above, provide a bri
theme={theme}
isOpen={symphonyModalOpen}
onClose={() => setSymphonyModalOpen(false)}
onStartContribution={async (data: SymphonyContributionData) => {
console.log('[Symphony] Creating session for contribution:', data);
onStartContribution={async (data: SymphonyContributionData) => {
console.log('[Symphony] Creating session for contribution:', data);
// Get agent definition
const agent = await window.maestro.agents.get(data.agentType);
if (!agent) {
console.error(`Agent not found: ${data.agentType}`);
addToast({
type: 'error',
title: 'Symphony Error',
message: `Agent not found: ${data.agentType}`,
});
return;
}
// Get agent definition
const agent = await window.maestro.agents.get(data.agentType);
if (!agent) {
console.error(`Agent not found: ${data.agentType}`);
addToast({
type: 'error',
title: 'Symphony Error',
message: `Agent not found: ${data.agentType}`,
});
return;
}
// Validate uniqueness
const validation = validateNewSession(
data.sessionName,
data.localPath,
data.agentType as ToolType,
sessions
);
if (!validation.valid) {
console.error(`Session validation failed: ${validation.error}`);
addToast({
type: 'error',
title: 'Session Creation Failed',
message: validation.error || 'Cannot create duplicate session',
});
return;
}
// Validate uniqueness
const validation = validateNewSession(
data.sessionName,
data.localPath,
data.agentType as ToolType,
sessions
);
if (!validation.valid) {
console.error(`Session validation failed: ${validation.error}`);
addToast({
type: 'error',
title: 'Session Creation Failed',
message: validation.error || 'Cannot create duplicate session',
});
return;
}
const newId = generateId();
const initialTabId = generateId();
const newId = generateId();
const initialTabId = generateId();
// Check git repo status
const isGitRepo = await gitService.isRepo(data.localPath);
let gitBranches: string[] | undefined;
let gitTags: string[] | undefined;
let gitRefsCacheTime: number | undefined;
// Check git repo status
const isGitRepo = await gitService.isRepo(data.localPath);
let gitBranches: string[] | undefined;
let gitTags: string[] | undefined;
let gitRefsCacheTime: number | undefined;
if (isGitRepo) {
[gitBranches, gitTags] = await Promise.all([
gitService.getBranches(data.localPath),
gitService.getTags(data.localPath),
]);
gitRefsCacheTime = Date.now();
}
if (isGitRepo) {
[gitBranches, gitTags] = await Promise.all([
gitService.getBranches(data.localPath),
gitService.getTags(data.localPath),
]);
gitRefsCacheTime = Date.now();
}
// Create initial tab
const initialTab: AITab = {
id: initialTabId,
agentSessionId: null,
name: null,
starred: false,
logs: [],
inputValue: '',
stagedImages: [],
createdAt: Date.now(),
state: 'idle',
saveToHistory: defaultSaveToHistory,
};
// Create initial tab
const initialTab: AITab = {
id: initialTabId,
agentSessionId: null,
name: null,
starred: false,
logs: [],
inputValue: '',
stagedImages: [],
createdAt: Date.now(),
state: 'idle',
saveToHistory: defaultSaveToHistory,
};
// Create session with Symphony metadata
const newSession: Session = {
id: newId,
name: data.sessionName,
toolType: data.agentType as ToolType,
state: 'idle',
cwd: data.localPath,
fullPath: data.localPath,
projectRoot: data.localPath,
isGitRepo,
gitBranches,
gitTags,
gitRefsCacheTime,
aiLogs: [],
shellLogs: [
{
id: generateId(),
timestamp: Date.now(),
source: 'system',
text: 'Shell Session Ready.',
},
],
workLog: [],
contextUsage: 0,
inputMode: 'ai',
aiPid: 0,
terminalPid: 0,
port: 3000 + Math.floor(Math.random() * 100),
isLive: false,
changedFiles: [],
fileTree: [],
fileExplorerExpanded: [],
fileExplorerScrollPos: 0,
fileTreeAutoRefreshInterval: 180,
shellCwd: data.localPath,
aiCommandHistory: [],
shellCommandHistory: [],
executionQueue: [],
activeTimeMs: 0,
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
unifiedClosedTabHistory: [],
// Custom agent config
customPath: data.customPath,
customArgs: data.customArgs,
customEnvVars: data.customEnvVars,
// Auto Run setup - use autoRunPath from contribution
autoRunFolderPath: data.autoRunPath,
// Symphony metadata for tracking
symphonyMetadata: {
isSymphonySession: true,
contributionId: data.contributionId,
repoSlug: data.repo.slug,
issueNumber: data.issue.number,
issueTitle: data.issue.title,
documentPaths: data.issue.documentPaths.map((d) => d.path),
status: 'running',
},
};
// Create session with Symphony metadata
const newSession: Session = {
id: newId,
name: data.sessionName,
toolType: data.agentType as ToolType,
state: 'idle',
cwd: data.localPath,
fullPath: data.localPath,
projectRoot: data.localPath,
isGitRepo,
gitBranches,
gitTags,
gitRefsCacheTime,
aiLogs: [],
shellLogs: [
{
id: generateId(),
timestamp: Date.now(),
source: 'system',
text: 'Shell Session Ready.',
},
],
workLog: [],
contextUsage: 0,
inputMode: 'ai',
aiPid: 0,
terminalPid: 0,
port: 3000 + Math.floor(Math.random() * 100),
isLive: false,
changedFiles: [],
fileTree: [],
fileExplorerExpanded: [],
fileExplorerScrollPos: 0,
fileTreeAutoRefreshInterval: 180,
shellCwd: data.localPath,
aiCommandHistory: [],
shellCommandHistory: [],
executionQueue: [],
activeTimeMs: 0,
aiTabs: [initialTab],
activeTabId: initialTabId,
closedTabHistory: [],
filePreviewTabs: [],
activeFileTabId: null,
unifiedTabOrder: [{ type: 'ai' as const, id: initialTabId }],
unifiedClosedTabHistory: [],
// Custom agent config
customPath: data.customPath,
customArgs: data.customArgs,
customEnvVars: data.customEnvVars,
// Auto Run setup - use autoRunPath from contribution
autoRunFolderPath: data.autoRunPath,
// Symphony metadata for tracking
symphonyMetadata: {
isSymphonySession: true,
contributionId: data.contributionId,
repoSlug: data.repo.slug,
issueNumber: data.issue.number,
issueTitle: data.issue.title,
documentPaths: data.issue.documentPaths.map((d) => d.path),
status: 'running',
},
};
setSessions((prev) => [...prev, newSession]);
setActiveSessionId(newId);
setSymphonyModalOpen(false);
setSessions((prev) => [...prev, newSession]);
setActiveSessionId(newId);
setSymphonyModalOpen(false);
// Register active contribution in Symphony persistent state
// This makes it show up in the Active tab of the Symphony modal
window.maestro.symphony
.registerActive({
contributionId: data.contributionId,
sessionId: newId,
repoSlug: data.repo.slug,
repoName: data.repo.name,
issueNumber: data.issue.number,
issueTitle: data.issue.title,
localPath: data.localPath,
branchName: data.branchName || '',
totalDocuments: data.issue.documentPaths.length,
agentType: data.agentType,
})
.catch((err: unknown) => {
console.error('[Symphony] Failed to register active contribution:', err);
});
// Register active contribution in Symphony persistent state
// This makes it show up in the Active tab of the Symphony modal
window.maestro.symphony
.registerActive({
contributionId: data.contributionId,
sessionId: newId,
repoSlug: data.repo.slug,
repoName: data.repo.name,
issueNumber: data.issue.number,
issueTitle: data.issue.title,
localPath: data.localPath,
branchName: data.branchName || '',
totalDocuments: data.issue.documentPaths.length,
agentType: data.agentType,
})
.catch((err: unknown) => {
console.error('[Symphony] Failed to register active contribution:', err);
});
// Track stats
updateGlobalStats({ totalSessions: 1 });
window.maestro.stats.recordSessionCreated({
sessionId: newId,
agentType: data.agentType,
projectPath: data.localPath,
createdAt: Date.now(),
isRemote: false,
});
// Track stats
updateGlobalStats({ totalSessions: 1 });
window.maestro.stats.recordSessionCreated({
sessionId: newId,
agentType: data.agentType,
projectPath: data.localPath,
createdAt: Date.now(),
isRemote: false,
});
// Focus input
setActiveFocus('main');
setTimeout(() => inputRef.current?.focus(), 50);
// Focus input
setActiveFocus('main');
setTimeout(() => inputRef.current?.focus(), 50);
// Switch to Auto Run tab so user sees the documents
setActiveRightTab('autorun');
}}
/>
// Switch to Auto Run tab so user sees the documents
setActiveRightTab('autorun');
}}
/>
</Suspense>
)}
@@ -13929,7 +13929,10 @@ You are taking over this conversation. Based on the context above, provide a bri
{gistPublishModalOpen && (activeFileTab || tabGistContent) && (
<GistPublishModal
theme={theme}
filename={tabGistContent?.filename ?? (activeFileTab ? activeFileTab.name + activeFileTab.extension : 'conversation.md')}
filename={
tabGistContent?.filename ??
(activeFileTab ? activeFileTab.name + activeFileTab.extension : 'conversation.md')
}
content={tabGistContent?.content ?? activeFileTab?.content ?? ''}
onClose={() => {
setGistPublishModalOpen(false);
@@ -13969,67 +13972,69 @@ You are taking over this conversation. Based on the context above, provide a bri
{graphFocusFilePath && (
<Suspense fallback={null}>
<DocumentGraphView
isOpen={isGraphViewOpen}
onClose={() => {
setIsGraphViewOpen(false);
setGraphFocusFilePath(undefined);
// Return focus to file preview if it was open
requestAnimationFrame(() => {
mainPanelRef.current?.focusFilePreview();
});
}}
theme={theme}
rootPath={activeSession?.projectRoot || activeSession?.cwd || ''}
onDocumentOpen={async (filePath) => {
// Open the document in a file tab (migrated from legacy setPreviewFile overlay)
const treeRoot = activeSession?.projectRoot || activeSession?.cwd || '';
const fullPath = `${treeRoot}/${filePath}`;
const filename = filePath.split('/').pop() || filePath;
isOpen={isGraphViewOpen}
onClose={() => {
setIsGraphViewOpen(false);
setGraphFocusFilePath(undefined);
// Return focus to file preview if it was open
requestAnimationFrame(() => {
mainPanelRef.current?.focusFilePreview();
});
}}
theme={theme}
rootPath={activeSession?.projectRoot || activeSession?.cwd || ''}
onDocumentOpen={async (filePath) => {
// Open the document in a file tab (migrated from legacy setPreviewFile overlay)
const treeRoot = activeSession?.projectRoot || activeSession?.cwd || '';
const fullPath = `${treeRoot}/${filePath}`;
const filename = filePath.split('/').pop() || filePath;
// Note: sshRemoteId is only set after AI agent spawns. For terminal-only SSH sessions,
// use sessionSshRemoteConfig.remoteId as fallback (see CLAUDE.md SSH Remote Sessions)
const sshRemoteId =
activeSession?.sshRemoteId ||
activeSession?.sessionSshRemoteConfig?.remoteId ||
undefined;
try {
// Fetch content and stat in parallel for efficiency
const [content, stat] = await Promise.all([
window.maestro.fs.readFile(fullPath, sshRemoteId),
window.maestro.fs.stat(fullPath, sshRemoteId).catch(() => null), // stat is optional
]);
if (content !== null) {
const lastModified = stat?.modifiedAt
? new Date(stat.modifiedAt).getTime()
: undefined;
handleOpenFileTab({
path: fullPath,
name: filename,
content,
sshRemoteId,
lastModified,
});
}
} catch (error) {
console.error('[DocumentGraph] Failed to open file:', error);
}
setIsGraphViewOpen(false);
}}
onExternalLinkOpen={(url) => {
// Open external URL in default browser
window.maestro.shell.openExternal(url);
}}
focusFilePath={graphFocusFilePath}
defaultShowExternalLinks={documentGraphShowExternalLinks}
onExternalLinksChange={settings.setDocumentGraphShowExternalLinks}
defaultMaxNodes={documentGraphMaxNodes}
defaultPreviewCharLimit={documentGraphPreviewCharLimit}
onPreviewCharLimitChange={settings.setDocumentGraphPreviewCharLimit}
// Note: sshRemoteId is only set after AI agent spawns. For terminal-only SSH sessions,
// use sessionSshRemoteConfig.remoteId as fallback (see CLAUDE.md SSH Remote Sessions)
const sshRemoteId =
sshRemoteId={
activeSession?.sshRemoteId ||
activeSession?.sessionSshRemoteConfig?.remoteId ||
undefined;
try {
// Fetch content and stat in parallel for efficiency
const [content, stat] = await Promise.all([
window.maestro.fs.readFile(fullPath, sshRemoteId),
window.maestro.fs.stat(fullPath, sshRemoteId).catch(() => null), // stat is optional
]);
if (content !== null) {
const lastModified = stat?.modifiedAt ? new Date(stat.modifiedAt).getTime() : undefined;
handleOpenFileTab({
path: fullPath,
name: filename,
content,
sshRemoteId,
lastModified,
});
}
} catch (error) {
console.error('[DocumentGraph] Failed to open file:', error);
undefined
}
setIsGraphViewOpen(false);
}}
onExternalLinkOpen={(url) => {
// Open external URL in default browser
window.maestro.shell.openExternal(url);
}}
focusFilePath={graphFocusFilePath}
defaultShowExternalLinks={documentGraphShowExternalLinks}
onExternalLinksChange={settings.setDocumentGraphShowExternalLinks}
defaultMaxNodes={documentGraphMaxNodes}
defaultPreviewCharLimit={documentGraphPreviewCharLimit}
onPreviewCharLimitChange={settings.setDocumentGraphPreviewCharLimit}
// Note: sshRemoteId is only set after AI agent spawns. For terminal-only SSH sessions,
// use sessionSshRemoteConfig.remoteId as fallback (see CLAUDE.md SSH Remote Sessions)
sshRemoteId={
activeSession?.sshRemoteId ||
activeSession?.sessionSshRemoteConfig?.remoteId ||
undefined
}
/>
/>
</Suspense>
)}

File diff suppressed because it is too large Load Diff