mirror of
https://github.com/khoaliber/dockhand.git
synced 2026-03-02 21:19:05 +00:00
227 lines
5.9 KiB
TypeScript
227 lines
5.9 KiB
TypeScript
/**
|
|
* Grid Preferences Store for Dockhand
|
|
*
|
|
* Manages column visibility and ordering preferences with:
|
|
* - localStorage sync for flash-free loading
|
|
* - Database persistence via API
|
|
* - Per-grid configuration
|
|
*/
|
|
|
|
import { writable, get } from 'svelte/store';
|
|
import type { AllGridPreferences, GridId, ColumnPreference, GridColumnPreferences } from '$lib/types';
|
|
import { getDefaultColumnPreferences, getConfigurableColumns } from '$lib/config/grid-columns';
|
|
|
|
const STORAGE_KEY = 'dockhand-grid-preferences';
|
|
|
|
// Load initial state from localStorage
|
|
function loadFromStorage(): AllGridPreferences {
|
|
if (typeof window === 'undefined') return {};
|
|
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored) {
|
|
return JSON.parse(stored);
|
|
}
|
|
} catch {
|
|
// Ignore parse errors
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// Save to localStorage
|
|
function saveToStorage(prefs: AllGridPreferences) {
|
|
if (typeof window === 'undefined') return;
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
|
|
} catch {
|
|
// Ignore storage errors
|
|
}
|
|
}
|
|
|
|
// Create the store
|
|
function createGridPreferencesStore() {
|
|
const { subscribe, set, update } = writable<AllGridPreferences>(loadFromStorage());
|
|
|
|
return {
|
|
subscribe,
|
|
|
|
// Initialize from API (called on mount)
|
|
async init() {
|
|
try {
|
|
const res = await fetch('/api/preferences/grid');
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
const prefs = data.preferences || {};
|
|
set(prefs);
|
|
saveToStorage(prefs);
|
|
}
|
|
} catch {
|
|
// Use localStorage fallback
|
|
}
|
|
},
|
|
|
|
// Get visible columns for a grid (in order)
|
|
getVisibleColumns(gridId: GridId): ColumnPreference[] {
|
|
const prefs = get({ subscribe });
|
|
const gridPrefs = prefs[gridId];
|
|
|
|
if (!gridPrefs?.columns?.length) {
|
|
// Return defaults (all visible)
|
|
return getDefaultColumnPreferences(gridId);
|
|
}
|
|
|
|
// Return columns in saved order, filtering to visible ones
|
|
return gridPrefs.columns.filter((col) => col.visible);
|
|
},
|
|
|
|
// Get all columns for a grid (visible and hidden, in order)
|
|
getAllColumns(gridId: GridId): ColumnPreference[] {
|
|
const prefs = get({ subscribe });
|
|
const gridPrefs = prefs[gridId];
|
|
|
|
if (!gridPrefs?.columns?.length) {
|
|
// Return defaults (all visible)
|
|
return getDefaultColumnPreferences(gridId);
|
|
}
|
|
|
|
// Merge with defaults to ensure new columns are included
|
|
const defaults = getDefaultColumnPreferences(gridId);
|
|
const savedIds = new Set(gridPrefs.columns.map((c) => c.id));
|
|
|
|
// Start with saved columns, then add any new defaults
|
|
const result = [...gridPrefs.columns];
|
|
for (const def of defaults) {
|
|
if (!savedIds.has(def.id)) {
|
|
result.push(def);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
// Check if a specific column is visible
|
|
isColumnVisible(gridId: GridId, columnId: string): boolean {
|
|
const prefs = get({ subscribe });
|
|
const gridPrefs = prefs[gridId];
|
|
|
|
if (!gridPrefs?.columns?.length) {
|
|
// Defaults to visible
|
|
return true;
|
|
}
|
|
|
|
const col = gridPrefs.columns.find((c) => c.id === columnId);
|
|
return col ? col.visible : true;
|
|
},
|
|
|
|
// Update column visibility/order for a grid
|
|
async setColumns(gridId: GridId, columns: ColumnPreference[]) {
|
|
update((prefs) => {
|
|
const newPrefs = {
|
|
...prefs,
|
|
[gridId]: { columns }
|
|
};
|
|
saveToStorage(newPrefs);
|
|
return newPrefs;
|
|
});
|
|
|
|
// Save to database (async, non-blocking)
|
|
try {
|
|
await fetch('/api/preferences/grid', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ gridId, columns })
|
|
});
|
|
} catch {
|
|
// Silently fail - localStorage has the value
|
|
}
|
|
},
|
|
|
|
// Toggle a column's visibility
|
|
async toggleColumn(gridId: GridId, columnId: string) {
|
|
const allCols = this.getAllColumns(gridId);
|
|
const newColumns = allCols.map((col) =>
|
|
col.id === columnId ? { ...col, visible: !col.visible } : col
|
|
);
|
|
await this.setColumns(gridId, newColumns);
|
|
},
|
|
|
|
// Reset a grid to default columns
|
|
async resetGrid(gridId: GridId) {
|
|
const defaults = getDefaultColumnPreferences(gridId);
|
|
|
|
update((prefs) => {
|
|
const newPrefs = { ...prefs };
|
|
delete newPrefs[gridId];
|
|
saveToStorage(newPrefs);
|
|
return newPrefs;
|
|
});
|
|
|
|
// Delete from database
|
|
try {
|
|
await fetch(`/api/preferences/grid?gridId=${gridId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
} catch {
|
|
// Silently fail
|
|
}
|
|
},
|
|
|
|
// Get ordered column IDs for rendering
|
|
getColumnOrder(gridId: GridId): string[] {
|
|
const allCols = this.getAllColumns(gridId);
|
|
return allCols.filter((c) => c.visible).map((c) => c.id);
|
|
},
|
|
|
|
// Get saved width for a specific column
|
|
getColumnWidth(gridId: GridId, columnId: string): number | undefined {
|
|
const prefs = get({ subscribe });
|
|
const gridPrefs = prefs[gridId];
|
|
if (!gridPrefs?.columns?.length) return undefined;
|
|
const col = gridPrefs.columns.find((c) => c.id === columnId);
|
|
return col?.width;
|
|
},
|
|
|
|
// Get all saved widths as a Map
|
|
getColumnWidths(gridId: GridId): Map<string, number> {
|
|
const prefs = get({ subscribe });
|
|
const gridPrefs = prefs[gridId];
|
|
const widths = new Map<string, number>();
|
|
if (gridPrefs?.columns) {
|
|
for (const col of gridPrefs.columns) {
|
|
if (col.width !== undefined) {
|
|
widths.set(col.id, col.width);
|
|
}
|
|
}
|
|
}
|
|
return widths;
|
|
},
|
|
|
|
// Set width for a specific column (works for both configurable and fixed columns)
|
|
async setColumnWidth(gridId: GridId, columnId: string, width: number) {
|
|
const allCols = this.getAllColumns(gridId);
|
|
let found = false;
|
|
const newColumns = allCols.map((col) => {
|
|
if (col.id === columnId) {
|
|
found = true;
|
|
return { ...col, width };
|
|
}
|
|
return col;
|
|
});
|
|
|
|
// If column wasn't found (e.g., fixed column), add it
|
|
if (!found) {
|
|
newColumns.push({ id: columnId, visible: true, width });
|
|
}
|
|
|
|
await this.setColumns(gridId, newColumns);
|
|
},
|
|
|
|
// Get current preferences
|
|
get(): AllGridPreferences {
|
|
return get({ subscribe });
|
|
}
|
|
};
|
|
}
|
|
|
|
export const gridPreferencesStore = createGridPreferencesStore();
|