feat(transcripts): migration v5 meta — starred, tags, template, language, segments persisted
This commit is contained in:
@@ -94,10 +94,30 @@ import { toasts } from "$lib/stores/toasts.svelte.js";
|
||||
export const history = $state([]);
|
||||
|
||||
/** Shape a TranscriptDto row from `list_transcripts` into the UI entry shape
|
||||
* that HistoryPage expects. UI-only fields that were never persisted to
|
||||
* SQLite (segments, starred, manualTags, language, template) are absent. */
|
||||
* that HistoryPage expects.
|
||||
*
|
||||
* Task 2.5 — the meta columns (starred, manualTags, template, language,
|
||||
* segments_json) are now carried by SQLite. `manualTags` is stored comma-
|
||||
* joined in a single TEXT column (empty string = no tags); `segmentsJson`
|
||||
* is a serialised JSON array of segment objects (empty string = no
|
||||
* segments).
|
||||
*/
|
||||
function mapTranscriptRow(row) {
|
||||
const text = row.text ?? "";
|
||||
// manual_tags is a single TEXT column. Empty string ⇒ empty array.
|
||||
const rawTags = row.manualTags ?? "";
|
||||
const manualTags = rawTags ? rawTags.split(",").filter(Boolean) : [];
|
||||
// segments_json is a serialised array. Empty string ⇒ empty array.
|
||||
const rawSegments = row.segmentsJson ?? "";
|
||||
let segments = [];
|
||||
if (rawSegments) {
|
||||
try {
|
||||
const parsed = JSON.parse(rawSegments);
|
||||
if (Array.isArray(parsed)) segments = parsed;
|
||||
} catch (err) {
|
||||
console.warn("mapTranscriptRow: segmentsJson parse failed", err);
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: row.id,
|
||||
text,
|
||||
@@ -110,6 +130,11 @@ function mapTranscriptRow(row) {
|
||||
createdAt: row.createdAt ?? null,
|
||||
date: row.createdAt ? new Date(row.createdAt).toLocaleString("en-GB") : "",
|
||||
preview: text.slice(0, 120),
|
||||
starred: !!row.starred,
|
||||
manualTags,
|
||||
template: row.template ?? "",
|
||||
language: row.language ?? "",
|
||||
segments,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,9 +163,9 @@ if (typeof window !== "undefined" && hasTauriRuntime()) {
|
||||
// `saveHistory` is retained as a no-op for callers in HistoryPage that use
|
||||
// it as a mutation hook (tag add/remove, clear-all). SQLite writes happen
|
||||
// via the specific `add_transcript` / `update_transcript` /
|
||||
// `delete_transcript` commands in the functions below; ad-hoc UI-only
|
||||
// mutations (e.g. manualTags) are session-scoped because they are not
|
||||
// backed by a SQLite column.
|
||||
// `update_transcript_meta_cmd` / `delete_transcript` commands in the
|
||||
// functions below. HistoryPage's manualTags mutations will need to call
|
||||
// `saveTranscriptMeta` directly (Task 2.5) to persist past reload.
|
||||
export function saveHistory() {}
|
||||
|
||||
/**
|
||||
@@ -211,6 +236,47 @@ export async function renameHistoryEntry(id, updates) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task 2.5 — persist viewer metadata to SQLite via update_transcript_meta_cmd.
|
||||
* `patch` may contain any of:
|
||||
* - `starred: boolean`
|
||||
* - `manualTags: string[] | string` (array joined on ',' server-side)
|
||||
* - `template: string`
|
||||
* - `language: string`
|
||||
* - `segments: Array<object>` (JSON.stringify'd before the wire hop)
|
||||
* Omitted fields are preserved by COALESCE server-side. The in-memory
|
||||
* history row (if present) is refreshed from the returned canonical row
|
||||
* so the main-window list stays consistent.
|
||||
*
|
||||
* Returns nothing — callers needing the new row should read `history`.
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {Record<string, any>} patch
|
||||
*/
|
||||
export async function saveTranscriptMeta(id, patch) {
|
||||
if (!hasTauriRuntime()) return;
|
||||
try {
|
||||
const payload = {
|
||||
starred: patch.starred,
|
||||
manualTags: patch.manualTags == null
|
||||
? undefined
|
||||
: (Array.isArray(patch.manualTags)
|
||||
? patch.manualTags.join(",")
|
||||
: String(patch.manualTags)),
|
||||
template: patch.template,
|
||||
language: patch.language,
|
||||
segmentsJson: patch.segments ? JSON.stringify(patch.segments) : undefined,
|
||||
};
|
||||
const row = await invoke("update_transcript_meta_cmd", { id: String(id), patch: payload });
|
||||
const idx = history.findIndex((h) => String(h.id) === String(id));
|
||||
if (idx !== -1) {
|
||||
history[idx] = mapTranscriptRow(row);
|
||||
}
|
||||
} catch (err) {
|
||||
toasts.error("Failed to save transcript metadata", String(err));
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteFromHistory(index) {
|
||||
const entry = history[index];
|
||||
history.splice(index, 1);
|
||||
|
||||
Reference in New Issue
Block a user