From 950be8e17d0d1e6548c9f748ec6be025f2a33d05 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Tue, 31 Mar 2026 19:27:32 +0200 Subject: [PATCH] Fix review issues: idempotent migration, toggle guard, picker states --- .../versions/112_add_prompt_library_schema.py | 16 ++++++-- .../components/PromptsContent.tsx | 38 ++++++++++++------- .../components/new-chat/prompt-picker.tsx | 19 +++++++--- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/surfsense_backend/alembic/versions/112_add_prompt_library_schema.py b/surfsense_backend/alembic/versions/112_add_prompt_library_schema.py index 48ab27d51..0b10113f6 100644 --- a/surfsense_backend/alembic/versions/112_add_prompt_library_schema.py +++ b/surfsense_backend/alembic/versions/112_add_prompt_library_schema.py @@ -6,6 +6,7 @@ Revises: 111 from collections.abc import Sequence +import sqlalchemy as sa from alembic import op revision: str = "112" @@ -31,10 +32,17 @@ def upgrade() -> None: "CREATE INDEX IF NOT EXISTS ix_prompts_default_prompt_slug" " ON prompts (default_prompt_slug)" ) - op.execute( - "ALTER TABLE prompts ADD CONSTRAINT uq_prompt_user_default_slug" - " UNIQUE (user_id, default_prompt_slug)" - ) + conn = op.get_bind() + exists = conn.execute( + sa.text( + "SELECT 1 FROM pg_constraint WHERE conname = 'uq_prompt_user_default_slug'" + ) + ).scalar() + if not exists: + op.execute( + "ALTER TABLE prompts ADD CONSTRAINT uq_prompt_user_default_slug" + " UNIQUE (user_id, default_prompt_slug)" + ) op.execute( "ALTER TABLE prompts ADD COLUMN IF NOT EXISTS" " version INTEGER NOT NULL DEFAULT 1" diff --git a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx index ee760caa9..476fd05a6 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx @@ -48,6 +48,7 @@ export function PromptsContent() { const [isSaving, setIsSaving] = useState(false); const [expandedId, setExpandedId] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); + const [togglingPublicIds, setTogglingPublicIds] = useState>(new Set()); const handleSave = useCallback(async () => { if (!formData.name.trim() || !formData.prompt.trim()) { @@ -96,13 +97,21 @@ export function PromptsContent() { const handleTogglePublic = useCallback( async (prompt: PromptRead) => { + if (togglingPublicIds.has(prompt.id)) return; + setTogglingPublicIds((prev) => new Set(prev).add(prompt.id)); try { await updatePrompt({ id: prompt.id, is_public: !prompt.is_public }); } catch { // toast handled by mutation atom + } finally { + setTogglingPublicIds((prev) => { + const next = new Set(prev); + next.delete(prompt.id); + return next; + }); } }, - [updatePrompt] + [updatePrompt, togglingPublicIds] ); const handleCancel = useCallback(() => { @@ -276,18 +285,21 @@ export function PromptsContent() { )}
- +