Web: Activity loads older events as you scroll, no Show older button
Preference 172. ScrollSentinel watches the end of a cursor-paged list and asks for the next page a screen early. It asks once per cursor, keeps going when a page lands without pushing the end off screen, and stops on a failure until Try again (an observer re-firing on a failure is a request loop). A failed older page now gets its own error beside the retry, instead of replacing the list's load error. Adapted from fabledstash's ScrollSentinel (snippet 3760). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { api } from "../api/client";
|
||||
import { errorMessage } from "../api/errors";
|
||||
import { formatShortDateTime } from "../notes/datetime";
|
||||
import { useLoad } from "../composables/useAction";
|
||||
import ScrollSentinel from "./ScrollSentinel.vue";
|
||||
|
||||
// Admin: what has happened to accounts on this instance, newest first (#2939 §5).
|
||||
// Kept for `audit_retention_days` (Settings → Security).
|
||||
@@ -52,6 +53,9 @@ const { loading, error, load } = useLoad(async () => {
|
||||
more.value = res.more;
|
||||
}, "Couldn't load activity.");
|
||||
const loadingMore = ref(false);
|
||||
const moreError = ref("");
|
||||
// The next page starts before the oldest event shown; empty once there is none.
|
||||
const cursor = computed(() => (more.value ? (events.value[events.value.length - 1]?.at ?? "") : ""));
|
||||
|
||||
async function page(before?: string) {
|
||||
const query = before ? `?before=${encodeURIComponent(before)}` : "";
|
||||
@@ -59,15 +63,15 @@ async function page(before?: string) {
|
||||
}
|
||||
|
||||
async function loadMore() {
|
||||
const last = events.value[events.value.length - 1];
|
||||
if (!last) return;
|
||||
if (!cursor.value || loadingMore.value) return;
|
||||
loadingMore.value = true;
|
||||
moreError.value = "";
|
||||
try {
|
||||
const res = await page(last.at);
|
||||
const res = await page(cursor.value);
|
||||
events.value.push(...res.events);
|
||||
more.value = res.more;
|
||||
} catch (e) {
|
||||
error.value = errorMessage(e, "Couldn't load older activity.");
|
||||
moreError.value = errorMessage(e, "Couldn't load older activity.");
|
||||
} finally {
|
||||
loadingMore.value = false;
|
||||
}
|
||||
@@ -106,14 +110,12 @@ onMounted(() => {
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button
|
||||
v-if="more"
|
||||
type="button"
|
||||
class="self-start btn-sm"
|
||||
:disabled="loadingMore"
|
||||
@click="loadMore"
|
||||
>
|
||||
Show older
|
||||
</button>
|
||||
<ScrollSentinel
|
||||
v-if="!loading"
|
||||
:cursor="cursor"
|
||||
:loading="loadingMore"
|
||||
:error="moreError"
|
||||
@more="loadMore"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user