Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions src/components/DataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ interface Props {
addButtonTestId?: string
search?: string
total: number
/** Fixed page size used for last-page / next calculations. Prefer this over inferring from the current page length. */
offset?: number
currentPage: number
columns: TableColumn[]
elementList: { [key: string]: any }[]
Expand Down Expand Up @@ -71,12 +73,19 @@ const pendingAdd = ref(false)
// const sorts = ref<TableSort>({})
// get columns from elementList

const offset = computed(() => {
if (!props.elementList)
return 0
// Page size must stay fixed across pages. Inferring it from the current page's
// row count breaks last-page / next controls when the final page is short
// (common after deletes).
const pageSize = computed(() => {
if (props.offset && props.offset > 0)
return props.offset
if (!props.elementList || props.elementList.length === 0)
return 1
return props.elementList.length
})

const totalPages = computed(() => Math.max(1, Math.ceil(props.total / pageSize.value)))

const selectedRows = ref<boolean[]>(props.elementList.map(_ => false))
const previousSelectedRow = ref<number | null>(null)

Expand Down Expand Up @@ -335,13 +344,15 @@ function tooltipIdFor(rowIndex: number, actionIndex: number): string {
}

const displayElemRange = computed(() => {
const begin = (props.currentPage - 1) * props.elementList.length
if (props.elementList.length === 0)
return '0-0'
const begin = (props.currentPage - 1) * pageSize.value
const end = begin + props.elementList.length
return `${begin}-${end}`
})

function canNext() {
return props.currentPage < Math.ceil(props.total / offset.value)
return props.currentPage < totalPages.value
}
function canPrev() {
return props.currentPage > 1
Expand All @@ -356,7 +367,7 @@ async function next() {
async function fastForward() {
if (canNext()) {
emit('fastForward')
emit('update:currentPage', Math.ceil(props.total / offset.value))
emit('update:currentPage', totalPages.value)
}
}
async function prev() {
Expand Down
3 changes: 3 additions & 0 deletions src/components/tables/AppTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const props = defineProps<{
apps: (Database['public']['Tables']['apps']['Row'])[]
deleteButton: boolean
total?: number
/** Fixed page size for server-side pagination controls */
offset?: number
currentPage?: number
search?: string
serverSidePagination?: boolean
Expand Down Expand Up @@ -308,6 +310,7 @@ const filteredApps = computed(() => {
v-model:search="internalSearch"
:show-add="!isMobile"
:total="props.total ?? filteredApps.length"
:offset="props.offset"
:element-list="filteredApps"
:search-placeholder="t('search-by-name-or-app-id')"
:is-loading="props.isLoading ?? false"
Expand Down
6 changes: 5 additions & 1 deletion src/components/tables/BundleTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { formatBytes } from '~/services/conversion'
import { formatDate } from '~/services/date'
import { checkPermissions } from '~/services/permissions'
import { useSupabase } from '~/services/supabase'
import { refetchIfPageOutOfRange } from '~/services/tablePagination'
import { useDialogV2Store } from '~/stores/dialogv2'

const props = defineProps<{
Expand Down Expand Up @@ -247,10 +248,12 @@ async function getData() {
const { data: dataVersions, count } = await req
if (!dataVersions)
return
total.value = count ?? 0
if (await refetchIfPageOutOfRange(currentPage, total.value, offset, getData))
return
const enhancedVersions = await enhanceVersionElems(dataVersions)
await fetchChannelsForVersions(enhancedVersions)
elements.value = enhancedVersions as any
total.value = count ?? 0
}
catch (error) {
console.error(error)
Expand Down Expand Up @@ -612,6 +615,7 @@ watch(props, async () => {
<DataTable
v-model:filters="filters" v-model:columns="columns" v-model:current-page="currentPage" v-model:search="search"
:total="total"
:offset="offset"
:show-add="!isMobile"
:element-list="elements"
filter-text="Filters"
Expand Down
1 change: 1 addition & 0 deletions src/components/tables/ChannelHistoryTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ watch([search, page], () => {
:search="search"
:search-placeholder="t('search-by-name')"
:total="total"
:offset="pageSize"
:current-page="page"
:columns="columns"
:element-list="historyEntries"
Expand Down
13 changes: 6 additions & 7 deletions src/components/tables/ChannelTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import IconTrash from '~icons/heroicons/trash'
import { formatDate } from '~/services/date'
import { checkPermissions } from '~/services/permissions'
import { useSupabase } from '~/services/supabase'
import { refetchIfPageOutOfRange } from '~/services/tablePagination'
import { useDialogV2Store } from '~/stores/dialogv2'
import { useMainStore } from '~/stores/main'
import { useOrganizationStore } from '~/stores/organization'
Expand Down Expand Up @@ -133,10 +134,11 @@ async function getData() {
const { data: dataVersions, count } = await req
if (!dataVersions)
return
total.value = count ?? 0
if (await refetchIfPageOutOfRange(currentPage, total.value, offset, getData))
return
elements.value.length = 0
elements.value.push(...dataVersions as any)
// console.log('count', count)
total.value = count ?? 0
if (count === 0) {
showAddModal()
}
Expand Down Expand Up @@ -166,16 +168,13 @@ async function getData() {
isLoading.value = false
}
async function refreshData(keepCurrentPage = false) {
// console.log('refreshData')
try {
const page = currentPage.value
if (!keepCurrentPage)
currentPage.value = 1

elements.value.length = 0
// getData clamps currentPage when deletes leave it past the last page
await getData()
if (keepCurrentPage)
currentPage.value = page
}
catch (error) {
console.error(error)
Expand Down Expand Up @@ -380,7 +379,7 @@ watch(props, async () => {
<div>
<DataTable
v-model:filters="filters" v-model:columns="columns" v-model:current-page="currentPage" v-model:search="search"
:total="total" :element-list="elements"
:total="total" :offset="offset" :element-list="elements"
Comment thread
cursor[bot] marked this conversation as resolved.
show-add
filter-text="Filters"
:is-loading="isLoading"
Expand Down
2 changes: 1 addition & 1 deletion src/components/tables/DeviceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ async function ensureVersionNames(devices: Device[]) {
<div>
<DataTable
v-model:filters="filters" v-model:columns="columns" v-model:current-page="currentPage" v-model:search="search"
:total="total" :element-list="elements"
:total="total" :offset="offset" :element-list="elements"
filter-text="Filters"
:show-add="showAddButton"
:is-loading="isLoading"
Expand Down
1 change: 1 addition & 0 deletions src/components/tables/HistoryTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ watch([() => props.channelId, () => props.bundleId, () => props.appId], () => {
:search="search"
:search-placeholder="t('search-by-name')"
:total="total"
:offset="pageSize"
:current-page="page"
:columns="columns"
:element-list="deployHistory"
Expand Down
1 change: 1 addition & 0 deletions src/pages/apps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ displayStore.defaultBack = '/apps'
:search="searchQuery"
:apps="apps"
:total="totalApps"
:offset="pageSize"
:delete-button="!organizationStore.currentOrganizationFailed"
:server-side-pagination="true"
:is-loading="isTableLoading"
Expand Down
17 changes: 17 additions & 0 deletions src/services/tablePagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* If the active page is past the last page for the new total, clamp it and refetch.
* Returns true when a refetch was started.
*/
export async function refetchIfPageOutOfRange(
currentPage: { value: number },
total: number,
pageSize: number,
refetch: () => Promise<void>,
): Promise<boolean> {
const maxPage = Math.max(1, Math.ceil(total / pageSize))
if (currentPage.value <= maxPage)
return false
currentPage.value = maxPage
await refetch()
return true
}
Loading