pagination

This commit is contained in:
harsh mahajan
2026-05-13 12:07:04 +05:30
parent b4aadf7134
commit 4d7f3d33d5
9 changed files with 107 additions and 32 deletions
@@ -251,15 +251,22 @@
on:click={handleCreateProject}>
{#each data.projects.projects as project}
{@const projectPlatforms =
(project as Models.Project & { platforms: Array<{ type: string }> })
.platforms ?? []}
(
project as Models.Project & {
platforms: Array<{ type: string }>;
platformsTotal?: number;
}
).platforms ?? []}
{@const platformsTotal =
(project as Models.Project & { platformsTotal?: number }).platformsTotal ??
projectPlatforms.length}
{@const platforms = filterPlatforms(
projectPlatforms.map((platform) => getPlatformInfo(platform.type))
)}
<GridItem1
href={`${base}/project-${project.region}-${project.$id}/overview/platforms`}>
<svelte:fragment slot="eyebrow">
{projectPlatforms.length ? projectPlatforms.length : 'No'} apps
{platformsTotal ? platformsTotal : 'No'} apps
</svelte:fragment>
<svelte:fragment slot="title">
{project.name}
@@ -284,10 +291,10 @@
</Badge>
{/each}
{#if platforms.length > 3}
{#if platformsTotal > 2}
<Badge
variant="secondary"
content={`+${platforms.length - 2}`}
content={`+${platformsTotal - 2}`}
style="width: max-content;" />
{/if}
@@ -43,13 +43,22 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) =>
]
});
// set `default` if no region!
for (const project of activeProjects.projects) {
project.region ??= 'default';
(project as Models.Project & { platforms: Array<{ type: string }> }).platforms = (
await sdk.forProject(project.region, project.$id).project.listPlatforms()
).platforms;
}
await Promise.all(
activeProjects.projects.map(async (project) => {
project.region ??= 'default';
const platformList = await sdk
.forProject(project.region, project.$id)
.project.listPlatforms({ queries: [Query.limit(3)] });
(
project as Models.Project & {
platforms: Array<{ type: string }>;
platformsTotal: number;
}
).platforms = platformList.platforms;
(project as Models.Project & { platformsTotal: number }).platformsTotal =
platformList.total;
})
);
return {
limit,
@@ -8,7 +8,7 @@ import { get } from 'svelte/store';
import { headerAlert } from '$lib/stores/headerAlert';
import PaymentFailed from '$lib/components/billing/alerts/paymentFailed.svelte';
import { loadAvailableRegions } from '$routes/(console)/regions';
import { type Models, Platform } from '@appwrite.io/console';
import { Query, type Models, Platform } from '@appwrite.io/console';
import { redirect } from '@sveltejs/kit';
import { resolve } from '$app/paths';
import { generateFingerprintToken } from '$lib/helpers/fingerprint';
@@ -57,8 +57,8 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
: null,
loadAvailableRegions(project.teamId),
projectSdk.listPlatforms(),
projectSdk.listKeys()
projectSdk.listPlatforms({ queries: [Query.limit(1)] }),
projectSdk.listKeys({ queries: [Query.limit(1)] })
]);
const regionalConsoleVariables = normalizeConsoleVariables(rawRegionalConsoleVariables);
@@ -1,6 +1,6 @@
<script lang="ts">
import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid } from '$lib/components';
import { CardGrid, PaginationInline } from '$lib/components';
import Confirm from '$lib/components/confirm.svelte';
import { InputPhone, InputOTP, Button } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
@@ -13,7 +13,7 @@
import EmptyCardImageCloud from '$lib/components/emptyCardImageCloud.svelte';
import { app } from '$lib/stores/app';
import Empty from '$lib/components/empty.svelte';
import type { Models } from '@appwrite.io/console';
import { Query, type Models } from '@appwrite.io/console';
import { Icon, Input, Layout, Link, Spinner, Tooltip } from '@appwrite.io/pink-svelte';
import { IconPlus, IconRefresh, IconTrash } from '@appwrite.io/pink-icons-svelte';
@@ -32,6 +32,9 @@
let savedNumbers: MockNumberForm[] = $state([]);
let draftNumbers: MockNumberForm[] = $state([]);
let isLoadingMockNumbers = $state(false);
let mockNumbersTotal = $state(0);
let mockNumbersOffset = $state(0);
const mockNumbersLimit = 10;
let lastProjectId: string | null = $state(null);
let pendingRow: string | null = $state(null);
let showDeleteConfirm = $state(false);
@@ -79,7 +82,16 @@
}
const response = await sdk
.forProject(project.region, project.$id)
.project.listMockPhones({});
.project.listMockPhones({
queries: [Query.limit(mockNumbersLimit), Query.offset(mockNumbersOffset)]
});
if (response.total > 0 && response.mockNumbers.length === 0 && mockNumbersOffset > 0) {
mockNumbersOffset =
Math.floor((response.total - 1) / mockNumbersLimit) * mockNumbersLimit;
await loadMockNumbers();
return;
}
mockNumbersTotal = response.total;
savedNumbers = getMockNumberRows(response.mockNumbers ?? []);
} catch (error) {
addNotification({ type: 'error', message: error.message });
@@ -381,7 +393,7 @@
id={`draft-key-${index}`}
bind:value={number.number}
placeholder="Enter phone number"
label={savedNumbers.length === 0 && index === 0
label={mockNumbersTotal === 0 && index === 0
? 'Phone number'
: undefined}
minlength={9}
@@ -404,7 +416,7 @@
id={`draft-value-${index}`}
bind:value={number.otp}
placeholder="Enter value"
label={savedNumbers.length === 0 && index === 0
label={mockNumbersTotal === 0 && index === 0
? 'Verification code'
: undefined}
maxlength={6}
@@ -442,17 +454,24 @@
</Layout.Stack>
</Layout.Stack>
{/each}
{#if savedNumbers.length + draftNumbers.length < 10}
{#if mockNumbersTotal + draftNumbers.length < 10}
<div>
<Button
secondary
on:click={addPhoneNumber}
disabled={savedNumbers.length + draftNumbers.length >= 10}>
disabled={mockNumbersTotal + draftNumbers.length >= 10}>
<Icon icon={IconPlus} slot="start" size="s" />
Add number
</Button>
</div>
{/if}
{#if mockNumbersTotal > mockNumbersLimit}
<PaginationInline
bind:offset={mockNumbersOffset}
limit={mockNumbersLimit}
total={mockNumbersTotal}
on:change={loadMockNumbers} />
{/if}
{:else}
<Empty on:click={addPhoneNumber}>Add a number</Empty>
{/if}
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import { goto } from '$app/navigation';
import { Empty, MultiSelectionTable } from '$lib/components';
import { Empty, MultiSelectionTable, PaginationWithLimit } from '$lib/components';
import { canWriteKeys } from '$lib/stores/roles';
import type { Models } from '@appwrite.io/console';
import { diffDays } from '$lib/helpers/date';
@@ -14,10 +14,14 @@
let {
keyType = 'api',
keys
keys,
limit,
offset
}: {
keyType?: 'api' | 'dev';
keys: Models.KeyList | Models.DevKeyList;
limit?: number;
offset?: number;
} = $props();
let selectedKeys = $state([]);
@@ -116,6 +120,13 @@
{/each}
{/snippet}
</MultiSelectionTable>
{#if limit !== undefined && offset !== undefined}
<PaginationWithLimit
name={`${capitalize(label)} keys`}
{limit}
{offset}
total={keys.total} />
{/if}
{:else}
<Empty
single
@@ -9,4 +9,4 @@
setOverviewAction(Action);
</script>
<Table keys={data.keys} />
<Table keys={data.keys} limit={data.limit} offset={data.offset} />
@@ -1,10 +1,21 @@
import { Dependencies } from '$lib/constants';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@appwrite.io/console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, depends }) => {
export const load: PageLoad = async ({ params, depends, route, url }) => {
depends(Dependencies.KEYS);
const projectSdk = sdk.forProject(params.region, params.project).project;
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
keys: await sdk.forProject(params.region, params.project).project.listKeys()
limit,
offset,
keys: await projectSdk.listKeys({
queries: [Query.limit(limit), Query.offset(offset)]
})
};
};
@@ -93,7 +93,8 @@
import {
type DeleteOperationState,
type DeleteOperation,
MultiSelectionTable
MultiSelectionTable,
PaginationWithLimit
} from '$lib/components';
import { sdk } from '$lib/stores/sdk';
import { Submit, trackError } from '$lib/actions/analytics';
@@ -200,6 +201,11 @@
{/each}
{/snippet}
</MultiSelectionTable>
<PaginationWithLimit
name="Platforms"
limit={data.limit}
offset={data.offset}
total={data.platforms.total} />
{:else}
<Card.Base padding="none">
<Empty
@@ -1,8 +1,20 @@
import { CARD_LIMIT, Dependencies } from '$lib/constants';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@appwrite.io/console';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ parent }) => {
const { platforms } = await parent();
export const load: PageLoad = async ({ depends, params, route, url }) => {
depends(Dependencies.PROJECT);
const page = getPage(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
return {
platforms
limit,
offset,
platforms: await sdk.forProject(params.region, params.project).project.listPlatforms({
queries: [Query.limit(limit), Query.offset(offset)]
})
};
};