diff --git a/ui/app/pages/tasks.vue b/ui/app/pages/tasks.vue
index e4ea0cad..e05a6570 100644
--- a/ui/app/pages/tasks.vue
+++ b/ui/app/pages/tasks.vue
@@ -113,7 +113,17 @@
-
{{ filteredTasks.length }} displayed
+
+
+
+
+
@@ -722,6 +745,8 @@ const config = useYtpConfig();
const socket = useAppSocket();
const stateStore = useQueueState();
const pageShell = requirePageShell('tasks');
+const route = useRoute();
+const router = useRouter();
const { confirmDialog } = useDialog();
const sessionCache = useSessionCache();
const { toggleExpand, expandClass } = useExpandableMeta();
@@ -731,6 +756,7 @@ const isMobile = useMediaQuery({ maxWidth: 639 });
const tasksComposable = useTasks();
const {
tasks,
+ pagination: paging,
isLoading,
addInProgress,
isTaskInProgress,
@@ -762,6 +788,7 @@ const inspectTask = ref(null);
const query = ref('');
const showFilter = ref(false);
const filterInput = ref<{ inputRef?: { value?: HTMLInputElement | null } } | null>(null);
+const page = ref(route.query.page ? parseInt(route.query.page as string, 10) : 1);
const CACHE_KEY = 'tasks:handler_support';
const taskHandlerSupport = ref>(sessionCache.get(CACHE_KEY) || {});
@@ -861,6 +888,19 @@ watch(
{ immediate: true },
);
+const syncPageQuery = async (pageNumber: number): Promise => {
+ const totalPages = tasksComposable.pagination.value.total_pages;
+ const nextQuery = { ...route.query };
+
+ if (totalPages > 1) {
+ nextQuery.page = String(pageNumber);
+ } else {
+ delete nextQuery.page;
+ }
+
+ await router.replace({ query: nextQuery });
+};
+
const toggleFilterPanel = async (): Promise => {
showFilter.value = !showFilter.value;
if (!showFilter.value) {
@@ -941,9 +981,15 @@ const willTaskBeProcessed = (item: Task): boolean => {
return hasTimer || hasHandler;
};
-const reloadContent = async (fromMounted: boolean = false) => {
+const loadContent = async (pageNumber = page.value, fromMounted: boolean = false) => {
+ page.value = pageNumber;
+
try {
- await tasksComposable.loadTasks();
+ await tasksComposable.loadTasks(pageNumber);
+
+ page.value = tasksComposable.pagination.value.page;
+ await nextTick();
+ await syncPageQuery(page.value);
if (tasks.value.length > 0) {
cleanStaleCache(tasks.value);
@@ -956,6 +1002,14 @@ const reloadContent = async (fromMounted: boolean = false) => {
}
};
+const reloadContent = async (fromMounted: boolean = false) => {
+ await loadContent(page.value, fromMounted);
+};
+
+const navigatePage = async (newPage: number): Promise => {
+ await loadContent(newPage);
+};
+
const resetForm = (closeForm: boolean = false) => {
task.value = createEmptyTask();
taskRef.value = null;
@@ -1400,7 +1454,7 @@ const itemActionGroups = (item: Task): DropdownMenuItem[][] => [
];
onMounted(async () => {
- await reloadContent(true);
+ await loadContent(page.value, true);
});
onBeforeUnmount(() => socket.off('item_status', statusHandler));
diff --git a/ui/app/spa-loading-template.html b/ui/app/spa-loading-template.html
index c74f7b2d..492615d1 100644
--- a/ui/app/spa-loading-template.html
+++ b/ui/app/spa-loading-template.html
@@ -163,8 +163,14 @@
}
@media (max-width: 560px) {
+ body {
+ padding-top: calc(1rem + env(safe-area-inset-top));
+ padding-bottom: calc(1rem + env(safe-area-inset-bottom));
+ }
+
.loading-card {
padding: 1.3rem;
+ transform: translateY(clamp(-2.75rem, -7vh, -1.5rem));
}
.brand {