From a836a2d12f10011c12cb334f24a51afd7ce700d8 Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Thu, 7 Nov 2024 16:22:34 -0500 Subject: [PATCH 1/8] Events infinite scrolling Signed-off-by: Gabriel Indik --- ui/client/package-lock.json | 35 ++++++++++++++++++ ui/client/package.json | 1 + ui/client/src/components/Events.tsx | 42 ++++++++++++++------- ui/client/src/components/config.ts | 2 +- ui/client/src/queries/events.ts | 57 +++++++++++++++++++++++++++-- 5 files changed, 118 insertions(+), 19 deletions(-) diff --git a/ui/client/package-lock.json b/ui/client/package-lock.json index 5a2cd07b5..6a730781e 100644 --- a/ui/client/package-lock.json +++ b/ui/client/package-lock.json @@ -21,6 +21,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^15.0.2", + "react-infinite-scroll-component": "^6.1.0", "react-json-pretty": "^2.2.0", "react-router-dom": "^6.26.2" }, @@ -3660,6 +3661,18 @@ } } }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "license": "MIT", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -3935,6 +3948,15 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6534,6 +6556,14 @@ "html-parse-stringify": "^3.0.1" } }, + "react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "requires": { + "throttle-debounce": "^2.1.0" + } + }, "react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -6717,6 +6747,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==" + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/ui/client/package.json b/ui/client/package.json index deb3d287f..416cb4af0 100644 --- a/ui/client/package.json +++ b/ui/client/package.json @@ -26,6 +26,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^15.0.2", + "react-infinite-scroll-component": "^6.1.0", "react-json-pretty": "^2.2.0", "react-router-dom": "^6.26.2" }, diff --git a/ui/client/src/components/Events.tsx b/ui/client/src/components/Events.tsx index ab291ba52..fde61a712 100644 --- a/ui/client/src/components/Events.tsx +++ b/ui/client/src/components/Events.tsx @@ -14,32 +14,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Alert, Box, Typography, useTheme } from "@mui/material"; -import { useQuery } from "@tanstack/react-query"; +import { Box, LinearProgress, Typography, useTheme } from "@mui/material"; +import { useInfiniteQuery } from "@tanstack/react-query"; import { t } from "i18next"; import { fetchEvents } from "../queries/events"; import { Event } from "./Event"; import { useContext } from "react"; import { ApplicationContext } from "../contexts/ApplicationContext"; import { altDarkModeScrollbarStyle, altLightModeScrollbarStyle } from "../themes/default"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { IEvent } from "../interfaces"; export const Events: React.FC = () => { const { lastBlockWithTransactions } = useContext(ApplicationContext); - const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light'? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - const { data: events, error, isFetching } = useQuery({ + const { data: events, fetchNextPage, hasNextPage } = useInfiniteQuery({ queryKey: ["events", lastBlockWithTransactions], - queryFn: () => fetchEvents(), + queryFn: ({ pageParam }) => fetchEvents(pageParam), + initialPageParam: undefined as IEvent | undefined, + getNextPageParam: (lastPage) => {return lastPage[lastPage.length - 1]} }); - if(isFetching) { - return <>; - } + const theme = useTheme(); + const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - if (error) { - return {error.message} + if (events?.pages === undefined) { + return <>; } return ( @@ -48,15 +49,28 @@ export const Events: React.FC = () => { {t("events")} - {events?.map((event) => ( - - ))} + fetchNextPage()} + hasMore={hasNextPage} + loader={} + > + { + events.pages.map(eventArray => eventArray.map( + (event) => ( + + ) + )) + } + ); diff --git a/ui/client/src/components/config.ts b/ui/client/src/components/config.ts index 7da1f9d3f..66437d593 100644 --- a/ui/client/src/components/config.ts +++ b/ui/client/src/components/config.ts @@ -1,6 +1,6 @@ export const constants = { COLOR_MODE_STORAGE_KEY: 'color-mode', - EVENT_QUERY_LIMIT: 100, + EVENT_QUERY_LIMIT: 10, PENDING_TRANSACTIONS_QUERY_LIMIT: 100, REGISTRY_ENTRIES_QUERY_LIMIT: 100, TRANSACTION_QUERY_LIMIT: 100, diff --git a/ui/client/src/queries/events.ts b/ui/client/src/queries/events.ts index ac97c7364..4681a740e 100644 --- a/ui/client/src/queries/events.ts +++ b/ui/client/src/queries/events.ts @@ -20,8 +20,8 @@ import { IEvent } from "../interfaces"; import { generatePostReq, returnResponse } from "./common"; import { RpcEndpoint, RpcMethods } from "./rpcMethods"; -export const fetchEvents = async (): Promise => { - const requestPayload = { +export const fetchEvents = async (pageParam?: IEvent): Promise => { + let requestPayload: any = { jsonrpc: "2.0", id: Date.now(), method: RpcMethods.bidx_QueryIndexedEvents, @@ -29,10 +29,59 @@ export const fetchEvents = async (): Promise => { { limit: constants.EVENT_QUERY_LIMIT, sort: ["blockNumber DESC", "transactionIndex DESC", "logIndex DESC"], - }, - ], + } + ] }; + if (pageParam !== undefined) { + requestPayload.params[0].or = [ + { + "lessThan": [ + { + "field": "blockNumber", + "value": pageParam.blockNumber + } + ] + }, + { + "and": [ + { + "equal": { + "field": "blockNumber", + "value": pageParam.blockNumber + } + }, + { + "or": [ + { + "lessThan": { + "field": "transactionIndex", + "value": pageParam.transactionIndex + } + }, + { + "and": [ + { + "equal": { + "field": "transactionIndex", + "value": pageParam.transactionIndex + } + }, + { + "lessThan": { + "field": "logIndex", + "value": pageParam.logIndex + } + } + ] + } + ] + } + ] + } + ] + } + return >( returnResponse( () => fetch(RpcEndpoint, generatePostReq(JSON.stringify(requestPayload))), From bc5a894261a1f898ea5ba0718c31d4721a284811 Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Fri, 8 Nov 2024 10:31:22 -0500 Subject: [PATCH 2/8] Adjust query Signed-off-by: Gabriel Indik --- ui/client/src/queries/events.ts | 46 ++++++++++++--------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/ui/client/src/queries/events.ts b/ui/client/src/queries/events.ts index 4681a740e..a30eaec56 100644 --- a/ui/client/src/queries/events.ts +++ b/ui/client/src/queries/events.ts @@ -44,38 +44,26 @@ export const fetchEvents = async (pageParam?: IEvent): Promise => { ] }, { - "and": [ + "equal": [{ + "field": "blockNumber", + "value": pageParam.blockNumber + }], + "or": [ { - "equal": { - "field": "blockNumber", - "value": pageParam.blockNumber - } + "lessThan": [{ + "field": "transactionIndex", + "value": pageParam.transactionIndex + }] }, { - "or": [ - { - "lessThan": { - "field": "transactionIndex", - "value": pageParam.transactionIndex - } - }, - { - "and": [ - { - "equal": { - "field": "transactionIndex", - "value": pageParam.transactionIndex - } - }, - { - "lessThan": { - "field": "logIndex", - "value": pageParam.logIndex - } - } - ] - } - ] + "equal": [{ + "field": "transactionIndex", + "value": pageParam.transactionIndex + }], + "lessThan": [{ + "field": "logIndex", + "value": pageParam.logIndex + }] } ] } From b97d99deb3208e1cfac6cc51f21c393a5ef5afed Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Fri, 8 Nov 2024 11:26:09 -0500 Subject: [PATCH 3/8] Infinite scroll for indexed transactions Signed-off-by: Gabriel Indik --- ui/client/src/components/Events.tsx | 4 +- ui/client/src/components/Transactions.tsx | 72 ++++++++++------------- ui/client/src/components/config.ts | 2 +- ui/client/src/interfaces.ts | 5 ++ ui/client/src/queries/events.ts | 2 +- ui/client/src/queries/transactions.ts | 59 ++++++++++++++++--- 6 files changed, 91 insertions(+), 53 deletions(-) diff --git a/ui/client/src/components/Events.tsx b/ui/client/src/components/Events.tsx index fde61a712..67dd8c0dc 100644 --- a/ui/client/src/components/Events.tsx +++ b/ui/client/src/components/Events.tsx @@ -49,7 +49,7 @@ export const Events: React.FC = () => { {t("events")} { }} > fetchNextPage()} hasMore={hasNextPage} diff --git a/ui/client/src/components/Transactions.tsx b/ui/client/src/components/Transactions.tsx index 7230d43b5..0d09c2dd6 100644 --- a/ui/client/src/components/Transactions.tsx +++ b/ui/client/src/components/Transactions.tsx @@ -14,49 +14,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Alert, Box, Typography, useTheme } from "@mui/material"; -import { useQuery } from "@tanstack/react-query"; +import { Alert, Box, LinearProgress, Typography, useTheme } from "@mui/material"; +import { useInfiniteQuery } from "@tanstack/react-query"; import { t } from "i18next"; import { useContext } from "react"; import { ApplicationContext } from "../contexts/ApplicationContext"; import { fetchIndexedTransactions, - fetchPaladinTransactions, - fetchTransactionReceipts, } from "../queries/transactions"; import { Transaction } from "./Transaction"; import { altLightModeScrollbarStyle, altDarkModeScrollbarStyle } from "../themes/default"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { ITransaction } from "../interfaces"; export const Transactions: React.FC = () => { const { lastBlockWithTransactions } = useContext(ApplicationContext); - + const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light'? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; + const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - const { data: transactions, error: transactionError, isRefetching: transactionFetching } = useQuery({ + const { data: transactions, fetchNextPage, hasNextPage, error } = useInfiniteQuery({ queryKey: ["transactions", lastBlockWithTransactions], - queryFn: () => fetchIndexedTransactions(), - }); - - const { data: transactionReceipts, error: receiptError, isFetching: receiptFetching } = useQuery({ - queryKey: ["transactionReceipts", transactions], - queryFn: () => fetchTransactionReceipts(transactions ?? []), - enabled: transactions !== undefined, + queryFn: ({ pageParam }) => fetchIndexedTransactions(pageParam), + initialPageParam: undefined as ITransaction | undefined, + getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] } }); - const { data: paladinTransactions, error: paladinTransactionError, isFetching: paladinTransactionFetching } = useQuery({ - queryKey: ["paladinTransactions", transactionReceipts], - queryFn: () => fetchPaladinTransactions(transactionReceipts ?? []), - enabled: transactionReceipts !== undefined, - }); - - if(transactionFetching || receiptFetching || paladinTransactionFetching) { - return <>; + if (error) { + return {error.message} } - if (transactionError || receiptError || paladinTransactionError) { - return {transactionError?.message ?? receiptError?.message ?? paladinTransactionError?.message} + if (transactions?.pages === undefined) { + return <>; } return ( @@ -65,29 +55,29 @@ export const Transactions: React.FC = () => { {t("transactions")} - {transactions?.map((transaction) => ( - - transactionReceipt.transactionHash === transaction.hash - )} - paladinTransactions={paladinTransactions?.filter( - (paladinTransaction) => - transactionReceipts?.filter( - (transactionReceipt) => - transactionReceipt.transactionHash === transaction.hash - ).map(transactionReceipt => (transactionReceipt.id)).includes(paladinTransaction.id) - )} - /> - ))} + fetchNextPage()} + hasMore={hasNextPage} + loader={} + > + {transactions.pages.map(transactionArrat => transactionArrat?.map((transaction) => ( + + )))} + ); diff --git a/ui/client/src/components/config.ts b/ui/client/src/components/config.ts index 66437d593..a85b02eed 100644 --- a/ui/client/src/components/config.ts +++ b/ui/client/src/components/config.ts @@ -3,7 +3,7 @@ export const constants = { EVENT_QUERY_LIMIT: 10, PENDING_TRANSACTIONS_QUERY_LIMIT: 100, REGISTRY_ENTRIES_QUERY_LIMIT: 100, - TRANSACTION_QUERY_LIMIT: 100, + TRANSACTION_QUERY_LIMIT: 10, UPDATE_FREQUENCY_MILLISECONDS: 3000, ELLAPSED_TIME_AUTO_REFRESH_FREQUENCY_SECONDS: 60 }; diff --git a/ui/client/src/interfaces.ts b/ui/client/src/interfaces.ts index efa22c508..4a679cec1 100644 --- a/ui/client/src/interfaces.ts +++ b/ui/client/src/interfaces.ts @@ -31,6 +31,11 @@ export interface ITransaction { block: IBlock; } +export interface IEnrichedTransaction extends ITransaction { + receipts: ITransactionReceipt[] + paladinTransactions: IPaladinTransaction[] +} + export interface IEvent { blockNumber: number; transactionIndex: number; diff --git a/ui/client/src/queries/events.ts b/ui/client/src/queries/events.ts index a30eaec56..7a4747238 100644 --- a/ui/client/src/queries/events.ts +++ b/ui/client/src/queries/events.ts @@ -67,7 +67,7 @@ export const fetchEvents = async (pageParam?: IEvent): Promise => { } ] } - ] + ]; } return >( diff --git a/ui/client/src/queries/transactions.ts b/ui/client/src/queries/transactions.ts index dae7e9e10..dbcf884e1 100644 --- a/ui/client/src/queries/transactions.ts +++ b/ui/client/src/queries/transactions.ts @@ -17,6 +17,7 @@ import i18next from "i18next"; import { constants } from "../components/config"; import { + IEnrichedTransaction, IPaladinTransaction, ITransaction, ITransactionReceipt, @@ -24,8 +25,8 @@ import { import { generatePostReq, returnResponse } from "./common"; import { RpcEndpoint, RpcMethods } from "./rpcMethods"; -export const fetchIndexedTransactions = async (): Promise => { - const payload = { +export const fetchIndexedTransactions = async (pageParam?: ITransaction): Promise => { + let requestPayload: any = { jsonrpc: "2.0", id: Date.now(), method: RpcMethods.bidx_QueryIndexedTransactions, @@ -37,12 +38,54 @@ export const fetchIndexedTransactions = async (): Promise => { ], }; - return >( - returnResponse( - () => fetch(RpcEndpoint, generatePostReq(JSON.stringify(payload))), - i18next.t("errorFetchingTransactions") - ) - ); + if (pageParam !== undefined) { + requestPayload.params[0].or = [ + { + "lessThan": [ + { + "field": "blockNumber", + "value": pageParam.blockNumber + } + ] + }, + { + "equal": [{ + "field": "blockNumber", + "value": pageParam.blockNumber + }], + "lessThan": [{ + "field": "transactionIndex", + "value": pageParam.transactionIndex + }] + } + ]; + } + + const transactions: ITransaction[] = await returnResponse( + () => fetch(RpcEndpoint, generatePostReq(JSON.stringify(requestPayload))), + i18next.t("errorFetchingTransactions") + ) + + const receiptsResult = await fetchTransactionReceipts(transactions); + const paladinTransactionsResult = await fetchPaladinTransactions(receiptsResult); + + let enrichedTransactions: IEnrichedTransaction[] = []; + + for (const transaction of transactions) { + enrichedTransactions.push({ + ...transaction, + receipts: receiptsResult.filter(receiptResult => receiptResult.transactionHash === transaction.hash), + paladinTransactions: paladinTransactionsResult.filter( + (paladinTransaction) => + receiptsResult?.filter( + (transactionReceipt) => + transactionReceipt.transactionHash === transaction.hash + ).map(transactionReceipt => (transactionReceipt.id)).includes(paladinTransaction.id) + ) + }) + } + + return enrichedTransactions; }; export const fetchSubmissions = async ( From c180230786772ce5ffa60d6548e772a95448806a Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Fri, 8 Nov 2024 11:53:24 -0500 Subject: [PATCH 4/8] Infinite scroll for submissions Signed-off-by: Gabriel Indik --- ui/client/src/components/Events.tsx | 8 +++-- ui/client/src/components/config.ts | 2 +- ui/client/src/queries/transactions.ts | 19 +++++++++-- ui/client/src/views/Submissions.tsx | 48 +++++++++++++++++---------- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/ui/client/src/components/Events.tsx b/ui/client/src/components/Events.tsx index 67dd8c0dc..25cab0d75 100644 --- a/ui/client/src/components/Events.tsx +++ b/ui/client/src/components/Events.tsx @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Box, LinearProgress, Typography, useTheme } from "@mui/material"; +import { Alert, Box, LinearProgress, Typography, useTheme } from "@mui/material"; import { useInfiniteQuery } from "@tanstack/react-query"; import { t } from "i18next"; import { fetchEvents } from "../queries/events"; @@ -29,7 +29,7 @@ export const Events: React.FC = () => { const { lastBlockWithTransactions } = useContext(ApplicationContext); - const { data: events, fetchNextPage, hasNextPage } = useInfiniteQuery({ + const { data: events, fetchNextPage, hasNextPage, error } = useInfiniteQuery({ queryKey: ["events", lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchEvents(pageParam), initialPageParam: undefined as IEvent | undefined, @@ -39,6 +39,10 @@ export const Events: React.FC = () => { const theme = useTheme(); const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; + if (error) { + return {error.message} + } + if (events?.pages === undefined) { return <>; } diff --git a/ui/client/src/components/config.ts b/ui/client/src/components/config.ts index a85b02eed..be34f49fc 100644 --- a/ui/client/src/components/config.ts +++ b/ui/client/src/components/config.ts @@ -1,7 +1,7 @@ export const constants = { COLOR_MODE_STORAGE_KEY: 'color-mode', EVENT_QUERY_LIMIT: 10, - PENDING_TRANSACTIONS_QUERY_LIMIT: 100, + SUBMISSIONS_QUERY_LIMIT: 10, REGISTRY_ENTRIES_QUERY_LIMIT: 100, TRANSACTION_QUERY_LIMIT: 10, UPDATE_FREQUENCY_MILLISECONDS: 3000, diff --git a/ui/client/src/queries/transactions.ts b/ui/client/src/queries/transactions.ts index dbcf884e1..8064f398d 100644 --- a/ui/client/src/queries/transactions.ts +++ b/ui/client/src/queries/transactions.ts @@ -89,14 +89,25 @@ export const fetchIndexedTransactions = async (pageParam?: ITransaction): Promis }; export const fetchSubmissions = async ( - type: "all" | "pending" + type: "all" | "pending", + pageParam?: IPaladinTransaction ): Promise => { - const allParams = [ + let allParams: any = [ { - limit: constants.PENDING_TRANSACTIONS_QUERY_LIMIT, + limit: constants.SUBMISSIONS_QUERY_LIMIT, sort: ["created DESC"], }, ]; + + if(pageParam !== undefined) { + allParams[0].lessThan = [ + { + "field": "created", + "value": pageParam.created + } + ]; + } + const pendingParams = [...allParams, true]; const payload = { jsonrpc: "2.0", @@ -108,6 +119,8 @@ export const fetchSubmissions = async ( params: type === "all" ? allParams : pendingParams, }; + console.log(JSON.stringify(payload)) + return >( returnResponse( () => fetch(RpcEndpoint, generatePostReq(JSON.stringify(payload))), diff --git a/ui/client/src/views/Submissions.tsx b/ui/client/src/views/Submissions.tsx index 867ede246..81761ce95 100644 --- a/ui/client/src/views/Submissions.tsx +++ b/ui/client/src/views/Submissions.tsx @@ -14,14 +14,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Alert, Box, Fade, ToggleButton, ToggleButtonGroup, Typography, useTheme } from "@mui/material"; -import { useQuery } from "@tanstack/react-query"; +import { Alert, Box, Fade, LinearProgress, ToggleButton, ToggleButtonGroup, Typography, useTheme } from "@mui/material"; +import { useInfiniteQuery } from "@tanstack/react-query"; import { t } from "i18next"; import { useContext, useState } from "react"; import { PaladinTransaction } from "../components/PaladinTransaction"; import { ApplicationContext } from "../contexts/ApplicationContext"; import { fetchSubmissions } from "../queries/transactions"; import { altLightModeScrollbarStyle, altDarkModeScrollbarStyle } from "../themes/default"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { IPaladinTransaction } from "../interfaces"; export const Submissions: React.FC = () => { const { lastBlockWithTransactions } = useContext(ApplicationContext); @@ -30,19 +32,21 @@ export const Submissions: React.FC = () => { const theme = useTheme(); const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - const { data: transactions, error, isFetching } = useQuery({ - queryKey: ["pendingTransactions", tab, lastBlockWithTransactions], - queryFn: () => fetchSubmissions(tab) + const { data: transactions, fetchNextPage, hasNextPage, error } = useInfiniteQuery({ + queryKey: ["submissions", tab, lastBlockWithTransactions], + queryFn: ({ pageParam }) => fetchSubmissions(tab, pageParam), + initialPageParam: undefined as IPaladinTransaction | undefined, + getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] } }); - if(isFetching) { - return <>; - } - if (error) { return {error.message} } + if (transactions?.pages === undefined) { + return <>; + } + return ( { - {transactions?.map(transaction => ( - - ))} - {transactions?.length === 0 && + fetchNextPage()} + hasMore={hasNextPage} + loader={} + > + {transactions.pages.map(transactionsArray => + transactionsArray.map(transaction => ( + + )) + )} + + {transactions.pages.length === 1 && transactions.pages[0].length === 0 && {t('noPendingTransactions')}} - ); From 098b44949546f176c6b8f42c652e99345d0beada Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Wed, 13 Nov 2024 11:51:24 -0500 Subject: [PATCH 5/8] Auto refresh feature Signed-off-by: Gabriel Indik --- ui/client/src/components/Events.tsx | 2 +- ui/client/src/components/Header.tsx | 95 ++++++++++++++----- ui/client/src/components/Transactions.tsx | 2 +- ui/client/src/contexts/ApplicationContext.tsx | 36 ++++++- ui/client/src/queries/transactions.ts | 2 - ui/client/src/translations/en.json | 5 +- ui/client/src/views/Registries.tsx | 4 +- ui/client/src/views/Submissions.tsx | 2 +- 8 files changed, 112 insertions(+), 36 deletions(-) diff --git a/ui/client/src/components/Events.tsx b/ui/client/src/components/Events.tsx index 25cab0d75..e7b895c77 100644 --- a/ui/client/src/components/Events.tsx +++ b/ui/client/src/components/Events.tsx @@ -33,7 +33,7 @@ export const Events: React.FC = () => { queryKey: ["events", lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchEvents(pageParam), initialPageParam: undefined as IEvent | undefined, - getNextPageParam: (lastPage) => {return lastPage[lastPage.length - 1]} + getNextPageParam: (lastPage) => {return lastPage[lastPage.length - 1]}, }); const theme = useTheme(); diff --git a/ui/client/src/components/Header.tsx b/ui/client/src/components/Header.tsx index ab085f0db..f3d17c4cd 100644 --- a/ui/client/src/components/Header.tsx +++ b/ui/client/src/components/Header.tsx @@ -14,17 +14,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { AppBar, Box, Grid2, IconButton, Tab, Tabs, Toolbar, Tooltip, useMediaQuery, useTheme } from "@mui/material"; +import { AppBar, Box, Button, Grid2, IconButton, Tab, Tabs, ToggleButton, ToggleButtonGroup, Toolbar, Tooltip, useMediaQuery, useTheme } from "@mui/material"; import { useContext, useState } from "react"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate } from "react-router-dom"; import Brightness4Icon from '@mui/icons-material/Brightness4'; import { ApplicationContext } from "../contexts/ApplicationContext"; - +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; +import PauseIcon from '@mui/icons-material/Pause'; +import RefreshIcon from '@mui/icons-material/Refresh'; export const Header: React.FC = () => { - const { colorMode } = useContext(ApplicationContext); + const { colorMode, autoRefreshEnabled, setAutoRefreshEnabled, refreshRequired, refresh } = useContext(ApplicationContext); const { t } = useTranslation(); const navigate = useNavigate(); const pathname = useLocation().pathname.toLowerCase(); @@ -53,37 +55,80 @@ export const Header: React.FC = () => { } }; + const handleAutoRefreshChange = (value: string) => { + switch (value) { + case 'play': setAutoRefreshEnabled(true); break; + case 'pause': setAutoRefreshEnabled(false); break; + } + }; + return ( <> theme.palette.background.paper }}> - - - - - - handleNavigation(value)} centered> - - - - - - - - colorMode.toggleColorMode()}> - - - + + + + + + handleNavigation(value)} centered> + + + + + + + + {refreshRequired && + + + } + + handleAutoRefreshChange(value)} value={autoRefreshEnabled ? 'play' : 'pause'}> + + + + + + + + + + + + + + + colorMode.toggleColorMode()}> + + + + + + - - lessThanMedium? '134px' : - theme.mixins.toolbar }} /> + lessThanMedium ? '190px' : + theme.mixins.toolbar + }} /> ); diff --git a/ui/client/src/components/Transactions.tsx b/ui/client/src/components/Transactions.tsx index 0d09c2dd6..396ff8abc 100644 --- a/ui/client/src/components/Transactions.tsx +++ b/ui/client/src/components/Transactions.tsx @@ -38,7 +38,7 @@ export const Transactions: React.FC = () => { queryKey: ["transactions", lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchIndexedTransactions(pageParam), initialPageParam: undefined as ITransaction | undefined, - getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] } + getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] }, }); if (error) { diff --git a/ui/client/src/contexts/ApplicationContext.tsx b/ui/client/src/contexts/ApplicationContext.tsx index 122870afa..5685027e4 100644 --- a/ui/client/src/contexts/ApplicationContext.tsx +++ b/ui/client/src/contexts/ApplicationContext.tsx @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { createContext } from "react"; +import { createContext, Dispatch, SetStateAction, useEffect, useState } from "react"; import { constants } from "../components/config"; import { ErrorDialog } from "../dialogs/Error"; import { fetchLatestBlockWithTxs } from "../queries/blocks"; @@ -9,6 +9,10 @@ interface IApplicationContext { toggleColorMode: () => void; }; lastBlockWithTransactions: number; + autoRefreshEnabled: boolean; + setAutoRefreshEnabled: Dispatch>; + refreshRequired: boolean; + refresh: () => void; } export const ApplicationContext = createContext({} as IApplicationContext); @@ -22,7 +26,11 @@ interface Props { export const ApplicationContextProvider = ({ children, colorMode }: Props) => { - const { data: lastBlockWithTransactions, error } = useQuery({ + const [autoRefreshEnabled, setAutoRefreshEnabled] = useState(true); + const [lastBlockWithTransactions, setLastBlockWithTransactions] = useState(0); + const [refreshRequired, setRefreshRequired] = useState(false); + + const { data: actualLastBlockWithTransactions, error } = useQuery({ queryKey: ["lastBlockWithTransactions"], queryFn: () => fetchLatestBlockWithTxs().then((res) => { @@ -35,9 +43,31 @@ export const ApplicationContextProvider = ({ children, colorMode }: Props) => { retry: false }); + + useEffect(() => { + if(actualLastBlockWithTransactions !== undefined + && actualLastBlockWithTransactions > lastBlockWithTransactions) { + if(autoRefreshEnabled) { + setLastBlockWithTransactions(actualLastBlockWithTransactions); + } else { + setRefreshRequired(true); + } + } + }, [actualLastBlockWithTransactions, lastBlockWithTransactions, setLastBlockWithTransactions]); + + const refresh = () => { + if(actualLastBlockWithTransactions !== undefined) { + setLastBlockWithTransactions(actualLastBlockWithTransactions); + } + setRefreshRequired(false); + }; + return ( {children} diff --git a/ui/client/src/queries/transactions.ts b/ui/client/src/queries/transactions.ts index 8064f398d..4f6221a12 100644 --- a/ui/client/src/queries/transactions.ts +++ b/ui/client/src/queries/transactions.ts @@ -119,8 +119,6 @@ export const fetchSubmissions = async ( params: type === "all" ? allParams : pendingParams, }; - console.log(JSON.stringify(payload)) - return >( returnResponse( () => fetch(RpcEndpoint, generatePostReq(JSON.stringify(payload))), diff --git a/ui/client/src/translations/en.json b/ui/client/src/translations/en.json index 1020c032c..3a522d612 100644 --- a/ui/client/src/translations/en.json +++ b/ui/client/src/translations/en.json @@ -78,5 +78,8 @@ "pending": "Pending", "indexer": "Indexer", "submissions": "Submissions", - "close": "Close" + "close": "Close", + "autoRefreshOn": "Auto-refresh on", + "autoRefreshOff": "Auto-refresh off", + "newData": "New Data" } diff --git a/ui/client/src/views/Registries.tsx b/ui/client/src/views/Registries.tsx index 5b1fcfcb1..46ea0200c 100644 --- a/ui/client/src/views/Registries.tsx +++ b/ui/client/src/views/Registries.tsx @@ -25,12 +25,12 @@ import { altDarkModeScrollbarStyle, altLightModeScrollbarStyle } from "../themes export const Registries: React.FC = () => { - const { lastBlockWithTransactions } = useContext(ApplicationContext); + const { lastBlockWithTransactions, autoRefreshEnabled } = useContext(ApplicationContext); const theme = useTheme(); const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; const { data: registries, error, isFetching } = useQuery({ - queryKey: ["registries", lastBlockWithTransactions], + queryKey: ["registries", autoRefreshEnabled, lastBlockWithTransactions], queryFn: () => fetchRegistries() }); diff --git a/ui/client/src/views/Submissions.tsx b/ui/client/src/views/Submissions.tsx index 81761ce95..8d4a8ca08 100644 --- a/ui/client/src/views/Submissions.tsx +++ b/ui/client/src/views/Submissions.tsx @@ -36,7 +36,7 @@ export const Submissions: React.FC = () => { queryKey: ["submissions", tab, lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchSubmissions(tab, pageParam), initialPageParam: undefined as IPaladinTransaction | undefined, - getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] } + getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] }, }); if (error) { From 80ea5db78d9919db360f0369d5a6d5f83b0dac43 Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Wed, 13 Nov 2024 11:57:23 -0500 Subject: [PATCH 6/8] Update casing Signed-off-by: Gabriel Indik --- ui/client/src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/client/src/translations/en.json b/ui/client/src/translations/en.json index 3a522d612..1a8f4aeba 100644 --- a/ui/client/src/translations/en.json +++ b/ui/client/src/translations/en.json @@ -81,5 +81,5 @@ "close": "Close", "autoRefreshOn": "Auto-refresh on", "autoRefreshOff": "Auto-refresh off", - "newData": "New Data" + "newData": "New data" } From 56290c05805bd436e263f0d86c516de60905a904 Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Fri, 15 Nov 2024 10:37:13 -0500 Subject: [PATCH 7/8] Adjust private label logic Signed-off-by: Gabriel Indik --- ui/client/src/components/Transaction.tsx | 2 +- ui/client/src/contexts/ApplicationContext.tsx | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ui/client/src/components/Transaction.tsx b/ui/client/src/components/Transaction.tsx index 0bb16cd23..8dd0b067b 100644 --- a/ui/client/src/components/Transaction.tsx +++ b/ui/client/src/components/Transaction.tsx @@ -45,7 +45,7 @@ export const Transaction: React.FC = ({ const [viewDetailsDialogOpen, setViewDetailsDialogOpen] = useState(false); const receiptCount = (transactionReceipts && transactionReceipts.length) ? transactionReceipts.length : 0; - const receiptIsPrivate = (transactionReceipts && transactionReceipts.length && transactionReceipts[0].domain !== ''); + const receiptIsPrivate = (transactionReceipts && transactionReceipts.length && transactionReceipts[0].domain !== undefined); const typeKey = receiptCount > 1 ? 'atomicNumber' : receiptIsPrivate ? 'private' : diff --git a/ui/client/src/contexts/ApplicationContext.tsx b/ui/client/src/contexts/ApplicationContext.tsx index 5685027e4..49fbffd40 100644 --- a/ui/client/src/contexts/ApplicationContext.tsx +++ b/ui/client/src/contexts/ApplicationContext.tsx @@ -26,8 +26,8 @@ interface Props { export const ApplicationContextProvider = ({ children, colorMode }: Props) => { - const [autoRefreshEnabled, setAutoRefreshEnabled] = useState(true); - const [lastBlockWithTransactions, setLastBlockWithTransactions] = useState(0); + const [autoRefreshEnabled, setAutoRefreshEnabled] = useState(false); + const [lastBlockWithTransactions, setLastBlockWithTransactions] = useState(-1); const [refreshRequired, setRefreshRequired] = useState(false); const { data: actualLastBlockWithTransactions, error } = useQuery({ @@ -43,15 +43,18 @@ export const ApplicationContextProvider = ({ children, colorMode }: Props) => { retry: false }); - useEffect(() => { + + if(actualLastBlockWithTransactions !== undefined && actualLastBlockWithTransactions > lastBlockWithTransactions) { - if(autoRefreshEnabled) { + + if(autoRefreshEnabled || lastBlockWithTransactions === -1) { setLastBlockWithTransactions(actualLastBlockWithTransactions); } else { setRefreshRequired(true); } + } }, [actualLastBlockWithTransactions, lastBlockWithTransactions, setLastBlockWithTransactions]); From fedf5d736714e323881008ce1934249feab52fa6 Mon Sep 17 00:00:00 2001 From: Gabriel Indik Date: Mon, 18 Nov 2024 11:48:53 -0500 Subject: [PATCH 8/8] Updates based on code review - first pass Signed-off-by: Gabriel Indik --- ui/client/src/components/Events.tsx | 9 +- ui/client/src/components/Header.tsx | 2 +- ui/client/src/components/Transactions.tsx | 5 +- ui/client/src/dialogs/TransactionDetails.tsx | 5 +- .../src/dialogs/TransactionReceiptDetails.tsx | 7 +- ui/client/src/themes/default.ts | 8 +- ui/client/src/translations/en.json | 168 +++++++++--------- ui/client/src/views/Registries.tsx | 5 +- ui/client/src/views/Submissions.tsx | 7 +- 9 files changed, 107 insertions(+), 109 deletions(-) diff --git a/ui/client/src/components/Events.tsx b/ui/client/src/components/Events.tsx index e7b895c77..bf2edf28f 100644 --- a/ui/client/src/components/Events.tsx +++ b/ui/client/src/components/Events.tsx @@ -21,7 +21,7 @@ import { fetchEvents } from "../queries/events"; import { Event } from "./Event"; import { useContext } from "react"; import { ApplicationContext } from "../contexts/ApplicationContext"; -import { altDarkModeScrollbarStyle, altLightModeScrollbarStyle } from "../themes/default"; +import { getAltModeScrollBarStyle } from "../themes/default"; import InfiniteScroll from "react-infinite-scroll-component"; import { IEvent } from "../interfaces"; @@ -33,12 +33,11 @@ export const Events: React.FC = () => { queryKey: ["events", lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchEvents(pageParam), initialPageParam: undefined as IEvent | undefined, - getNextPageParam: (lastPage) => {return lastPage[lastPage.length - 1]}, + getNextPageParam: (lastPage) => { return lastPage.length > 0? lastPage[lastPage.length - 1] : undefined }, }); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - + if (error) { return {error.message} } @@ -57,7 +56,7 @@ export const Events: React.FC = () => { sx={{ height: "calc(100vh - 170px)", paddingRight: "15px", - ...addedStyle + ...getAltModeScrollBarStyle(theme.palette.mode) }} > { } }; - const handleAutoRefreshChange = (value: string) => { + const handleAutoRefreshChange = (value: 'play' | 'pause') => { switch (value) { case 'play': setAutoRefreshEnabled(true); break; case 'pause': setAutoRefreshEnabled(false); break; diff --git a/ui/client/src/components/Transactions.tsx b/ui/client/src/components/Transactions.tsx index 396ff8abc..2e8cc0a26 100644 --- a/ui/client/src/components/Transactions.tsx +++ b/ui/client/src/components/Transactions.tsx @@ -23,7 +23,7 @@ import { fetchIndexedTransactions, } from "../queries/transactions"; import { Transaction } from "./Transaction"; -import { altLightModeScrollbarStyle, altDarkModeScrollbarStyle } from "../themes/default"; +import { getAltModeScrollBarStyle } from "../themes/default"; import InfiniteScroll from "react-infinite-scroll-component"; import { ITransaction } from "../interfaces"; @@ -32,7 +32,6 @@ export const Transactions: React.FC = () => { const { lastBlockWithTransactions } = useContext(ApplicationContext); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; const { data: transactions, fetchNextPage, hasNextPage, error } = useInfiniteQuery({ queryKey: ["transactions", lastBlockWithTransactions], @@ -59,7 +58,7 @@ export const Transactions: React.FC = () => { sx={{ height: "calc(100vh - 170px)", paddingRight: "15px", - ...addedStyle + ...getAltModeScrollBarStyle(theme.palette.mode) }} > = ({ const { t } = useTranslation(); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light'? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; const selectedTransaction = paladinTransactions?.find(r => (r.id == selectedPaladinTransactionId)); @@ -67,7 +66,7 @@ export const PaladinTransactionsDetailsDialog: React.FC = ({ {t('transaction')} - + 1} label={t('id')} fullWidth size="small" value={selectedPaladinTransactionId} onChange={event => setSelectedPaladinTransactionId(event.target.value)}> diff --git a/ui/client/src/dialogs/TransactionReceiptDetails.tsx b/ui/client/src/dialogs/TransactionReceiptDetails.tsx index fcf0baaac..7397f2dc3 100644 --- a/ui/client/src/dialogs/TransactionReceiptDetails.tsx +++ b/ui/client/src/dialogs/TransactionReceiptDetails.tsx @@ -29,7 +29,7 @@ import { useTranslation } from 'react-i18next'; import { IPaladinTransaction, ITransactionReceipt } from '../interfaces'; import { PaladinTransactionsDetails } from '../components/TransactionDetails'; import { useEffect, useState } from 'react'; -import { altLightModeScrollbarStyle, altDarkModeScrollbarStyle } from '../themes/default'; +import { getAltModeScrollBarStyle } from '../themes/default'; type Props = { paladinTransactions?: IPaladinTransaction[] @@ -49,8 +49,7 @@ export const PaladinTransactionsReceiptDetailsDialog: React.FC = ({ const { t } = useTranslation(); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; - + const selectedReceipt = paladinReceipts?.find(r => (r.id == selectedPaladinTransactionId)); const selectedTransaction = paladinTransactions?.find(r => (r.id == selectedPaladinTransactionId)); @@ -70,7 +69,7 @@ export const PaladinTransactionsReceiptDetailsDialog: React.FC = ({ {t('transaction')} - + setSelectedPaladinTransactionId(event.target.value)}> diff --git a/ui/client/src/themes/default.ts b/ui/client/src/themes/default.ts index 3c7b43090..3dcaaa1bb 100644 --- a/ui/client/src/themes/default.ts +++ b/ui/client/src/themes/default.ts @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { ThemeOptions } from '@mui/material'; +import { PaletteMode, ThemeOptions } from '@mui/material'; export const darkThemeOptions: ThemeOptions = { @@ -75,4 +75,8 @@ export const altLightModeScrollbarStyle = { backgroundColor: '#F0F0F0', border: '3px solid #FFFFFF', }, -}; \ No newline at end of file +}; + +export const getAltModeScrollBarStyle = (paletteMode: PaletteMode) => ( + paletteMode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle +); diff --git a/ui/client/src/translations/en.json b/ui/client/src/translations/en.json index 1a8f4aeba..af41c06c1 100644 --- a/ui/client/src/translations/en.json +++ b/ui/client/src/translations/en.json @@ -1,85 +1,85 @@ { - "active": "Active", - "all": "All", - "block": "Block", - "contract": "Contract", - "copied": "Copied!", - "copyToClipboard": "Copy to Clipboard", - "created": "Created", - "dismiss": "Dismiss", - "domain": "Domain", - "entries": "Entries", - "errorConnectingToPaladinNode": "Error connecting to Paladin node", - "errorFetchingLatestBlock": "Error fetching latest block", - "errorFetchingLatestEvents": "Error fetching latest events", - "errorFetchingPaladinTransactions": "Error fetching Paladin transactions", - "errorFetchingRegistries": "Error fetching registries", - "errorFetchingRegistryEntries": "Error fetching registry entries", - "errorFetchingSubmissions": "Error fetching submissions", - "errorFetchingTransactionReceipts": "Error fetching transaction receipts", - "errorFetchingTransactionReceipt": "Error fetching transaction receipt", - "errorFetchingTransactions": "Error fetching transactions", - "errorFetchingStateReceipt": "Error fetching state receipt", - "errorFetchingDomainReceipt": "Error fetching domain receipt", - "events": "Events", - "from": "From", - "hash": "Hash", - "id": "ID", - "live": "Live", - "logIndex": "Log Index", - "name": "Name", - "nonce": "Nonce", - "owner": "Owner", - "paladin": "Paladin", - "paused": "Paused", - "pendingTransactions": "Pending Transactions", - "private": "Private", - "public": "Public", - "registry": "Registry", - "registryName": "Registry {{name}}", - "result": "Result", - "signature": "Signature", - "success": "Success", - "transaction": "Transaction", - "transactionHash": "Tx Hash", - "transactionIndex": "Tx Index", - "transactions": "Transactions", - "transactionsAndEvents": "Transactions & Events", - "type": "Type", - "switchThemeMode": "Switch theme mode", - "showProperties": "Show Properties", - "hideProperties": "Hide Properties", - "noProperties": "No Properties", - "viewDetails": "View Details", - "registryEntry": "Registry Entry", - "noPendingTransactions": "No Pending Transactions", - "event": "Event", - "details": "Details", - "receipt": "Receipt", - "stateReceipt": "State Receipt", - "domainReceipt": "Domain Receipt", - "timestamp": "Timestamp", - "localTime": "Local Time", - "ISO": "ISO", - "epoch": "Epoch", - "to": "To", - "debug": "Debug", - "atomic": "Atomic", - "numberNanoseconds": "{{number}} (nanoseconds)", - "numberMilliseconds": "{{number}} (milliseconds)", - "numberSeconds": "{{number}} (seconds)", - "atomicNumber": "Atomic ({{number}})", - "evmPrivateTransaction": "EVM Private Transaction", - "evmPrivateReceipt": "EVM Private Receipt", - "evmPrivateLog": "EVM Private Log {{logIndex}}", - "decodedFunction": "Decoded function:", - "decodedEvent": "Decoded event:", - "topic": "Topic", - "pending": "Pending", - "indexer": "Indexer", - "submissions": "Submissions", - "close": "Close", - "autoRefreshOn": "Auto-refresh on", - "autoRefreshOff": "Auto-refresh off", - "newData": "New data" -} + "ISO": "ISO", + "active": "Active", + "all": "All", + "atomic": "Atomic", + "atomicNumber": "Atomic ({{number}})", + "autoRefreshOff": "Auto-refresh off", + "autoRefreshOn": "Auto-refresh on", + "block": "Block", + "close": "Close", + "contract": "Contract", + "copied": "Copied!", + "copyToClipboard": "Copy to Clipboard", + "created": "Created", + "debug": "Debug", + "decodedEvent": "Decoded event:", + "decodedFunction": "Decoded function:", + "details": "Details", + "dismiss": "Dismiss", + "domain": "Domain", + "domainReceipt": "Domain Receipt", + "entries": "Entries", + "epoch": "Epoch", + "errorConnectingToPaladinNode": "Error connecting to Paladin node", + "errorFetchingDomainReceipt": "Error fetching domain receipt", + "errorFetchingLatestBlock": "Error fetching latest block", + "errorFetchingLatestEvents": "Error fetching latest events", + "errorFetchingPaladinTransactions": "Error fetching Paladin transactions", + "errorFetchingRegistries": "Error fetching registries", + "errorFetchingRegistryEntries": "Error fetching registry entries", + "errorFetchingStateReceipt": "Error fetching state receipt", + "errorFetchingSubmissions": "Error fetching submissions", + "errorFetchingTransactionReceipt": "Error fetching transaction receipt", + "errorFetchingTransactionReceipts": "Error fetching transaction receipts", + "errorFetchingTransactions": "Error fetching transactions", + "event": "Event", + "events": "Events", + "evmPrivateLog": "EVM Private Log {{logIndex}}", + "evmPrivateReceipt": "EVM Private Receipt", + "evmPrivateTransaction": "EVM Private Transaction", + "from": "From", + "hash": "Hash", + "hideProperties": "Hide Properties", + "id": "ID", + "indexer": "Indexer", + "live": "Live", + "localTime": "Local Time", + "logIndex": "Log Index", + "name": "Name", + "newData": "New data", + "noPendingTransactions": "No Pending Transactions", + "noProperties": "No Properties", + "nonce": "Nonce", + "numberMilliseconds": "{{number}} (milliseconds)", + "numberNanoseconds": "{{number}} (nanoseconds)", + "numberSeconds": "{{number}} (seconds)", + "owner": "Owner", + "paladin": "Paladin", + "paused": "Paused", + "pending": "Pending", + "pendingTransactions": "Pending Transactions", + "private": "Private", + "public": "Public", + "receipt": "Receipt", + "registry": "Registry", + "registryEntry": "Registry Entry", + "registryName": "Registry {{name}}", + "result": "Result", + "showProperties": "Show Properties", + "signature": "Signature", + "stateReceipt": "State Receipt", + "submissions": "Submissions", + "success": "Success", + "switchThemeMode": "Switch theme mode", + "timestamp": "Timestamp", + "to": "To", + "topic": "Topic", + "transaction": "Transaction", + "transactionHash": "Tx Hash", + "transactionIndex": "Tx Index", + "transactions": "Transactions", + "transactionsAndEvents": "Transactions & Events", + "type": "Type", + "viewDetails": "View Details" +} \ No newline at end of file diff --git a/ui/client/src/views/Registries.tsx b/ui/client/src/views/Registries.tsx index 46ea0200c..150a43585 100644 --- a/ui/client/src/views/Registries.tsx +++ b/ui/client/src/views/Registries.tsx @@ -21,13 +21,12 @@ import { useContext } from "react"; import { Registry } from "../components/Registry"; import { ApplicationContext } from "../contexts/ApplicationContext"; import { fetchRegistries } from "../queries/registry"; -import { altDarkModeScrollbarStyle, altLightModeScrollbarStyle } from "../themes/default"; +import { getAltModeScrollBarStyle } from "../themes/default"; export const Registries: React.FC = () => { const { lastBlockWithTransactions, autoRefreshEnabled } = useContext(ApplicationContext); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; const { data: registries, error, isFetching } = useQuery({ queryKey: ["registries", autoRefreshEnabled, lastBlockWithTransactions], @@ -59,7 +58,7 @@ export const Registries: React.FC = () => { sx={{ paddingRight: '15px', height: "calc(100vh - 170px)", - ...addedStyle + ...getAltModeScrollBarStyle(theme.palette.mode) }} > {registries?.map((registry) => ( diff --git a/ui/client/src/views/Submissions.tsx b/ui/client/src/views/Submissions.tsx index 8d4a8ca08..7ac34d873 100644 --- a/ui/client/src/views/Submissions.tsx +++ b/ui/client/src/views/Submissions.tsx @@ -21,7 +21,7 @@ import { useContext, useState } from "react"; import { PaladinTransaction } from "../components/PaladinTransaction"; import { ApplicationContext } from "../contexts/ApplicationContext"; import { fetchSubmissions } from "../queries/transactions"; -import { altLightModeScrollbarStyle, altDarkModeScrollbarStyle } from "../themes/default"; +import { getAltModeScrollBarStyle } from "../themes/default"; import InfiniteScroll from "react-infinite-scroll-component"; import { IPaladinTransaction } from "../interfaces"; @@ -30,13 +30,12 @@ export const Submissions: React.FC = () => { const [tab, setTab] = useState<'all' | 'pending'>('all'); const theme = useTheme(); - const addedStyle = theme.palette.mode === 'light' ? altLightModeScrollbarStyle : altDarkModeScrollbarStyle; const { data: transactions, fetchNextPage, hasNextPage, error } = useInfiniteQuery({ queryKey: ["submissions", tab, lastBlockWithTransactions], queryFn: ({ pageParam }) => fetchSubmissions(tab, pageParam), initialPageParam: undefined as IPaladinTransaction | undefined, - getNextPageParam: (lastPage) => { return lastPage[lastPage.length - 1] }, + getNextPageParam: (lastPage) => { return lastPage.length > 0? lastPage[lastPage.length - 1] : undefined }, }); if (error) { @@ -68,7 +67,7 @@ export const Submissions: React.FC = () => { sx={{ paddingRight: "15px", height: "calc(100vh - 178px)", - ...addedStyle + ...getAltModeScrollBarStyle(theme.palette.mode) }} >