From bcde710cabfc0a716306dfd01d503642c73472d0 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Wed, 25 Mar 2026 21:12:17 +0300 Subject: [PATCH] fix: search store now parses API envelope response correctly The search API returns { success, data: [...] } but the store was looking for data.apps and data.boards (which don't exist). Fixed to read from data.data[] and also added url/icon fields to search API response so app results are clickable and show icons. --- src/lib/stores/search.svelte.ts | 33 +++++++++++++++----------------- src/routes/api/search/+server.ts | 31 ++++++++++++++++-------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/lib/stores/search.svelte.ts b/src/lib/stores/search.svelte.ts index 416dfad..d36ea1c 100644 --- a/src/lib/stores/search.svelte.ts +++ b/src/lib/stores/search.svelte.ts @@ -100,31 +100,28 @@ class SearchStore { return; } - const data = await res.json(); + const json = await res.json(); + const results = json.data ?? []; const items: SearchResultItem[] = []; - if (data.apps) { - for (const app of data.apps) { + for (const item of results) { + if (item.type === 'app') { items.push({ type: 'app', - id: app.id, - name: app.name, - description: app.description ?? null, - url: app.url, - icon: app.icon ?? null + id: item.id, + name: item.name, + description: item.description ?? null, + url: item.url ?? `/apps/${item.id}`, + icon: item.icon ?? null }); - } - } - - if (data.boards) { - for (const board of data.boards) { + } else if (item.type === 'board') { items.push({ type: 'board', - id: board.id, - name: board.name, - description: board.description ?? null, - url: `/boards/${board.id}`, - icon: board.icon ?? null + id: item.id, + name: item.name, + description: item.description ?? null, + url: `/boards/${item.id}`, + icon: item.icon ?? null }); } } diff --git a/src/routes/api/search/+server.ts b/src/routes/api/search/+server.ts index 5bcab37..4cff7bb 100644 --- a/src/routes/api/search/+server.ts +++ b/src/routes/api/search/+server.ts @@ -11,6 +11,8 @@ interface SearchResult { readonly id: string; readonly name: string; readonly description: string | null; + readonly url?: string; + readonly icon?: string | null; readonly category?: string | null; } @@ -39,6 +41,9 @@ export const GET: RequestHandler = async (event) => { select: { id: true, name: true, + url: true, + icon: true, + iconType: true, description: true, category: true }, @@ -66,14 +71,18 @@ export const GET: RequestHandler = async (event) => { // Filter apps by permission const filteredApps: SearchResult[] = []; for (const app of apps) { + const appResult: SearchResult = { + type: 'app', + id: app.id, + name: app.name, + description: app.description, + url: app.url, + icon: app.icon, + category: app.category + }; + if (isAdmin) { - filteredApps.push({ - type: 'app', - id: app.id, - name: app.name, - description: app.description, - category: app.category - }); + filteredApps.push(appResult); continue; } @@ -84,13 +93,7 @@ export const GET: RequestHandler = async (event) => { PermissionLevel.VIEW ); if (check.hasPermission) { - filteredApps.push({ - type: 'app', - id: app.id, - name: app.name, - description: app.description, - category: app.category - }); + filteredApps.push(appResult); } }