Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
"use client";

import { CommandIcon, CornerDownLeft, LoaderIcon, PauseIcon, PlayIcon } from "lucide-react";
import { ClockIcon, CommandIcon, CornerDownLeft, LoaderIcon, PauseIcon, PlayIcon } from "lucide-react";
import { KeyCode, KeyMod, editor } from "monaco-editor/esm/vs/editor/editor.api";
import { useQueryState } from "nuqs";
import { useConfig } from "wagmi";
import { getBlock } from "wagmi/actions";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { Table } from "@latticexyz/config";
import Editor from "@monaco-editor/react";
import { Tooltip } from "../../../../../../components/Tooltip";
import { Button } from "../../../../../../components/ui/Button";
import { Form, FormField } from "../../../../../../components/ui/Form";
import { Input } from "../../../../../../components/ui/Input";
import { cn } from "../../../../../../utils";
import { useChain } from "../../../../hooks/useChain";
import { useTableDataQuery } from "../../../../queries/useTableDataQuery";
import { PAGE_SIZE_OPTIONS, monacoOptions } from "./consts";
import { usePaginationState } from "./hooks/usePaginationState";
Expand All @@ -31,6 +36,12 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
const [isUserTriggeredRefetch, setIsUserTriggeredRefetch] = useState(false);
const [pagination, setPagination] = usePaginationState();
const [query, setQuery] = useSQLQueryState();
const [blockHeight, setBlockHeight] = useQueryState("blockHeight");
const [blockTimestamp, setBlockTimestamp] = useState<number | null>(null);
const [isLoadingBlock, setIsLoadingBlock] = useState(false);

const wagmiConfig = useConfig();
const { id: chainId } = useChain();

const validateQuery = useQueryValidator(table);
const { data: tableData, refetch, isRefetching: isTableDataRefetching } = useTableDataQuery({ table, isLiveQuery });
Expand Down Expand Up @@ -76,6 +87,32 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
form.reset({ query });
}, [query, form]);

// Fetch block timestamp when blockHeight changes
useEffect(() => {
const fetchBlockTimestamp = async () => {
if (!blockHeight || !wagmiConfig || !chainId) {
setBlockTimestamp(null);
return;
}

setIsLoadingBlock(true);
try {
const block = await getBlock(wagmiConfig, {
chainId,
blockNumber: BigInt(blockHeight),
});
setBlockTimestamp(Number(block.timestamp));
} catch (error) {
console.error("Failed to fetch block timestamp:", error);
setBlockTimestamp(null);
} finally {
setIsLoadingBlock(false);
}
};

fetchBlockTimestamp();
}, [blockHeight, wagmiConfig, chainId]);

const updateHeight = () => {
if (editorRef.current) {
const contentHeight = Math.min(200, editorRef.current.getContentHeight());
Expand Down Expand Up @@ -182,6 +219,29 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
</>
) : null}

<Input
type="number"
step="1000"
className="w-[120px]"
value={blockHeight ?? ""}
onChange={(e) => setBlockHeight(e.target.value)}
/>

{blockHeight && (
<div className="flex items-center gap-2 text-xs text-white/60">
<ClockIcon className="h-3 w-3" />
{isLoadingBlock ? (
<span>Loading...</span>
) : blockTimestamp ? (
<Tooltip text={new Date(blockTimestamp * 1000).toISOString()}>
<span>{new Date(blockTimestamp * 1000).toLocaleString()}</span>
</Tooltip>
) : (
<span>Invalid block</span>
)}
</div>
)}

<Button className="group relative flex gap-2 pl-4 pr-3" type="submit" disabled={isRefetching}>
Run
<span className="relative flex items-center gap-0.5 text-white/60">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useParams } from "next/navigation";
import { useQueryState } from "nuqs";
import { Hex, stringify } from "viem";
import { Table } from "@latticexyz/config";
import { useQuery } from "@tanstack/react-query";
Expand All @@ -24,6 +25,7 @@ export function useTableDataQuery({ table, isLiveQuery }: Props) {
const { chainName, worldAddress } = useParams();
const { id: chainId } = useChain();
const [query] = useSQLQueryState();
const [blockHeightParm] = useQueryState("blockHeight");
const indexer = useIndexerForChainId(chainId);

return useQuery<DozerResponse & { queryDuration: number; blockHeight: number }, Error, TData | undefined>({
Expand All @@ -39,6 +41,7 @@ export function useTableDataQuery({ table, isLiveQuery }: Props) {
{
address: worldAddress as Hex,
query,
...(blockHeightParm ? { block_height: parseInt(blockHeightParm), block_height_direction: "<=" } : {}),
},
]),
});
Expand Down
2 changes: 1 addition & 1 deletion packages/explorer/src/components/LatestBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function LatestBlock() {
watch: true,
chainId,
query: {
refetchInterval: 1000,
refetchInterval: 2_000,
},
});

Expand Down
117 changes: 114 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading