Skip to content

Commit

Permalink
feat: fix sorting, add pagination to all names page
Browse files Browse the repository at this point in the history
  • Loading branch information
hstove committed Dec 4, 2023
1 parent 7430a23 commit 990d12b
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 39 deletions.
68 changes: 49 additions & 19 deletions api/src/fetchers/adapters/db-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ import { searchNamesFuzzy } from '@fetchers/search';
import { inscriptionBuffToId } from '@fetchers/inscriptions';
import { bytesToHex, hexToBytes } from 'micro-stacks/common';

interface InscribedNamesRow {
inscriptionId: string;
id: bigint;
name: string;
namespace: string;
blockHeight: number;
txid: Buffer;
}

export class DbFetcher implements BaseFetcher {
bnsDb: BnsDb;
stacksDb: StacksDb;
Expand Down Expand Up @@ -249,33 +258,54 @@ export class DbFetcher implements BaseFetcher {
}
}

async fetchInscribedNamesRows(cursor?: number) {
let rows: InscribedNamesRow[];
if (typeof cursor === 'undefined') {
rows = await this.bnsDb.$queryRaw<InscribedNamesRow[]>`
select i.id
, i.inscription_id as "inscriptionId"
, i.block_height as "blockHeight"
, i.txid
, n.name
, n.namespace
from public.inscribed_names i
join public.names n on n.id = i.id
order by i.id desc
limit 100
offset 0
`;
} else {
rows = await this.bnsDb.$queryRaw<InscribedNamesRow[]>`
select i.id
, i.inscription_id as "inscriptionId"
, i.block_height as "blockHeight"
, i.txid
, n.name
, n.namespace
from public.inscribed_names i
join public.names n on n.id = i.id
where i.id < ${cursor}
order by i.id desc
limit 100
offset 0
`;
}
return rows;
}

async fetchInscribedNames(cursor?: number) {
const rows = await this.bnsDb.inscribedNames.findMany({
include: {
name: true,
},
orderBy: {
id: 'desc',
},
cursor:
typeof cursor === 'undefined'
? undefined
: {
id: cursor,
},
take: -100,
skip: typeof cursor === 'undefined' ? undefined : 1,
});
const rows = await this.fetchInscribedNamesRows(cursor);
return rows
.map(row => {
if (row.name === null) return null;

const name = convertDbName(row.name);
const { name, namespace, id } = row;
const _name = convertDbName({ name, namespace, id });

return {
inscriptionId: inscriptionBuffToId(hexToBytes(row.inscription_id)),
inscriptionId: inscriptionBuffToId(hexToBytes(row.inscriptionId)),
id: Number(row.id),
name: name.combined,
name: _name.combined,
blockHeight: row.blockHeight,
txid: bytesToHex(row.txid),
};
Expand Down
41 changes: 40 additions & 1 deletion api/src/prisma-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,45 @@ function getStacksDb() {
return new StacksDb();
}

function getBnsDb() {
if (process.env.DEBUG_SLOW_QUERIES_BNSX === 'true') {
const bnsPrisma = new BnsDb({
log: [
{
emit: 'event',
level: 'query',
},
{
emit: 'stdout',
level: 'error',
},
{
emit: 'stdout',
level: 'info',
},
{
emit: 'stdout',
level: 'warn',
},
],
});
bnsPrisma.$on('query', e => {
if (e.duration > 500) {
logger.warn(
{
query: e.query,
duration: e.duration,
params: e.params,
},
'slow query'
);
}
});
return bnsPrisma;
}
return new BnsDb();
}

export const prismaPlugin: FastifyPluginAsync = fp(async server => {
const dbEnv = process.env.STACKS_API_POSTGRES;
if (typeof dbEnv === 'undefined' || dbEnv === '') {
Expand All @@ -65,7 +104,7 @@ export const prismaPlugin: FastifyPluginAsync = fp(async server => {
logger.debug({ params }, 'Stacks DB connection query parameters');
const promises = [stacksPrisma.$connect()];
const prismaDbEnv = process.env.BNSX_DB_URL;
const prisma = new BnsDb();
const prisma = getBnsDb();
if (typeof prismaDbEnv !== 'undefined') {
promises.push(prisma.$connect());
server.decorate('prisma', prisma);
Expand Down
21 changes: 20 additions & 1 deletion web/common/store/bridge.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { atom } from 'jotai';
import type { BridgeSignerResponse, BridgeSignerResponseOk } from '../../pages/api/bridge-sig';
import { hashAtom, txidQueryAtom } from '@store/migration';
import { atomsWithQuery } from 'jotai-tanstack-query';
import { atomsWithInfiniteQuery, atomsWithQuery } from 'jotai-tanstack-query';
import { trpc } from '@store/api';
import { atomFamily } from 'jotai/utils';
import { makeClarityHash } from 'micro-stacks/connect';
Expand Down Expand Up @@ -77,6 +77,8 @@ export type InscribedNamesResult = Awaited<
ReturnType<typeof trpc.bridgeRouter.inscribedNames.query>
>['results'][0];

export const inscribedNamesCursorAtom = atom<number | undefined>(undefined);

export const inscribedNamesAtom = atomsWithQuery(_get => ({
queryKey: ['inscribedNames'],
queryFn: async () => {
Expand All @@ -85,6 +87,23 @@ export const inscribedNamesAtom = atomsWithQuery(_get => ({
},
}))[0];

export const inscribedNamesInfiniteAtom = atomsWithInfiniteQuery<InscribedNamesResult[]>(_get => ({
queryKey: ['inscribedNamesInfinite'],
queryFn: async ({ pageParam }: { pageParam?: number }) => {
const { results } = await trpc.bridgeRouter.inscribedNames.query({ cursor: pageParam });
return results;
// return { data: results, nextCursor: results.at(-1)?.id };
},
getNextPageParam: lastPage => {
return lastPage.at(-1)?.id;
},
}));

export const lastInscribedNameIdState = atom(get => {
const names = get(inscribedNamesAtom);
return names.at(-1)?.id;
});

export const inscriptionForNameAtom = atomFamily((fqn: string) => {
return atomsWithQuery(() => ({
queryKey: ['inscriptionForName', fqn],
Expand Down
35 changes: 18 additions & 17 deletions web/components/p/bridge/names.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
import React, { useMemo } from 'react';
import React from 'react';
import { Text } from '@components/ui/text';
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@components/ui/table';
import { inscribedNamesAtom } from '@store/bridge';
import { useAtomValue } from 'jotai';
import { Table, TableBody, TableHead, TableHeader, TableRow } from '@components/ui/table';
import { inscribedNamesInfiniteAtom } from '@store/bridge';
import { useAtom } from 'jotai';
import { Button } from '@components/ui/button';
import { BridgedNameRow } from '@components/p/bridge/names/name-row';
import { useDeepMemo } from '@common/hooks/use-deep-memo';

export const BridgeNames: React.FC<{ children?: React.ReactNode }> = () => {
const names = useAtomValue(inscribedNamesAtom);
const [names, dispatch] = useAtom(inscribedNamesInfiniteAtom[0]);
const fetchNextPage = React.useCallback(() => {
dispatch({ type: 'fetchNextPage' });
}, [dispatch]);

const nameRows = useMemo(() => {
return names.map(name => {
return <BridgedNameRow name={name} key={name.name} />;
});
const nameRows = useDeepMemo(() => {
return [
...names.pages.map(page => page.map(name => <BridgedNameRow name={name} key={name.name} />)),
];
}, [names]);

const hasMore = (names.pages.at(-1)?.length ?? 0) === 100;

return (
<div className="flex flex-col gap-5 px-[29px]">
<Text variant="Heading02">BNS on L1</Text>
<Table>
<TableHeader>
<TableRow>
<TableHead className="text-caption01 text-text w-[200px]">Name</TableHead>
<TableHead className="text-right">Time</TableHead>
<TableHead className="text-right">View</TableHead>
</TableRow>
</TableHeader>
<TableBody>{nameRows}</TableBody>
</Table>
<div>{hasMore && <Button onClick={fetchNextPage}>Load More</Button>}</div>
</div>
);
};
26 changes: 25 additions & 1 deletion web/components/p/bridge/names/name-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Button } from '@components/ui/button';
import type { InscribedNamesResult } from '@store/bridge';
import { useTxUrl } from '@common/hooks/use-tx-url';
import { ordinalsBaseUrl } from '@common/constants';
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from '@components/ui/tooltip';
import { Text } from '@components/ui/text';
import {
DropdownMenu,
Expand All @@ -19,6 +18,26 @@ import { useCopyToClipboard } from 'usehooks-ts';
import { useToast } from '@common/hooks/use-toast';
import { BoxLink } from '@components/link';
import { useAccountPath } from '@common/hooks/use-account-path';
import { useAtomValue } from 'jotai';
import { coreNodeInfoAtom } from '@store/api';
import formatDistance from 'date-fns/formatDistance';

const NameTimestamp: React.FC<{ blockHeight: number }> = ({ blockHeight }) => {
const coreInfo = useAtomValue(coreNodeInfoAtom);
const curHeight = coreInfo.stacks_tip_height;
const diff = curHeight - blockHeight;

const now = new Date();
const distance = formatDistance(new Date(now.getTime() - diff * 10 * 60 * 1000), now, {
addSuffix: true,
});

return (
<Text variant="Caption01" className="text-right">
about {distance}
</Text>
);
};

export const BridgedNameRow: React.FC<{
children?: React.ReactNode;
Expand Down Expand Up @@ -46,6 +65,11 @@ export const BridgedNameRow: React.FC<{
return (
<TableRow className="items-center">
<TableCell className="text-heading05">{name.name}</TableCell>
<TableCell>
<React.Suspense fallback={<></>}>
<NameTimestamp blockHeight={name.blockHeight} />
</React.Suspense>
</TableCell>
<TableCell>
<div className="flex gap-3 justify-end">
<DropdownMenu>
Expand Down

0 comments on commit 990d12b

Please sign in to comment.