From 44e501ff6b306df2f5023b9686bfa5f32d041b55 Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:21:22 -0500 Subject: [PATCH 01/11] prevent dss email soup call infinite search --- js/app/packages/app/component/UnifiedListView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/js/app/packages/app/component/UnifiedListView.tsx b/js/app/packages/app/component/UnifiedListView.tsx index f80336134..87aa487fe 100644 --- a/js/app/packages/app/component/UnifiedListView.tsx +++ b/js/app/packages/app/component/UnifiedListView.tsx @@ -830,6 +830,7 @@ export function UnifiedListView(props: UnifiedListViewProps) { email_filters: { recipients: emailActive() && + !isSearchActive() && view().viewType !== 'project' && (entityTypeFilter().includes('email') || entityTypeFilter().length === 0) From 37fcd2b7f76376f91bde8a1638e03ebd4c4e2a99 Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:32:33 -0500 Subject: [PATCH 02/11] nit rename --- js/app/packages/macro-entity/src/queries/dss.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/app/packages/macro-entity/src/queries/dss.ts b/js/app/packages/macro-entity/src/queries/dss.ts index 073de2db8..6725d6444 100644 --- a/js/app/packages/macro-entity/src/queries/dss.ts +++ b/js/app/packages/macro-entity/src/queries/dss.ts @@ -102,14 +102,14 @@ const fetchPaginatedDocumentsPost = async ({ }; export function createDssInfiniteQuery( - _params?: Accessor, + initialParams?: Accessor, options?: { disabled?: Accessor; requestBody?: Accessor; } ) { const params = () => { - const argParams = _params?.(); + const argParams = initialParams?.(); let limit = 100; let sort_method; let emailView; From b3bb1f05ecf87b4dc52223d29e4c466f4e80eb37 Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:06:58 -0500 Subject: [PATCH 03/11] memoize!! --- js/app/packages/core/email-link/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/app/packages/core/email-link/index.ts b/js/app/packages/core/email-link/index.ts index 480329272..8be37dff5 100644 --- a/js/app/packages/core/email-link/index.ts +++ b/js/app/packages/core/email-link/index.ts @@ -10,7 +10,7 @@ import { emailClient } from '@service-email/client'; import { updateUserInfo } from '@service-gql/client'; import { useQuery } from '@tanstack/solid-query'; import { err, okAsync, ResultAsync } from 'neverthrow'; -import { createSignal } from 'solid-js'; +import { createMemo, createSignal } from 'solid-js'; import { queryClient } from '../../macro-entity/src/queries/client'; export const [emailRefetchInterval, setEmailRefetchInterval] = createSignal< @@ -38,12 +38,12 @@ export function useEmailLinksQuery() { export function useEmailLinksStatus() { const links = useEmailLinksQuery(); - return () => { + return createMemo(() => { if (!links.data || links.error) { return false; } - return links.data?.length > 0; - }; + return links.data.length > 0; + }); } function invalidateEmailLinks() { From 8cdff37acef4c1f922647be181bc6b1a122c73fc Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:25:21 -0500 Subject: [PATCH 04/11] move request body out of options --- js/app/packages/app/component/UnifiedListView.tsx | 11 +++++++---- js/app/packages/macro-entity/src/queries/dss.ts | 11 +++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/js/app/packages/app/component/UnifiedListView.tsx b/js/app/packages/app/component/UnifiedListView.tsx index 87aa487fe..189eb52e7 100644 --- a/js/app/packages/app/component/UnifiedListView.tsx +++ b/js/app/packages/app/component/UnifiedListView.tsx @@ -972,10 +972,13 @@ export function UnifiedListView(props: UnifiedListViewProps) { const channelsQuery = createChannelsQuery({ disabled: disableChannelsQuery, }); - const dssInfiniteQuery = createDssInfiniteQuery(dssQueryParams, { - disabled: disableDssInfiniteQuery, - requestBody: dssQueryRequestBody, - }); + const dssInfiniteQuery = createDssInfiniteQuery( + dssQueryParams, + dssQueryRequestBody, + { + disabled: disableDssInfiniteQuery, + } + ); const searchNameContentInfiniteQuery = createUnifiedSearchInfiniteQuery( searchUnifiedNameContentQueryParams, { disabled: disableSearchService } diff --git a/js/app/packages/macro-entity/src/queries/dss.ts b/js/app/packages/macro-entity/src/queries/dss.ts index 6725d6444..f82d9aba9 100644 --- a/js/app/packages/macro-entity/src/queries/dss.ts +++ b/js/app/packages/macro-entity/src/queries/dss.ts @@ -103,9 +103,9 @@ const fetchPaginatedDocumentsPost = async ({ export function createDssInfiniteQuery( initialParams?: Accessor, + getRequestBody?: Accessor, options?: { disabled?: Accessor; - requestBody?: Accessor; } ) { const params = () => { @@ -113,10 +113,9 @@ export function createDssInfiniteQuery( let limit = 100; let sort_method; let emailView; - const requestBody = options?.requestBody; - if (requestBody) { - const body = requestBody(); + if (getRequestBody) { + const body = getRequestBody(); if (body?.limit) { limit = body.limit; } @@ -140,7 +139,7 @@ export function createDssInfiniteQuery( const instructionsIdQuery = useInstructionsMdIdQuery(); return useInfiniteQuery(() => { - const requestBody = options?.requestBody?.(); + const requestBody = getRequestBody?.(); // Include all filters in query key so query refetches when any filter changes const documentFilters = requestBody?.document_filters; const projectFilters = requestBody?.project_filters; @@ -170,7 +169,7 @@ export function createDssInfiniteQuery( queryFn: ({ pageParam }) => { return fetchPaginatedDocumentsPost({ apiToken: authQuery.data, - requestBody: requestBody, + requestBody, params: { cursor: pageParam.cursor }, }); }, From d32192c86c351899d1978e361a15b1d31dbb854c Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:30:11 -0500 Subject: [PATCH 05/11] provide abort signal to fetch paginated documents post --- js/app/packages/macro-entity/src/queries/dss.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/app/packages/macro-entity/src/queries/dss.ts b/js/app/packages/macro-entity/src/queries/dss.ts index f82d9aba9..e05c865c3 100644 --- a/js/app/packages/macro-entity/src/queries/dss.ts +++ b/js/app/packages/macro-entity/src/queries/dss.ts @@ -74,10 +74,12 @@ const fetchPaginatedDocumentsPost = async ({ apiToken, params, requestBody, + signal, }: { apiToken?: string; requestBody?: PostSoupRequest; params?: PostItemsSoupParams; + signal?: AbortSignal; }) => { if (!apiToken) throw new Error('No API token provided'); const Authorization = `Bearer ${apiToken}`; @@ -93,6 +95,7 @@ const fetchPaginatedDocumentsPost = async ({ headers: { Authorization, 'Content-Type': 'application/json' }, method: 'POST', body: requestBody ? JSON.stringify(requestBody) : undefined, + signal, }); if (!response.ok) throw new Error('Failed to fetch documents', { cause: response }); @@ -166,11 +169,12 @@ export function createDssInfiniteQuery( return { queryKey, queryHash: hashKey(queryKey), - queryFn: ({ pageParam }) => { + queryFn: ({ pageParam, signal }) => { return fetchPaginatedDocumentsPost({ apiToken: authQuery.data, requestBody, params: { cursor: pageParam.cursor }, + signal, }); }, initialPageParam: params(), From 0fb15cd0fe67b17422ef819116cdfa578071f76f Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:33:44 -0500 Subject: [PATCH 06/11] move serach active before its usage --- .../app/component/UnifiedListView.tsx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/js/app/packages/app/component/UnifiedListView.tsx b/js/app/packages/app/component/UnifiedListView.tsx index 189eb52e7..32ce9bd2c 100644 --- a/js/app/packages/app/component/UnifiedListView.tsx +++ b/js/app/packages/app/component/UnifiedListView.tsx @@ -799,6 +799,19 @@ export function UnifiedListView(props: UnifiedListViewProps) { const emailActive = useEmailLinksStatus(); + const validSearchTerms = createMemo(() => { + return debouncedSearchForService().length >= 3; + }); + const validSearchFilters = createMemo(() => { + const senders = unifiedSearchFilters()?.email?.senders; + if (senders && senders.length > 0) return true; + return false; + }); + + const isSearchActive = createMemo(() => { + return validSearchTerms() || validSearchFilters(); + }); + const dssQueryParams = createMemo( (): GetItemsSoupParams => ({ limit: props.defaultDisplayOptions?.limit ?? 100, @@ -875,19 +888,6 @@ export function UnifiedListView(props: UnifiedListViewProps) { }) ); - const validSearchTerms = createMemo(() => { - return debouncedSearchForService().length >= 3; - }); - const validSearchFilters = createMemo(() => { - const senders = unifiedSearchFilters()?.email?.senders; - if (senders && senders.length > 0) return true; - return false; - }); - - const isSearchActive = createMemo(() => { - return validSearchTerms() || validSearchFilters(); - }); - const disableSearchService = createMemo(() => { return !isSearchActive(); }); From c91208d05b795902cec9fa3a7a71275332101ceb Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:15:37 -0500 Subject: [PATCH 07/11] remove valid search filter since its not used in search --- js/app/packages/app/component/UnifiedListView.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/js/app/packages/app/component/UnifiedListView.tsx b/js/app/packages/app/component/UnifiedListView.tsx index 32ce9bd2c..1062bd069 100644 --- a/js/app/packages/app/component/UnifiedListView.tsx +++ b/js/app/packages/app/component/UnifiedListView.tsx @@ -802,14 +802,8 @@ export function UnifiedListView(props: UnifiedListViewProps) { const validSearchTerms = createMemo(() => { return debouncedSearchForService().length >= 3; }); - const validSearchFilters = createMemo(() => { - const senders = unifiedSearchFilters()?.email?.senders; - if (senders && senders.length > 0) return true; - return false; - }); - const isSearchActive = createMemo(() => { - return validSearchTerms() || validSearchFilters(); + return validSearchTerms(); }); const dssQueryParams = createMemo( From d9e705f6058619d54b1777c461ead81bf869924d Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:15:55 -0500 Subject: [PATCH 08/11] nit typo --- .../macro-entity/src/components/UnifiedInfiniteList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx b/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx index 3b7683311..faed9b92e 100644 --- a/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx +++ b/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx @@ -311,7 +311,7 @@ export function createUnifiedInfiniteList({ const searching = isSearchActive?.(); if (searching) { - // NOTE: the default sort will be channels, then local fuzzy name, then serach service + // NOTE: the default sort will be channels, then local fuzzy name, then search service // avoiding doing an extra sort as a speed optimization return entities.toSorted(sortEntitiesForSearch); } From cf38ef0d628cb48ca486c9a85bd0e4ed6148b0ca Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:41:40 -0500 Subject: [PATCH 09/11] disable fetch more --- js/app/packages/app/component/UnifiedListView.tsx | 11 +++++++++++ .../src/components/UnifiedInfiniteList.tsx | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/js/app/packages/app/component/UnifiedListView.tsx b/js/app/packages/app/component/UnifiedListView.tsx index 1062bd069..a43d39fc2 100644 --- a/js/app/packages/app/component/UnifiedListView.tsx +++ b/js/app/packages/app/component/UnifiedListView.tsx @@ -986,6 +986,16 @@ export function UnifiedListView(props: UnifiedListViewProps) { }; }; + // We want to be to be able to search over locally cached emails without actually + // fetching more data when we have a invalid search term (i.e. one or two chars). + // If we're using search service for a valid term, we can safely fetch more data + // from dss for fuzzy name search since we won't be searching over emails (too big). + const disableFetchMore = createMemo(() => { + const searchAllEmails = + (dssQueryRequestBody().email_filters?.recipients ?? []).length === 0; + return searchText().length > 0 && searchAllEmails; + }); + const { UnifiedListComponent, entities, isLoading } = createUnifiedInfiniteList< WithNotification | EntityData> @@ -1009,6 +1019,7 @@ export function UnifiedListView(props: UnifiedListViewProps) { entitySort, searchFilter: nameFuzzySearchFilter, isSearchActive, + disableFetchMore, }); createEffect(() => { diff --git a/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx b/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx index faed9b92e..f0629d719 100644 --- a/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx +++ b/js/app/packages/macro-entity/src/components/UnifiedInfiniteList.tsx @@ -206,6 +206,7 @@ interface UnifiedInfiniteListContext { entitySort?: Accessor>; searchFilter?: Accessor | undefined>; isSearchActive?: Accessor; + disableFetchMore?: Accessor; } export function createUnifiedInfiniteList({ @@ -217,6 +218,7 @@ export function createUnifiedInfiniteList({ entitySort, searchFilter, isSearchActive, + disableFetchMore, }: UnifiedInfiniteListContext) { const [sortedEntitiesStore, setSortedEntitiesStore] = createStore([]); const allEntities = createMemo(() => { @@ -388,7 +390,7 @@ export function createUnifiedInfiniteList({ let isFetchingMore = false; const fetchMoreData = async () => { - if (isFetchingMore) return; + if (disableFetchMore?.() || isFetchingMore) return; isFetchingMore = true; const results = entityInfiniteQueries.map((query) => { From f982bbc0885a058ad60609fef7036fdc4f2dc752 Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:06:59 -0500 Subject: [PATCH 10/11] bump provider stale time --- js/app/packages/macro-entity/src/components/Provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/app/packages/macro-entity/src/components/Provider.tsx b/js/app/packages/macro-entity/src/components/Provider.tsx index 86d76acd2..032d36cac 100644 --- a/js/app/packages/macro-entity/src/components/Provider.tsx +++ b/js/app/packages/macro-entity/src/components/Provider.tsx @@ -49,7 +49,7 @@ export function Provider(props: ParentProps) { staleTime: 1000 * 10, // 10 seconds }); queryClient.setQueryDefaults(queryKeys.all.dss, { - staleTime: 1000 * 5, // 5 seconds + staleTime: 1000 * 60, // 1 minute }); queryClient.setQueryDefaults(queryKeys.all.email, { staleTime: 1000, // 1 second From c572910c1612cbb84cab617bdd698104f3dd6cbb Mon Sep 17 00:00:00 2001 From: Gabriel Birman <25272206+gbirman@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:07:15 -0500 Subject: [PATCH 11/11] use query key hash fn --- js/app/packages/macro-entity/src/queries/dss.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/app/packages/macro-entity/src/queries/dss.ts b/js/app/packages/macro-entity/src/queries/dss.ts index e05c865c3..f23aa501c 100644 --- a/js/app/packages/macro-entity/src/queries/dss.ts +++ b/js/app/packages/macro-entity/src/queries/dss.ts @@ -168,7 +168,7 @@ export function createDssInfiniteQuery( return { queryKey, - queryHash: hashKey(queryKey), + queryKeyHashFn: hashKey, queryFn: ({ pageParam, signal }) => { return fetchPaginatedDocumentsPost({ apiToken: authQuery.data,