applied 10 cache
CI / checks (push) Failing after 1m58s Details
CI / checks (pull_request) Failing after 1m53s Details

pull/79/head
ahmed.mujtaba 2026-09-07 18:55:42 +05:00
parent 5cc1dc1997
commit 7c9e18741d
2 changed files with 42 additions and 4 deletions

View File

@ -203,9 +203,6 @@ async def fetch_form_data(
search: str | None = Query(None),
processing_state: str | None = Query(None),
is_duplicate: bool | None = Query(None),
# Tri-valued, like is_duplicate above: omit for no filter, true for rows that
# have the link, false for the ones missing it. Chasing the gaps is half the
# reason these exist, so `false` has to be a real filter and not "unset".
has_linkedin: bool | None = Query(None),
has_resume: bool | None = Query(None),
city: str | None = Query(None),
@ -213,7 +210,6 @@ async def fetch_form_data(
assigned: bool | None = Query(None),
no_suggestions: bool | None = Query(None),
offset: int = Query(0,ge=0),
# Caller-chosen page size (Inbox sends 10/25/50/100). None = unpaged.
limit: int | None = Query(None,ge=1,le=500),
current_user: dict = Depends(_FORM_DATA_READ),
session: AsyncSession = Depends(get_session),

View File

@ -68,6 +68,43 @@ const LIST_CACHE = {
}
const COUNT_CACHE = { staleTime: INBOX_STALE_MS, gcTime: INBOX_GC_MS }
/**
* Last 10 opened applicant details. The queue list is a light row; GET-by-id
* is the body, suggested roles, resume text. Re-opening one of these should
* not pay that trip again. Cap is LRU the 11th open drops the oldest from
* the query cache. Mutations that write THIS row still invalidate its key.
*/
const OPENED_DETAIL_CAP = 10
const openedDetailLru = []
function detailQueryKey(kind, id) {
return kind === 'form' ? qk.mailbox.formRow(id) : qk.mailbox.message(id)
}
function rememberOpenedDetail(qc, kind, id) {
if (!id) return
const sig = `${kind}:${id}`
const key = detailQueryKey(kind, id)
const next = openedDetailLru.filter((x) => x.sig !== sig)
next.push({ sig, kind, id, key })
while (next.length > OPENED_DETAIL_CAP) {
const dropped = next.shift()
if (dropped && dropped.sig !== sig) {
qc.removeQueries({ queryKey: dropped.key })
}
}
openedDetailLru.length = 0
openedDetailLru.push(...next)
}
const DETAIL_CACHE = {
staleTime: Infinity,
gcTime: INBOX_GC_MS,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
}
/** Typing must not put a query key (and a skeleton) on screen per keystroke. */
const SEARCH_DEBOUNCE_MS = 300
@ -1388,7 +1425,12 @@ export default function Inbox() {
queryKey: selectedKind === 'form' ? qk.mailbox.formRow(selectedId) : qk.mailbox.message(selectedId),
queryFn: () => (selectedKind === 'form' ? fetchFormDetail(selectedId) : fetchMessageDetail(selectedId)),
enabled: Boolean(selectedId),
...DETAIL_CACHE,
})
useEffect(() => {
if (!selectedId || !detailQuery.isSuccess || !detailQuery.data) return
rememberOpenedDetail(qc, selectedKind, selectedId)
}, [qc, selectedId, selectedKind, detailQuery.isSuccess, detailQuery.data])
// List rows paint immediately; GET-by-id is the full application. Block every
// control in the detail pane until that fetch succeeds. The queue stays live.
const detailLocked = Boolean(selectedId) && !detailQuery.isError && !detailQuery.isSuccess