Frontend: Refactored pagination
ci/woodpecker/push/ociImagePush Pipeline was successful Details

This commit is contained in:
Natty 2024-01-01 20:29:33 +01:00
parent 6003f5e404
commit ab18633fbc
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
5 changed files with 43 additions and 159 deletions

View File

@ -30,11 +30,6 @@ export default defineComponent({
required: false, required: false,
default: false, default: false,
}, },
ad: {
type: Boolean,
required: false,
default: false,
},
}, },
setup(props, { slots, expose }) { setup(props, { slots, expose }) {

View File

@ -20,7 +20,6 @@
:direction="pagination.reversed ? 'up' : 'down'" :direction="pagination.reversed ? 'up' : 'down'"
:reversed="pagination.reversed" :reversed="pagination.reversed"
:no-gap="noGap" :no-gap="noGap"
:ad="true"
class="notes" class="notes"
> >
<XNoteResolvingProxy <XNoteResolvingProxy

View File

@ -19,7 +19,7 @@
<div v-else ref="rootEl" class="list"> <div v-else ref="rootEl" class="list">
<div <div
v-show="pagination.reversed && more" v-show="pagination.reversed && hasMore"
key="_more_" key="_more_"
class="cxiknjgy _gap" class="cxiknjgy _gap"
> >
@ -29,7 +29,7 @@
:disabled="moreFetching" :disabled="moreFetching"
:style="{ cursor: moreFetching ? 'wait' : 'pointer' }" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"
primary primary
@click="fetchMoreAhead" @click="fetchMore"
> >
{{ i18n.ts.loadMore }} {{ i18n.ts.loadMore }}
</MkButton> </MkButton>
@ -37,7 +37,7 @@
</div> </div>
<slot :items="items"></slot> <slot :items="items"></slot>
<div <div
v-show="!pagination.reversed && more" v-show="!pagination.reversed && hasMore"
key="_more_" key="_more_"
class="cxiknjgy _gap" class="cxiknjgy _gap"
> >
@ -134,7 +134,7 @@ const queue = ref<Item[]>([]);
const offset = ref(0); const offset = ref(0);
const fetching = ref(true); const fetching = ref(true);
const moreFetching = ref(false); const moreFetching = ref(false);
const more = ref(false); const hasMore = ref(false);
const backed = ref(false); // const backed = ref(false); //
const isBackTop = ref(false); const isBackTop = ref(false);
const empty = computed(() => items.value.length === 0); const empty = computed(() => items.value.length === 0);
@ -151,27 +151,14 @@ const init = async (): Promise<void> => {
await os await os
.api(props.pagination.endpoint, { .api(props.pagination.endpoint, {
...params, ...params,
limit: props.pagination.noPaging limit: props.pagination.limit || 10,
? props.pagination.limit || 10
: (props.pagination.limit || 10) + 1,
}) })
.then( .then(
(res) => { (res) => {
if ( items.value = props.pagination.reversed
!props.pagination.noPaging && ? [...res].reverse()
res.length > (props.pagination.limit || 10) : res;
) { hasMore.value = !props.pagination.noPaging && res.length > 0;
res.pop();
items.value = props.pagination.reversed
? [...res].reverse()
: res;
more.value = true;
} else {
items.value = props.pagination.reversed
? [...res].reverse()
: res;
more.value = false;
}
offset.value = res.length; offset.value = res.length;
error.value = false; error.value = false;
fetching.value = false; fetching.value = false;
@ -202,17 +189,14 @@ const refresh = async (): Promise<void> => {
}) })
.then( .then(
(res) => { (res) => {
let ids = items.value.reduce((a, b) => { let ids = new Set(items.value.map((i) => i.id));
a[b.id] = true;
return a;
}, {} as { [id: string]: boolean });
for (let i = 0; i < res.length; i++) { for (let i = 0; i < res.length; i++) {
const item = res[i]; const item = res[i];
if (!updateItem(item.id, (old) => item)) { if (!updateItem(item.id, (old) => item)) {
append(item); append(item);
} }
delete ids[item.id]; ids.delete(item.id);
} }
for (const id in ids) { for (const id in ids) {
@ -228,12 +212,13 @@ const refresh = async (): Promise<void> => {
const fetchMore = async (): Promise<void> => { const fetchMore = async (): Promise<void> => {
if ( if (
!more.value || !hasMore.value ||
fetching.value || fetching.value ||
moreFetching.value || moreFetching.value ||
items.value.length === 0 items.value.length === 0
) )
return; return;
moreFetching.value = true; moreFetching.value = true;
backed.value = true; backed.value = true;
const params = props.pagination.params const params = props.pagination.params
@ -241,117 +226,34 @@ const fetchMore = async (): Promise<void> => {
? props.pagination.params.value ? props.pagination.params.value
: props.pagination.params : props.pagination.params
: {}; : {};
const lastItem = items.value.at(props.pagination.reversed ? 0 : -1);
await os await os
.api(props.pagination.endpoint, { .api(props.pagination.endpoint, {
...params, ...params,
limit: SECOND_FETCH_LIMIT + 1, limit: SECOND_FETCH_LIMIT,
...(props.pagination.offsetMode ...(props.pagination.offsetMode
? { ? {
offset: offset.value, offset: offset.value,
} }
: props.pagination.reversed
? {
sinceDate: new Date(
magTransProperty(
items.value[0],
"createdAt",
"created_at"
)
).getTime(),
sinceId: items.value[0].id,
}
: { : {
untilDate: new Date( untilDate: lastItem
magTransProperty( ? new Date(
items.value[items.value.length - 1], magTransProperty(
"createdAt", lastItem,
"created_at" "createdAt",
) "created_at"
).getTime(), )
untilId: items.value[items.value.length - 1].id, ).getTime()
: undefined,
untilId: lastItem?.id ?? undefined,
}), }),
}) })
.then( .then(
(res) => { (res) => {
if (res.length > SECOND_FETCH_LIMIT) { items.value = props.pagination.reversed
res.pop(); ? [...res].reverse().concat(items.value)
items.value = props.pagination.reversed : items.value.concat(res);
? [...res].reverse().concat(items.value) hasMore.value = res.length > 0;
: items.value.concat(res);
more.value = true;
} else {
items.value = props.pagination.reversed
? [...res].reverse().concat(items.value)
: items.value.concat(res);
more.value = false;
}
offset.value += res.length;
moreFetching.value = false;
},
(err) => {
moreFetching.value = false;
}
);
};
const fetchMoreAhead = async (): Promise<void> => {
if (
!more.value ||
fetching.value ||
moreFetching.value ||
items.value.length === 0
)
return;
moreFetching.value = true;
const params = props.pagination.params
? isRef(props.pagination.params)
? props.pagination.params.value
: props.pagination.params
: {};
await os
.api(props.pagination.endpoint, {
...params,
limit: SECOND_FETCH_LIMIT + 1,
...(props.pagination.offsetMode
? {
offset: offset.value,
}
: props.pagination.reversed
? {
untilDate: new Date(
magTransProperty(
items.value[0],
"createdAt",
"created_at"
)
),
untilId: items.value[0].id,
}
: {
sinceDate: new Date(
magTransProperty(
items.value[items.value.length - 1],
"createdAt",
"created_at"
)
),
sinceId: items.value[items.value.length - 1].createdAt,
}),
})
.then(
(res) => {
if (res.length > SECOND_FETCH_LIMIT) {
res.pop();
items.value = props.pagination.reversed
? [...res].reverse().concat(items.value)
: items.value.concat(res);
more.value = true;
} else {
items.value = props.pagination.reversed
? [...res].reverse().concat(items.value)
: items.value.concat(res);
more.value = false;
}
offset.value += res.length; offset.value += res.length;
moreFetching.value = false; moreFetching.value = false;
}, },
@ -373,15 +275,8 @@ const prepend = (item: Item): void => {
const height = container.scrollHeight; const height = container.scrollHeight;
const isBottom = pos + viewHeight > height - 32; const isBottom = pos + viewHeight > height - 32;
if (isBottom) { if (isBottom) {
// items.value = items.value.slice(-props.displayLimit);
if (items.value.length >= props.displayLimit) { hasMore.value = true;
// Vue 3.2
//items.value = items.value.slice(-props.displayLimit);
while (items.value.length >= props.displayLimit) {
items.value.shift();
}
more.value = true;
}
} }
} }
} }
@ -402,24 +297,19 @@ const prepend = (item: Item): void => {
if (isTop) { if (isTop) {
// Prepend the item // Prepend the item
items.value.unshift(item); items.value.unshift(item);
items.value = items.value.slice(0, props.displayLimit);
//
if (items.value.length >= props.displayLimit) {
// Vue 3.2
//this.items = items.value.slice(0, props.displayLimit);
while (items.value.length >= props.displayLimit) {
items.value.pop();
}
more.value = true;
}
} else { } else {
if (!queue.value.length) {
onScrollTop(rootEl.value, () => {
for (const queueItem of queue.value) {
prepend(queueItem);
}
queue.value = [];
});
}
queue.value.push(item); queue.value.push(item);
onScrollTop(rootEl.value, () => { queue.value = queue.value.slice(0, props.displayLimit);
for (const queueItem of queue.value) {
prepend(queueItem);
}
queue.value = [];
});
} }
} }
}; };

View File

@ -20,7 +20,6 @@
:items="items" :items="items"
:direction="'down'" :direction="'down'"
:no-gap="false" :no-gap="false"
:ad="false"
> >
<XNoteResolvingProxy <XNoteResolvingProxy
:key="item.id" :key="item.id"

View File

@ -114,6 +114,7 @@ const nextPagination = {
appearNote appearNote
? { ? {
userId: appearNote.user.id, userId: appearNote.user.id,
sinceDate: new Date(appearNote.created_at).getTime(),
sinceId: appearNote.id, sinceId: appearNote.id,
} }
: null : null