From 1d52f5d856c6c18bd6de2cf30f6ebb19e4021985 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Nov 2025 16:41:47 +0000 Subject: [PATCH 1/3] fix(api): fix JSONB cast error in GetApplication query The GetApplication query was failing with "invalid input syntax for type json" when catalog_template_id was NULL. This occurred because COALESCE(ct.manifest, '') tried to cast empty string to JSONB. Changed to COALESCE(ct.manifest::text, '{}') which: - Casts JSONB to text first - Uses valid JSON '{}' as default instead of invalid '' Fixes delete application 404 error. --- api/internal/db/applications.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/internal/db/applications.go b/api/internal/db/applications.go index 603bcbbc..2e27666e 100644 --- a/api/internal/db/applications.go +++ b/api/internal/db/applications.go @@ -167,7 +167,7 @@ func (a *ApplicationDB) GetApplication(ctx context.Context, appID string) (*mode COALESCE(ct.name, '') as template_name, COALESCE(ct.display_name, ia.display_name) as template_display_name, COALESCE(ct.description, '') as description, COALESCE(ct.category, '') as category, COALESCE(ct.app_type, '') as app_type, COALESCE(ct.icon_url, '') as icon_url, - COALESCE(ct.manifest, '') as manifest, + COALESCE(ct.manifest::text, '{}') as manifest, COALESCE(ia.install_status, '') as install_status, COALESCE(ia.install_message, '') as install_message FROM installed_applications ia From 20362d9e103b23c8a0b6ba5e594a6344b2f90551 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Nov 2025 16:51:19 +0000 Subject: [PATCH 2/3] fix(ui): optimistically update UI after deleting application Immediately removes the deleted application from state for instant UI feedback, then refreshes from server to ensure consistency. This prevents the delay caused by browser caching of GET requests. --- ui/src/pages/Applications.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/pages/Applications.tsx b/ui/src/pages/Applications.tsx index 7ad371c0..130a2a55 100644 --- a/ui/src/pages/Applications.tsx +++ b/ui/src/pages/Applications.tsx @@ -191,6 +191,8 @@ function ApplicationsContent() { try { await api.deleteApplication(selectedApp.id); + // Optimistically remove from state immediately for instant UI feedback + setApplications(prev => prev.filter(app => app.id !== selectedApp.id)); addNotification({ message: 'Application deleted successfully', severity: 'success', @@ -198,6 +200,7 @@ function ApplicationsContent() { }); setDeleteDialogOpen(false); setSelectedApp(null); + // Still refresh to ensure consistency with server await loadApplications(); } catch (error) { console.error('Failed to delete application:', error); From cdc6d66584fa00def4d06645c0aac996fe029908 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Nov 2025 16:57:19 +0000 Subject: [PATCH 3/3] fix(ui): add cache-busting to listApplications API call Adds timestamp parameter to prevent browser HTTP caching of the applications list endpoint, ensuring fresh data on page refresh. --- ui/src/lib/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/lib/api.ts b/ui/src/lib/api.ts index f8bda7c9..821301f8 100644 --- a/ui/src/lib/api.ts +++ b/ui/src/lib/api.ts @@ -1151,7 +1151,7 @@ class APIClient { // ============================================================================ async listApplications(enabledOnly?: boolean): Promise<{ applications: InstalledApplication[]; total: number }> { - const params: Record = {}; + const params: Record = { _t: Date.now().toString() }; // Cache bust if (enabledOnly) params.enabled = 'true'; const response = await this.client.get<{ applications: InstalledApplication[]; total: number }>('/applications', { params }); return response.data;