web/src/lib/storage.ts 2.0 K raw
1
import type { Profile } from './types';
2
3
const STORAGE_KEY = 'kd_profiles';
4
5
export function loadProfiles(): Profile[] {
6
  try {
7
    const raw = localStorage.getItem(STORAGE_KEY);
8
    if (!raw) return [];
9
    const parsed = JSON.parse(raw);
10
    if (!Array.isArray(parsed)) return [];
11
    return parsed.filter(
12
      (p: any) =>
13
        p &&
14
        typeof p.id === 'string' &&
15
        typeof p.name === 'string' &&
16
        Array.isArray(p.aggregations),
17
    );
18
  } catch {
19
    return [];
20
  }
21
}
22
23
export function saveProfile(profile: Profile): void {
24
  const profiles = loadProfiles();
25
  profiles.push(profile);
26
  localStorage.setItem(STORAGE_KEY, JSON.stringify(profiles));
27
}
28
29
export function deleteProfile(id: string): void {
30
  const profiles = loadProfiles().filter((p) => p.id !== id);
31
  localStorage.setItem(STORAGE_KEY, JSON.stringify(profiles));
32
}
33
34
export function exportProfile(profile: Profile): void {
35
  const json = JSON.stringify(profile, null, 2);
36
  const blob = new Blob([json], { type: 'application/json' });
37
  const url = URL.createObjectURL(blob);
38
  const a = document.createElement('a');
39
  a.href = url;
40
  a.download = `${profile.name.replace(/[^a-z0-9_-]/gi, '_')}.json`;
41
  a.click();
42
  URL.revokeObjectURL(url);
43
}
44
45
export function importProfile(file: File): Promise<Profile> {
46
  return new Promise((resolve, reject) => {
47
    const reader = new FileReader();
48
    reader.onload = () => {
49
      try {
50
        const profile = JSON.parse(reader.result as string);
51
        if (
52
          !profile ||
53
          typeof profile.name !== 'string' ||
54
          !Array.isArray(profile.aggregations)
55
        ) {
56
          reject(new Error('Invalid profile format'));
57
          return;
58
        }
59
        // Assign a new ID to avoid collisions
60
        profile.id = crypto.randomUUID();
61
        resolve(profile as Profile);
62
      } catch {
63
        reject(new Error('Failed to parse profile JSON'));
64
      }
65
    };
66
    reader.onerror = () => reject(new Error('Failed to read file'));
67
    reader.readAsText(file);
68
  });
69
}