diff --git a/apps/sim/app/api/knowledge/[id]/tag-definitions/route.ts b/apps/sim/app/api/knowledge/[id]/tag-definitions/route.ts index 09f1fc7873..ba52994c88 100644 --- a/apps/sim/app/api/knowledge/[id]/tag-definitions/route.ts +++ b/apps/sim/app/api/knowledge/[id]/tag-definitions/route.ts @@ -2,7 +2,7 @@ import { randomUUID } from 'crypto' import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' -import { getSession } from '@/lib/auth' +import { checkHybridAuth } from '@/lib/auth/hybrid' import { SUPPORTED_FIELD_TYPES } from '@/lib/knowledge/constants' import { createTagDefinition, getTagDefinitions } from '@/lib/knowledge/tags/service' import { checkKnowledgeBaseAccess } from '@/app/api/knowledge/utils' @@ -19,19 +19,32 @@ export async function GET(req: NextRequest, { params }: { params: Promise<{ id: try { logger.info(`[${requestId}] Getting tag definitions for knowledge base ${knowledgeBaseId}`) - const session = await getSession() - if (!session?.user?.id) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + const auth = await checkHybridAuth(req, { requireWorkflowId: false }) + if (!auth.success) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) } - const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, session.user.id) - if (!accessCheck.hasAccess) { - return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) + // Only allow session and internal JWT auth (not API key) + if (auth.authType === 'api_key') { + return NextResponse.json( + { error: 'API key auth not supported for this endpoint' }, + { status: 401 } + ) + } + + // For session auth, verify KB access. Internal JWT is trusted. + if (auth.authType === 'session' && auth.userId) { + const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, auth.userId) + if (!accessCheck.hasAccess) { + return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) + } } const tagDefinitions = await getTagDefinitions(knowledgeBaseId) - logger.info(`[${requestId}] Retrieved ${tagDefinitions.length} tag definitions`) + logger.info( + `[${requestId}] Retrieved ${tagDefinitions.length} tag definitions (${auth.authType})` + ) return NextResponse.json({ success: true, @@ -51,14 +64,25 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id: try { logger.info(`[${requestId}] Creating tag definition for knowledge base ${knowledgeBaseId}`) - const session = await getSession() - if (!session?.user?.id) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + const auth = await checkHybridAuth(req, { requireWorkflowId: false }) + if (!auth.success) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) } - const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, session.user.id) - if (!accessCheck.hasAccess) { - return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) + // Only allow session and internal JWT auth (not API key) + if (auth.authType === 'api_key') { + return NextResponse.json( + { error: 'API key auth not supported for this endpoint' }, + { status: 401 } + ) + } + + // For session auth, verify KB access. Internal JWT is trusted. + if (auth.authType === 'session' && auth.userId) { + const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, auth.userId) + if (!accessCheck.hasAccess) { + return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) + } } const body = await req.json() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-selector/document-selector.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-selector/document-selector.tsx index 938b45029e..012c78338f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-selector/document-selector.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-selector/document-selector.tsx @@ -15,6 +15,7 @@ interface DocumentSelectorProps { onDocumentSelect?: (documentId: string) => void isPreview?: boolean previewValue?: string | null + previewContextValues?: Record } export function DocumentSelector({ @@ -24,9 +25,15 @@ export function DocumentSelector({ onDocumentSelect, isPreview = false, previewValue, + previewContextValues, }: DocumentSelectorProps) { - const { finalDisabled } = useDependsOnGate(blockId, subBlock, { disabled, isPreview }) - const [knowledgeBaseIdValue] = useSubBlockValue(blockId, 'knowledgeBaseId') + const { finalDisabled } = useDependsOnGate(blockId, subBlock, { + disabled, + isPreview, + previewContextValues, + }) + const [knowledgeBaseIdFromStore] = useSubBlockValue(blockId, 'knowledgeBaseId') + const knowledgeBaseIdValue = previewContextValues?.knowledgeBaseId ?? knowledgeBaseIdFromStore const normalizedKnowledgeBaseId = typeof knowledgeBaseIdValue === 'string' && knowledgeBaseIdValue.trim().length > 0 ? knowledgeBaseIdValue diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx index fcdee23504..ae05f4ad58 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx @@ -37,6 +37,7 @@ interface DocumentTagEntryProps { disabled?: boolean isPreview?: boolean previewValue?: any + previewContextValues?: Record } /** @@ -56,6 +57,7 @@ export function DocumentTagEntry({ disabled = false, isPreview = false, previewValue, + previewContextValues, }: DocumentTagEntryProps) { const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlock.id) const accessiblePrefixes = useAccessibleReferencePrefixes(blockId) @@ -74,8 +76,12 @@ export function DocumentTagEntry({ disabled, }) - const [knowledgeBaseIdValue] = useSubBlockValue(blockId, 'knowledgeBaseId') - const knowledgeBaseId = knowledgeBaseIdValue || null + const [knowledgeBaseIdFromStore] = useSubBlockValue(blockId, 'knowledgeBaseId') + const knowledgeBaseIdValue = previewContextValues?.knowledgeBaseId ?? knowledgeBaseIdFromStore + const knowledgeBaseId = + typeof knowledgeBaseIdValue === 'string' && knowledgeBaseIdValue.trim().length > 0 + ? knowledgeBaseIdValue + : null const { tagDefinitions, isLoading } = useKnowledgeBaseTagDefinitions(knowledgeBaseId) const emitTagSelection = useTagSelection(blockId, subBlock.id) @@ -131,11 +137,16 @@ export function DocumentTagEntry({ } /** - * Removes a tag by ID (prevents removing the last tag) + * Removes a tag by ID, or resets it if it's the last one */ const removeTag = (id: string) => { - if (isReadOnly || tags.length === 1) return - updateTags(tags.filter((t) => t.id !== id)) + if (isReadOnly) return + if (tags.length === 1) { + // Reset the last tag instead of removing it + updateTags([createDefaultTag()]) + } else { + updateTags(tags.filter((t) => t.id !== id)) + } } /** @@ -222,6 +233,7 @@ export function DocumentTagEntry({ /** * Renders the tag header with name, badge, and action buttons + * Shows tag name only when collapsed (as summary), generic label when expanded */ const renderTagHeader = (tag: DocumentTag, index: number) => (
- {tag.tagName || `Tag ${index + 1}`} + {tag.collapsed ? tag.tagName || `Tag ${index + 1}` : `Tag ${index + 1}`} - {tag.tagName && {FIELD_TYPE_LABELS[tag.fieldType] || 'Text'}} + {tag.collapsed && tag.tagName && ( + {FIELD_TYPE_LABELS[tag.fieldType] || 'Text'} + )}
e.stopPropagation()}>