mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
Fixed StateAction types in UILayoutContext.ts + used state from UILayoutProvider instead of redundant local useState duplications in App.tsx
This commit is contained in:
25094
src/renderer/App.tsx
25094
src/renderer/App.tsx
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,15 @@
|
||||
* Phase 2 of App.tsx decomposition - see refactor-details-2.md for full plan.
|
||||
*/
|
||||
|
||||
import React, { createContext, useContext, useState, useCallback, useMemo, ReactNode, useRef } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useMemo,
|
||||
ReactNode,
|
||||
useRef
|
||||
} from 'react';
|
||||
import type { FocusArea, RightPanelTab } from '../types';
|
||||
import type { FlatFileItem } from '../components/FileSearchModal';
|
||||
|
||||
@@ -15,81 +23,83 @@ import type { FlatFileItem } from '../components/FileSearchModal';
|
||||
* UI Layout context value - all layout states and their setters
|
||||
*/
|
||||
export interface UILayoutContextValue {
|
||||
// Sidebar State
|
||||
leftSidebarOpen: boolean;
|
||||
setLeftSidebarOpen: (open: boolean) => void;
|
||||
toggleLeftSidebar: () => void;
|
||||
rightPanelOpen: boolean;
|
||||
setRightPanelOpen: (open: boolean) => void;
|
||||
toggleRightPanel: () => void;
|
||||
// Sidebar State
|
||||
leftSidebarOpen: boolean;
|
||||
setLeftSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
toggleLeftSidebar: () => void;
|
||||
rightPanelOpen: boolean;
|
||||
setRightPanelOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
toggleRightPanel: () => void;
|
||||
|
||||
// Focus State
|
||||
activeFocus: FocusArea;
|
||||
setActiveFocus: (focus: FocusArea) => void;
|
||||
activeRightTab: RightPanelTab;
|
||||
setActiveRightTab: (tab: RightPanelTab) => void;
|
||||
// Focus State
|
||||
activeFocus: FocusArea;
|
||||
setActiveFocus: React.Dispatch<React.SetStateAction<FocusArea>>;
|
||||
activeRightTab: RightPanelTab;
|
||||
setActiveRightTab: React.Dispatch<React.SetStateAction<RightPanelTab>>;
|
||||
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed: boolean;
|
||||
setBookmarksCollapsed: (collapsed: boolean) => void;
|
||||
toggleBookmarksCollapsed: () => void;
|
||||
groupChatsExpanded: boolean;
|
||||
setGroupChatsExpanded: (expanded: boolean) => void;
|
||||
toggleGroupChatsExpanded: () => void;
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed: boolean;
|
||||
setBookmarksCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
toggleBookmarksCollapsed: () => void;
|
||||
groupChatsExpanded: boolean;
|
||||
setGroupChatsExpanded: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
toggleGroupChatsExpanded: () => void;
|
||||
|
||||
// Session list filter state
|
||||
showUnreadOnly: boolean;
|
||||
setShowUnreadOnly: (show: boolean) => void;
|
||||
toggleShowUnreadOnly: () => void;
|
||||
preFilterActiveTabIdRef: React.MutableRefObject<string | null>;
|
||||
// Session list filter state
|
||||
showUnreadOnly: boolean;
|
||||
setShowUnreadOnly: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
toggleShowUnreadOnly: () => void;
|
||||
preFilterActiveTabIdRef: React.MutableRefObject<string | null>;
|
||||
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex: number;
|
||||
setSelectedSidebarIndex: (index: number) => void;
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex: number;
|
||||
setSelectedSidebarIndex: React.Dispatch<React.SetStateAction<number>>;
|
||||
|
||||
// File Explorer State
|
||||
previewFile: { name: string; content: string; path: string } | null;
|
||||
setPreviewFile: (file: { name: string; content: string; path: string } | null) => void;
|
||||
selectedFileIndex: number;
|
||||
setSelectedFileIndex: (index: number) => void;
|
||||
flatFileList: FlatFileItem[];
|
||||
setFlatFileList: (list: FlatFileItem[]) => void;
|
||||
fileTreeFilter: string;
|
||||
setFileTreeFilter: (filter: string) => void;
|
||||
fileTreeFilterOpen: boolean;
|
||||
setFileTreeFilterOpen: (open: boolean) => void;
|
||||
// File Explorer State
|
||||
previewFile: { name: string; content: string; path: string } | null;
|
||||
setPreviewFile: React.Dispatch<
|
||||
React.SetStateAction<{ name: string; content: string; path: string } | null>
|
||||
>;
|
||||
selectedFileIndex: number;
|
||||
setSelectedFileIndex: React.Dispatch<React.SetStateAction<number>>;
|
||||
flatFileList: FlatFileItem[];
|
||||
setFlatFileList: React.Dispatch<React.SetStateAction<FlatFileItem[]>>;
|
||||
fileTreeFilter: string;
|
||||
setFileTreeFilter: React.Dispatch<React.SetStateAction<string>>;
|
||||
fileTreeFilterOpen: boolean;
|
||||
setFileTreeFilterOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
// Flash notification state (inline notifications)
|
||||
flashNotification: string | null;
|
||||
setFlashNotification: (notification: string | null) => void;
|
||||
successFlashNotification: string | null;
|
||||
setSuccessFlashNotification: (notification: string | null) => void;
|
||||
// Flash notification state (inline notifications)
|
||||
flashNotification: string | null;
|
||||
setFlashNotification: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
successFlashNotification: string | null;
|
||||
setSuccessFlashNotification: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
|
||||
// Output search state
|
||||
outputSearchOpen: boolean;
|
||||
setOutputSearchOpen: (open: boolean) => void;
|
||||
outputSearchQuery: string;
|
||||
setOutputSearchQuery: (query: string) => void;
|
||||
// Output search state
|
||||
outputSearchOpen: boolean;
|
||||
setOutputSearchOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
outputSearchQuery: string;
|
||||
setOutputSearchQuery: React.Dispatch<React.SetStateAction<string>>;
|
||||
|
||||
// Drag and drop state
|
||||
draggingSessionId: string | null;
|
||||
setDraggingSessionId: (id: string | null) => void;
|
||||
isDraggingImage: boolean;
|
||||
setIsDraggingImage: (isDragging: boolean) => void;
|
||||
dragCounterRef: React.MutableRefObject<number>;
|
||||
// Drag and drop state
|
||||
draggingSessionId: string | null;
|
||||
setDraggingSessionId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
isDraggingImage: boolean;
|
||||
setIsDraggingImage: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
dragCounterRef: React.MutableRefObject<number>;
|
||||
|
||||
// Editing state (inline renaming in sidebar)
|
||||
editingGroupId: string | null;
|
||||
setEditingGroupId: (id: string | null) => void;
|
||||
editingSessionId: string | null;
|
||||
setEditingSessionId: (id: string | null) => void;
|
||||
// Editing state (inline renaming in sidebar)
|
||||
editingGroupId: string | null;
|
||||
setEditingGroupId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
editingSessionId: string | null;
|
||||
setEditingSessionId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
}
|
||||
|
||||
// Create context with null as default (will throw if used outside provider)
|
||||
const UILayoutContext = createContext<UILayoutContextValue | null>(null);
|
||||
|
||||
interface UILayoutProviderProps {
|
||||
children: ReactNode;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,172 +116,198 @@ interface UILayoutProviderProps {
|
||||
* </UILayoutProvider>
|
||||
*/
|
||||
export function UILayoutProvider({ children }: UILayoutProviderProps) {
|
||||
// Sidebar State
|
||||
const [leftSidebarOpen, setLeftSidebarOpen] = useState(true);
|
||||
const [rightPanelOpen, setRightPanelOpen] = useState(true);
|
||||
// Sidebar State
|
||||
const [leftSidebarOpen, setLeftSidebarOpen] = useState(true);
|
||||
const [rightPanelOpen, setRightPanelOpen] = useState(true);
|
||||
|
||||
// Focus State
|
||||
const [activeFocus, setActiveFocus] = useState<FocusArea>('main');
|
||||
const [activeRightTab, setActiveRightTab] = useState<RightPanelTab>('files');
|
||||
// Focus State
|
||||
const [activeFocus, setActiveFocus] = useState<FocusArea>('main');
|
||||
const [activeRightTab, setActiveRightTab] = useState<RightPanelTab>('files');
|
||||
|
||||
// Sidebar collapse/expand state
|
||||
const [bookmarksCollapsed, setBookmarksCollapsed] = useState(false);
|
||||
const [groupChatsExpanded, setGroupChatsExpanded] = useState(true);
|
||||
// Sidebar collapse/expand state
|
||||
const [bookmarksCollapsed, setBookmarksCollapsed] = useState(false);
|
||||
const [groupChatsExpanded, setGroupChatsExpanded] = useState(true);
|
||||
|
||||
// Session list filter state
|
||||
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
|
||||
// Track the active tab ID before entering unread filter mode, so we can restore it when exiting
|
||||
const preFilterActiveTabIdRef = useRef<string | null>(null);
|
||||
// Session list filter state
|
||||
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
|
||||
// Track the active tab ID before entering unread filter mode, so we can restore it when exiting
|
||||
const preFilterActiveTabIdRef = useRef<string | null>(null);
|
||||
|
||||
// Session sidebar selection
|
||||
const [selectedSidebarIndex, setSelectedSidebarIndex] = useState(0);
|
||||
// Session sidebar selection
|
||||
const [selectedSidebarIndex, setSelectedSidebarIndex] = useState(0);
|
||||
|
||||
// File Explorer State
|
||||
const [previewFile, setPreviewFile] = useState<{ name: string; content: string; path: string } | null>(null);
|
||||
const [selectedFileIndex, setSelectedFileIndex] = useState(0);
|
||||
const [flatFileList, setFlatFileList] = useState<FlatFileItem[]>([]);
|
||||
const [fileTreeFilter, setFileTreeFilter] = useState('');
|
||||
const [fileTreeFilterOpen, setFileTreeFilterOpen] = useState(false);
|
||||
// File Explorer State
|
||||
const [previewFile, setPreviewFile] = useState<{
|
||||
name: string;
|
||||
content: string;
|
||||
path: string;
|
||||
} | null>(null);
|
||||
const [selectedFileIndex, setSelectedFileIndex] = useState(0);
|
||||
const [flatFileList, setFlatFileList] = useState<FlatFileItem[]>([]);
|
||||
const [fileTreeFilter, setFileTreeFilter] = useState('');
|
||||
const [fileTreeFilterOpen, setFileTreeFilterOpen] = useState(false);
|
||||
|
||||
// Flash notification state
|
||||
const [flashNotification, setFlashNotification] = useState<string | null>(null);
|
||||
const [successFlashNotification, setSuccessFlashNotification] = useState<string | null>(null);
|
||||
// Flash notification state
|
||||
const [flashNotification, setFlashNotification] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
const [successFlashNotification, setSuccessFlashNotification] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
// Output search state
|
||||
const [outputSearchOpen, setOutputSearchOpen] = useState(false);
|
||||
const [outputSearchQuery, setOutputSearchQuery] = useState('');
|
||||
// Output search state
|
||||
const [outputSearchOpen, setOutputSearchOpen] = useState(false);
|
||||
const [outputSearchQuery, setOutputSearchQuery] = useState('');
|
||||
|
||||
// Drag and drop state
|
||||
const [draggingSessionId, setDraggingSessionId] = useState<string | null>(null);
|
||||
const [isDraggingImage, setIsDraggingImage] = useState(false);
|
||||
const dragCounterRef = useRef(0); // Track nested drag enter/leave events
|
||||
// Drag and drop state
|
||||
const [draggingSessionId, setDraggingSessionId] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
const [isDraggingImage, setIsDraggingImage] = useState(false);
|
||||
const dragCounterRef = useRef(0); // Track nested drag enter/leave events
|
||||
|
||||
// Editing state (inline renaming in sidebar)
|
||||
const [editingGroupId, setEditingGroupId] = useState<string | null>(null);
|
||||
const [editingSessionId, setEditingSessionId] = useState<string | null>(null);
|
||||
// Editing state (inline renaming in sidebar)
|
||||
const [editingGroupId, setEditingGroupId] = useState<string | null>(null);
|
||||
const [editingSessionId, setEditingSessionId] = useState<string | null>(null);
|
||||
|
||||
// Convenience toggle methods
|
||||
const toggleLeftSidebar = useCallback(() => {
|
||||
setLeftSidebarOpen(open => !open);
|
||||
}, []);
|
||||
// Convenience toggle methods
|
||||
const toggleLeftSidebar = useCallback(() => {
|
||||
setLeftSidebarOpen(open => !open);
|
||||
}, []);
|
||||
|
||||
const toggleRightPanel = useCallback(() => {
|
||||
setRightPanelOpen(open => !open);
|
||||
}, []);
|
||||
const toggleRightPanel = useCallback(() => {
|
||||
setRightPanelOpen(open => !open);
|
||||
}, []);
|
||||
|
||||
const toggleBookmarksCollapsed = useCallback(() => {
|
||||
setBookmarksCollapsed(collapsed => !collapsed);
|
||||
}, []);
|
||||
const toggleBookmarksCollapsed = useCallback(() => {
|
||||
setBookmarksCollapsed(collapsed => !collapsed);
|
||||
}, []);
|
||||
|
||||
const toggleGroupChatsExpanded = useCallback(() => {
|
||||
setGroupChatsExpanded(expanded => !expanded);
|
||||
}, []);
|
||||
const toggleGroupChatsExpanded = useCallback(() => {
|
||||
setGroupChatsExpanded(expanded => !expanded);
|
||||
}, []);
|
||||
|
||||
const toggleShowUnreadOnly = useCallback(() => {
|
||||
setShowUnreadOnly(show => !show);
|
||||
}, []);
|
||||
const toggleShowUnreadOnly = useCallback(() => {
|
||||
setShowUnreadOnly(show => !show);
|
||||
}, []);
|
||||
|
||||
// Memoize the context value to prevent unnecessary re-renders
|
||||
const value = useMemo<UILayoutContextValue>(() => ({
|
||||
// Sidebar State
|
||||
leftSidebarOpen,
|
||||
setLeftSidebarOpen,
|
||||
toggleLeftSidebar,
|
||||
rightPanelOpen,
|
||||
setRightPanelOpen,
|
||||
toggleRightPanel,
|
||||
// Memoize the context value to prevent unnecessary re-renders
|
||||
const value = useMemo<UILayoutContextValue>(
|
||||
() => ({
|
||||
// Sidebar State
|
||||
leftSidebarOpen,
|
||||
setLeftSidebarOpen,
|
||||
toggleLeftSidebar,
|
||||
rightPanelOpen,
|
||||
setRightPanelOpen,
|
||||
toggleRightPanel,
|
||||
|
||||
// Focus State
|
||||
activeFocus,
|
||||
setActiveFocus,
|
||||
activeRightTab,
|
||||
setActiveRightTab,
|
||||
// Focus State
|
||||
activeFocus,
|
||||
setActiveFocus,
|
||||
activeRightTab,
|
||||
setActiveRightTab,
|
||||
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed,
|
||||
setBookmarksCollapsed,
|
||||
toggleBookmarksCollapsed,
|
||||
groupChatsExpanded,
|
||||
setGroupChatsExpanded,
|
||||
toggleGroupChatsExpanded,
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed,
|
||||
setBookmarksCollapsed,
|
||||
toggleBookmarksCollapsed,
|
||||
groupChatsExpanded,
|
||||
setGroupChatsExpanded,
|
||||
toggleGroupChatsExpanded,
|
||||
|
||||
// Session list filter state
|
||||
showUnreadOnly,
|
||||
setShowUnreadOnly,
|
||||
toggleShowUnreadOnly,
|
||||
preFilterActiveTabIdRef,
|
||||
// Session list filter state
|
||||
showUnreadOnly,
|
||||
setShowUnreadOnly,
|
||||
toggleShowUnreadOnly,
|
||||
preFilterActiveTabIdRef,
|
||||
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex,
|
||||
setSelectedSidebarIndex,
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex,
|
||||
setSelectedSidebarIndex,
|
||||
|
||||
// File Explorer State
|
||||
previewFile,
|
||||
setPreviewFile,
|
||||
selectedFileIndex,
|
||||
setSelectedFileIndex,
|
||||
flatFileList,
|
||||
setFlatFileList,
|
||||
fileTreeFilter,
|
||||
setFileTreeFilter,
|
||||
fileTreeFilterOpen,
|
||||
setFileTreeFilterOpen,
|
||||
// File Explorer State
|
||||
previewFile,
|
||||
setPreviewFile,
|
||||
selectedFileIndex,
|
||||
setSelectedFileIndex,
|
||||
flatFileList,
|
||||
setFlatFileList,
|
||||
fileTreeFilter,
|
||||
setFileTreeFilter,
|
||||
fileTreeFilterOpen,
|
||||
setFileTreeFilterOpen,
|
||||
|
||||
// Flash notification state
|
||||
flashNotification,
|
||||
setFlashNotification,
|
||||
successFlashNotification,
|
||||
setSuccessFlashNotification,
|
||||
// Flash notification state
|
||||
flashNotification,
|
||||
setFlashNotification,
|
||||
successFlashNotification,
|
||||
setSuccessFlashNotification,
|
||||
|
||||
// Output search state
|
||||
outputSearchOpen,
|
||||
setOutputSearchOpen,
|
||||
outputSearchQuery,
|
||||
setOutputSearchQuery,
|
||||
// Output search state
|
||||
outputSearchOpen,
|
||||
setOutputSearchOpen,
|
||||
outputSearchQuery,
|
||||
setOutputSearchQuery,
|
||||
|
||||
// Drag and drop state
|
||||
draggingSessionId,
|
||||
setDraggingSessionId,
|
||||
isDraggingImage,
|
||||
setIsDraggingImage,
|
||||
dragCounterRef,
|
||||
// Drag and drop state
|
||||
draggingSessionId,
|
||||
setDraggingSessionId,
|
||||
isDraggingImage,
|
||||
setIsDraggingImage,
|
||||
dragCounterRef,
|
||||
|
||||
// Editing state
|
||||
editingGroupId,
|
||||
setEditingGroupId,
|
||||
editingSessionId,
|
||||
setEditingSessionId,
|
||||
}), [
|
||||
// Sidebar State
|
||||
leftSidebarOpen, toggleLeftSidebar,
|
||||
rightPanelOpen, toggleRightPanel,
|
||||
// Focus State
|
||||
activeFocus, activeRightTab,
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed, toggleBookmarksCollapsed,
|
||||
groupChatsExpanded, toggleGroupChatsExpanded,
|
||||
// Session list filter state
|
||||
showUnreadOnly, toggleShowUnreadOnly,
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex,
|
||||
// File Explorer State
|
||||
previewFile, selectedFileIndex, flatFileList,
|
||||
fileTreeFilter, fileTreeFilterOpen,
|
||||
// Flash notification state
|
||||
flashNotification, successFlashNotification,
|
||||
// Output search state
|
||||
outputSearchOpen, outputSearchQuery,
|
||||
// Drag and drop state
|
||||
draggingSessionId, isDraggingImage,
|
||||
// Editing state
|
||||
editingGroupId, editingSessionId,
|
||||
]);
|
||||
// Editing state
|
||||
editingGroupId,
|
||||
setEditingGroupId,
|
||||
editingSessionId,
|
||||
setEditingSessionId
|
||||
}),
|
||||
[
|
||||
// Sidebar State
|
||||
leftSidebarOpen,
|
||||
toggleLeftSidebar,
|
||||
rightPanelOpen,
|
||||
toggleRightPanel,
|
||||
// Focus State
|
||||
activeFocus,
|
||||
activeRightTab,
|
||||
// Sidebar collapse/expand state
|
||||
bookmarksCollapsed,
|
||||
toggleBookmarksCollapsed,
|
||||
groupChatsExpanded,
|
||||
toggleGroupChatsExpanded,
|
||||
// Session list filter state
|
||||
showUnreadOnly,
|
||||
toggleShowUnreadOnly,
|
||||
// Session sidebar selection
|
||||
selectedSidebarIndex,
|
||||
// File Explorer State
|
||||
previewFile,
|
||||
selectedFileIndex,
|
||||
flatFileList,
|
||||
fileTreeFilter,
|
||||
fileTreeFilterOpen,
|
||||
// Flash notification state
|
||||
flashNotification,
|
||||
successFlashNotification,
|
||||
// Output search state
|
||||
outputSearchOpen,
|
||||
outputSearchQuery,
|
||||
// Drag and drop state
|
||||
draggingSessionId,
|
||||
isDraggingImage,
|
||||
// Editing state
|
||||
editingGroupId,
|
||||
editingSessionId
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<UILayoutContext.Provider value={value}>
|
||||
{children}
|
||||
</UILayoutContext.Provider>
|
||||
);
|
||||
return (
|
||||
<UILayoutContext.Provider value={value}>
|
||||
{children}
|
||||
</UILayoutContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,11 +327,11 @@ export function UILayoutProvider({ children }: UILayoutProviderProps) {
|
||||
* if (activeFocus === 'main') { ... }
|
||||
*/
|
||||
export function useUILayout(): UILayoutContextValue {
|
||||
const context = useContext(UILayoutContext);
|
||||
const context = useContext(UILayoutContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('useUILayout must be used within a UILayoutProvider');
|
||||
}
|
||||
if (!context) {
|
||||
throw new Error('useUILayout must be used within a UILayoutProvider');
|
||||
}
|
||||
|
||||
return context;
|
||||
return context;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user