Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e622b6e
improvement(tables): improve table filtering UX
waleedlatif1 Mar 29, 2026
bcc7974
fix(table-filter): use ref to stabilize handleRemove/handleApply call…
waleedlatif1 Mar 29, 2026
5d037ac
improvement(tables,kb): remove hacky patterns, fix KB filter popover …
waleedlatif1 Mar 29, 2026
2e67864
feat(knowledge): add sort and filter to KB list page
waleedlatif1 Mar 29, 2026
866e91d
feat(files): add sort and filter to files list page
waleedlatif1 Mar 29, 2026
6c18471
feat(scheduled-tasks): add sort and filter to scheduled tasks page
waleedlatif1 Mar 29, 2026
f46f83c
fix(table-filter): use explicit close handler instead of toggle
waleedlatif1 Mar 29, 2026
8a1f3dc
improvement(files,knowledge): replace manual debounce with useDebounc…
waleedlatif1 Mar 29, 2026
4899dc3
fix(resource): prevent popover from inheriting anchor min-width
waleedlatif1 Mar 29, 2026
f6edb88
feat(tables): add sort to tables list page
waleedlatif1 Mar 29, 2026
51c9df9
feat(knowledge): add content and owner filters to KB list
waleedlatif1 Mar 29, 2026
12ea734
feat(scheduled-tasks): add status and health filters
waleedlatif1 Mar 29, 2026
a3ffc2f
feat(files): add size and uploaded-by filters to files list
waleedlatif1 Mar 29, 2026
0142c69
feat(tables): add row count, owner, and column type filters
waleedlatif1 Mar 29, 2026
2553cac
improvement(scheduled-tasks): use combobox filter panel matching logs…
waleedlatif1 Mar 29, 2026
9dd3028
improvement(knowledge): use combobox filter panel matching logs UI style
waleedlatif1 Mar 29, 2026
446a665
improvement(files): use combobox filter panel matching logs UI style
waleedlatif1 Mar 29, 2026
c56e3ac
improvement(tables): use combobox filter panel matching logs UI style
waleedlatif1 Mar 29, 2026
f0e988d
feat(settings): add sort to recently deleted page
waleedlatif1 Mar 29, 2026
bf0bcf3
feat(logs): add sort to logs page
waleedlatif1 Mar 29, 2026
ffe6806
improvement(knowledge): upgrade document list filter to combobox style
waleedlatif1 Mar 29, 2026
483c35c
fix(resources): fix missing imports, memoization, and stale refs acro…
waleedlatif1 Mar 29, 2026
c8672f7
improvement(tables): remove column type filter
waleedlatif1 Mar 29, 2026
71794bb
fix(resources): fix filter/sort correctness issues from audit
waleedlatif1 Mar 29, 2026
aeeec6b
fix(chunks): add server-side sort to document chunks API
waleedlatif1 Mar 29, 2026
7b13a1a
perf(resources): memoize filterContent JSX across all resource pages
waleedlatif1 Mar 29, 2026
90bd958
fix(resources): add missing sort options for all visible columns
waleedlatif1 Mar 29, 2026
0318725
whitelabeling updates, sidebar fixes, files bug
waleedlatif1 Mar 29, 2026
432e4d0
increased type safety
waleedlatif1 Mar 29, 2026
f8a26a3
pr fixes
waleedlatif1 Mar 29, 2026
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
@@ -1,4 +1,4 @@
import { memo, type ReactNode, useCallback, useRef, useState } from 'react'
import { memo, type ReactNode } from 'react'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import {
ArrowDown,
Expand All @@ -19,8 +19,6 @@ import { cn } from '@/lib/core/utils/cn'
const SEARCH_ICON = (
<Search className='pointer-events-none h-[14px] w-[14px] shrink-0 text-[var(--text-icon)]' />
)
const FILTER_ICON = <ListFilter className='mr-1.5 h-[14px] w-[14px] text-[var(--text-icon)]' />
const SORT_ICON = <ArrowUpDown className='mr-1.5 h-[14px] w-[14px] text-[var(--text-icon)]' />

type SortDirection = 'asc' | 'desc'

Expand Down Expand Up @@ -67,7 +65,12 @@ export interface SearchConfig {
interface ResourceOptionsBarProps {
search?: SearchConfig
sort?: SortConfig
/** Popover content — renders inside a Popover (used by logs, etc.) */
filter?: ReactNode
/** When provided, Filter button acts as a toggle instead of opening a Popover */
onFilterToggle?: () => void
/** Whether the filter is currently active (highlights the toggle button) */
filterActive?: boolean
filterTags?: FilterTag[]
extras?: ReactNode
}
Expand All @@ -76,10 +79,13 @@ export const ResourceOptionsBar = memo(function ResourceOptionsBar({
search,
sort,
filter,
onFilterToggle,
filterActive,
filterTags,
extras,
}: ResourceOptionsBarProps) {
const hasContent = search || sort || filter || extras || (filterTags && filterTags.length > 0)
const hasContent =
search || sort || filter || onFilterToggle || extras || (filterTags && filterTags.length > 0)
if (!hasContent) return null

return (
Expand All @@ -88,38 +94,53 @@ export const ResourceOptionsBar = memo(function ResourceOptionsBar({
{search && <SearchSection search={search} />}
<div className='flex items-center gap-1.5'>
{extras}
{filterTags?.map((tag) => (
{filterTags?.map((tag, i) => (
<Button
key={tag.label}
key={`${tag.label}-${i}`}
variant='subtle'
className='px-2 py-1 text-caption'
className='max-w-[200px] px-2 py-1 text-caption'
onClick={tag.onRemove}
>
{tag.label}
<span className='ml-1 text-[var(--text-icon)] text-micro'>✕</span>
<span className='truncate'>{tag.label}</span>
<span className='ml-1 shrink-0 text-[var(--text-icon)] text-micro'>✕</span>
</Button>
))}
{filter && (
{onFilterToggle ? (
<Button
variant='subtle'
className={cn(
'px-2 py-1 text-caption',
filterActive && 'bg-[var(--surface-3)] text-[var(--text-primary)]'
)}
onClick={onFilterToggle}
>
<ListFilter
className={cn(
'mr-1.5 h-[14px] w-[14px]',
filterActive ? 'text-[var(--text-primary)]' : 'text-[var(--text-icon)]'
)}
/>
Filter
</Button>
) : filter ? (
<PopoverPrimitive.Root>
<PopoverPrimitive.Trigger asChild>
<Button variant='subtle' className='px-2 py-1 text-caption'>
{FILTER_ICON}
<ListFilter className='mr-1.5 h-[14px] w-[14px] text-[var(--text-icon)]' />
Filter
</Button>
</PopoverPrimitive.Trigger>
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
align='start'
sideOffset={6}
className={cn(
'z-50 rounded-lg border border-[var(--border)] bg-[var(--bg)] shadow-sm'
)}
className='z-50 rounded-lg border border-[var(--border)] bg-[var(--bg)] shadow-sm'
>
{filter}
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
</PopoverPrimitive.Root>
)}
) : null}
{sort && <SortDropdown config={sort} />}
</div>
</div>
Expand All @@ -128,34 +149,6 @@ export const ResourceOptionsBar = memo(function ResourceOptionsBar({
})

const SearchSection = memo(function SearchSection({ search }: { search: SearchConfig }) {
const [localValue, setLocalValue] = useState(search.value)

const lastReportedRef = useRef(search.value)

if (search.value !== lastReportedRef.current) {
setLocalValue(search.value)
lastReportedRef.current = search.value
}

const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const next = e.target.value
setLocalValue(next)
search.onChange(next)
},
[search.onChange]
)

const handleClearAll = useCallback(() => {
setLocalValue('')
lastReportedRef.current = ''
if (search.onClearAll) {
search.onClearAll()
} else {
search.onChange('')
}
}, [search.onClearAll, search.onChange])

return (
<div className='relative flex flex-1 items-center'>
{SEARCH_ICON}
Expand All @@ -177,20 +170,20 @@ const SearchSection = memo(function SearchSection({ search }: { search: SearchCo
<input
ref={search.inputRef}
type='text'
value={localValue}
onChange={handleInputChange}
value={search.value}
onChange={(e) => search.onChange(e.target.value)}
onKeyDown={search.onKeyDown}
onFocus={search.onFocus}
onBlur={search.onBlur}
placeholder={search.tags?.length ? '' : (search.placeholder ?? 'Search...')}
className='min-w-[80px] flex-1 bg-transparent py-1 text-[var(--text-secondary)] text-caption outline-none placeholder:text-[var(--text-subtle)]'
/>
</div>
{search.tags?.length || localValue ? (
{search.tags?.length || search.value ? (
<button
type='button'
className='mr-0.5 flex h-[14px] w-[14px] shrink-0 items-center justify-center text-[var(--text-subtle)] transition-colors hover-hover:text-[var(--text-secondary)]'
onClick={handleClearAll}
onClick={search.onClearAll ?? (() => search.onChange(''))}
>
<span className='text-caption'>✕</span>
</button>
Expand All @@ -213,8 +206,19 @@ const SortDropdown = memo(function SortDropdown({ config }: { config: SortConfig
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant='subtle' className='px-2 py-1 text-caption'>
{SORT_ICON}
<Button
variant='subtle'
className={cn(
'px-2 py-1 text-caption',
active && 'bg-[var(--surface-3)] text-[var(--text-primary)]'
)}
>
<ArrowUpDown
className={cn(
'mr-1.5 h-[14px] w-[14px]',
active ? 'text-[var(--text-primary)]' : 'text-[var(--text-icon)]'
)}
/>
Sort
</Button>
</DropdownMenuTrigger>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ export function KnowledgeBase({
}

const filterContent = (
<div className='w-[320px]'>
<div className='w-[200px]'>
<div className='border-[var(--border-1)] border-b px-3 py-2'>
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
</div>
Expand Down
Loading
Loading