From 96d6e8811a06a2793a0694d6c5d7f70b68735bd9 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 31 Jul 2025 21:19:50 -0700 Subject: [PATCH 1/3] fix(kb-tags): docs page kb tags ui --- .../components/upload-modal/upload-modal.tsx | 38 +- .../document-tag-entry/document-tag-entry.tsx | 455 ++++++++++-------- 2 files changed, 262 insertions(+), 231 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/upload-modal/upload-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/upload-modal/upload-modal.tsx index 29195f1386b..ccb474fd94a 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/upload-modal/upload-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/upload-modal/upload-modal.tsx @@ -6,10 +6,6 @@ import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Label } from '@/components/ui/label' import { createLogger } from '@/lib/logs/console/logger' -import { - type DocumentTag, - DocumentTagEntry, -} from '@/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry' import { useKnowledgeUpload } from '@/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload' const logger = createLogger('UploadModal') @@ -50,7 +46,7 @@ export function UploadModal({ }: UploadModalProps) { const fileInputRef = useRef(null) const [files, setFiles] = useState([]) - const [tags, setTags] = useState([]) + const [fileError, setFileError] = useState(null) const [isDragging, setIsDragging] = useState(false) @@ -66,7 +62,6 @@ export function UploadModal({ if (isUploading) return // Prevent closing during upload setFiles([]) - setTags([]) setFileError(null) setIsDragging(false) onOpenChange(false) @@ -145,23 +140,7 @@ export function UploadModal({ if (files.length === 0) return try { - // Convert DocumentTag array to TagData format - const tagData: Record = {} - tags.forEach((tag) => { - if (tag.value.trim()) { - tagData[tag.slot] = tag.value.trim() - } - }) - - // Create files with tags for upload - const filesWithTags = files.map((file) => { - // Add tags as custom properties to the file object - const fileWithTags = file as unknown as File & Record - Object.assign(fileWithTags, tagData) - return fileWithTags - }) - - await uploadFiles(filesWithTags, knowledgeBaseId, { + await uploadFiles(files, knowledgeBaseId, { chunkSize: chunkingConfig?.maxSize || 1024, minCharactersPerChunk: chunkingConfig?.minSize || 100, chunkOverlap: chunkingConfig?.overlap || 200, @@ -180,19 +159,6 @@ export function UploadModal({
- {/* Document Tag Entry Section */} - { - // For upload modal, tags are saved when document is uploaded - // This is a placeholder as tags will be applied during upload - }} - /> - {/* File Upload Section */}
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx index 9985842abde..f6eedc20613 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx @@ -3,14 +3,23 @@ import { useState } from 'react' import { ChevronDown, Plus, X } from 'lucide-react' import { + Badge, Button, + Dialog, + DialogContent, + DialogHeader, + DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, - formatDisplayText, Input, Label, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, } from '@/components/ui' import { MAX_TAG_SLOTS, TAG_SLOTS, type TagSlot } from '@/lib/constants/knowledge' import { useKnowledgeBaseTagDefinitions } from '@/hooks/use-knowledge-base-tag-definitions' @@ -29,7 +38,7 @@ interface DocumentTagEntryProps { disabled?: boolean knowledgeBaseId: string documentId: string | null - onSave: (tagsToSave: DocumentTag[]) => Promise + onSave?: (tagsToSave: DocumentTag[]) => Promise } export function DocumentTagEntry({ @@ -40,19 +49,26 @@ export function DocumentTagEntry({ documentId, onSave, }: DocumentTagEntryProps) { - const { saveTagDefinitions } = useTagDefinitions(knowledgeBaseId, documentId) - const { tagDefinitions: kbTagDefinitions, fetchTagDefinitions: refreshTagDefinitions } = - useKnowledgeBaseTagDefinitions(knowledgeBaseId) + // Use different hooks based on whether we have a documentId + const documentTagHook = useTagDefinitions(knowledgeBaseId, documentId) + const kbTagHook = useKnowledgeBaseTagDefinitions(knowledgeBaseId) - const [editingTag, setEditingTag] = useState<{ - index: number - value: string - tagName: string - isNew: boolean - } | null>(null) + // Use the document-level hook since we have documentId + const { saveTagDefinitions } = documentTagHook + const { tagDefinitions: kbTagDefinitions, fetchTagDefinitions: refreshTagDefinitions } = kbTagHook + + // Modal state for tag editing + const [editingTagIndex, setEditingTagIndex] = useState(null) + const [modalOpen, setModalOpen] = useState(false) + const [editForm, setEditForm] = useState({ + displayName: '', + fieldType: 'text', + value: '', + }) const getNextAvailableSlot = (): DocumentTag['slot'] => { - const usedSlots = new Set(tags.map((tag) => tag.slot)) + // Check which slots are used at the KB level (tag definitions) + const usedSlots = new Set(kbTagDefinitions.map((def) => def.tagSlot)) for (const slot of TAG_SLOTS) { if (!usedSlots.has(slot)) { return slot @@ -61,82 +77,124 @@ export function DocumentTagEntry({ return TAG_SLOTS[0] // Fallback to first slot if all are used } - const handleAddTag = () => { - if (tags.length >= MAX_TAG_SLOTS) return + const handleRemoveTag = (index: number) => { + const updatedTags = tags.filter((_, i) => i !== index) + onTagsChange(updatedTags) + } - const newTag: DocumentTag = { - slot: getNextAvailableSlot(), + // Open modal to edit tag + const openTagModal = (index: number) => { + const tag = tags[index] + setEditingTagIndex(index) + setEditForm({ + displayName: tag.displayName, + fieldType: tag.fieldType, + value: tag.value, + }) + setModalOpen(true) + } + + // Open modal to create new tag + const openNewTagModal = () => { + setEditingTagIndex(null) + setEditForm({ displayName: '', fieldType: 'text', value: '', - } - - const updatedTags = [...tags, newTag] - onTagsChange(updatedTags) - - // Set editing state for the new tag - setEditingTag({ - index: updatedTags.length - 1, - value: '', - tagName: '', - isNew: true, }) + setModalOpen(true) } - const handleRemoveTag = (index: number) => { - const updatedTags = tags.filter((_, i) => i !== index) - onTagsChange(updatedTags) - } + // Save tag from modal + const saveTagFromModal = async () => { + if (!editForm.displayName.trim()) return - const handleTagUpdate = (index: number, field: keyof DocumentTag, value: string) => { - const updatedTags = [...tags] - updatedTags[index] = { ...updatedTags[index], [field]: value } - onTagsChange(updatedTags) - } + console.log('Saving tag from modal:', editForm, 'editingTagIndex:', editingTagIndex) - const handleSaveTag = async (index: number, tagName: string) => { - if (!tagName.trim()) return + try { + if (editingTagIndex !== null) { + // Editing existing tag + const updatedTags = [...tags] + updatedTags[editingTagIndex] = { + ...updatedTags[editingTagIndex], + displayName: editForm.displayName, + fieldType: editForm.fieldType, + value: editForm.value, + } + onTagsChange(updatedTags) + } else { + // Creating new tag - calculate slot once + const newSlot = getNextAvailableSlot() + const newTag: DocumentTag = { + slot: newSlot, + displayName: editForm.displayName, + fieldType: editForm.fieldType, + value: editForm.value, + } + const newTags = [...tags, newTag] + console.log('Adding new tag:', newTag, 'New tags array:', newTags) + onTagsChange(newTags) + } - // Check if this is creating a new tag definition - const existingDefinition = kbTagDefinitions.find( - (def) => def.displayName.toLowerCase() === tagName.toLowerCase() - ) + // Auto-save tag definition if it's a new name + const existingDefinition = kbTagDefinitions.find( + (def) => def.displayName.toLowerCase() === editForm.displayName.toLowerCase() + ) - if (!existingDefinition) { - // Create new tag definition - const newDefinition: TagDefinitionInput = { - displayName: tagName, - fieldType: 'text', - tagSlot: tags[index].slot as TagSlot, - } + if (!existingDefinition) { + // Use the same slot for both tag and definition + const targetSlot = + editingTagIndex !== null ? tags[editingTagIndex].slot : getNextAvailableSlot() - try { - await saveTagDefinitions([newDefinition]) + const newDefinition: TagDefinitionInput = { + displayName: editForm.displayName, + fieldType: editForm.fieldType, + tagSlot: targetSlot as TagSlot, + } + + if (saveTagDefinitions) { + console.log('Saving tag definition:', newDefinition) + await saveTagDefinitions([newDefinition]) + console.log('Tag definition saved successfully') + } else { + throw new Error('Cannot save tag definitions without a document ID') + } + console.log('Refreshing tag definitions...') await refreshTagDefinitions() - } catch (error) { - console.error('Failed to save tag definition:', error) - return + console.log('Tag definitions refreshed') } - } - - // Update the tag - handleTagUpdate(index, 'displayName', tagName) - setEditingTag(null) - } - const handleCancelEdit = () => { - if (editingTag?.isNew) { - // Remove the new tag if editing was cancelled - handleRemoveTag(editingTag.index) - } - setEditingTag(null) - } + // Save the actual document tags if onSave is provided + if (onSave) { + console.log('Saving document tags...') + const updatedTags = + editingTagIndex !== null + ? tags.map((tag, index) => + index === editingTagIndex + ? { + ...tag, + displayName: editForm.displayName, + fieldType: editForm.fieldType, + value: editForm.value, + } + : tag + ) + : [ + ...tags, + { + slot: getNextAvailableSlot(), + displayName: editForm.displayName, + fieldType: editForm.fieldType, + value: editForm.value, + }, + ] + await onSave(updatedTags) + console.log('Document tags saved successfully') + } - const handleSaveAll = async () => { - try { - await onSave(tags) + setModalOpen(false) } catch (error) { - console.error('Failed to save tags:', error) + console.error('Failed to save tag:', error) } } @@ -149,142 +207,149 @@ export function DocumentTagEntry({

Document Tags

-
- - -
+ {tag.displayName || 'Unnamed Tag'} + {tag.value && ( + <> + : + {tag.value} + + )} + + + ))} + + {/* Add Tag Button */} +
- {tags.length === 0 ? ( + {tags.length === 0 && (
-

No tags added yet

+

+ No tags added yet. Click "Add Tag" to get started. +

- ) : ( -
- {tags.map((tag, index) => ( -
-
- {editingTag?.index === index ? ( -
-
- setEditingTag({ ...editingTag, tagName: e.target.value })} - placeholder='Tag name' - className='flex-1' - autoFocus - /> - - - - - - {availableDefinitions.map((def) => ( - - setEditingTag({ ...editingTag, tagName: def.displayName }) - } - > - {def.displayName} - - ))} - {availableDefinitions.length === 0 && ( - No available tags - )} - - -
-
- - -
-
- ) : ( -
-
-
-
- {tag.displayName || 'Unnamed Tag'} -
-
- Slot: {tag.slot} • Type: {tag.fieldType} -
-
- -
-
- -
- handleTagUpdate(index, 'value', e.target.value)} - placeholder='Enter tag value' - disabled={disabled} - className='w-full text-transparent caret-foreground' - /> -
-
{formatDisplayText(tag.value)}
-
-
-
-
+ + + {availableDefinitions.map((def) => ( + + setEditForm({ + ...editForm, + displayName: def.displayName, + fieldType: def.fieldType, + }) + } + > + {def.displayName} + + ))} + + )}
-
+ + {/* Tag Type */} +
+ +
- ))} -
- )} -
- {tags.length} of {MAX_TAG_SLOTS} tag slots used -
+ {/* Tag Value */} +
+ + setEditForm({ ...editForm, value: e.target.value })} + placeholder='Enter tag value' + /> +
+
+ +
+ + +
+ +
) } From 5f35102874ed4414387c219f0322227c634fac55 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 31 Jul 2025 21:22:59 -0700 Subject: [PATCH 2/3] remove console logs --- .../components/document-tag-entry/document-tag-entry.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx index f6eedc20613..d3e2530005d 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx @@ -109,8 +109,6 @@ export function DocumentTagEntry({ const saveTagFromModal = async () => { if (!editForm.displayName.trim()) return - console.log('Saving tag from modal:', editForm, 'editingTagIndex:', editingTagIndex) - try { if (editingTagIndex !== null) { // Editing existing tag @@ -132,7 +130,6 @@ export function DocumentTagEntry({ value: editForm.value, } const newTags = [...tags, newTag] - console.log('Adding new tag:', newTag, 'New tags array:', newTags) onTagsChange(newTags) } @@ -153,20 +150,15 @@ export function DocumentTagEntry({ } if (saveTagDefinitions) { - console.log('Saving tag definition:', newDefinition) await saveTagDefinitions([newDefinition]) - console.log('Tag definition saved successfully') } else { throw new Error('Cannot save tag definitions without a document ID') } - console.log('Refreshing tag definitions...') await refreshTagDefinitions() - console.log('Tag definitions refreshed') } // Save the actual document tags if onSave is provided if (onSave) { - console.log('Saving document tags...') const updatedTags = editingTagIndex !== null ? tags.map((tag, index) => @@ -189,7 +181,6 @@ export function DocumentTagEntry({ }, ] await onSave(updatedTags) - console.log('Document tags saved successfully') } setModalOpen(false) From 1622f216c5ad6e5dc2aece144e8e1d8ebc8fa0e0 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 31 Jul 2025 21:24:01 -0700 Subject: [PATCH 3/3] remove console error --- .../components/document-tag-entry/document-tag-entry.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx index d3e2530005d..55baabc5829 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/document-tag-entry/document-tag-entry.tsx @@ -184,9 +184,7 @@ export function DocumentTagEntry({ } setModalOpen(false) - } catch (error) { - console.error('Failed to save tag:', error) - } + } catch (error) {} } // Filter available tag definitions (exclude already used ones)