124 lines
3.5 KiB
TypeScript
124 lines
3.5 KiB
TypeScript
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 });
|
|
},
|
|
};
|