improve pagination

This commit is contained in:
Anbraten 2024-04-17 11:37:19 +02:00
parent d316e3c5cb
commit 3880844a79
6 changed files with 69 additions and 22 deletions

View file

@ -7,8 +7,8 @@
</p> </p>
<br/> <br/>
<p align="center"> <p align="center">
<a href="https://ci.woodpecker-ci.org/repos/3780" title="Build Status"> <a href="https://ci.woodpecker-ci.org/repos/3780" title="Pipeline Status">
<img src="https://ci.woodpecker-ci.org/api/badges/3780/status.svg" alt="Build Status"> <img src="https://ci.woodpecker-ci.org/api/badges/3780/status.svg" alt="Pipeline Status">
</a> </a>
<a href="https://codecov.io/gh/woodpecker-ci/woodpecker"> <a href="https://codecov.io/gh/woodpecker-ci/woodpecker">
<img src="https://codecov.io/gh/woodpecker-ci/woodpecker/branch/main/graph/badge.svg" alt="Code coverage"> <img src="https://codecov.io/gh/woodpecker-ci/woodpecker/branch/main/graph/badge.svg" alt="Code coverage">

1
web/components.d.ts vendored
View file

@ -85,6 +85,7 @@ declare module 'vue' {
Navbar: typeof import('./src/components/layout/header/Navbar.vue')['default'] Navbar: typeof import('./src/components/layout/header/Navbar.vue')['default']
NumberField: typeof import('./src/components/form/NumberField.vue')['default'] NumberField: typeof import('./src/components/form/NumberField.vue')['default']
OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default'] OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default']
Pagination: typeof import('./src/components/layout/Pagination.vue')['default']
Panel: typeof import('./src/components/layout/Panel.vue')['default'] Panel: typeof import('./src/components/layout/Panel.vue')['default']
PipelineFeedItem: typeof import('./src/components/pipeline-feed/PipelineFeedItem.vue')['default'] PipelineFeedItem: typeof import('./src/components/pipeline-feed/PipelineFeedItem.vue')['default']
PipelineFeedSidebar: typeof import('./src/components/pipeline-feed/PipelineFeedSidebar.vue')['default'] PipelineFeedSidebar: typeof import('./src/components/pipeline-feed/PipelineFeedSidebar.vue')['default']

View file

@ -0,0 +1,38 @@
<template>
<div>
<div v-if="loading">loading ...</div>
<div v-else>
<slot />
</div>
<Button v-if="hasMore" :is-loading="loading" text="Load more" class="mx-auto mt-4" @click="nextPage" />
</div>
</template>
<script lang="ts" setup>
import { computed, nextTick } from 'vue';
import Button from '~/components/atomic/Button.vue';
import { usePagination } from '~/compositions/usePaginate';
const props = defineProps<{
pagination: ReturnType<typeof usePagination>;
}>();
const loading = computed(() => props.pagination.loading.value);
const hasMore = computed(() => props.pagination.hasMore.value);
function scrollDown() {
window.scrollTo({
top: document.body.scrollHeight,
behavior: 'smooth',
});
}
function nextPage() {
props.pagination.nextPage();
nextTick(() => {
setTimeout(scrollDown, 100);
});
}
</script>

View file

@ -14,14 +14,15 @@
<Button v-else :text="$t('repo.settings.secrets.add')" start-icon="plus" @click="showAddSecret" /> <Button v-else :text="$t('repo.settings.secrets.add')" start-icon="plus" @click="showAddSecret" />
</template> </template>
<SecretList <Pagination v-if="!selectedSecret" :pagination="secretsPagination">
v-if="!selectedSecret" <SecretList
:model-value="secrets" :model-value="secrets"
i18n-prefix="repo.settings.secrets." i18n-prefix="repo.settings.secrets."
:is-deleting="isDeleting" :is-deleting="isDeleting"
@edit="editSecret" @edit="editSecret"
@delete="deleteSecret" @delete="deleteSecret"
/> />
</Pagination>
<SecretEdit <SecretEdit
v-else v-else
@ -81,9 +82,12 @@ async function loadSecrets(page: number, level: 'repo' | 'org' | 'global'): Prom
} }
} }
const { resetPage, data: _secrets } = usePagination(loadSecrets, () => !selectedSecret.value, { const secretsPagination = usePagination(loadSecrets, () => !selectedSecret.value, {
each: ['repo', 'org', 'global'], each: ['repo', 'org', 'global'],
scrollElement: null,
pageSize: 50,
}); });
const { resetPage, data: _secrets } = secretsPagination;
const secrets = computed(() => { const secrets = computed(() => {
const secretsList: Record<string, Secret & { edit?: boolean; level: 'repo' | 'org' | 'global' }> = {}; const secretsList: Record<string, Secret & { edit?: boolean; level: 'repo' | 'org' | 'global' }> = {};

View file

@ -18,11 +18,15 @@ export async function usePaginate<T>(getSingle: (page: number) => Promise<T[]>):
export function usePagination<T, S = unknown>( export function usePagination<T, S = unknown>(
_loadData: (page: number, arg: S) => Promise<T[] | null>, _loadData: (page: number, arg: S) => Promise<T[] | null>,
isActive: () => boolean = () => true, isActive: () => boolean = () => true,
{ scrollElement: _scrollElement, each: _each }: { scrollElement?: Ref<HTMLElement | null>; each?: S[] } = {}, {
scrollElement: _scrollElement,
each: _each,
pageSize: _pageSize,
}: { scrollElement?: Ref<HTMLElement | null> | null; each?: S[]; pageSize?: number } = {},
) { ) {
const scrollElement = _scrollElement ?? ref(document.getElementById('scroll-component')); const scrollElement = _scrollElement === null ? null : ref(document.getElementById('scroll-component'));
const page = ref(1); const page = ref(1);
const pageSize = ref(0); const pageSize = ref(_pageSize ?? 0);
const hasMore = ref(true); const hasMore = ref(true);
const data = ref<T[]>([]) as Ref<T[]>; const data = ref<T[]>([]) as Ref<T[]>;
const loading = ref(false); const loading = ref(false);
@ -33,8 +37,6 @@ export function usePagination<T, S = unknown>(
return; return;
} }
console.log('loadData', page.value, each.value);
loading.value = true; loading.value = true;
const newData = (await _loadData(page.value, each.value?.[0] as S)) ?? []; const newData = (await _loadData(page.value, each.value?.[0] as S)) ?? [];
hasMore.value = newData.length >= pageSize.value && newData.length > 0; hasMore.value = newData.length >= pageSize.value && newData.length > 0;
@ -42,14 +44,14 @@ export function usePagination<T, S = unknown>(
data.value.push(...newData); data.value.push(...newData);
} }
console.log('loadData1', page.value, hasMore.value, each.value); console.log('loadData', each.value?.[0], page.value);
// last page and each has more // last page and each has more
if (!hasMore.value && each.value.length > 0) { if (!hasMore.value && each.value.length > 0) {
// use next each element // use next each element
each.value.shift(); each.value.shift();
page.value = 1; page.value = 1;
pageSize.value = 0; pageSize.value = _pageSize ?? 0;
hasMore.value = each.value.length > 0; hasMore.value = each.value.length > 0;
if (hasMore.value) { if (hasMore.value) {
loading.value = false; loading.value = false;
@ -69,13 +71,15 @@ export function usePagination<T, S = unknown>(
} }
} }
useInfiniteScroll(scrollElement, nextPage, { distance: 10 }); if (scrollElement !== null) {
useInfiniteScroll(scrollElement, nextPage, { distance: 10 });
}
async function resetPage() { async function resetPage() {
const _page = page.value; const _page = page.value;
page.value = 1; page.value = 1;
pageSize.value = 0; pageSize.value = _pageSize ?? 0;
hasMore.value = true; hasMore.value = true;
data.value = []; data.value = [];
loading.value = false; loading.value = false;

View file

@ -20,7 +20,7 @@
<Tab id="secrets" :title="$t('repo.settings.secrets.secrets')"> <Tab id="secrets" :title="$t('repo.settings.secrets.secrets')">
<SecretsTab /> <SecretsTab />
</Tab> </Tab>
<Tab id="registries" :title="$t('repo.settings.registries.registries')"> <!-- <Tab id="registries" :title="$t('repo.settings.registries.registries')">
<RegistriesTab /> <RegistriesTab />
</Tab> </Tab>
<Tab id="crons" :title="$t('repo.settings.crons.crons')"> <Tab id="crons" :title="$t('repo.settings.crons.crons')">
@ -31,7 +31,7 @@
</Tab> </Tab>
<Tab id="actions" :title="$t('repo.settings.actions.actions')"> <Tab id="actions" :title="$t('repo.settings.actions.actions')">
<ActionsTab /> <ActionsTab />
</Tab> </Tab> -->
</Scaffold> </Scaffold>
</template> </template>