fix: Add pagination controls to uMod browse tab
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
Prev/Next buttons at top and bottom of results table. New search resets to page 1. Buttons disable at bounds and during loading. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ const toast = useToastStore()
|
|||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const tab = ref<'installed' | 'browse' | 'upload'>('installed')
|
const tab = ref<'installed' | 'browse' | 'upload'>('installed')
|
||||||
const browseQuery = ref('')
|
const browseQuery = ref('')
|
||||||
|
const browsePage = ref(1)
|
||||||
const browseDebounce = ref<ReturnType<typeof setTimeout> | null>(null)
|
const browseDebounce = ref<ReturnType<typeof setTimeout> | null>(null)
|
||||||
const installing = ref<string | null>(null)
|
const installing = ref<string | null>(null)
|
||||||
|
|
||||||
@@ -71,10 +72,11 @@ async function handleUninstall(plugin: PluginEntry) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleBrowseSearch() {
|
async function handleBrowseSearch(page = 1) {
|
||||||
if (!browseQuery.value.trim()) return
|
if (!browseQuery.value.trim()) return
|
||||||
|
browsePage.value = page
|
||||||
try {
|
try {
|
||||||
await pluginStore.browseUmod(browseQuery.value.trim())
|
await pluginStore.browseUmod(browseQuery.value.trim(), page)
|
||||||
} catch {
|
} catch {
|
||||||
toast.error('Failed to search uMod plugins')
|
toast.error('Failed to search uMod plugins')
|
||||||
}
|
}
|
||||||
@@ -82,7 +84,17 @@ async function handleBrowseSearch() {
|
|||||||
|
|
||||||
function scheduleBrowseSearch() {
|
function scheduleBrowseSearch() {
|
||||||
if (browseDebounce.value) clearTimeout(browseDebounce.value)
|
if (browseDebounce.value) clearTimeout(browseDebounce.value)
|
||||||
browseDebounce.value = setTimeout(handleBrowseSearch, 400)
|
browseDebounce.value = setTimeout(() => handleBrowseSearch(1), 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
function browsePrev() {
|
||||||
|
if (browsePage.value > 1) handleBrowseSearch(browsePage.value - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function browseNext() {
|
||||||
|
if (pluginStore.browseResults && browsePage.value < pluginStore.browseResults.last_page) {
|
||||||
|
handleBrowseSearch(browsePage.value + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installFromBrowse(result: UmodPlugin) {
|
async function installFromBrowse(result: UmodPlugin) {
|
||||||
@@ -325,6 +337,22 @@ onMounted(() => {
|
|||||||
{{ pluginStore.browseResults.total.toLocaleString() }} plugins found
|
{{ pluginStore.browseResults.total.toLocaleString() }} plugins found
|
||||||
• Page {{ pluginStore.browseResults.current_page }} of {{ pluginStore.browseResults.last_page }}
|
• Page {{ pluginStore.browseResults.current_page }} of {{ pluginStore.browseResults.last_page }}
|
||||||
</p>
|
</p>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
@click="browsePrev"
|
||||||
|
:disabled="browsePage <= 1 || pluginStore.isBrowseLoading"
|
||||||
|
class="px-2.5 py-1 text-xs font-medium rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
← Prev
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="browseNext"
|
||||||
|
:disabled="!pluginStore.browseResults || browsePage >= pluginStore.browseResults.last_page || pluginStore.isBrowseLoading"
|
||||||
|
class="px-2.5 py-1 text-xs font-medium rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800"
|
||||||
|
>
|
||||||
|
Next →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="w-full">
|
<table class="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -366,6 +394,28 @@ onMounted(() => {
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<!-- Bottom pagination -->
|
||||||
|
<div v-if="pluginStore.browseResults && pluginStore.browseResults.last_page > 1" class="px-4 py-3 border-t border-neutral-800 flex items-center justify-between">
|
||||||
|
<p class="text-xs text-neutral-500">
|
||||||
|
Page {{ pluginStore.browseResults.current_page }} of {{ pluginStore.browseResults.last_page }}
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
@click="browsePrev"
|
||||||
|
:disabled="browsePage <= 1 || pluginStore.isBrowseLoading"
|
||||||
|
class="px-3 py-1.5 text-xs font-medium rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-neutral-400 hover:text-neutral-200 bg-neutral-800 hover:bg-neutral-700"
|
||||||
|
>
|
||||||
|
← Previous
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="browseNext"
|
||||||
|
:disabled="!pluginStore.browseResults || browsePage >= pluginStore.browseResults.last_page || pluginStore.isBrowseLoading"
|
||||||
|
class="px-3 py-1.5 text-xs font-medium rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed text-neutral-400 hover:text-neutral-200 bg-neutral-800 hover:bg-neutral-700"
|
||||||
|
>
|
||||||
|
Next →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user