sewt all limit
parent
0ede681a30
commit
e378b323b9
|
|
@ -215,6 +215,18 @@ try {
|
||||||
hasSkeleton(view.html()) && rowCount(view.html()) === 0,
|
hasSkeleton(view.html()) && rowCount(view.html()) === 0,
|
||||||
`skeleton=${hasSkeleton(view.html())} rows=${rowCount(view.html())}`,
|
`skeleton=${hasSkeleton(view.html())} rows=${rowCount(view.html())}`,
|
||||||
)
|
)
|
||||||
|
const allFormFetch = requestsMatching('/sheet/form-data/fetch')
|
||||||
|
const allEmailFetch = requestsMatching('/inbox/all-applications').filter((u) => !u.includes('/count'))
|
||||||
|
check(
|
||||||
|
'All channel sends the UI page size, not the whole form_data table',
|
||||||
|
allFormFetch.some((u) => u.includes('limit=10')),
|
||||||
|
allFormFetch.slice(-1)[0] || 'no form-data fetch on All',
|
||||||
|
)
|
||||||
|
check(
|
||||||
|
'All channel emails send the same page size',
|
||||||
|
allEmailFetch.some((u) => u.includes('top=10')),
|
||||||
|
allEmailFetch.slice(-1)[0] || 'no email fetch on All',
|
||||||
|
)
|
||||||
|
|
||||||
// ---- frame 2: email home, sheet still travelling ------------------------
|
// ---- frame 2: email home, sheet still travelling ------------------------
|
||||||
// THE REGRESSION: this frame used to render six placeholders on top of two
|
// THE REGRESSION: this frame used to render six placeholders on top of two
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,10 @@ const PAGE_SIZE_MAX = 500
|
||||||
* This list is a local table, not a live feed. Applications only appear when
|
* This list is a local table, not a live feed. Applications only appear when
|
||||||
* the Sync worker writes them, and that path already invalidates
|
* the Sync worker writes them, and that path already invalidates
|
||||||
* qk.mailbox.all() the moment a run completes — so refetching on every visit
|
* qk.mailbox.all() the moment a run completes — so refetching on every visit
|
||||||
* bought nothing and cost a full-width skeleton each time. The All channel
|
* bought nothing and cost a full-width skeleton each time.
|
||||||
* makes that worse: it fetches BOTH sources unpaged, so the "loading" state a
|
*
|
||||||
* recruiter saw on re-entry was thousands of rows being re-downloaded to
|
* List fetches always send the UI page size (10 / 50 / 100), including All —
|
||||||
* render the same ten.
|
* omitting limit used to dump the whole form_data table into the browser.
|
||||||
*
|
*
|
||||||
* staleTime therefore covers a normal working stretch, and keepPreviousData
|
* staleTime therefore covers a normal working stretch, and keepPreviousData
|
||||||
* means a tab switch, a page turn or a keystroke re-renders the rows already
|
* means a tab switch, a page turn or a keystroke re-renders the rows already
|
||||||
|
|
@ -1010,22 +1010,22 @@ export default function Inbox() {
|
||||||
}, [deepOpen, deepKind, setSearchParams])
|
}, [deepOpen, deepKind, setSearchParams])
|
||||||
|
|
||||||
const isForms = channel === 'forms'
|
const isForms = channel === 'forms'
|
||||||
// Combined channel: both sources fetched UNPAGED (each endpoint reads a
|
// Combined channel: each source is fetched with the UI page size, then
|
||||||
// missing top/limit as no LIMIT), merged by date, and paged client-side —
|
// merged newest-first. Per-source pages are not a perfect global timeline,
|
||||||
// per-source skip/top cannot compose into a correct global page.
|
// but omitting limit dumped the whole form_data table on open.
|
||||||
const isAllChannel = channel === 'all'
|
const isAllChannel = channel === 'all'
|
||||||
const channelTabs = isForms || isAllChannel ? FORM_TABS : TABS
|
const channelTabs = isForms || isAllChannel ? FORM_TABS : TABS
|
||||||
|
const pageLimit = pageSize === 'all' ? undefined : pageSize
|
||||||
|
|
||||||
const tabFilter = TAB_FILTERS[tab] ?? {}
|
const tabFilter = TAB_FILTERS[tab] ?? {}
|
||||||
const formTabFilter = FORM_TAB_FILTERS[tab] ?? {}
|
const formTabFilter = FORM_TAB_FILTERS[tab] ?? {}
|
||||||
const listParams = useMemo(() => ({
|
const listParams = useMemo(() => ({
|
||||||
...tabFilter,
|
...tabFilter,
|
||||||
// 'all' page size and the All channel drop the param entirely — the
|
// Show-all omits top (no LIMIT). Otherwise send the pager size — 10, 50, 100.
|
||||||
// endpoint reads a missing top as unpaged.
|
top: pageLimit,
|
||||||
top: pageSize === 'all' || isAllChannel ? undefined : pageSize,
|
skip: pageLimit == null ? 0 : skip,
|
||||||
skip: isAllChannel ? 0 : skip,
|
|
||||||
...(search ? { search } : {}),
|
...(search ? { search } : {}),
|
||||||
}), [tabFilter, skip, pageSize, search, isAllChannel])
|
}), [tabFilter, skip, pageLimit, search])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sheet Forms only. On the All channel these rows are merged with email ones,
|
* Sheet Forms only. On the All channel these rows are merged with email ones,
|
||||||
|
|
@ -1042,12 +1042,12 @@ export default function Inbox() {
|
||||||
const formParams = useMemo(() => ({
|
const formParams = useMemo(() => ({
|
||||||
// All channel spans every sheet tab, not just the selected one.
|
// All channel spans every sheet tab, not just the selected one.
|
||||||
sheet: isAllChannel ? undefined : (formSheet || undefined),
|
sheet: isAllChannel ? undefined : (formSheet || undefined),
|
||||||
offset: isAllChannel ? 0 : skip,
|
offset: pageLimit == null ? 0 : skip,
|
||||||
limit: pageSize === 'all' || isAllChannel ? undefined : pageSize,
|
limit: pageLimit,
|
||||||
...formTabFilter,
|
...formTabFilter,
|
||||||
...(search ? { search } : {}),
|
...(search ? { search } : {}),
|
||||||
...linkFilters,
|
...linkFilters,
|
||||||
}), [formSheet, skip, pageSize, search, formTabFilter, isAllChannel, linkFilters])
|
}), [formSheet, skip, pageLimit, search, formTabFilter, isAllChannel, linkFilters])
|
||||||
|
|
||||||
const applicationsQuery = useQuery({
|
const applicationsQuery = useQuery({
|
||||||
queryKey: qk.mailbox.applications(listParams),
|
queryKey: qk.mailbox.applications(listParams),
|
||||||
|
|
@ -1135,8 +1135,7 @@ export default function Inbox() {
|
||||||
}
|
}
|
||||||
}, [isForms, formSheetsQuery.data, formSheet])
|
}, [isForms, formSheetsQuery.data, formSheet])
|
||||||
|
|
||||||
// All channel: both sources arrive unpaged; merge newest-first and let the
|
// All channel: one page from each source, merged newest-first.
|
||||||
// pager slice the merged array below.
|
|
||||||
const mergedRows = useMemo(() => {
|
const mergedRows = useMemo(() => {
|
||||||
if (!isAllChannel) return null
|
if (!isAllChannel) return null
|
||||||
const emails = Array.isArray(applicationsQuery.data?.rows) ? applicationsQuery.data.rows : []
|
const emails = Array.isArray(applicationsQuery.data?.rows) ? applicationsQuery.data.rows : []
|
||||||
|
|
@ -1198,15 +1197,17 @@ export default function Inbox() {
|
||||||
const countsReady = isAllChannel
|
const countsReady = isAllChannel
|
||||||
? countsQuery.isSuccess && formCountsQuery.isSuccess
|
? countsQuery.isSuccess && formCountsQuery.isSuccess
|
||||||
: (isForms ? formCountsQuery.isSuccess : countsQuery.isSuccess)
|
: (isForms ? formCountsQuery.isSuccess : countsQuery.isSuccess)
|
||||||
|
const searchTotal = isAllChannel
|
||||||
|
? (Number(applicationsQuery.data?.total ?? 0) + Number(formQuery.data?.total ?? 0))
|
||||||
|
: (activeQuery.data?.total ?? 0)
|
||||||
const total = search
|
const total = search
|
||||||
? (activeQuery.data?.total ?? 0)
|
? searchTotal
|
||||||
: (countsReady ? tabTotal : (poolTotal || (activeQuery.data?.total ?? 0)))
|
: (countsReady ? tabTotal : (poolTotal || (activeQuery.data?.total ?? 0)))
|
||||||
// 'all' = unpaged: the fetch omits top/limit (the endpoints treat a missing
|
// 'all' = unpaged: the fetch omits top/limit (the endpoints treat a missing
|
||||||
// page size as no LIMIT), so the whole tab is one page.
|
// page size as no LIMIT), so the whole tab is one page.
|
||||||
const showAll = pageSize === 'all'
|
const showAll = pageSize === 'all'
|
||||||
const pages = showAll ? 1 : Math.max(1, Math.ceil(total / pageSize))
|
const pages = showAll ? 1 : Math.max(1, Math.ceil(total / pageSize))
|
||||||
const from = total ? skip + 1 : 0
|
const from = total ? skip + 1 : 0
|
||||||
const to = showAll ? total : Math.min(skip + pageSize, total)
|
|
||||||
const currentPage = showAll ? 1 : Math.min(Math.floor(skip / pageSize) + 1, pages)
|
const currentPage = showAll ? 1 : Math.min(Math.floor(skip / pageSize) + 1, pages)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -1215,8 +1216,9 @@ export default function Inbox() {
|
||||||
setSkip(Math.max(0, Math.floor((total - 1) / pageSize) * pageSize))
|
setSkip(Math.max(0, Math.floor((total - 1) / pageSize) * pageSize))
|
||||||
}, [total, pageSize, skip, showAll])
|
}, [total, pageSize, skip, showAll])
|
||||||
|
|
||||||
// All channel pages the merged array client-side; single channels page on the server.
|
// Server already applied skip/limit (or the whole tab when Show all).
|
||||||
const list = isAllChannel && !showAll ? inbox.slice(skip, skip + pageSize) : inbox
|
const list = inbox
|
||||||
|
const to = showAll ? total : Math.min(skip + (isAllChannel ? list.length : pageSize), total)
|
||||||
|
|
||||||
// Mixed rows: the row's own kind picks the detail endpoint, not the channel.
|
// Mixed rows: the row's own kind picks the detail endpoint, not the channel.
|
||||||
const selectedKind = inbox.find((i) => sameInboxId(i.id, selectedId))?.kind
|
const selectedKind = inbox.find((i) => sameInboxId(i.id, selectedId))?.kind
|
||||||
|
|
@ -1399,8 +1401,7 @@ export default function Inbox() {
|
||||||
|
|
||||||
/** Styled XLSX of the rows already loaded in this view — the DB filtered
|
/** Styled XLSX of the rows already loaded in this view — the DB filtered
|
||||||
them when the list was fetched (channel, tab, search); no extra request.
|
them when the list was fetched (channel, tab, search); no extra request.
|
||||||
Paged channels export the loaded page; the All channel and the "All"
|
Paged channels export the loaded page; Show all exports the whole view. */
|
||||||
page size hold the whole view, so those export everything. */
|
|
||||||
async function exportRows() {
|
async function exportRows() {
|
||||||
const rows = inbox
|
const rows = inbox
|
||||||
if (!rows.length) {
|
if (!rows.length) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue