Skip to content

Commit 7b13a1a

Browse files
committed
perf(resources): memoize filterContent JSX across all resource pages
Resource is wrapped in React.memo, so an unstable filterContent reference on every parent re-render defeats the memo. Wrap filterContent in useMemo with correct deps in all 6 pages (files, tables, scheduled-tasks, knowledge, base, document).
1 parent aeeec6b commit 7b13a1a

6 files changed

Lines changed: 383 additions & 324 deletions

File tree

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

Lines changed: 81 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -871,82 +871,98 @@ export function Files() {
871871
const hasActiveFilters =
872872
typeFilter.length > 0 || sizeFilter.length > 0 || uploadedByFilter.length > 0
873873

874-
const filterContent = (
875-
<div className='flex w-[240px] flex-col gap-3 p-3'>
876-
<div className='flex flex-col gap-1.5'>
877-
<span className='font-medium text-[var(--text-secondary)] text-caption'>File Type</span>
878-
<Combobox
879-
options={[
880-
{ value: 'document', label: 'Documents' },
881-
{ value: 'audio', label: 'Audio' },
882-
{ value: 'video', label: 'Video' },
883-
]}
884-
multiSelect
885-
multiSelectValues={typeFilter}
886-
onMultiSelectChange={setTypeFilter}
887-
overlayContent={
888-
<span className='truncate text-[var(--text-primary)]'>{typeDisplayLabel}</span>
889-
}
890-
showAllOption
891-
allOptionLabel='All'
892-
size='sm'
893-
className='h-[32px] w-full rounded-md'
894-
/>
895-
</div>
896-
<div className='flex flex-col gap-1.5'>
897-
<span className='font-medium text-[var(--text-secondary)] text-caption'>Size</span>
898-
<Combobox
899-
options={[
900-
{ value: 'small', label: 'Small (< 1 MB)' },
901-
{ value: 'medium', label: 'Medium (1–10 MB)' },
902-
{ value: 'large', label: 'Large (> 10 MB)' },
903-
]}
904-
multiSelect
905-
multiSelectValues={sizeFilter}
906-
onMultiSelectChange={setSizeFilter}
907-
overlayContent={
908-
<span className='truncate text-[var(--text-primary)]'>{sizeDisplayLabel}</span>
909-
}
910-
showAllOption
911-
allOptionLabel='All'
912-
size='sm'
913-
className='h-[32px] w-full rounded-md'
914-
/>
915-
</div>
916-
{memberOptions.length > 0 && (
874+
const filterContent = useMemo(
875+
() => (
876+
<div className='flex w-[240px] flex-col gap-3 p-3'>
917877
<div className='flex flex-col gap-1.5'>
918-
<span className='font-medium text-[var(--text-secondary)] text-caption'>Uploaded By</span>
878+
<span className='font-medium text-[var(--text-secondary)] text-caption'>File Type</span>
919879
<Combobox
920-
options={memberOptions}
880+
options={[
881+
{ value: 'document', label: 'Documents' },
882+
{ value: 'audio', label: 'Audio' },
883+
{ value: 'video', label: 'Video' },
884+
]}
921885
multiSelect
922-
multiSelectValues={uploadedByFilter}
923-
onMultiSelectChange={setUploadedByFilter}
886+
multiSelectValues={typeFilter}
887+
onMultiSelectChange={setTypeFilter}
924888
overlayContent={
925-
<span className='truncate text-[var(--text-primary)]'>{uploadedByDisplayLabel}</span>
889+
<span className='truncate text-[var(--text-primary)]'>{typeDisplayLabel}</span>
926890
}
927-
searchable
928-
searchPlaceholder='Search members...'
929891
showAllOption
930892
allOptionLabel='All'
931893
size='sm'
932894
className='h-[32px] w-full rounded-md'
933895
/>
934896
</div>
935-
)}
936-
{hasActiveFilters && (
937-
<button
938-
type='button'
939-
onClick={() => {
940-
setTypeFilter([])
941-
setSizeFilter([])
942-
setUploadedByFilter([])
943-
}}
944-
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
945-
>
946-
Clear all filters
947-
</button>
948-
)}
949-
</div>
897+
<div className='flex flex-col gap-1.5'>
898+
<span className='font-medium text-[var(--text-secondary)] text-caption'>Size</span>
899+
<Combobox
900+
options={[
901+
{ value: 'small', label: 'Small (< 1 MB)' },
902+
{ value: 'medium', label: 'Medium (1–10 MB)' },
903+
{ value: 'large', label: 'Large (> 10 MB)' },
904+
]}
905+
multiSelect
906+
multiSelectValues={sizeFilter}
907+
onMultiSelectChange={setSizeFilter}
908+
overlayContent={
909+
<span className='truncate text-[var(--text-primary)]'>{sizeDisplayLabel}</span>
910+
}
911+
showAllOption
912+
allOptionLabel='All'
913+
size='sm'
914+
className='h-[32px] w-full rounded-md'
915+
/>
916+
</div>
917+
{memberOptions.length > 0 && (
918+
<div className='flex flex-col gap-1.5'>
919+
<span className='font-medium text-[var(--text-secondary)] text-caption'>
920+
Uploaded By
921+
</span>
922+
<Combobox
923+
options={memberOptions}
924+
multiSelect
925+
multiSelectValues={uploadedByFilter}
926+
onMultiSelectChange={setUploadedByFilter}
927+
overlayContent={
928+
<span className='truncate text-[var(--text-primary)]'>
929+
{uploadedByDisplayLabel}
930+
</span>
931+
}
932+
searchable
933+
searchPlaceholder='Search members...'
934+
showAllOption
935+
allOptionLabel='All'
936+
size='sm'
937+
className='h-[32px] w-full rounded-md'
938+
/>
939+
</div>
940+
)}
941+
{hasActiveFilters && (
942+
<button
943+
type='button'
944+
onClick={() => {
945+
setTypeFilter([])
946+
setSizeFilter([])
947+
setUploadedByFilter([])
948+
}}
949+
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
950+
>
951+
Clear all filters
952+
</button>
953+
)}
954+
</div>
955+
),
956+
[
957+
typeFilter,
958+
sizeFilter,
959+
uploadedByFilter,
960+
memberOptions,
961+
typeDisplayLabel,
962+
sizeDisplayLabel,
963+
uploadedByDisplayLabel,
964+
hasActiveFilters,
965+
]
950966
)
951967

952968
const filterTags: FilterTag[] = useMemo(() => {

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

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -595,45 +595,48 @@ export function Document({
595595
return `${enabledFilter.length} selected`
596596
}, [enabledFilter])
597597

598-
const filterContent = (
599-
<div className='flex w-[240px] flex-col gap-3 p-3'>
600-
<div className='flex flex-col gap-1.5'>
601-
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
602-
<Combobox
603-
options={[
604-
{ value: 'enabled', label: 'Enabled' },
605-
{ value: 'disabled', label: 'Disabled' },
606-
]}
607-
multiSelect
608-
multiSelectValues={enabledFilter}
609-
onMultiSelectChange={(values) => {
610-
setEnabledFilter(values)
611-
setSelectedChunks(new Set())
612-
void goToPage(1)
613-
}}
614-
overlayContent={
615-
<span className='truncate text-[var(--text-primary)]'>{enabledDisplayLabel}</span>
616-
}
617-
showAllOption
618-
allOptionLabel='All'
619-
size='sm'
620-
className='h-[32px] w-full rounded-md'
621-
/>
598+
const filterContent = useMemo(
599+
() => (
600+
<div className='flex w-[240px] flex-col gap-3 p-3'>
601+
<div className='flex flex-col gap-1.5'>
602+
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
603+
<Combobox
604+
options={[
605+
{ value: 'enabled', label: 'Enabled' },
606+
{ value: 'disabled', label: 'Disabled' },
607+
]}
608+
multiSelect
609+
multiSelectValues={enabledFilter}
610+
onMultiSelectChange={(values) => {
611+
setEnabledFilter(values)
612+
setSelectedChunks(new Set())
613+
void goToPage(1)
614+
}}
615+
overlayContent={
616+
<span className='truncate text-[var(--text-primary)]'>{enabledDisplayLabel}</span>
617+
}
618+
showAllOption
619+
allOptionLabel='All'
620+
size='sm'
621+
className='h-[32px] w-full rounded-md'
622+
/>
623+
</div>
624+
{enabledFilter.length > 0 && (
625+
<button
626+
type='button'
627+
onClick={() => {
628+
setEnabledFilter([])
629+
setSelectedChunks(new Set())
630+
void goToPage(1)
631+
}}
632+
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
633+
>
634+
Clear all filters
635+
</button>
636+
)}
622637
</div>
623-
{enabledFilter.length > 0 && (
624-
<button
625-
type='button'
626-
onClick={() => {
627-
setEnabledFilter([])
628-
setSelectedChunks(new Set())
629-
void goToPage(1)
630-
}}
631-
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
632-
>
633-
Clear all filters
634-
</button>
635-
)}
636-
</div>
638+
),
639+
[enabledFilter, enabledDisplayLabel, goToPage]
637640
)
638641

639642
const filterTags: FilterTag[] = useMemo(

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -826,57 +826,60 @@ export function KnowledgeBase({
826826
[sortBy, sortOrder]
827827
)
828828

829-
const filterContent = (
830-
<div className='flex w-[240px] flex-col gap-3 p-3'>
831-
<div className='flex flex-col gap-1.5'>
832-
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
833-
<Combobox
834-
options={[
835-
{ value: 'enabled', label: 'Enabled' },
836-
{ value: 'disabled', label: 'Disabled' },
837-
]}
838-
multiSelect
839-
multiSelectValues={enabledFilter}
840-
onMultiSelectChange={(values) => {
841-
setEnabledFilter(values)
829+
const filterContent = useMemo(
830+
() => (
831+
<div className='flex w-[240px] flex-col gap-3 p-3'>
832+
<div className='flex flex-col gap-1.5'>
833+
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
834+
<Combobox
835+
options={[
836+
{ value: 'enabled', label: 'Enabled' },
837+
{ value: 'disabled', label: 'Disabled' },
838+
]}
839+
multiSelect
840+
multiSelectValues={enabledFilter}
841+
onMultiSelectChange={(values) => {
842+
setEnabledFilter(values)
843+
setCurrentPage(1)
844+
setSelectedDocuments(new Set())
845+
setIsSelectAllMode(false)
846+
}}
847+
overlayContent={
848+
<span className='truncate text-[var(--text-primary)]'>{enabledDisplayLabel}</span>
849+
}
850+
showAllOption
851+
allOptionLabel='All'
852+
size='sm'
853+
className='h-[32px] w-full rounded-md'
854+
/>
855+
</div>
856+
{enabledFilter.length > 0 && (
857+
<button
858+
type='button'
859+
onClick={() => {
860+
setEnabledFilter([])
861+
setCurrentPage(1)
862+
setSelectedDocuments(new Set())
863+
setIsSelectAllMode(false)
864+
}}
865+
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
866+
>
867+
Clear status filter
868+
</button>
869+
)}
870+
<TagFilterSection
871+
tagDefinitions={tagDefinitions}
872+
entries={tagFilterEntries}
873+
onChange={(entries) => {
874+
setTagFilterEntries(entries)
842875
setCurrentPage(1)
843876
setSelectedDocuments(new Set())
844877
setIsSelectAllMode(false)
845878
}}
846-
overlayContent={
847-
<span className='truncate text-[var(--text-primary)]'>{enabledDisplayLabel}</span>
848-
}
849-
showAllOption
850-
allOptionLabel='All'
851-
size='sm'
852-
className='h-[32px] w-full rounded-md'
853879
/>
854880
</div>
855-
{enabledFilter.length > 0 && (
856-
<button
857-
type='button'
858-
onClick={() => {
859-
setEnabledFilter([])
860-
setCurrentPage(1)
861-
setSelectedDocuments(new Set())
862-
setIsSelectAllMode(false)
863-
}}
864-
className='flex h-[32px] w-full items-center justify-center rounded-md text-[var(--text-secondary)] text-caption transition-colors hover-hover:bg-[var(--surface-active)]'
865-
>
866-
Clear status filter
867-
</button>
868-
)}
869-
<TagFilterSection
870-
tagDefinitions={tagDefinitions}
871-
entries={tagFilterEntries}
872-
onChange={(entries) => {
873-
setTagFilterEntries(entries)
874-
setCurrentPage(1)
875-
setSelectedDocuments(new Set())
876-
setIsSelectAllMode(false)
877-
}}
878-
/>
879-
</div>
881+
),
882+
[enabledFilter, enabledDisplayLabel, tagDefinitions, tagFilterEntries]
880883
)
881884

882885
const connectorBadges =

0 commit comments

Comments
 (0)