diff --git a/adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md b/adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md index 07629ca9a..6970446c3 100644 --- a/adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md +++ b/adminforth/documentation/docs/tutorial/03-Customization/13-standardPagesTuning.md @@ -523,6 +523,26 @@ And `edit` action will be available as quick action: +## Show + +### Next record button + +By default, when a user opens a record from the list view, a **Next** button appears on the show page. It allows navigating through records one by one, respecting the current filters and sorting applied in the list. When the user reaches the last record on the current page, AdminForth automatically fetches the next page and continues navigation seamlessly. + +To disable the Next button for a resource, set `showNextButton` to `false`: + +```typescript title="./resources/apartments.ts" +export default { + resourceId: 'aparts', + options: { +//diff-add + showNextButton: false, + } +} +``` + +> ☝️ The Next button is only shown when the user navigates to the show page from the list view. Opening a record directly via URL will not display the button. + ## Creating ### Fill with default values diff --git a/adminforth/modules/restApi.ts b/adminforth/modules/restApi.ts index c1eb65229..f4120e185 100644 --- a/adminforth/modules/restApi.ts +++ b/adminforth/modules/restApi.ts @@ -318,6 +318,7 @@ const getResourceDataResponseSchema: AnySchemaObject = createErrorOrSuccessSchem items: genericObjectSchema, }, total: { type: 'number' }, + recordIds: { type: 'array', items: {} }, options: genericObjectSchema, }, additionalProperties: true, @@ -1563,6 +1564,11 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI { } } + if (source === 'list') { + const pkField = resource.columns.find((col) => col.primaryKey).name; + (data as any).recordIds = data.data.map((item) => item[pkField]); + } + return data; }, }); diff --git a/adminforth/spa/src/components/ResourceListTable.vue b/adminforth/spa/src/components/ResourceListTable.vue index 18fdb04b2..380b165f7 100644 --- a/adminforth/spa/src/components/ResourceListTable.vue +++ b/adminforth/spa/src/components/ResourceListTable.vue @@ -406,7 +406,8 @@ const props = withDefaults(defineProps<{ bufferSize?: number, customActionIconsThreeDotsMenuItems?: AdminForthComponentDeclaration[] tableRowReplaceInjection?: AdminForthComponentDeclaration, - isVirtualScrollEnabled: boolean + isVirtualScrollEnabled: boolean, + filters?: any[] }>(), { sort: () => [] }); @@ -599,6 +600,12 @@ async function onClick(e: any, row: any) { // user asked to nothing on click return; } + coreStore.listRecordIds = props.rows?.map(r => r._primaryKeyValue) ?? []; + coreStore.listResourceId = props.resource?.resourceId ?? null; + coreStore.listSort = props.sort; + coreStore.listPage = page.value; + coreStore.listPageSize = props.pageSize; + coreStore.listFilters = props.filters ?? []; if (e.ctrlKey || e.metaKey || row._clickUrl?.includes('target=_blank')) { if (row._clickUrl) { diff --git a/adminforth/spa/src/stores/core.ts b/adminforth/spa/src/stores/core.ts index eb0763e71..e7e7fb910 100644 --- a/adminforth/spa/src/stores/core.ts +++ b/adminforth/spa/src/stores/core.ts @@ -22,6 +22,12 @@ export const useCoreStore = defineStore('core', () => { const isResourceFetching = ref(false); const isInternetError = ref(false); const screenWidth = ref(window.innerWidth); + const listRecordIds: Ref = ref([]); + const listResourceId: Ref = ref(null); + const listFilters: Ref = ref([]); + const listSort: Ref = ref([]); + const listPage: Ref = ref(0); + const listPageSize: Ref = ref(0); onMounted(() => { window.addEventListener('resize', updateWidth); @@ -290,5 +296,11 @@ export const useCoreStore = defineStore('core', () => { isIos, isInternetError, isMobile, + listRecordIds, + listResourceId, + listFilters, + listSort, + listPage, + listPageSize, } }) diff --git a/adminforth/spa/src/utils/listUtils.ts b/adminforth/spa/src/utils/listUtils.ts index 7fee0fdb9..7a818874f 100644 --- a/adminforth/spa/src/utils/listUtils.ts +++ b/adminforth/spa/src/utils/listUtils.ts @@ -47,11 +47,12 @@ export async function getList(resource: AdminForthResourceFrontend, isPageLoaded return row; }); totalRows = data.total; - + const recordIds = data.recordIds || []; + // if checkboxes have items which are not in current data, remove them checkboxes.value = checkboxes.value.filter((pk: any) => rows.some((r: any) => r._primaryKeyValue === pk)); await nextTick(); - return { rows, totalRows }; + return { rows, totalRows, recordIds }; } diff --git a/adminforth/spa/src/views/ListView.vue b/adminforth/spa/src/views/ListView.vue index 90804acce..905458d67 100644 --- a/adminforth/spa/src/views/ListView.vue +++ b/adminforth/spa/src/views/ListView.vue @@ -180,6 +180,7 @@ @update:records="getListInner" @update:pageSize="(newSize) => { pageSize = newSize; page = 1; }" :sort="sort" + :filters="filtersStore.filters" :pageSizeOptions="Array.isArray(coreStore.resource?.options?.listPageSizeOptions) ? coreStore.resource?.options?.listPageSizeOptions : []" :pageSize="pageSize" :totalRows="totalRows" diff --git a/adminforth/spa/src/views/ShowView.vue b/adminforth/spa/src/views/ShowView.vue index 75985e78d..4f28d3006 100644 --- a/adminforth/spa/src/views/ShowView.vue +++ b/adminforth/spa/src/views/ShowView.vue @@ -10,6 +10,17 @@ :adminUser="coreStore.adminUser" /> + +