fix: page past the 100-row cap in application pickers
get_pagination_params clamps perpage to MAX_PAGE_SIZE (100) and reports nothing about having done so, so a caller asking for perpage: 1000 gets the first 100 rows and a success response. Every picker built that way looked complete and was not. Found on a live site with 126 active applications: the 26 sorting last were absent from the knowledge-base topic dropdown, so an article could not be filed against them. Nothing was wrong with those application records, and editing them could never have helped. Adds fetchAllPages() to the api module, generalizing the one call site that already handled this correctly (modelsApi.listAll), and points the four application pickers at a new applicationsApi.listAll(): the KB article form, the KB list's topic filter, the notification form, and the report filter builder. Lists that render a page at a time are untouched - they page for a reason. Other callers still asking for more than 100 rows of vendors, locations, models, subnets and the rest are latent: correct only while those tables stay under 100, and silent on the day they do not.
This commit is contained in:
@@ -50,6 +50,30 @@ api.interceptors.response.use(
|
||||
|
||||
export default api
|
||||
|
||||
// The backend clamps perpage to MAX_PAGE_SIZE (100) and says nothing about it,
|
||||
// so asking for `perpage: 1000` silently returns the first 100 rows and drops
|
||||
// the rest. A picker built that way looks complete and is not: with 126
|
||||
// applications on a live site, the 26 sorting last were simply unselectable.
|
||||
//
|
||||
// Use this wherever a control needs the WHOLE list (dropdowns, pickers, label
|
||||
// batches) rather than a page of it. Returns the full array directly, not an
|
||||
// axios response. Anything that renders a paged table should keep calling
|
||||
// list() with a real page number instead.
|
||||
export async function fetchAllPages(path, params = {}) {
|
||||
const first = await api.get(path, { params: { ...params, perpage: 100, page: 1 } })
|
||||
let items = first.data.data || []
|
||||
const totalpages = first.data.meta?.pagination?.totalpages || 1
|
||||
if (totalpages > 1) {
|
||||
const rest = await Promise.all(
|
||||
Array.from({ length: totalpages - 1 }, (_, i) =>
|
||||
api.get(path, { params: { ...params, perpage: 100, page: i + 2 } })
|
||||
)
|
||||
)
|
||||
rest.forEach(response => { items = items.concat(response.data.data || []) })
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// Auth API
|
||||
export const authApi = {
|
||||
login(username, password) {
|
||||
@@ -388,19 +412,8 @@ export const modelsApi = {
|
||||
// Backend caps perpage at 100, so page through every model. Returns the
|
||||
// full array directly (not an axios response). Use in forms whose model
|
||||
// dropdown must include the editing record's model regardless of page.
|
||||
async listAll() {
|
||||
const first = await api.get('/models', { params: { perpage: 100, page: 1 } })
|
||||
let items = first.data.data || []
|
||||
const totalpages = first.data.meta?.pagination?.totalpages || 1
|
||||
if (totalpages > 1) {
|
||||
const rest = await Promise.all(
|
||||
Array.from({ length: totalpages - 1 }, (_, i) =>
|
||||
api.get('/models', { params: { perpage: 100, page: i + 2 } })
|
||||
)
|
||||
)
|
||||
rest.forEach(r => { items = items.concat(r.data.data || []) })
|
||||
}
|
||||
return items
|
||||
listAll(params = {}) {
|
||||
return fetchAllPages('/models', params)
|
||||
},
|
||||
get(id) {
|
||||
return api.get(`/models/${id}`)
|
||||
@@ -468,6 +481,12 @@ export const applicationsApi = {
|
||||
list(params = {}) {
|
||||
return api.get('/applications', { params })
|
||||
},
|
||||
// Every application, paged past the backend's 100-row cap. The catalogue is
|
||||
// already over 100 entries on a live site, so any picker offering "all
|
||||
// applications" must use this and not list({ perpage: <big number> }).
|
||||
listAll(params = {}) {
|
||||
return fetchAllPages('/applications', params)
|
||||
},
|
||||
get(id) {
|
||||
return api.get(`/applications/${id}`)
|
||||
},
|
||||
|
||||
@@ -270,8 +270,10 @@ async function loadFilterOptions(fields) {
|
||||
filterOptions.value.locations = response.data.data || []
|
||||
}
|
||||
if (fields.includes('application') && !filterOptions.value.applications.length) {
|
||||
const response = await applicationsApi.list({ perpage: 100 })
|
||||
filterOptions.value.applications = response.data.data || []
|
||||
// listAll: 100 is the server-side cap, not a generous limit, and the
|
||||
// catalogue is past it - a report filtered by a late-alphabet
|
||||
// application could not be built.
|
||||
filterOptions.value.applications = await applicationsApi.listAll()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading filter options:', error)
|
||||
|
||||
Reference in New Issue
Block a user