mirror of
https://codeberg.org/MarkusThielker/next-ory.git
synced 2025-04-18 00:21:18 +00:00
NORY-15: implement pagination mechanics
This commit is contained in:
parent
3378fee9ec
commit
2eb4b80607
2 changed files with 78 additions and 9 deletions
|
@ -5,12 +5,18 @@ import { Identity } from '@ory/client';
|
||||||
import { DataTable } from '@/components/ui/data-table';
|
import { DataTable } from '@/components/ui/data-table';
|
||||||
import { CircleCheck, CircleX } from 'lucide-react';
|
import { CircleCheck, CircleX } from 'lucide-react';
|
||||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { FetchIdentityPageProps } from '@/app/user/page';
|
||||||
|
|
||||||
interface IdentityDataTableProps {
|
interface IdentityDataTableProps {
|
||||||
data: Identity[];
|
data: Identity[];
|
||||||
|
pageSize: number;
|
||||||
|
pageToken: string | undefined;
|
||||||
|
query: string;
|
||||||
|
fetchIdentityPage: (props: FetchIdentityPageProps) => Promise<{ data: Identity[], tokens: Map<string, string> }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IdentityDataTable({ data }: IdentityDataTableProps) {
|
export function IdentityDataTable({ data, pageSize, pageToken, query, fetchIdentityPage }: IdentityDataTableProps) {
|
||||||
|
|
||||||
const columns: ColumnDef<Identity>[] = [
|
const columns: ColumnDef<Identity>[] = [
|
||||||
{
|
{
|
||||||
|
@ -80,5 +86,23 @@ export function IdentityDataTable({ data }: IdentityDataTableProps) {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return <DataTable columns={columns} data={data}/>;
|
const [items, setItems] = useState<Identity[]>(data);
|
||||||
|
const [nextToken, setNextToken] = useState<string | undefined>(pageToken);
|
||||||
|
|
||||||
|
const fetchMore = async () => {
|
||||||
|
|
||||||
|
if (!nextToken) return;
|
||||||
|
|
||||||
|
const response = await fetchIdentityPage({
|
||||||
|
pageSize: pageSize,
|
||||||
|
pageToken: nextToken,
|
||||||
|
query: query,
|
||||||
|
});
|
||||||
|
|
||||||
|
setItems([...items, ...response.data]);
|
||||||
|
setNextToken(response.tokens.get('next') ?? undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: fetch more when scrolling to the end of list
|
||||||
|
return <DataTable columns={columns} data={items}/>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,48 @@ import { IdentityDataTable } from '@/app/user/data-table';
|
||||||
import { getIdentityApi } from '@/ory/sdk/server';
|
import { getIdentityApi } from '@/ory/sdk/server';
|
||||||
import { SearchInput } from '@/components/search-input';
|
import { SearchInput } from '@/components/search-input';
|
||||||
|
|
||||||
|
export interface FetchIdentityPageProps {
|
||||||
|
pageSize: number;
|
||||||
|
pageToken: string;
|
||||||
|
query: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchIdentityPage({ pageSize, pageToken, query }: FetchIdentityPageProps) {
|
||||||
|
'use server';
|
||||||
|
|
||||||
|
const identityApi = await getIdentityApi();
|
||||||
|
const response = await identityApi.listIdentities({
|
||||||
|
pageSize: pageSize,
|
||||||
|
pageToken: pageToken,
|
||||||
|
previewCredentialsIdentifierSimilar: query,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: response.data,
|
||||||
|
tokens: parseTokens(response.headers.link),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTokens(link: string) {
|
||||||
|
|
||||||
|
const parsed = link.split(',').map((it) => {
|
||||||
|
const startRel = it.lastIndexOf('rel="');
|
||||||
|
const endRel = it.lastIndexOf('"');
|
||||||
|
const rel = it.slice(startRel, endRel);
|
||||||
|
|
||||||
|
const startToken = it.lastIndexOf('page_token=');
|
||||||
|
const endToken = it.lastIndexOf('&');
|
||||||
|
const token = it.slice(startToken, endToken);
|
||||||
|
|
||||||
|
return [rel, token];
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Map(parsed.map(obj => [
|
||||||
|
obj[0].replace('rel="', ''),
|
||||||
|
obj[1].replace('page_token=', ''),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
export default async function UserPage(
|
export default async function UserPage(
|
||||||
{
|
{
|
||||||
searchParams,
|
searchParams,
|
||||||
|
@ -11,15 +53,13 @@ export default async function UserPage(
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const identityApi = await getIdentityApi();
|
|
||||||
|
|
||||||
const params = await searchParams;
|
const params = await searchParams;
|
||||||
const query = params.query ? params.query as string : '';
|
const query = params.query ? params.query as string : '';
|
||||||
|
|
||||||
const data = await identityApi.listIdentities({
|
let pageSize = 200;
|
||||||
pageSize: 100,
|
let pageToken: string = '00000000-0000-0000-0000-000000000000';
|
||||||
previewCredentialsIdentifierSimilar: query,
|
|
||||||
}).then(response => response.data);
|
const initialFetch = await fetchIdentityPage({ pageSize, pageToken, query: '' });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
@ -31,7 +71,12 @@ export default async function UserPage(
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<SearchInput queryParamKey="query" placeholder="Search"/>
|
<SearchInput queryParamKey="query" placeholder="Search"/>
|
||||||
<IdentityDataTable data={data}/>
|
<IdentityDataTable
|
||||||
|
data={initialFetch.data}
|
||||||
|
pageSize={pageSize}
|
||||||
|
pageToken={initialFetch.tokens.get('next')}
|
||||||
|
query={query}
|
||||||
|
fetchIdentityPage={fetchIdentityPage}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue