-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#68 Add summaries of the last 6 inputs and the last 6 applications on…
… home page (#81) Co-authored-by: Neven Diulgerov <[email protected]> Co-authored-by: Bruno Menezes <[email protected]>
- Loading branch information
1 parent
25cdd72
commit a59614e
Showing
17 changed files
with
731 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
"use client"; | ||
|
||
import type { FC } from "react"; | ||
import PageError from "../../components/pageError"; | ||
|
||
interface PageErrorProps { | ||
reset: () => void; | ||
} | ||
|
||
const Error: FC<PageErrorProps> = ({ reset }) => <PageError reset={reset} />; | ||
|
||
export default Error; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import PageLoader from "../../components/pageLoader"; | ||
|
||
export default function Loading() { | ||
return <PageLoader />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Group, Stack, Title } from "@mantine/core"; | ||
import { TbInbox } from "react-icons/tb"; | ||
import { Metadata } from "next"; | ||
import Inputs from "../../components/inputs"; | ||
import Breadcrumbs from "../../components/breadcrumbs"; | ||
|
||
export const metadata: Metadata = { | ||
title: "Inputs", | ||
}; | ||
|
||
export default function InputsPage() { | ||
return ( | ||
<Stack> | ||
<Breadcrumbs | ||
breadcrumbs={[ | ||
{ | ||
href: "/", | ||
label: "Home", | ||
}, | ||
]} | ||
/> | ||
|
||
<Group> | ||
<TbInbox size={40} /> | ||
<Title order={2}>Inputs</Title> | ||
</Group> | ||
|
||
<Inputs /> | ||
</Stack> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
"use client"; | ||
import { Card } from "@cartesi/rollups-explorer-ui"; | ||
import { Button, Grid, Group, Text, useMantineTheme } from "@mantine/core"; | ||
import type { FC } from "react"; | ||
import Link from "next/link"; | ||
import { TbApps, TbInbox } from "react-icons/tb"; | ||
import LatestEntriesTable, { Entry } from "./latestEntriesTable"; | ||
import { | ||
ApplicationOrderByInput, | ||
InputOrderByInput, | ||
useApplicationsConnectionQuery, | ||
useInputsQuery, | ||
} from "../graphql"; | ||
import type { Address as AddressType } from "abitype/dist/types/abi"; | ||
import { IconType } from "react-icons"; | ||
import { useMediaQuery } from "@mantine/hooks"; | ||
|
||
interface LatestEntriesCard { | ||
title: string; | ||
Icon: IconType; | ||
entries: Entry[]; | ||
fetching: boolean; | ||
totalCount: number; | ||
viewAllText: string; | ||
viewAllHref: string; | ||
} | ||
|
||
export const LatestEntriesCard: FC<LatestEntriesCard> = (props) => { | ||
const { | ||
title, | ||
Icon, | ||
entries, | ||
fetching, | ||
totalCount, | ||
viewAllText, | ||
viewAllHref, | ||
} = props; | ||
const theme = useMantineTheme(); | ||
const isSmallDevice = useMediaQuery(`(max-width:${theme.breakpoints.sm})`); | ||
|
||
return ( | ||
<Card h="100%"> | ||
<Group gap={5} align="center"> | ||
<Icon size={20} /> | ||
<Text c="dimmed" lh={1}> | ||
{title} | ||
</Text> | ||
</Group> | ||
|
||
<Group gap={5}> | ||
<LatestEntriesTable | ||
entries={entries} | ||
fetching={fetching} | ||
totalCount={totalCount} | ||
/> | ||
</Group> | ||
|
||
<Group gap={5} mt="auto"> | ||
<Button | ||
component={Link} | ||
href={viewAllHref} | ||
variant="light" | ||
fullWidth={isSmallDevice} | ||
mt="md" | ||
mx="auto" | ||
radius="md" | ||
tt="uppercase" | ||
> | ||
{viewAllText} | ||
</Button> | ||
</Group> | ||
</Card> | ||
); | ||
}; | ||
|
||
const LatestEntries: FC = () => { | ||
const [{ data: inputsData, fetching: isFetchingInputs }] = useInputsQuery({ | ||
variables: { | ||
orderBy: InputOrderByInput.TimestampDesc, | ||
limit: 6, | ||
}, | ||
}); | ||
const [{ data: applicationsData, fetching: isFetchingApplications }] = | ||
useApplicationsConnectionQuery({ | ||
variables: { | ||
orderBy: ApplicationOrderByInput.TimestampDesc, | ||
limit: 6, | ||
}, | ||
}); | ||
const inputs = | ||
inputsData?.inputsConnection.edges.map((edge) => ({ | ||
appId: edge.node.application.id as AddressType, | ||
timestamp: Number(edge.node.timestamp), | ||
href: `/applications/${edge.node.application.id}`, | ||
})) ?? []; | ||
const applications = | ||
applicationsData?.applicationsConnection.edges.map((edge) => ({ | ||
appId: edge.node.id as AddressType, | ||
timestamp: Number(edge.node.timestamp), | ||
href: `/applications/${edge.node.id}`, | ||
})) ?? []; | ||
|
||
return ( | ||
<Grid gutter="md"> | ||
<Grid.Col span={{ base: 12, md: 6 }} my="md"> | ||
<LatestEntriesCard | ||
title="Latest inputs" | ||
Icon={TbInbox} | ||
entries={inputs} | ||
fetching={isFetchingInputs} | ||
totalCount={inputsData?.inputsConnection.totalCount ?? 0} | ||
viewAllText="View all inputs" | ||
viewAllHref="/inputs" | ||
/> | ||
</Grid.Col> | ||
|
||
<Grid.Col span={{ base: 12, md: 6 }} my="md"> | ||
<LatestEntriesCard | ||
title="Latest applications" | ||
Icon={TbApps} | ||
entries={applications} | ||
fetching={isFetchingApplications} | ||
totalCount={ | ||
applicationsData?.applicationsConnection.totalCount ?? 0 | ||
} | ||
viewAllText="View all applications" | ||
viewAllHref="/applications" | ||
/> | ||
</Grid.Col> | ||
</Grid> | ||
); | ||
}; | ||
|
||
export default LatestEntries; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
"use client"; | ||
import { Button, Loader, Table, Text } from "@mantine/core"; | ||
import { FC, useCallback, useState } from "react"; | ||
import Address from "./address"; | ||
import type { Address as AddressType } from "abitype/dist/types/abi"; | ||
import prettyMilliseconds from "pretty-ms"; | ||
|
||
export interface Entry { | ||
appId: AddressType; | ||
timestamp: number; | ||
href: string; | ||
} | ||
|
||
export interface LatestEntriesTableProps { | ||
entries: Entry[]; | ||
fetching: boolean; | ||
totalCount: number; | ||
} | ||
|
||
const LatestEntriesTable: FC<LatestEntriesTableProps> = ({ | ||
entries, | ||
fetching, | ||
totalCount, | ||
}) => { | ||
const [timeType, setTimeType] = useState("age"); | ||
|
||
const onChangeTimeColumnType = useCallback(() => { | ||
setTimeType((timeType) => (timeType === "age" ? "timestamp" : "age")); | ||
}, []); | ||
|
||
return ( | ||
<Table> | ||
<Table.Thead> | ||
<Table.Tr> | ||
<Table.Th>Address</Table.Th> | ||
<Table.Th> | ||
<Button | ||
variant="transparent" | ||
px={0} | ||
onClick={onChangeTimeColumnType} | ||
> | ||
{timeType === "age" ? "Age" : "Timestamp (UTC)"} | ||
</Button> | ||
</Table.Th> | ||
</Table.Tr> | ||
</Table.Thead> | ||
<Table.Tbody> | ||
{fetching ? ( | ||
<Table.Tr> | ||
<Table.Td align="center" colSpan={2}> | ||
<Loader data-testid="inputs-table-spinner" /> | ||
</Table.Td> | ||
</Table.Tr> | ||
) : ( | ||
totalCount === 0 && ( | ||
<Table.Tr> | ||
<Table.Td colSpan={3} align="center"> | ||
No inputs | ||
</Table.Td> | ||
</Table.Tr> | ||
) | ||
)} | ||
{entries.map((entry) => ( | ||
<Table.Tr key={`${entry.appId}-${entry.timestamp}`}> | ||
<Table.Td> | ||
<Address | ||
value={entry.appId} | ||
icon | ||
shorten | ||
href={entry.href} | ||
/> | ||
</Table.Td> | ||
<Table.Td> | ||
<Text> | ||
{timeType === "age" | ||
? `${prettyMilliseconds( | ||
Date.now() - entry.timestamp * 1000, | ||
{ | ||
unitCount: 2, | ||
secondsDecimalDigits: 0, | ||
verbose: true, | ||
}, | ||
)} ago` | ||
: new Date( | ||
entry.timestamp * 1000, | ||
).toISOString()} | ||
</Text> | ||
</Table.Td> | ||
</Table.Tr> | ||
))} | ||
</Table.Tbody> | ||
</Table> | ||
); | ||
}; | ||
|
||
export default LatestEntriesTable; |
Oops, something went wrong.
a59614e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
rollups-explorer-workshop – ./apps/workshop
rollups-explorer-workshop.vercel.app
rollups-explorer-workshop-cartesi.vercel.app
rollups-explorer-workshop-git-main-cartesi.vercel.app
a59614e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
rollups-explorer-sepolia – ./apps/web
rollups-explorer-sepolia-cartesi.vercel.app
sepolia-rollups.vercel.app
rollups-explorer-sepolia-git-main-cartesi.vercel.app
sepolia.cartesiscan.io
rollups-explorer-sepolia.vercel.app