feat(store): profiles store with create/update/delete/active selection
This commit is contained in:
123
src/lib/stores/profiles.svelte.ts
Normal file
123
src/lib/stores/profiles.svelte.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import { toasts } from "$lib/stores/toasts.svelte.ts";
|
||||
import { errorMessage } from "$lib/utils/errors.js";
|
||||
import { hasTauriRuntime } from "$lib/utils/runtime.js";
|
||||
|
||||
// Matches the SQLite-seeded Default profile UUID (see migration v6). Used as
|
||||
// the in-memory default for `activeProfileId` on boot. Cross-session
|
||||
// persistence of the selection is out of scope for Phase 2 — see Task 14
|
||||
// plan notes.
|
||||
export const DEFAULT_PROFILE_ID = "00000000-0000-0000-0000-000000000001";
|
||||
|
||||
// DTOs mirror the serde-camelCase shape emitted by the Tauri commands added
|
||||
// in Task 12. Kept local to this store until a second consumer appears.
|
||||
export interface ProfileDto {
|
||||
id: string;
|
||||
name: string;
|
||||
initialPrompt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface ProfileTermDto {
|
||||
id: string;
|
||||
profileId: string;
|
||||
term: string;
|
||||
note: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
let profilesState = $state<ProfileDto[]>([]);
|
||||
let activeProfileIdState = $state<string>(DEFAULT_PROFILE_ID);
|
||||
|
||||
export const profilesStore = {
|
||||
get profiles(): ProfileDto[] {
|
||||
return profilesState;
|
||||
},
|
||||
get activeProfileId(): string {
|
||||
return activeProfileIdState;
|
||||
},
|
||||
get active(): ProfileDto | null {
|
||||
return profilesState.find((p) => p.id === activeProfileIdState) ?? null;
|
||||
},
|
||||
|
||||
async load(): Promise<void> {
|
||||
if (!hasTauriRuntime()) return;
|
||||
try {
|
||||
profilesState = await invoke<ProfileDto[]>("list_profiles_cmd");
|
||||
} catch (err) {
|
||||
toasts.error("Failed to load profiles", errorMessage(err));
|
||||
}
|
||||
},
|
||||
|
||||
setActive(id: string): void {
|
||||
if (profilesState.find((p) => p.id === id)) {
|
||||
activeProfileIdState = id;
|
||||
}
|
||||
},
|
||||
|
||||
async create(name: string, initialPrompt: string): Promise<ProfileDto | null> {
|
||||
if (!hasTauriRuntime()) return null;
|
||||
try {
|
||||
const row = await invoke<ProfileDto>("create_profile_cmd", {
|
||||
name,
|
||||
initialPrompt,
|
||||
});
|
||||
profilesState = [...profilesState, row];
|
||||
return row;
|
||||
} catch (err) {
|
||||
toasts.error("Failed to create profile", errorMessage(err));
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update(id: string, name: string, initialPrompt: string): Promise<void> {
|
||||
if (!hasTauriRuntime()) return;
|
||||
try {
|
||||
await invoke("update_profile_cmd", { id, name, initialPrompt });
|
||||
profilesState = profilesState.map((p) =>
|
||||
p.id === id ? { ...p, name, initialPrompt } : p,
|
||||
);
|
||||
} catch (err) {
|
||||
toasts.error("Failed to update profile", errorMessage(err));
|
||||
}
|
||||
},
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
if (id === DEFAULT_PROFILE_ID) {
|
||||
toasts.error("Default profile cannot be deleted");
|
||||
return;
|
||||
}
|
||||
if (!hasTauriRuntime()) return;
|
||||
try {
|
||||
await invoke("delete_profile_cmd", { id });
|
||||
profilesState = profilesState.filter((p) => p.id !== id);
|
||||
if (activeProfileIdState === id) activeProfileIdState = DEFAULT_PROFILE_ID;
|
||||
} catch (err) {
|
||||
toasts.error("Failed to delete profile", errorMessage(err));
|
||||
}
|
||||
},
|
||||
|
||||
async listTerms(profileId: string): Promise<ProfileTermDto[]> {
|
||||
if (!hasTauriRuntime()) return [];
|
||||
return invoke<ProfileTermDto[]>("list_profile_terms_cmd", { profileId });
|
||||
},
|
||||
|
||||
async addTerm(
|
||||
profileId: string,
|
||||
term: string,
|
||||
note = "",
|
||||
): Promise<ProfileTermDto | null> {
|
||||
if (!hasTauriRuntime()) return null;
|
||||
return invoke<ProfileTermDto>("add_profile_term_cmd", {
|
||||
profileId,
|
||||
term,
|
||||
note,
|
||||
});
|
||||
},
|
||||
|
||||
async deleteTerm(termId: string): Promise<void> {
|
||||
if (!hasTauriRuntime()) return;
|
||||
await invoke("delete_profile_term_cmd", { id: termId });
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user