// #region TaskDrawerStore [C:3] [TYPE Store] [SEMANTICS task, drawer, store, resource, mapping] // @ingroup Stores // @BRIEF Manage Task Drawer visibility, active task binding, and resource-to-task mapping. // @LAYER UI // @RELATION BINDS_TO -> [ActivityStore] // @UX_STATE Closed -> Drawer hidden, no active task // @UX_STATE Open -> Drawer visible with task logs or task list // @RATIONALE Migrated from Svelte 4 writable to Svelte 5 $state runes. // Backward-compatible .subscribe() retained for $taskDrawerStore syntax. interface TaskInfo { taskId: string; status: string; } interface ResourceTaskMap { [k: string]: TaskInfo; } interface TaskDrawerState { isOpen: boolean; activeTaskId: string | null; scrollToHint: string | null; resourceTaskMap: ResourceTaskMap; } const TASK_DRAWER_AUTO_OPEN_STORAGE_KEY = 'ss_tools.profile.auto_open_task_drawer'; function readAutoOpenTaskDrawerPreference(): boolean { if (typeof window === 'undefined') return true; const rawValue = window.localStorage.getItem(TASK_DRAWER_AUTO_OPEN_STORAGE_KEY); if (rawValue === 'false') return false; return true; } let autoOpenTaskDrawerPreference: boolean = readAutoOpenTaskDrawerPreference(); const initialState: TaskDrawerState = { isOpen: false, activeTaskId: null, scrollToHint: null, resourceTaskMap: {}, }; // Reactive state (Svelte 5 rune) let _state: TaskDrawerState = $state(initialState); // Subscriber list for backward compat with $taskDrawerStore syntax let _subscribers: Array<(_value: TaskDrawerState) => void> = []; function _notify(): void { const current = _state; _subscribers.forEach((fn) => fn(current)); } export const taskDrawerStore = { subscribe(run: (_value: TaskDrawerState) => void): () => void { _subscribers.push(run); run(_state); return () => { _subscribers = _subscribers.filter((fn) => fn !== run); }; }, get value(): TaskDrawerState { return _state; }, set(newState: TaskDrawerState) { _state = newState; _notify(); }, update(fn: (_state: TaskDrawerState) => TaskDrawerState) { _state = fn(_state); _notify(); }, }; export function openDrawerForTask(taskId: string, scrollToHint?: string): boolean { if (!taskId) { return false; } if (_state.isOpen && _state.activeTaskId === taskId) return true; // Already open for this task _state = { ..._state, isOpen: true, activeTaskId: taskId, scrollToHint: scrollToHint ?? null }; _notify(); return true; } export function setTaskDrawerAutoOpenPreference(enabled: boolean): void { autoOpenTaskDrawerPreference = enabled !== false; if (typeof window !== 'undefined') { window.localStorage.setItem( TASK_DRAWER_AUTO_OPEN_STORAGE_KEY, autoOpenTaskDrawerPreference ? 'true' : 'false', ); } } export function getTaskDrawerAutoOpenPreference(): boolean { return autoOpenTaskDrawerPreference; } export function openDrawerForTaskIfPreferred(taskId: string): boolean { if (autoOpenTaskDrawerPreference !== true) { return false; } return openDrawerForTask(taskId); } export function openDrawer(): void { if (_state.isOpen && _state.activeTaskId === null) return; _state = { ..._state, isOpen: true, activeTaskId: null }; _notify(); } export function closeDrawer(): void { if (!_state.isOpen) return; _state = { ..._state, isOpen: false, activeTaskId: null }; _notify(); } export function updateResourceTask(resourceId: string, taskId: string, status: string): void { const newMap: ResourceTaskMap = { ..._state.resourceTaskMap }; if (status === 'IDLE' || status === 'SUCCESS' || status === 'ERROR') { delete newMap[resourceId]; } else { newMap[resourceId] = { taskId, status }; } _state = { ..._state, resourceTaskMap: newMap }; _notify(); } export function getTaskForResource(resourceId: string): TaskInfo | null { return _state.resourceTaskMap[resourceId] || null; } // #endregion TaskDrawerStore