fix(combos): include DB id column in combo records for dashboard links

getCombos() selected only data/sort_order/context_cache_protection, so
combos whose JSON blob lacked an id field returned id: undefined. The
dashboard then linked to /dashboard/combos/undefined and Combo Control
Center failed with 'Combo not found'. Merge the id column into parsed
rows (authoritative, only when the blob has no id).
This commit is contained in:
Egor
2026-07-31 12:50:29 +03:00
parent 3eca8d9c0c
commit 904d45e011

View File

@@ -27,6 +27,21 @@ function getSortOrder(value: unknown): number | null {
return typeof row.sort_order === "number" ? row.sort_order : null;
}
function getComboId(value: unknown): string | null {
const row = asRecord(value);
return typeof row.id === "string" && row.id.trim().length > 0 ? row.id : null;
}
function withRowId(payload: string, row: JsonRecord): JsonRecord | null {
const parsed = withSortOrder(payload, getSortOrder(row));
if (!parsed) return null;
const comboId = getComboId(row);
if (comboId && typeof parsed.id !== "string") {
parsed.id = comboId;
}
return parsed;
}
function withSortOrder(payload: string, sortOrder: number | null): JsonRecord | null {
let parsed: JsonRecord;
try {
@@ -78,7 +93,7 @@ function normalizeStoredCombo(
function parseComboRow(row: unknown): JsonRecord | null {
const payload = getSerializedData(row);
if (!payload) return null;
const parsed = withSortOrder(payload, getSortOrder(row));
const parsed = withRowId(payload, asRecord(row));
if (!parsed) return null;
// Merge deduplicated column values back into the record
const record = asRecord(row);
@@ -104,7 +119,7 @@ function getNextSortOrder() {
export async function getCombos(limit?: number, offset?: number) {
const db = getDbInstance();
let sql =
"SELECT data, sort_order, context_cache_protection FROM combos ORDER BY sort_order ASC, name COLLATE NOCASE ASC";
"SELECT id, data, sort_order, context_cache_protection FROM combos ORDER BY sort_order ASC, name COLLATE NOCASE ASC";
const params: unknown[] = [];
if (limit !== undefined) {
sql += " LIMIT ? OFFSET ?";
@@ -136,7 +151,7 @@ export function getCombosCount(): number {
export async function getComboById(id: string) {
const db = getDbInstance();
const row = db
.prepare("SELECT data, sort_order, context_cache_protection FROM combos WHERE id = ?")
.prepare("SELECT id, data, sort_order, context_cache_protection FROM combos WHERE id = ?")
.get(id);
const combo = parseComboRow(row);
if (!combo) return null;
@@ -146,7 +161,7 @@ export async function getComboById(id: string) {
export async function getComboByName(name: string) {
const db = getDbInstance();
const row = db
.prepare("SELECT data, sort_order, context_cache_protection FROM combos WHERE name = ?")
.prepare("SELECT id, data, sort_order, context_cache_protection FROM combos WHERE name = ?")
.get(name);
const combo = parseComboRow(row);
if (!combo) return null;
@@ -162,7 +177,7 @@ export async function getComboByNameInsensitive(name: string) {
const db = getDbInstance();
const row = db
.prepare(
"SELECT data, sort_order, context_cache_protection FROM combos WHERE name = ? COLLATE NOCASE"
"SELECT id, data, sort_order, context_cache_protection FROM combos WHERE name = ? COLLATE NOCASE"
)
.get(name);
const combo = parseComboRow(row);
@@ -207,7 +222,7 @@ export async function createCombo(data: JsonRecord) {
export async function updateCombo(id: string, data: JsonRecord) {
const db = getDbInstance();
const existing = db
.prepare("SELECT data, sort_order, context_cache_protection FROM combos WHERE id = ?")
.prepare("SELECT id, data, sort_order, context_cache_protection FROM combos WHERE id = ?")
.get(id);
if (!existing) return null;