Skip to content

Commit c6b49d0

Browse files
BillLeoutsakosvl346Bill Leoutsakos
andauthored
refactor(resources): share filter panel structure (#8260)
Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local>
1 parent e6e3a1f commit c6b49d0

6 files changed

Lines changed: 119 additions & 27 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/components/resource/components/resource-options/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { ResourceFilterPanel, ResourceFilterSection } from './resource-filter-panel'
12
export type {
23
ColumnOption,
34
FilterConfig,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use client'
2+
3+
import type { ReactNode } from 'react'
4+
import { FILTER_SECTION_LABEL_CLASS } from '@/app/workspace/[workspaceId]/components/resource/components/resource-options/resource-options'
5+
6+
interface ResourceFilterPanelProps {
7+
children: ReactNode
8+
}
9+
10+
/** The filter content frame shared by resource lists and document chunks. */
11+
export function ResourceFilterPanel({ children }: ResourceFilterPanelProps) {
12+
return <div className='flex w-[240px] flex-col gap-3 p-3'>{children}</div>
13+
}
14+
15+
interface ResourceFilterSectionProps {
16+
label: string
17+
children: ReactNode
18+
/** A distinct label treatment, such as the document chunk status label. */
19+
labelClassName?: string
20+
}
21+
22+
export function ResourceFilterSection({
23+
label,
24+
children,
25+
labelClassName = FILTER_SECTION_LABEL_CLASS,
26+
}: ResourceFilterSectionProps) {
27+
return (
28+
<div className='flex flex-col gap-1.5'>
29+
<span className={labelClassName}>{label}</span>
30+
{children}
31+
</div>
32+
)
33+
}

‎apps/sim/app/workspace/[workspaceId]/components/resource/components/resource-options/resource-options.test.tsx‎

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
import { act } from 'react'
55
import { createRoot, type Root } from 'react-dom/client'
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7-
import { SortDropdown } from '@/app/workspace/[workspaceId]/components/resource/components/resource-options/resource-options'
7+
import {
8+
ResourceFilterPanel,
9+
ResourceFilterSection,
10+
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options/resource-filter-panel'
11+
import {
12+
ResourceOptions,
13+
SortDropdown,
14+
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options/resource-options'
815

916
const LONG_COLUMN_LABEL = 'highest_current_champion_role_across_the_entire_company'
1017

@@ -125,3 +132,47 @@ describe('SortDropdown', () => {
125132
expect(onOpenChange).toHaveBeenCalledWith(false)
126133
})
127134
})
135+
136+
describe('ResourceOptions filter content', () => {
137+
it('keeps section controls focusable and clear actions working in the filter popover', () => {
138+
const onClear = vi.fn()
139+
act(() => {
140+
root.render(
141+
<ResourceOptions
142+
filter={{
143+
content: (
144+
<ResourceFilterPanel>
145+
<ResourceFilterSection label='Status'>
146+
<button type='button'>Choose status</button>
147+
</ResourceFilterSection>
148+
<button type='button' onClick={onClear}>
149+
Clear all filters
150+
</button>
151+
</ResourceFilterPanel>
152+
),
153+
}}
154+
/>
155+
)
156+
})
157+
158+
const trigger = [...document.querySelectorAll<HTMLButtonElement>('button')].find(
159+
(button) => button.textContent === 'Filter'
160+
)
161+
expect(trigger).toBeDefined()
162+
act(() => trigger?.click())
163+
164+
const choice = [...document.querySelectorAll<HTMLButtonElement>('button')].find(
165+
(button) => button.textContent === 'Choose status'
166+
)
167+
expect(choice).toBeDefined()
168+
expect(document.body).toHaveTextContent('Status')
169+
act(() => choice?.focus())
170+
expect(document.activeElement).toBe(choice)
171+
172+
const clear = [...document.querySelectorAll<HTMLButtonElement>('button')].find(
173+
(button) => button.textContent === 'Clear all filters'
174+
)
175+
act(() => clear?.click())
176+
expect(onClear).toHaveBeenCalledOnce()
177+
})
178+
})

‎apps/sim/app/workspace/[workspaceId]/files/files.tsx‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ import type {
9494
SearchConfig,
9595
SortConfig,
9696
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
97-
import { FILTER_SECTION_LABEL_CLASS } from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
97+
import {
98+
ResourceFilterPanel,
99+
ResourceFilterSection,
100+
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
98101
import { timeCell } from '@/app/workspace/[workspaceId]/components/resource/components/time-cell'
99102
import { resourceListState } from '@/app/workspace/[workspaceId]/components/resource/is-resource-list-empty'
100103
import type {
@@ -2004,9 +2007,8 @@ function FilesContent() {
20042007
: `${uploadedByFilter.length} members`
20052008

20062009
return (
2007-
<div className='flex w-[240px] flex-col gap-3 p-3'>
2008-
<div className='flex flex-col gap-1.5'>
2009-
<span className={FILTER_SECTION_LABEL_CLASS}>File Type</span>
2010+
<ResourceFilterPanel>
2011+
<ResourceFilterSection label='File Type'>
20102012
<ChipCombobox
20112013
options={[
20122014
{ value: 'document', label: 'Documents' },
@@ -2023,9 +2025,8 @@ function FilesContent() {
20232025
allOptionLabel='All'
20242026
className='w-full'
20252027
/>
2026-
</div>
2027-
<div className='flex flex-col gap-1.5'>
2028-
<span className={FILTER_SECTION_LABEL_CLASS}>Size</span>
2028+
</ResourceFilterSection>
2029+
<ResourceFilterSection label='Size'>
20292030
<ChipCombobox
20302031
options={[
20312032
{ value: 'small', label: 'Small (< 1 MB)' },
@@ -2041,10 +2042,9 @@ function FilesContent() {
20412042
allOptionLabel='All'
20422043
className='w-full'
20432044
/>
2044-
</div>
2045+
</ResourceFilterSection>
20452046
{memberOptions.length > 0 && (
2046-
<div className='flex flex-col gap-1.5'>
2047-
<span className={FILTER_SECTION_LABEL_CLASS}>Uploaded By</span>
2047+
<ResourceFilterSection label='Uploaded By'>
20482048
<ChipCombobox
20492049
options={memberOptions}
20502050
multiSelect
@@ -2058,7 +2058,7 @@ function FilesContent() {
20582058
allOptionLabel='All'
20592059
className='w-full'
20602060
/>
2061-
</div>
2061+
</ResourceFilterSection>
20622062
)}
20632063
{hasActiveFilters && (
20642064
<Button
@@ -2069,7 +2069,7 @@ function FilesContent() {
20692069
Clear all filters
20702070
</Button>
20712071
)}
2072-
</div>
2072+
</ResourceFilterPanel>
20732073
)
20742074
}, [
20752075
typeFilter,

‎apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ import type {
3939
SearchConfig,
4040
SortConfig,
4141
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
42+
import {
43+
ResourceFilterPanel,
44+
ResourceFilterSection,
45+
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
4246
import type {
4347
PaginationConfig,
4448
ResourceColumn,
@@ -737,9 +741,11 @@ export function Document({
737741

738742
const filterContent = useMemo(
739743
() => (
740-
<div className='flex w-[240px] flex-col gap-3 p-3'>
741-
<div className='flex flex-col gap-1.5'>
742-
<span className='text-[var(--text-secondary)] text-caption'>Status</span>
744+
<ResourceFilterPanel>
745+
<ResourceFilterSection
746+
label='Status'
747+
labelClassName='text-[var(--text-secondary)] text-caption'
748+
>
743749
<ChipCombobox
744750
options={[
745751
{ value: 'enabled', label: 'Enabled' },
@@ -757,7 +763,7 @@ export function Document({
757763
allOptionLabel='All'
758764
className='w-full'
759765
/>
760-
</div>
766+
</ResourceFilterSection>
761767
{enabledFilter.length > 0 && (
762768
<button
763769
type='button'
@@ -770,7 +776,7 @@ export function Document({
770776
Clear all filters
771777
</button>
772778
)}
773-
</div>
779+
</ResourceFilterPanel>
774780
),
775781
[enabledFilter, setEnabledFilter]
776782
)

‎apps/sim/app/workspace/[workspaceId]/tables/tables.tsx‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ import type {
5353
SearchConfig,
5454
SortConfig,
5555
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
56-
import { FILTER_SECTION_LABEL_CLASS } from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
56+
import {
57+
ResourceFilterPanel,
58+
ResourceFilterSection,
59+
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-options'
5760
import { timeCell } from '@/app/workspace/[workspaceId]/components/resource/components/time-cell'
5861
import { resourceListState } from '@/app/workspace/[workspaceId]/components/resource/is-resource-list-empty'
5962
import type {
@@ -727,9 +730,8 @@ function TablesContent() {
727730

728731
const filterContent = useMemo(
729732
() => (
730-
<div className='flex w-[240px] flex-col gap-3 p-3'>
731-
<div className='flex flex-col gap-1.5'>
732-
<span className={FILTER_SECTION_LABEL_CLASS}>Row Count</span>
733+
<ResourceFilterPanel>
734+
<ResourceFilterSection label='Row Count'>
733735
<ChipCombobox
734736
options={[
735737
{ value: 'empty', label: 'Empty' },
@@ -745,10 +747,9 @@ function TablesContent() {
745747
allOptionLabel='All'
746748
className='w-full'
747749
/>
748-
</div>
750+
</ResourceFilterSection>
749751
{memberOptions.length > 0 && (
750-
<div className='flex flex-col gap-1.5'>
751-
<span className={FILTER_SECTION_LABEL_CLASS}>Owner</span>
752+
<ResourceFilterSection label='Owner'>
752753
<ChipCombobox
753754
options={memberOptions}
754755
multiSelect
@@ -762,7 +763,7 @@ function TablesContent() {
762763
allOptionLabel='All'
763764
className='w-full'
764765
/>
765-
</div>
766+
</ResourceFilterSection>
766767
)}
767768
{hasActiveFilters && (
768769
<button
@@ -773,7 +774,7 @@ function TablesContent() {
773774
Clear all filters
774775
</button>
775776
)}
776-
</div>
777+
</ResourceFilterPanel>
777778
),
778779
[
779780
rowCountFilter,

0 commit comments

Comments
 (0)