Dashboard Hooks Reference
The web dashboard provides 10 custom React hooks in src/lib/hooks/. All hooks are client-side ('use client') and handle concerns ranging from AI streaming to theme persistence. This page documents each hook's interface, internal behavior, and usage patterns.
File Overview
src/lib/hooks/
use-ai-stream.ts # Server-sent event streaming for AI chat
use-chat-history.ts # Chat message state management
use-keyboard-shortcuts.ts # Global keyboard shortcut bindings
use-local-storage.ts # SSR-safe localStorage synchronization
use-mounted.ts # Client-side mount detection
use-plugin-settings.ts # Plugin settings form management
use-plugin-toggle.ts # Plugin enable/disable with optimistic UI
use-provider-selection.ts # AI/search/screenshot provider picker state
use-sidebar-persistence.ts # Sidebar width and collapsed state persistence
use-theme.ts # Dark/light theme management
useAIStream
Manages streaming responses from the AI chat endpoint using the Fetch API's ReadableStream.
interface StreamChunk {
content?: string;
done?: boolean;
error?: string;
metadata?: Record<string, any>;
}
interface UseAIStreamOptions {
onChunk?: (chunk: StreamChunk) => void;
onComplete?: (fullContent: string) => void;
onError?: (error: Error) => void;
}
function useAIStream(options?: UseAIStreamOptions): {
streamMessage: (endpoint: string, data: any) => Promise<string>;
isStreaming: boolean;
content: string;
error: Error | null;
reset: () => void;
};
Internal Behavior:
- Sends a POST request to the streaming endpoint and reads the response body via
ReadableStream.getReader() - Parses newline-delimited JSON chunks with a resilient parser that handles partial JSON and non-JSON prefix text
- Accumulates content from each chunk into a single string, updating React state after each chunk
- Calls
onChunkfor every parsed chunk,onCompletewhendone: trueor the stream ends, andonErroron failure - The
resetfunction clears content, error, and streaming state
useChatHistory
Manages the chat message list for the AI chat interface.
type ChatMessageRole = 'user' | 'assistant' | 'system' | 'tool' | 'function';
type ChatMessage = {
id: string;
role: ChatMessageRole;
content: string;
timestamp: string | null;
isStreaming?: boolean;
metadata?: Record<string, any>;
error?: string;
};
function useChatHistory(): {
messages: ChatMessage[];
error: string | null;
isLoading: boolean;
setMessages: React.Dispatch<React.SetStateAction<ChatMessage[]>>;
loadHistory: () => void;
resetHistory: () => void;
};
Internal Behavior:
- Initializes with an empty message array and sets
isLoading: true loadHistory()populates the array with a single initial assistant greeting message; uses a ref to ensure it only runs onceresetHistory()resets to the initial greeting and clears the loaded refgenerateMessageId()is exported as a utility: creates IDs likemsg_1709123456789_a3b2c1- Returns a memoized value object to avoid unnecessary re-renders
useKeyboardShortcuts
Registers global keyboard shortcuts for the dashboard.
interface KeyboardShortcutsOptions {
onOpenHelp?: () => void;
}
function useKeyboardShortcuts(options?: KeyboardShortcutsOptions): void;
Registered Shortcuts:
| Shortcut | Condition | Action |
|---|---|---|
Ctrl/Cmd + K | Always | Navigate to works page with search focused |
C | Not in input field | Navigate to new work page |
? | Not in input field, onOpenHelp provided | Open help drawer |
Internal Behavior:
- Uses
useEffectto add akeydownevent listener ondocument - Detects input fields (
input,textarea,select,contentEditable) and skips non-modifier shortcuts when focus is inside one - Uses
next-intlawareuseRouterfor navigation
useLocalStorage
SSR-safe hook that synchronizes React state with localStorage.
function useLocalStorage<T>(
key: string,
defaultValue: T,
options?: {
serialize?: (value: T) => string;
deserialize?: (raw: string) => T;
validate?: (value: T) => boolean;
}
): [T, (value: T) => void];
Hydration Strategy:
- Always initializes with
defaultValueso the server render matches the first client render (no hydration mismatch) - Uses
useIsomorphicLayoutEffect(runsuseLayoutEffecton client,useEffecton server) to read fromlocalStoragebefore the browser paints, eliminating any visible flash - Listens for
StorageEventto sync across tabs/windows
Ref Pattern: serialize, deserialize, and validate callbacks are stored in refs and updated every render. This avoids stale closures when callers pass inline function literals, and avoids requiring them as effect dependencies.