Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
handleKeyboardActivation,
Label,
} from '@sim/emcn'
import { Trash } from '@sim/emcn/icons'
import { createLogger } from '@sim/logger'
import { formatDate } from '@sim/utils/formatting'
import {
Expand All @@ -27,6 +26,7 @@ import {
} from '@/lib/knowledge/constants'
import type { DocumentTag } from '@/lib/knowledge/tags/types'
import type { DocumentData } from '@/lib/knowledge/types'
import { KnowledgeTagRow } from '@/app/workspace/[workspaceId]/knowledge/components/knowledge-tag-row'
import {
type TagDefinition,
useKnowledgeBaseTagDefinitions,
Expand Down Expand Up @@ -385,40 +385,24 @@ export function DocumentTagsModal({
<div className='space-y-2'>
{documentTags.map((tag, index) => (
<div key={tag.displayName} className='space-y-2'>
<div
<KnowledgeTagRow
role='button'
tabIndex={0}
className='flex cursor-pointer items-center gap-2 rounded-sm border p-2 hover-hover:bg-[var(--surface-2)]'
onClick={() => startEditingTag(index)}
onKeyDown={(event) => {
if (event.target !== event.currentTarget) return
handleKeyboardActivation(event, () => startEditingTag(index))
}}
>
<span className='min-w-0 truncate text-[var(--text-primary)] text-caption'>
{tag.displayName}
</span>
<span className='rounded-[3px] bg-[var(--surface-3)] px-1.5 py-0.5 text-[var(--text-muted)] text-micro'>
{FIELD_TYPE_LABELS[tag.fieldType] || tag.fieldType}
</span>
<div className='mb-[-1.5px] h-[14px] w-[1.25px] shrink-0 rounded-full bg-[var(--border-1)]' />
<span className='min-w-0 flex-1 truncate text-[var(--text-muted)] text-caption'>
{formatValueForDisplay(tag.value, tag.fieldType)}
</span>
<div className='flex shrink-0 items-center gap-1'>
<Button
aria-label='Remove tag'
variant='ghost-destructive-muted'
onClick={(e) => {
e.stopPropagation()
handleRemoveTag(index)
}}
className='size-4 p-0'
>
<Trash className='size-3' />
</Button>
</div>
</div>
name={tag.displayName}
typeLabel={FIELD_TYPE_LABELS[tag.fieldType] || tag.fieldType}
detail={formatValueForDisplay(tag.value, tag.fieldType)}
truncateDetail
removeLabel='Remove tag'
onRemove={(e) => {
e.stopPropagation()
handleRemoveTag(index)
}}
/>

{editingTagIndex === index && (
<div className='space-y-2 rounded-md border p-3'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
type ComboboxOption,
handleKeyboardActivation,
} from '@sim/emcn'
import { Trash } from '@sim/emcn/icons'
import { createLogger } from '@sim/logger'
import { getDocumentIcon } from '@/components/icons/document-icons'
import type { TagUsageData } from '@/lib/api/contracts/knowledge'
Expand All @@ -24,6 +23,7 @@ import {
SUPPORTED_FIELD_TYPES,
TAG_SLOT_CONFIG,
} from '@/lib/knowledge/constants'
import { KnowledgeTagRow } from '@/app/workspace/[workspaceId]/knowledge/components/knowledge-tag-row'
import {
type TagDefinition,
useKnowledgeBaseTagDefinitions,
Expand Down Expand Up @@ -270,41 +270,28 @@ export function BaseTagsModal({ open, onOpenChange, knowledgeBaseId }: BaseTagsM
{kbTagDefinitions.map((tag) => {
const usage = getTagUsage(tag.tagSlot)
return (
<div
<KnowledgeTagRow
key={tag.id}
role='button'
tabIndex={0}
className='flex cursor-pointer items-center gap-2 rounded-sm border p-2 hover-hover:bg-[var(--surface-2)]'
onClick={() => handleViewDocuments(tag)}
onKeyDown={(event) => {
if (event.target !== event.currentTarget) return
handleKeyboardActivation(event, () => handleViewDocuments(tag))
}}
>
<span className='min-w-0 truncate text-[var(--text-primary)] text-caption'>
{tag.displayName}
</span>
<span className='rounded-[3px] bg-[var(--surface-3)] px-1.5 py-0.5 text-[var(--text-muted)] text-micro'>
{FIELD_TYPE_LABELS[tag.fieldType] || tag.fieldType}
</span>
<div className='mb-[-1.5px] h-[14px] w-[1.25px] shrink-0 rounded-full bg-[var(--border-1)]' />
<span className='min-w-0 flex-1 text-[var(--text-muted)] text-caption'>
{usage.documentCount} document{usage.documentCount !== 1 ? 's' : ''}
</span>
<div className='flex shrink-0 items-center gap-1'>
<Button
aria-label='Delete Tag'
variant='ghost-destructive-muted'
onClick={(e) => {
e.stopPropagation()
handleDeleteTagClick(tag)
}}
className='size-4 p-0'
>
<Trash className='size-3' />
</Button>
</div>
</div>
name={tag.displayName}
typeLabel={FIELD_TYPE_LABELS[tag.fieldType] || tag.fieldType}
detail={
<>
{usage.documentCount} document{usage.documentCount !== 1 ? 's' : ''}
</>
}
removeLabel='Delete Tag'
onRemove={(e) => {
e.stopPropagation()
handleDeleteTagClick(tag)
}}
/>
)
})}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { HTMLAttributes, MouseEventHandler, ReactNode } from 'react'
import { Button, cn } from '@sim/emcn'
import { Trash } from '@sim/emcn/icons'

interface KnowledgeTagRowProps
extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className'> {
name: string
typeLabel: string
detail: ReactNode
truncateDetail?: boolean
removeLabel: string
onRemove: MouseEventHandler<HTMLButtonElement>
}

/** Shared tag summary; callers retain activation, keyboard and removal behavior. */
export function KnowledgeTagRow({
name,
typeLabel,
detail,
truncateDetail = false,
removeLabel,
onRemove,
...props
}: KnowledgeTagRowProps) {
return (
<div
{...props}
className='flex cursor-pointer items-center gap-2 rounded-sm border p-2 hover-hover:bg-[var(--surface-2)]'
>
<span className='min-w-0 truncate text-[var(--text-primary)] text-caption'>{name}</span>
<span className='rounded-[3px] bg-[var(--surface-3)] px-1.5 py-0.5 text-[var(--text-muted)] text-micro'>
{typeLabel}
</span>
<div className='mb-[-1.5px] h-[14px] w-[1.25px] shrink-0 rounded-full bg-[var(--border-1)]' />
<span
className={cn(
'min-w-0 flex-1 text-[var(--text-muted)] text-caption',
truncateDetail && 'truncate'
)}
>
{detail}
</span>
<div className='flex shrink-0 items-center gap-1'>
<Button
aria-label={removeLabel}
variant='ghost-destructive-muted'
onClick={onRemove}
className='size-4 p-0'
>
<Trash className='size-3' />
</Button>
</div>
</div>
)
}
Loading