Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(explorer): tables viewer pagination #3426

Merged
merged 30 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3082640
paginate by offset/limit
karooolis Feb 6, 2025
887772f
paginate pages based on sql query
karooolis Feb 6, 2025
b2ecd6c
keep previous data while switching pages
karooolis Feb 6, 2025
2ea5775
use next/prev btns to paginate (without page numbers)
karooolis Feb 6, 2025
fe20de1
ehance sql query with offset + limit
karooolis Feb 6, 2025
a885b7d
update table offset + limit dynamically
karooolis Feb 6, 2025
46a35be
show current page, go back to first page
karooolis Feb 7, 2025
8c1f942
edit page offset/limit when page number changes
karooolis Feb 7, 2025
2e0e940
more robust pagination change handler
karooolis Feb 7, 2025
4730196
only enable pagination if limit/offset match pagination size
karooolis Feb 7, 2025
95eae61
cleanup query state
karooolis Feb 7, 2025
60bea28
set page based on query
karooolis Feb 7, 2025
9ab189f
Create metal-years-raise.md
karooolis Feb 7, 2025
5040978
set default page size
karooolis Feb 7, 2025
35c3bab
overlay table body when fetching
karooolis Feb 7, 2025
781f37e
added back double-quoted tablenames
karooolis Feb 7, 2025
d6d24cc
use pagination query state
karooolis Feb 7, 2025
66411d3
use pagination query hook, parse as json
karooolis Feb 7, 2025
808adbb
undo worlds.json change
karooolis Feb 7, 2025
6f9b76f
reuse pagination query
karooolis Feb 7, 2025
e0f7bfe
clean up useTableDataQuery
karooolis Feb 7, 2025
1183bbb
use useSQLQueryState hook
karooolis Feb 7, 2025
587226d
move hooks from .tsx to .ts
karooolis Feb 7, 2025
7328838
use PostgresSQL db for sql parser
karooolis Feb 7, 2025
7849b58
remove worlds.json
karooolis Feb 7, 2025
1027d98
gitignore worlds.json
karooolis Feb 7, 2025
5f9e127
change usePaginationState to use page/pageSize query params
karooolis Feb 13, 2025
addec31
reset page index on table change
karooolis Feb 13, 2025
650b36e
adjust sql queries hooks return types
karooolis Feb 13, 2025
9997c5a
remove unnecessary encodeURIComponent from SQLEditor
karooolis Feb 13, 2025
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
5 changes: 5 additions & 0 deletions .changeset/metal-years-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/explorer": patch
---

The Explore tab's table viewer now supports pagination through limit/offset clauses in SQL queries.
3 changes: 3 additions & 0 deletions examples/local-explorer/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ node_modules
# sqlite indexer data
*.db
*.db-journal

# worlds configuration
worlds.json
5 changes: 0 additions & 5 deletions examples/local-explorer/packages/contracts/worlds.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useParams } from "next/navigation";
import { parseAsString, useQueryState } from "nuqs";
import { useQueryState } from "nuqs";
import { Hex } from "viem";
import { useEffect, useState } from "react";
import { useChain } from "../../../../hooks/useChain";
Expand All @@ -12,39 +12,55 @@ import { indexerForChainId } from "../../../../utils/indexerForChainId";
import { SQLEditor } from "./SQLEditor";
import { TableSelector } from "./TableSelector";
import { TablesViewer } from "./TablesViewer";
import { usePaginationState } from "./hooks/usePaginationState";
import { useSQLQueryState } from "./hooks/useSQLQueryState";

export function Explorer() {
const { worldAddress } = useParams();
const { id: chainId } = useChain();
const indexer = indexerForChainId(chainId);
const [isLiveQuery, setIsLiveQuery] = useState(false);
const [query, setQuery] = useQueryState("query", parseAsString.withDefault(""));
const [{ pageSize }, setPagination] = usePaginationState();
const [query, setQuery] = useSQLQueryState();
const [selectedTableId] = useQueryState("tableId");
const prevSelectedTableId = usePrevious(selectedTableId);

const { data: tables } = useTablesQuery();
const table = tables?.find(({ tableId }) => tableId === selectedTableId);

useEffect(() => {
if (table && (!query || prevSelectedTableId !== selectedTableId)) {
const tableName = constructTableName(table, worldAddress as Hex, chainId);

if (indexer.type === "sqlite") {
setQuery(`SELECT * FROM "${tableName}";`);
} else {
const columns = Object.keys(table.schema).map((column) => `"${column}"`);
setQuery(`SELECT ${columns.join(", ")} FROM "${tableName}";`);
setQuery(`SELECT ${columns.join(", ")} FROM "${tableName}" LIMIT ${pageSize} OFFSET 0;`);
setPagination({
pageIndex: 0,
pageSize,
});
}
}
}, [chainId, setQuery, selectedTableId, table, worldAddress, prevSelectedTableId, query, indexer.type]);
}, [
chainId,
setQuery,
selectedTableId,
table,
worldAddress,
prevSelectedTableId,
query,
indexer.type,
pageSize,
setPagination,
]);

return (
<div className="space-y-4">
<TableSelector tables={tables} />
{indexer.type !== "sqlite" && (
<SQLEditor table={table} isLiveQuery={isLiveQuery} setIsLiveQuery={setIsLiveQuery} />
)}
<TablesViewer table={table} query={query} isLiveQuery={isLiveQuery} />
<TablesViewer table={table} isLiveQuery={isLiveQuery} />
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { 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 { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { Table } from "@latticexyz/config";
Expand All @@ -12,9 +11,12 @@ import { Button } from "../../../../../../components/ui/Button";
import { Form, FormField } from "../../../../../../components/ui/Form";
import { cn } from "../../../../../../utils";
import { useTableDataQuery } from "../../../../queries/useTableDataQuery";
import { monacoOptions } from "./consts";
import { PAGE_SIZE_OPTIONS, monacoOptions } from "./consts";
import { usePaginationState } from "./hooks/usePaginationState";
import { useSQLQueryState } from "./hooks/useSQLQueryState";
import { useMonacoSuggestions } from "./useMonacoSuggestions";
import { useQueryValidator } from "./useQueryValidator";
import { getLimitOffset } from "./utils/getLimitOffset";

type Props = {
table?: Table;
Expand All @@ -27,7 +29,9 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
const containerRef = useRef<HTMLDivElement>(null);
const [isFocused, setIsFocused] = useState(false);
const [isUserTriggeredRefetch, setIsUserTriggeredRefetch] = useState(false);
const [query, setQuery] = useQueryState("query", { defaultValue: "" });
const [pagination, setPagination] = usePaginationState();
const [query, setQuery] = useSQLQueryState();

const validateQuery = useQueryValidator(table);
const {
data: tableData,
Expand All @@ -48,9 +52,28 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
});
const currentQuery = form.watch("query");

const handleSubmit = form.handleSubmit((data) => {
if (validateQuery(data.query)) {
setQuery(data.query);
const handleSubmit = form.handleSubmit(({ query }) => {
if (validateQuery(query)) {
setQuery(query);

// Set the page based on the query
const { limit, offset } = getLimitOffset(query);
if (limit == null || offset == null) {
setPagination({
...pagination,
pageIndex: 0,
});
} else if (PAGE_SIZE_OPTIONS.includes(limit) && (offset === 0 || offset % limit === 0)) {
setPagination({
pageSize: limit,
pageIndex: offset / limit,
});
} else {
setPagination({
...pagination,
pageIndex: 0,
});
}

setIsUserTriggeredRefetch(true);
refetch().finally(() => setIsUserTriggeredRefetch(false));
Expand Down Expand Up @@ -100,10 +123,7 @@ export function SQLEditor({ table, isLiveQuery, setIsLiveQuery }: Props) {
id: "executeSQL",
label: "Execute SQL command",
keybindings: [KeyMod.CtrlCmd | KeyCode.Enter],
run: () => {
console.log("EXECUTING SQL COMMAND");
handleSubmit();
},
run: () => handleSubmit(),
});

updateHeight();
Expand Down
Loading
Loading