186 lines
4.6 KiB
TypeScript
186 lines
4.6 KiB
TypeScript
import type { IStatePersistenceConfig, IAppUIState } from '../../interfaces/appconfig.js';
|
|
|
|
/**
|
|
* Manager for persisting and restoring UI state
|
|
*/
|
|
export class StateManager {
|
|
private config: Required<IStatePersistenceConfig>;
|
|
private memoryStorage: Map<string, string> = new Map();
|
|
|
|
constructor(config: IStatePersistenceConfig = { enabled: false }) {
|
|
this.config = {
|
|
enabled: config.enabled,
|
|
storageKey: config.storageKey || 'dees-appui-state',
|
|
storage: config.storage || 'localStorage',
|
|
persist: {
|
|
mainMenuCollapsed: true,
|
|
secondaryMenuCollapsed: true,
|
|
selectedView: true,
|
|
secondaryMenuSelection: true,
|
|
collapsedGroups: true,
|
|
...config.persist,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if state persistence is enabled
|
|
*/
|
|
public isEnabled(): boolean {
|
|
return this.config.enabled;
|
|
}
|
|
|
|
/**
|
|
* Save current UI state
|
|
*/
|
|
public save(state: Partial<IAppUIState>): void {
|
|
if (!this.config.enabled) return;
|
|
|
|
const existingState = this.load() || {};
|
|
const newState: IAppUIState = {
|
|
...existingState,
|
|
timestamp: Date.now(),
|
|
};
|
|
|
|
// Only save what's configured
|
|
if (this.config.persist.selectedView && state.currentViewId !== undefined) {
|
|
newState.currentViewId = state.currentViewId;
|
|
}
|
|
if (this.config.persist.mainMenuCollapsed && state.mainMenuCollapsed !== undefined) {
|
|
newState.mainMenuCollapsed = state.mainMenuCollapsed;
|
|
}
|
|
if (this.config.persist.secondaryMenuCollapsed && state.secondaryMenuCollapsed !== undefined) {
|
|
newState.secondaryMenuCollapsed = state.secondaryMenuCollapsed;
|
|
}
|
|
if (this.config.persist.secondaryMenuSelection && state.secondaryMenuSelectedKey !== undefined) {
|
|
newState.secondaryMenuSelectedKey = state.secondaryMenuSelectedKey;
|
|
}
|
|
if (this.config.persist.collapsedGroups && state.collapsedGroups !== undefined) {
|
|
newState.collapsedGroups = state.collapsedGroups;
|
|
}
|
|
|
|
this.setItem(this.config.storageKey, JSON.stringify(newState));
|
|
}
|
|
|
|
/**
|
|
* Load persisted UI state
|
|
*/
|
|
public load(): IAppUIState | null {
|
|
if (!this.config.enabled) return null;
|
|
|
|
try {
|
|
const data = this.getItem(this.config.storageKey);
|
|
if (!data) return null;
|
|
return JSON.parse(data) as IAppUIState;
|
|
} catch (e) {
|
|
console.warn('Failed to load UI state:', e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear persisted state
|
|
*/
|
|
public clear(): void {
|
|
this.removeItem(this.config.storageKey);
|
|
}
|
|
|
|
/**
|
|
* Check if state exists
|
|
*/
|
|
public hasState(): boolean {
|
|
return this.getItem(this.config.storageKey) !== null;
|
|
}
|
|
|
|
/**
|
|
* Get state age in milliseconds
|
|
*/
|
|
public getStateAge(): number | null {
|
|
const state = this.load();
|
|
if (!state?.timestamp) return null;
|
|
return Date.now() - state.timestamp;
|
|
}
|
|
|
|
/**
|
|
* Update specific state properties
|
|
*/
|
|
public update(updates: Partial<IAppUIState>): void {
|
|
const currentState = this.load() || {};
|
|
this.save({ ...currentState, ...updates });
|
|
}
|
|
|
|
/**
|
|
* Get the storage key being used
|
|
*/
|
|
public getStorageKey(): string {
|
|
return this.config.storageKey;
|
|
}
|
|
|
|
// Storage abstraction methods
|
|
|
|
private getItem(key: string): string | null {
|
|
switch (this.config.storage) {
|
|
case 'localStorage':
|
|
try {
|
|
return localStorage.getItem(key);
|
|
} catch {
|
|
return null;
|
|
}
|
|
case 'sessionStorage':
|
|
try {
|
|
return sessionStorage.getItem(key);
|
|
} catch {
|
|
return null;
|
|
}
|
|
case 'memory':
|
|
return this.memoryStorage.get(key) || null;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private setItem(key: string, value: string): void {
|
|
switch (this.config.storage) {
|
|
case 'localStorage':
|
|
try {
|
|
localStorage.setItem(key, value);
|
|
} catch (e) {
|
|
console.warn('Failed to save to localStorage:', e);
|
|
}
|
|
break;
|
|
case 'sessionStorage':
|
|
try {
|
|
sessionStorage.setItem(key, value);
|
|
} catch (e) {
|
|
console.warn('Failed to save to sessionStorage:', e);
|
|
}
|
|
break;
|
|
case 'memory':
|
|
this.memoryStorage.set(key, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private removeItem(key: string): void {
|
|
switch (this.config.storage) {
|
|
case 'localStorage':
|
|
try {
|
|
localStorage.removeItem(key);
|
|
} catch {
|
|
// Ignore
|
|
}
|
|
break;
|
|
case 'sessionStorage':
|
|
try {
|
|
sessionStorage.removeItem(key);
|
|
} catch {
|
|
// Ignore
|
|
}
|
|
break;
|
|
case 'memory':
|
|
this.memoryStorage.delete(key);
|
|
break;
|
|
}
|
|
}
|
|
}
|