Add pagination to IPs table for improved navigation
This commit is contained in:
@@ -63,6 +63,8 @@
|
|||||||
let ipSearch = $state('');
|
let ipSearch = $state('');
|
||||||
let ipSortKey = $state<'user' | 'ip' | 'geo' | null>(null);
|
let ipSortKey = $state<'user' | 'ip' | 'geo' | null>(null);
|
||||||
let ipSortDir = $state<SortDir | null>(null);
|
let ipSortDir = $state<SortDir | null>(null);
|
||||||
|
const ipsPerPage = 25;
|
||||||
|
let ipsPage = $state(1);
|
||||||
|
|
||||||
let flatIpRows = $derived.by((): IpFlatRow[] => {
|
let flatIpRows = $derived.by((): IpFlatRow[] => {
|
||||||
const out: IpFlatRow[] = [];
|
const out: IpFlatRow[] = [];
|
||||||
@@ -102,6 +104,22 @@
|
|||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let ipsPageCount = $derived(Math.max(1, Math.ceil(displayedIpRows.length / ipsPerPage)));
|
||||||
|
let pagedIpRows = $derived.by(() => {
|
||||||
|
const start = (ipsPage - 1) * ipsPerPage;
|
||||||
|
return displayedIpRows.slice(start, start + ipsPerPage);
|
||||||
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
ipSearch;
|
||||||
|
aliasFilter;
|
||||||
|
ipsPage = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (ipsPage > ipsPageCount) ipsPage = ipsPageCount;
|
||||||
|
});
|
||||||
|
|
||||||
function toggleIpSort(key: 'user' | 'ip' | 'geo') {
|
function toggleIpSort(key: 'user' | 'ip' | 'geo') {
|
||||||
const next = nextSortDir(ipSortDir, key, ipSortKey);
|
const next = nextSortDir(ipSortDir, key, ipSortKey);
|
||||||
ipSortKey = next === null ? null : key;
|
ipSortKey = next === null ? null : key;
|
||||||
@@ -604,6 +622,7 @@
|
|||||||
ipSearch = '';
|
ipSearch = '';
|
||||||
ipSortKey = null;
|
ipSortKey = null;
|
||||||
ipSortDir = null;
|
ipSortDir = null;
|
||||||
|
ipsPage = 1;
|
||||||
}}
|
}}
|
||||||
>Сброс</Button>
|
>Сброс</Button>
|
||||||
</DataTableToolbar>
|
</DataTableToolbar>
|
||||||
@@ -655,7 +674,7 @@
|
|||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
{:else}
|
{:else}
|
||||||
{#each displayedIpRows as { username, ip } (username + (ip.ip ?? ''))}
|
{#each pagedIpRows as { username, ip } (username + (ip.ip ?? ''))}
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
<Table.Cell class="font-medium">
|
<Table.Cell class="font-medium">
|
||||||
<a href="/users/{encodeURIComponent(username)}" class="text-primary hover:underline">
|
<a href="/users/{encodeURIComponent(username)}" class="text-primary hover:underline">
|
||||||
@@ -686,6 +705,31 @@
|
|||||||
</Table.Body>
|
</Table.Body>
|
||||||
</Table.Root>
|
</Table.Root>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
{#if displayedIpRows.length > ipsPerPage}
|
||||||
|
<div
|
||||||
|
class="flex flex-wrap items-center justify-between gap-2 border-t px-4 py-3 text-sm text-muted-foreground"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{displayedIpRows.length === 0
|
||||||
|
? '0'
|
||||||
|
: `${(ipsPage - 1) * ipsPerPage + 1}–${Math.min(ipsPage * ipsPerPage, displayedIpRows.length)}`} из {displayedIpRows.length}
|
||||||
|
</span>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={ipsPage <= 1}
|
||||||
|
onclick={() => (ipsPage = Math.max(1, ipsPage - 1))}>Назад</Button
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
disabled={ipsPage >= ipsPageCount}
|
||||||
|
onclick={() => (ipsPage = Math.min(ipsPageCount, ipsPage + 1))}>Вперёд</Button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</DataTableCard>
|
</DataTableCard>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</DataQueryState>
|
</DataQueryState>
|
||||||
|
|||||||
@@ -265,8 +265,8 @@
|
|||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Card.Content class="overflow-x-auto px-2 sm:px-6">
|
<Card.Content class="overflow-x-auto px-2 sm:px-6">
|
||||||
<Table.Root>
|
<Table.Root>
|
||||||
<Table.Header>
|
<Table.Header class="sticky top-0 z-10 bg-muted">
|
||||||
<Table.Row>
|
<Table.Row class="border-b border-border/80 hover:bg-transparent">
|
||||||
<Table.Head class="text-xs sm:text-sm">Alias</Table.Head>
|
<Table.Head class="text-xs sm:text-sm">Alias</Table.Head>
|
||||||
<Table.Head class="text-xs sm:text-sm">Контроллер</Table.Head>
|
<Table.Head class="text-xs sm:text-sm">Контроллер</Table.Head>
|
||||||
<Table.Head class="text-xs sm:text-sm">Статус</Table.Head>
|
<Table.Head class="text-xs sm:text-sm">Статус</Table.Head>
|
||||||
|
|||||||
@@ -88,8 +88,8 @@
|
|||||||
<BuildingIcon class="size-5" aria-hidden="true" />
|
<BuildingIcon class="size-5" aria-hidden="true" />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
<Table.Root>
|
<Table.Root>
|
||||||
<Table.Header>
|
<Table.Header class="sticky top-0 z-10 bg-muted">
|
||||||
<Table.Row>
|
<Table.Row class="border-b border-border/80 hover:bg-transparent">
|
||||||
<Table.Head>DC</Table.Head>
|
<Table.Head>DC</Table.Head>
|
||||||
<Table.Head class="text-right">RTT</Table.Head>
|
<Table.Head class="text-right">RTT</Table.Head>
|
||||||
<Table.Head class="text-right">Writers</Table.Head>
|
<Table.Head class="text-right">Writers</Table.Head>
|
||||||
|
|||||||
@@ -232,8 +232,8 @@
|
|||||||
<UsersIcon class="size-5" aria-hidden="true" />
|
<UsersIcon class="size-5" aria-hidden="true" />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
<Table.Root>
|
<Table.Root>
|
||||||
<Table.Header>
|
<Table.Header class="sticky top-0 z-10 bg-muted">
|
||||||
<Table.Row>
|
<Table.Row class="border-b border-border/80 hover:bg-transparent">
|
||||||
<Table.Head>Имя</Table.Head>
|
<Table.Head>Имя</Table.Head>
|
||||||
<Table.Head>Ссылки</Table.Head>
|
<Table.Head>Ссылки</Table.Head>
|
||||||
<Table.Head class="text-right">Conn</Table.Head>
|
<Table.Head class="text-right">Conn</Table.Head>
|
||||||
|
|||||||
@@ -205,8 +205,8 @@
|
|||||||
|
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<Table.Root>
|
<Table.Root>
|
||||||
<Table.Header>
|
<Table.Header class="sticky top-0 z-10 bg-muted">
|
||||||
<Table.Row>
|
<Table.Row class="border-b border-border/80 hover:bg-transparent">
|
||||||
<Table.Head class="text-xs sm:text-sm">IP</Table.Head>
|
<Table.Head class="text-xs sm:text-sm">IP</Table.Head>
|
||||||
<Table.Head class="text-xs sm:text-sm">
|
<Table.Head class="text-xs sm:text-sm">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
|
|||||||
Reference in New Issue
Block a user