From fcec7547519af0ee765fb12492ad1a7665dcbdd2 Mon Sep 17 00:00:00 2001 From: Semen Loktionov Date: Tue, 7 Nov 2023 16:35:41 +0200 Subject: [PATCH 1/5] add oracles, tss pages --- codegen.ts | 2 +- package.json | 22 ++- src/app/[locale]/oracles/[address]/page.tsx | 37 ++++ src/app/[locale]/oracles/page.tsx | 16 ++ src/app/[locale]/tss/[address]/page.tsx | 31 ++++ src/app/[locale]/tss/page.tsx | 16 ++ src/callers/index.ts | 1 + src/callers/rarimocore.ts | 94 +++++++++++ .../HomeStatisticsRow.tsx => DataBox.tsx} | 6 +- src/components/Header/Header.tsx | 6 +- .../Header/HeaderBlockchainMenu.tsx | 87 +--------- src/components/Header/HeaderBridgeMenu.tsx | 16 ++ src/components/Header/HeaderDropdownMenu.tsx | 80 +++++++++ src/components/Home/HomeStatistics.tsx | 6 +- src/components/Navbar/Navbar.tsx | 6 +- src/components/Oracles/Oracle.tsx | 100 +++++++++++ src/components/Oracles/OracleStatus.tsx | 34 ++++ src/components/Oracles/Oracles.tsx | 111 ++++++++++++ src/components/Oracles/OraclesRow.tsx | 81 +++++++++ src/components/Oracles/index.tsx | 2 + src/components/OverviewTable.tsx | 2 +- src/components/Proposal/ProposalDetails.tsx | 6 +- src/components/TSS/TSSDetails.tsx | 97 +++++++++++ src/components/TSS/TSSList.tsx | 104 ++++++++++++ src/components/TSS/TSSListRow.tsx | 76 +++++++++ src/components/TSS/TSSState.tsx | 79 +++++++++ src/components/TSS/TSSStatus.tsx | 32 ++++ src/components/TSS/TSSs.tsx | 49 ++++++ src/components/TSS/index.ts | 2 + src/components/Transaction/Transaction.tsx | 25 ++- .../Validator/ValidatorDelegationListRow.tsx | 2 +- src/components/Validator/ValidatorDetails.tsx | 10 +- src/components/index.ts | 2 + src/graphql/fragments/Oracle.gql | 11 ++ src/graphql/fragments/OracleBase.gql | 6 + src/graphql/fragments/RarimocoreParams.gql | 6 + src/graphql/fragments/TSS.gql | 12 ++ src/graphql/fragments/TSSList.gql | 7 + src/graphql/generated.ts | 158 ++++++++++++++++++ src/graphql/queries/GetOracleBase.gql | 5 + src/graphql/queries/GetOracleByAddress.gql | 5 + src/graphql/queries/GetOracleCount.gql | 7 + src/graphql/queries/GetRarimocoreParams.gql | 5 + src/graphql/queries/GetTSSByAddress.gql | 5 + src/graphql/queries/GetTSSCount.gql | 7 + src/graphql/queries/GetTSSList.gql | 5 + src/hooks/useLocalize.ts | 6 +- src/locales/en.ts | 76 +++++++++ src/locales/localizers/index.ts | 2 + src/locales/localizers/oracle.ts | 12 ++ src/locales/localizers/tss.ts | 12 ++ src/types/routes.ts | 8 + yarn.lock | 20 +-- 53 files changed, 1491 insertions(+), 124 deletions(-) create mode 100644 src/app/[locale]/oracles/[address]/page.tsx create mode 100644 src/app/[locale]/oracles/page.tsx create mode 100644 src/app/[locale]/tss/[address]/page.tsx create mode 100644 src/app/[locale]/tss/page.tsx create mode 100644 src/callers/rarimocore.ts rename src/components/{Home/HomeStatisticsRow.tsx => DataBox.tsx} (96%) create mode 100644 src/components/Header/HeaderBridgeMenu.tsx create mode 100644 src/components/Header/HeaderDropdownMenu.tsx create mode 100644 src/components/Oracles/Oracle.tsx create mode 100644 src/components/Oracles/OracleStatus.tsx create mode 100644 src/components/Oracles/Oracles.tsx create mode 100644 src/components/Oracles/OraclesRow.tsx create mode 100644 src/components/Oracles/index.tsx create mode 100644 src/components/TSS/TSSDetails.tsx create mode 100644 src/components/TSS/TSSList.tsx create mode 100644 src/components/TSS/TSSListRow.tsx create mode 100644 src/components/TSS/TSSState.tsx create mode 100644 src/components/TSS/TSSStatus.tsx create mode 100644 src/components/TSS/TSSs.tsx create mode 100644 src/components/TSS/index.ts create mode 100644 src/graphql/fragments/Oracle.gql create mode 100644 src/graphql/fragments/OracleBase.gql create mode 100644 src/graphql/fragments/RarimocoreParams.gql create mode 100644 src/graphql/fragments/TSS.gql create mode 100644 src/graphql/fragments/TSSList.gql create mode 100644 src/graphql/queries/GetOracleBase.gql create mode 100644 src/graphql/queries/GetOracleByAddress.gql create mode 100644 src/graphql/queries/GetOracleCount.gql create mode 100644 src/graphql/queries/GetRarimocoreParams.gql create mode 100644 src/graphql/queries/GetTSSByAddress.gql create mode 100644 src/graphql/queries/GetTSSCount.gql create mode 100644 src/graphql/queries/GetTSSList.gql create mode 100644 src/locales/localizers/oracle.ts create mode 100644 src/locales/localizers/tss.ts diff --git a/codegen.ts b/codegen.ts index 759aa1c..42358aa 100644 --- a/codegen.ts +++ b/codegen.ts @@ -3,7 +3,7 @@ import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { overwrite: true, require: ['dotenv/config'], - schema: process.env.GRAPHQL_URL, + schema: process.env.NEXT_PUBLIC_GRAPHQL_URL, documents: ['src/**/*.gql'], generates: { 'src/graphql/generated.ts': { diff --git a/package.json b/package.json index ea924d1..496ef6f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lint:scripts": "next lint", "lint:styles": "stylelint \"src/**/*.{css,sass,scss}\" --max-warnings=0", "rsc": "node scripts/release-sanity-check.mjs", - "codegen-generate": "graphql-codegen --require dotenv/config --config codegen.ts dotenv_config_path=.env" + "codegen-generate": "graphql-codegen --require dotenv/config --config codegen.ts dotenv_config_path=.env.local" }, "dependencies": { "@apollo/client": "^3.7.17", @@ -72,5 +72,23 @@ "stylelint-scss": "^5.0.1", "yorkie": "^2.0.0" }, - "packageManager": "yarn@3.6.1" + "packageManager": "yarn@3.6.1", + "resolutions": { + "rarimo-js-sdk-monorepo-root": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk", + "@rarimo/auth-zkp-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/auth-zkp-iden3", + "@rarimo/bridge": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/bridge", + "@rarimo/client": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client", + "@rarimo/identity-gen-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/identity-gen-iden3", + "@rarimo/nft-checkout": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/nft-checkout", + "@rarimo/provider": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/provider", + "@rarimo/providers-evm": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-evm", + "@rarimo/providers-near": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-near", + "@rarimo/providers-solana": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-solana", + "@rarimo/react-nft-checkout": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/react-nft-checkout", + "@rarimo/react-provider": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/react-provider", + "@rarimo/shared": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared", + "@rarimo/shared-zkp-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared-zkp-iden3", + "@rarimo/swap": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/swap", + "@rarimo/zkp-gen-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/zkp-gen-iden3" + } } diff --git a/src/app/[locale]/oracles/[address]/page.tsx b/src/app/[locale]/oracles/[address]/page.tsx new file mode 100644 index 0000000..d2d7aea --- /dev/null +++ b/src/app/[locale]/oracles/[address]/page.tsx @@ -0,0 +1,37 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getOracleByAddress } from '@/callers' +import { getClient } from '@/client' +import { AccountTransactions, Oracle, PageContainer } from '@/components' +import { createMetadata } from '@/config' +import { OracleFragment } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getOracle = async (address: string) => { + return getServerSideProps(() => { + return getOracleByAddress(address) + }) +} + +export function generateMetadata({ params }: { params: { address: string } }): Metadata { + return createMetadata(`Oracle ${params.address} Details`) +} + +export default async function ProposalPage({ + params: { address }, +}: { + params: { address: string } +}) { + const { isNotFound } = await getOracle(address) + if (isNotFound) notFound() + + const account = await getClient().query.getAccount(address) + + return ( + + + + + ) +} diff --git a/src/app/[locale]/oracles/page.tsx b/src/app/[locale]/oracles/page.tsx new file mode 100644 index 0000000..527373f --- /dev/null +++ b/src/app/[locale]/oracles/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { Oracles, PageContainer } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata('Oracles') +} + +export default function OraclesPage() { + return ( + + + + ) +} diff --git a/src/app/[locale]/tss/[address]/page.tsx b/src/app/[locale]/tss/[address]/page.tsx new file mode 100644 index 0000000..7650296 --- /dev/null +++ b/src/app/[locale]/tss/[address]/page.tsx @@ -0,0 +1,31 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getTSSByAddress } from '@/callers' +import { getClient } from '@/client' +import { AccountTransactions, PageContainer, TSSDetails } from '@/components' +import { createMetadata } from '@/config' +import { TssFragment } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getTSS = (address: string) => { + return getServerSideProps(() => getTSSByAddress(address)) +} + +export function generateMetadata({ params }: { params: { address: string } }): Metadata { + return createMetadata(`TSS ${params.address} Details`) +} + +export default async function TSSPage({ params: { address } }: { params: { address: string } }) { + const { isNotFound } = await getTSS(address) + if (isNotFound) notFound() + + const account = await getClient().query.getAccount(address) + + return ( + + + + + ) +} diff --git a/src/app/[locale]/tss/page.tsx b/src/app/[locale]/tss/page.tsx new file mode 100644 index 0000000..d2ca759 --- /dev/null +++ b/src/app/[locale]/tss/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { PageContainer, TSSs } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata('TSS') +} + +export default function TSSPage() { + return ( + + + + ) +} diff --git a/src/callers/index.ts b/src/callers/index.ts index 43d9d69..791a2c5 100644 --- a/src/callers/index.ts +++ b/src/callers/index.ts @@ -1,5 +1,6 @@ export * from './block' export * from './proposal' +export * from './rarimocore' export * from './stats' export * from './tx' export * from './validators' diff --git a/src/callers/rarimocore.ts b/src/callers/rarimocore.ts new file mode 100644 index 0000000..2025520 --- /dev/null +++ b/src/callers/rarimocore.ts @@ -0,0 +1,94 @@ +import { CONFIG } from '@/config' +import { + apolloClient, + GetOracleBase, + GetOracleBaseQuery, + GetOracleByAddress, + GetOracleByAddressQuery, + GetOracleCount, + GetOracleCountQuery, + GetRarimocoreParams, + GetRarimocoreParamsQuery, + GetTssByAddress, + GetTssByAddressQuery, + GetTssCount, + GetTssCountQuery, + GetTssList, + GetTssListQuery, + OracleBaseFragment, + OracleFragment, + TssFragment, + TssListFragment, +} from '@/graphql' + +export const getRarimocoreParams = async () => { + const { data } = await apolloClient.query({ + query: GetRarimocoreParams, + fetchPolicy: 'network-only', + }) + return data +} + +export const getTSSList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, +): Promise => { + const { data } = await apolloClient.query({ + query: GetTssList, + fetchPolicy: 'network-only', + variables: { limit, offset }, + }) + + return data?.parties ?? [] +} + +export const getTSSCount = async (): Promise => { + const { data } = await apolloClient.query({ + query: GetTssCount, + fetchPolicy: 'network-only', + }) + + return data?.parties_aggregate.aggregate?.count ?? 0 +} + +export const getTSSByAddress = async (address: string): Promise => { + const { data } = await apolloClient.query({ + query: GetTssByAddress, + fetchPolicy: 'network-only', + variables: { address }, + }) + + return data?.parties?.[0] as TssFragment +} + +export const getOracleList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, +): Promise => { + const { data } = await apolloClient.query({ + query: GetOracleBase, + fetchPolicy: 'network-only', + variables: { limit, offset }, + }) + + return data?.oracle ?? [] +} + +export const getOracleCount = async (): Promise => { + const { data } = await apolloClient.query({ + query: GetOracleCount, + fetchPolicy: 'network-only', + }) + + return data?.oracle_aggregate.aggregate?.count ?? 0 +} + +export const getOracleByAddress = async (address: string): Promise => { + const { data } = await apolloClient.query({ + query: GetOracleByAddress, + fetchPolicy: 'network-only', + variables: { address }, + }) + + return data?.oracle?.[0] as OracleFragment +} diff --git a/src/components/Home/HomeStatisticsRow.tsx b/src/components/DataBox.tsx similarity index 96% rename from src/components/Home/HomeStatisticsRow.tsx rename to src/components/DataBox.tsx index 5610b7d..1885754 100644 --- a/src/components/Home/HomeStatisticsRow.tsx +++ b/src/components/DataBox.tsx @@ -4,7 +4,7 @@ import { ReactNode, useMemo } from 'react' import { FlexboxDirection } from '@/types' -interface HomeStatisticsBoxProps { +interface DataBoxProps { direction?: 'vertical' | 'horizontal' isLoading: boolean header: { @@ -22,12 +22,12 @@ const sx = { wordBreak: 'break-word', } -export default function HomeStatisticsRow({ +export default function DataBox({ isLoading, header, footer, direction = 'vertical', -}: HomeStatisticsBoxProps) { +}: DataBoxProps) { const theme = useTheme() const isVertical = useMemo(() => direction === 'vertical', [direction]) diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 1703456..f00a15b 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -9,6 +9,7 @@ import { usePathname } from 'next/navigation' import React, { useContext, useEffect, useMemo, useState } from 'react' import HeaderBlockchainMenu from '@/components/Header/HeaderBlockchainMenu' +import HeaderBridgeMenu from '@/components/Header/HeaderBridgeMenu' import HeaderNetworkSwitcher from '@/components/Header/HeaderNetworkSwitcher' import Logo from '@/components/Logo' import Search from '@/components/Search' @@ -111,8 +112,9 @@ export default function Header() { flex={1} sx={{ ml: { xs: 0, md: 6 } }} > - + + diff --git a/src/components/Header/HeaderBlockchainMenu.tsx b/src/components/Header/HeaderBlockchainMenu.tsx index ffab8cc..f9a4bd2 100644 --- a/src/components/Header/HeaderBlockchainMenu.tsx +++ b/src/components/Header/HeaderBlockchainMenu.tsx @@ -1,42 +1,9 @@ -import { MenuItem, SelectChangeEvent, Stack } from '@mui/material' -import { usePathname, useRouter } from 'next/navigation' -import { useEffect, useState } from 'react' - -import MouseOverDropdown from '@/components/MouseOverDropdown' -import { Bus } from '@/helpers' +import { HeaderBridgeMenuProps, HeaderDropdownMenu } from '@/components/Header/HeaderDropdownMenu' import { useI18n } from '@/locales/client' import { RoutePaths } from '@/types' -type AvailableRoutes = - | RoutePaths.Validators - | RoutePaths.Proposals - | RoutePaths.Transactions - | RoutePaths.Blocks - -const AVAILABLE_ROUTES: AvailableRoutes[] = [ - RoutePaths.Validators, - RoutePaths.Proposals, - RoutePaths.Transactions, - RoutePaths.Blocks, -] - -export default function HeaderBlockchainMenu({ - displayXs = false, - onClick, -}: { - displayXs?: boolean - onClick?: () => void -}) { - const router = useRouter() - const pathname = usePathname() +export default function HeaderBlockchainMenu(props: Omit) { const t = useI18n() - const [route, setRoute] = useState('' as AvailableRoutes) - - const handleChange = (event: SelectChangeEvent) => { - if (!event.target.value) return - setRoute(event.target.value as AvailableRoutes) - router.push(event.target.value) - } const itemList = [ { label: t('header-blockchain-menu.menu-lbl'), href: '' }, @@ -46,53 +13,5 @@ export default function HeaderBlockchainMenu({ { label: t('header-blockchain-menu.blocks-lbl'), href: RoutePaths.Blocks }, ] - Bus.on(Bus.eventList.redirectToHome, () => { - if (String(route) === '') return - setRoute('' as AvailableRoutes) - }) - - useEffect(() => { - if (![...AVAILABLE_ROUTES, ''].includes(pathname as AvailableRoutes)) return - setRoute((pathname ?? '') as AvailableRoutes) - }, [pathname]) - - useEffect(() => { - AVAILABLE_ROUTES.forEach(route => { - if (pathname.startsWith(route)) setRoute(route as AvailableRoutes) - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - return ( - - - {itemList.map((item, idx) => ( - { - onClick?.() - if (route === item.href) router.push(item.href) - }} - > - {item.label} - - ))} - - - ) + return } diff --git a/src/components/Header/HeaderBridgeMenu.tsx b/src/components/Header/HeaderBridgeMenu.tsx new file mode 100644 index 0000000..26d6998 --- /dev/null +++ b/src/components/Header/HeaderBridgeMenu.tsx @@ -0,0 +1,16 @@ +import { useI18n } from '@/locales/client' +import { RoutePaths } from '@/types' + +import { HeaderBridgeMenuProps, HeaderDropdownMenu } from './HeaderDropdownMenu' + +export default function HeaderBridgeMenu(props: Omit) { + const t = useI18n() + + const itemList = [ + { label: t('header-bridge-menu.menu-lbl'), href: '' }, + { label: t('header-bridge-menu.tss-lbl'), href: RoutePaths.TSSs }, + { label: t('header-bridge-menu.oracles-lbl'), href: RoutePaths.Oracles }, + ] + + return +} diff --git a/src/components/Header/HeaderDropdownMenu.tsx b/src/components/Header/HeaderDropdownMenu.tsx new file mode 100644 index 0000000..cf1eaea --- /dev/null +++ b/src/components/Header/HeaderDropdownMenu.tsx @@ -0,0 +1,80 @@ +import { MenuItem, SelectChangeEvent, Stack } from '@mui/material' +import { usePathname, useRouter } from 'next/navigation' +import { useEffect, useMemo, useState } from 'react' + +import MouseOverDropdown from '@/components/MouseOverDropdown' +import { Bus } from '@/helpers' +import { RoutePaths } from '@/types' + +export type HeaderBridgeMenuProps = { + displayXs?: boolean + onClick?: () => void + items: { label: string; href: string }[] +} + +export function HeaderDropdownMenu({ displayXs = false, onClick, items }: HeaderBridgeMenuProps) { + const router = useRouter() + const pathname = usePathname() + const [route, setRoute] = useState('' as RoutePaths) + + const availableRoutes = useMemo(() => items.map(item => item.href), [items]) + + const handleChange = (event: SelectChangeEvent) => { + if (!event.target.value) return + setRoute(event.target.value as RoutePaths) + router.push(event.target.value) + } + + Bus.on(Bus.eventList.redirectToHome, () => { + if (String(route) === '') return + setRoute('' as RoutePaths) + }) + + useEffect(() => { + if (!availableRoutes.includes(pathname as RoutePaths)) { + setRoute('' as RoutePaths) + return + } + setRoute((pathname ?? '') as RoutePaths) + }, [availableRoutes, pathname]) + + useEffect(() => { + availableRoutes.forEach(route => { + if (pathname.startsWith(route)) setRoute(route as RoutePaths) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + + + {items.map((item, idx) => ( + { + onClick?.() + if (route === item.href) router.push(item.href) + }} + > + {item.label} + + ))} + + + ) +} diff --git a/src/components/Home/HomeStatistics.tsx b/src/components/Home/HomeStatistics.tsx index c991cf8..bab7d25 100644 --- a/src/components/Home/HomeStatistics.tsx +++ b/src/components/Home/HomeStatistics.tsx @@ -4,7 +4,7 @@ import { Stack, Typography, useTheme } from '@mui/material' import { getStatisticData } from '@/callers' import ContentSection from '@/components/Content/ContentSection' -import HomeStatisticsRow from '@/components/Home/HomeStatisticsRow' +import DataBox from '@/components/DataBox' import { CONFIG } from '@/config' import { GetStatisticQuery } from '@/graphql' import { formatCurrency, formatSeconds } from '@/helpers' @@ -31,7 +31,7 @@ export default function HomeStatistics() { justifyContent={'space-between'} flex={'1'} > - - {menuToolbar} - + + + + ({} as OracleFragment, () => getOracleByAddress(address)) + + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('oracle.account-col-lbl'), + body: withSkeleton( + + + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('oracle.chain-col-lbl'), + body: withSkeleton( + + {oracle?.chain} + , + TABLE_SMALL_TEXT_SKELETON_SX, + ), + }, + { + head: t('oracle.status-col-lbl'), + body: withSkeleton( + , + TABLE_TYPE_BOX_SKELETON_SX, + ), + }, + { + head: t('oracle.stake-col-lbl'), + body: withSkeleton(formatCurrencyWithDenom(oracle?.stake), TABLE_MEDIUM_TEXT_SKELETON_SX), + }, + { + head: t('oracle.violations-col-lbl'), + body: withSkeleton(oracle?.violations_count, TABLE_SMALL_TEXT_SKELETON_SX), + }, + { + head: t('oracle.missed-col-lbl'), + body: withSkeleton(oracle?.missed_count, TABLE_SMALL_TEXT_SKELETON_SX), + }, + { + head: t('oracle.votes-col-lbl'), + body: withSkeleton(oracle?.votes_count, TABLE_SMALL_TEXT_SKELETON_SX), + }, + { + head: t('oracle.operations-col-lbl'), + body: withSkeleton(oracle?.create_operations_count, TABLE_SMALL_TEXT_SKELETON_SX), + }, + { + head: t('oracle.freeze-end-block-col-lbl'), + body: withSkeleton(oracle?.freeze_end_block, TABLE_SMALL_TEXT_SKELETON_SX), + }, + ] + + return ( + + + + + + + + ) +} diff --git a/src/components/Oracles/OracleStatus.tsx b/src/components/Oracles/OracleStatus.tsx new file mode 100644 index 0000000..ecd8e5c --- /dev/null +++ b/src/components/Oracles/OracleStatus.tsx @@ -0,0 +1,34 @@ +import { Chip } from '@mui/material' +import { OracleStatus as OracleStatusEnum, oracleStatusFromJSON } from '@rarimo/client' + +import { useLocalize } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function OracleStatus({ status }: { status?: string | number }) { + const t = useI18n() + const { localizeOracleStatus } = useLocalize() + + const getTSSStatusColor = (status?: string | number) => { + switch (oracleStatusFromJSON(status!)) { + case OracleStatusEnum.Inactive: + case OracleStatusEnum.Frozen: + return 'secondary' + case OracleStatusEnum.Active: + return 'primary' + case OracleStatusEnum.Slashed: + return 'error' + default: + return 'default' + } + } + + return ( + + ) +} diff --git a/src/components/Oracles/Oracles.tsx b/src/components/Oracles/Oracles.tsx new file mode 100644 index 0000000..ab28e50 --- /dev/null +++ b/src/components/Oracles/Oracles.tsx @@ -0,0 +1,111 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { getOracleCount, getOracleList } from '@/callers' +import TableWithPagination from '@/components/TableWithPagination' +import { OracleBaseFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' +import { TableColumn } from '@/types' + +import { ContentBox, ContentSection, ContentWrapper } from '../Content' +import OraclesRow from './OraclesRow' + +export enum OraclesColumnIds { + Account = 'account', + Chain = 'chain', + Stake = 'stake', + Status = 'status', +} + +export default function Oracles() { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingOracleCount, + isLoadingError: isLoadingOracleCountError, + } = useLoading(0, getOracleCount) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getOracleList(limit, offset), + { + loadArgs: [limit, offset], + }, + ) + + const columns: readonly TableColumn[] = [ + { + id: OraclesColumnIds.Account, + label: t('oracles.account-col-lbl'), + sx: { + minWidth: 260, + maxWidth: 260, + }, + }, + { + id: OraclesColumnIds.Chain, + label: t('oracles.chain-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 150, + }, + }, + { + id: OraclesColumnIds.Stake, + label: t('oracles.stake-col-lbl'), + sx: { + minWidth: 200, + maxWidth: 200, + }, + }, + { + id: OraclesColumnIds.Status, + label: t('oracles.status-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 150, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as OracleBaseFragment) : data).map( + (row, idx) => , + ) + + return ( + + + + + + + + ) +} diff --git a/src/components/Oracles/OraclesRow.tsx b/src/components/Oracles/OraclesRow.tsx new file mode 100644 index 0000000..9cb13ba --- /dev/null +++ b/src/components/Oracles/OraclesRow.tsx @@ -0,0 +1,81 @@ +import { Link as MuiLink, TableCell, TableRow } from '@mui/material' +import Link from 'next/link' + +import { OVERFLOW_SX } from '@/const' +import { OracleBaseFragment } from '@/graphql' +import { createColumnMap, formatCurrencyWithDenom, generatePath } from '@/helpers' +import { useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { OraclesColumnIds } from './Oracles' +import OracleStatus from './OracleStatus' + +export default function OraclesRow({ + oracle, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + oracle?: OracleBaseFragment + isLoading: boolean +}) { + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + return ( + + + {withSkeleton( + + {oracle?.account} + , + { width: '100%' }, + )} + + + + {withSkeleton(oracle?.chain, columnMap[OraclesColumnIds.Chain]?.sx)} + + + + {withSkeleton( + formatCurrencyWithDenom(oracle?.stake), + columnMap[OraclesColumnIds.Stake]?.sx, + )} + + + + {withSkeleton(, { + height: 32, + width: '100%', + })} + + + ) +} diff --git a/src/components/Oracles/index.tsx b/src/components/Oracles/index.tsx new file mode 100644 index 0000000..58fc5e9 --- /dev/null +++ b/src/components/Oracles/index.tsx @@ -0,0 +1,2 @@ +export { default as Oracle } from './Oracle' +export { default as Oracles } from './Oracles' diff --git a/src/components/OverviewTable.tsx b/src/components/OverviewTable.tsx index 86afe86..3b32e35 100644 --- a/src/components/OverviewTable.tsx +++ b/src/components/OverviewTable.tsx @@ -112,7 +112,7 @@ export default function OverviewTable({ sx={ sx || { '& > tr:last-child td, & > tr:last-child th': { - border: 0, + borderBottom: 'none!important', }, } } diff --git a/src/components/Proposal/ProposalDetails.tsx b/src/components/Proposal/ProposalDetails.tsx index c550d93..6151096 100644 --- a/src/components/Proposal/ProposalDetails.tsx +++ b/src/components/Proposal/ProposalDetails.tsx @@ -23,6 +23,8 @@ import { useProposalMetadata, useSkeleton } from '@/hooks' import { useI18n } from '@/locales/client' import { RoutePaths } from '@/types' +import CopyToClipboardWrapper from '../CopyToClipboardWrapper' + export default function ProposalDetails({ isLoading, isLoadingError, @@ -52,7 +54,9 @@ export default function ProposalDetails({ { head: t('proposal-details.proposer-account-id-lbl'), body: withSkeleton( - , + + + , TABLE_LARGE_SKELETON_SX, ), }, diff --git a/src/components/TSS/TSSDetails.tsx b/src/components/TSS/TSSDetails.tsx new file mode 100644 index 0000000..a4e6018 --- /dev/null +++ b/src/components/TSS/TSSDetails.tsx @@ -0,0 +1,97 @@ +'use client' + +import { getTSSByAddress } from '@/callers' +import { AvatarName } from '@/components/Avatar' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import CopyToClipboardWrapper from '@/components/CopyToClipboardWrapper' +import OverviewTable from '@/components/OverviewTable' +import TSSStatus from '@/components/TSS/TSSStatus' +import { + TABLE_BIG_SKELETON_SX, + TABLE_LARGE_SKELETON_SX, + TABLE_MEDIUM_TEXT_SKELETON_SX, + TABLE_SMALL_TEXT_SKELETON_SX, + TABLE_TYPE_BOX_SKELETON_SX, +} from '@/const' +import { TssFragment } from '@/graphql' +import { abbr } from '@/helpers' +import { useLoading, useSkeleton } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function TSSDetails({ address }: { address: string }) { + const t = useI18n() + + const { + data: tss, + isLoading, + isLoadingError, + isEmpty, + } = useLoading({} as TssFragment, () => getTSSByAddress(address)) + + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('tss-details.account-col-lbl'), + body: withSkeleton( + + + , + TABLE_LARGE_SKELETON_SX, + ), + }, + { + head: t('tss-details.delegator-col-lbl'), + body: withSkeleton( + + + , + TABLE_LARGE_SKELETON_SX, + ), + }, + { + head: t('tss-details.address-col-lbl'), + body: withSkeleton( + {tss?.address}, + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('tss-details.status-col-lbl'), + body: withSkeleton(, TABLE_TYPE_BOX_SKELETON_SX), + }, + { + head: t('tss-details.public-key-col-lbl'), + body: withSkeleton( + + {abbr(tss?.pub_key, 18, 24)} + , + TABLE_MEDIUM_TEXT_SKELETON_SX, + ), + }, + { + head: t('tss-details.violations-col-lbl'), + body: withSkeleton(tss?.violations_count, TABLE_SMALL_TEXT_SKELETON_SX), + }, + { + head: t('tss-details.freeze-end-block-col-lbl'), + body: withSkeleton(tss?.freeze_end_block, TABLE_SMALL_TEXT_SKELETON_SX), + }, + ] + + return ( + + + + + + + + ) +} diff --git a/src/components/TSS/TSSList.tsx b/src/components/TSS/TSSList.tsx new file mode 100644 index 0000000..5afd5f4 --- /dev/null +++ b/src/components/TSS/TSSList.tsx @@ -0,0 +1,104 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { ContentBox, ContentWrapper } from '@/components/Content' +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { TssListFragment } from '@/graphql' +import { useI18n } from '@/locales/client' +import { TableColumn, TableListProps } from '@/types' + +import TSSListRow from './TSSListRow' + +export enum TSSColumnIds { + Account = 'account', + Status = 'status', + Delegator = 'delegator', + Violations = 'violations', +} + +export default function TSSList({ + isLoading, + isLoadingError, + limit, + offset, + list, + count, + handleChangePage, + handleChangeRowsPerPage, + isMinHeighted = true, +}: TableListProps) { + const t = useI18n() + + const columns: readonly TableColumn[] = [ + { + id: TSSColumnIds.Account, + label: t('tss-list.account-col-lbl'), + sx: { + minWidth: 260, + maxWidth: 260, + }, + }, + { + id: TSSColumnIds.Delegator, + label: t('tss-list.delegator-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 260, + maxWidth: 260, + }, + }, + { + id: TSSColumnIds.Violations, + label: t('tss-list.violations-col-lbl'), + sx: { + minWidth: 80, + maxWidth: 80, + }, + }, + { + id: TSSColumnIds.Status, + label: t('tss-list.status-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 150, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as TssListFragment) : list).map((row, idx) => ( + + )) + + return ( + + + + + + ) +} diff --git a/src/components/TSS/TSSListRow.tsx b/src/components/TSS/TSSListRow.tsx new file mode 100644 index 0000000..9531337 --- /dev/null +++ b/src/components/TSS/TSSListRow.tsx @@ -0,0 +1,76 @@ +'use client' + +import { Link as MuiLink, TableCell, TableRow } from '@mui/material' +import Link from 'next/link' + +import { AvatarName } from '@/components/Avatar' +import { OVERFLOW_SX } from '@/const' +import { TssListFragment } from '@/graphql' +import { createColumnMap, generatePath } from '@/helpers' +import { useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { TSSColumnIds } from './TSSList' +import TSSStatus from './TSSStatus' + +export default function TSSListRow({ + tss, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + tss?: TssListFragment + isLoading: boolean +}) { + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + return ( + + + {withSkeleton( + + {tss?.account} + , + columnMap[TSSColumnIds.Account]?.sx, + )} + + + + {withSkeleton( + , + { + width: '100%', + }, + )} + + + + {withSkeleton(tss?.violations_count, { width: 80 })} + + + + {withSkeleton(, { + height: 32, + width: '100%', + })} + + + ) +} diff --git a/src/components/TSS/TSSState.tsx b/src/components/TSS/TSSState.tsx new file mode 100644 index 0000000..e268d71 --- /dev/null +++ b/src/components/TSS/TSSState.tsx @@ -0,0 +1,79 @@ +import { Stack, Typography } from '@mui/material' +import { useMemo } from 'react' + +import { getRarimocoreParams } from '@/callers' +import DataBox from '@/components/DataBox' +import { CONFIG } from '@/config' +import { GetRarimocoreParamsQuery } from '@/graphql' +import { useInterval, useLoading } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function TSSState() { + const t = useI18n() + + const { data, isLoading, isLoadingError, update } = useLoading( + {} as GetRarimocoreParamsQuery, + getRarimocoreParams, + ) + + useInterval(update, CONFIG.UPDATE_INTERVAL) + + const isUpdateRequired = useMemo( + () => + data?.rarimocore_params?.[0]?.is_update_required + ? t('tss-state.is-update-required-yes-lbl') + : t('tss-state.is-update-required-no-lbl'), + [data?.rarimocore_params, t], + ) + + return ( + + {!isLoadingError && ( + + + + + {data?.rarimocore_params?.[0]?.key_ecdsa} + + ), + }} + isLoading={isLoading} + /> + + + )} + + ) +} diff --git a/src/components/TSS/TSSStatus.tsx b/src/components/TSS/TSSStatus.tsx new file mode 100644 index 0000000..c3c5d11 --- /dev/null +++ b/src/components/TSS/TSSStatus.tsx @@ -0,0 +1,32 @@ +import { Chip } from '@mui/material' +import { PartyStatus as PartyStatusEnum, partyStatusFromJSON } from '@rarimo/client' + +import { useLocalize } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function TSSStatus({ status }: { status?: string | number }) { + const t = useI18n() + const { localizeTSSStatus } = useLocalize() + + const getTSSStatusColor = (status?: string | number) => { + switch (partyStatusFromJSON(status!)) { + case PartyStatusEnum.Inactive: + case PartyStatusEnum.Frozen: + return 'secondary' + case PartyStatusEnum.Active: + return 'primary' + case PartyStatusEnum.Slashed: + return 'error' + default: + return 'default' + } + } + + return ( + + ) +} diff --git a/src/components/TSS/TSSs.tsx b/src/components/TSS/TSSs.tsx new file mode 100644 index 0000000..d0c3b02 --- /dev/null +++ b/src/components/TSS/TSSs.tsx @@ -0,0 +1,49 @@ +'use client' + +import { Stack } from '@mui/material' + +import { getTSSCount, getTSSList } from '@/callers' +import { ContentSection } from '@/components/Content' +import TSSList from '@/components/TSS/TSSList' +import TSSState from '@/components/TSS/TSSState' +import { TssListFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function TSSs() { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: tssCount, + isLoading: isLoadingTSSCount, + isLoadingError: isLoadingTSSCountError, + } = useLoading(0, getTSSCount) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getTSSList(limit, offset), + { + loadArgs: [limit, offset], + }, + ) + + return ( + + + + + + + ) +} diff --git a/src/components/TSS/index.ts b/src/components/TSS/index.ts new file mode 100644 index 0000000..3eaf00f --- /dev/null +++ b/src/components/TSS/index.ts @@ -0,0 +1,2 @@ +export { default as TSSDetails } from './TSSDetails' +export { default as TSSs } from './TSSs' diff --git a/src/components/Transaction/Transaction.tsx b/src/components/Transaction/Transaction.tsx index 5ed9503..b32c15a 100644 --- a/src/components/Transaction/Transaction.tsx +++ b/src/components/Transaction/Transaction.tsx @@ -3,6 +3,7 @@ import { time } from '@distributedlab/tools' import { Chip, Link as MuiLink } from '@mui/material' import Link from 'next/link' +import { useMemo } from 'react' import { getTransactionByHash } from '@/callers' import { AvatarName } from '@/components/Avatar' @@ -40,6 +41,8 @@ export default function Transaction({ hash }: { hash: string }) { const withSkeleton = useSkeleton(isLoading) + const address = useMemo(() => parseAddress(transaction), [transaction]) + const rows = [ { head: t('transaction-details.hash-lbl'), @@ -60,14 +63,16 @@ export default function Transaction({ hash }: { hash: string }) { { head: t('transaction-details.block-lbl'), body: withSkeleton( - - {transaction?.height} - , + + + {transaction?.height} + + , TABLE_MEDIUM_TEXT_SKELETON_SX, ), }, @@ -81,7 +86,9 @@ export default function Transaction({ hash }: { hash: string }) { { head: t('transaction-details.sender-lbl'), body: withSkeleton( - , + + + , TABLE_LARGE_SKELETON_SX, ), }, diff --git a/src/components/Validator/ValidatorDelegationListRow.tsx b/src/components/Validator/ValidatorDelegationListRow.tsx index 16d3615..62da119 100644 --- a/src/components/Validator/ValidatorDelegationListRow.tsx +++ b/src/components/Validator/ValidatorDelegationListRow.tsx @@ -31,7 +31,7 @@ export default function ValidatorDelegationListRow({ {withSkeleton( formatCurrencyWithDenom(delegation?.coins?.[0]?.amount), - columnMap[ValidatorDelagationListColumnIds.Address]?.sx, + columnMap[ValidatorDelagationListColumnIds.Amount]?.sx, )} diff --git a/src/components/Validator/ValidatorDetails.tsx b/src/components/Validator/ValidatorDetails.tsx index 280654f..d28b30f 100644 --- a/src/components/Validator/ValidatorDetails.tsx +++ b/src/components/Validator/ValidatorDetails.tsx @@ -113,10 +113,12 @@ export default function ValidatorDetails({ { head: t('validator-details.validator-address-lbl'), body: withSkeleton( - , + + + , TABLE_TYPE_BOX_SKELETON_SX, ), }, diff --git a/src/components/index.ts b/src/components/index.ts index 04887f2..7269585 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -5,6 +5,8 @@ export * from './Transaction' export * from './Block' export * from './Proposal' export * from './Validator' +export * from './TSS' +export * from './Oracles' export { default as Avatar } from './Avatar/Avatar' export { default as AvatarName } from './Avatar/AvatarName' diff --git a/src/graphql/fragments/Oracle.gql b/src/graphql/fragments/Oracle.gql new file mode 100644 index 0000000..205483b --- /dev/null +++ b/src/graphql/fragments/Oracle.gql @@ -0,0 +1,11 @@ +fragment Oracle on oracle { + account + chain + status + stake + missed_count + freeze_end_block + violations_count + votes_count + create_operations_count +} diff --git a/src/graphql/fragments/OracleBase.gql b/src/graphql/fragments/OracleBase.gql new file mode 100644 index 0000000..b023f97 --- /dev/null +++ b/src/graphql/fragments/OracleBase.gql @@ -0,0 +1,6 @@ +fragment OracleBase on oracle { + account + chain + status + stake +} diff --git a/src/graphql/fragments/RarimocoreParams.gql b/src/graphql/fragments/RarimocoreParams.gql new file mode 100644 index 0000000..3143135 --- /dev/null +++ b/src/graphql/fragments/RarimocoreParams.gql @@ -0,0 +1,6 @@ +fragment RarimocoreParams on rarimocore_params { + is_update_required + key_ecdsa + threshold + max_violations_count +} diff --git a/src/graphql/fragments/TSS.gql b/src/graphql/fragments/TSS.gql new file mode 100644 index 0000000..7d0cbdd --- /dev/null +++ b/src/graphql/fragments/TSS.gql @@ -0,0 +1,12 @@ +fragment TSS on parties { + account + delegator + status + violations_count + address + committed_global_public_key + freeze_end_block + pub_key + reported_sessions +} + diff --git a/src/graphql/fragments/TSSList.gql b/src/graphql/fragments/TSSList.gql new file mode 100644 index 0000000..f1f1cce --- /dev/null +++ b/src/graphql/fragments/TSSList.gql @@ -0,0 +1,7 @@ +fragment TSSList on parties { + account + delegator + status + violations_count +} + diff --git a/src/graphql/generated.ts b/src/graphql/generated.ts index cdd4f8b..8e4a477 100644 --- a/src/graphql/generated.ts +++ b/src/graphql/generated.ts @@ -18461,6 +18461,10 @@ export type BlockBaseFragment = { __typename?: 'block', height: any, timestamp: export type BlockListFragment = { __typename?: 'block', height: any, timestamp: any, total_gas?: any | null, transactions_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', moniker?: string | null, avatar_url?: string | null }> } | null }; +export type OracleFragment = { __typename?: 'oracle', account: string, chain: string, status: number, stake: string, missed_count: number, freeze_end_block: number, violations_count: number, votes_count: number, create_operations_count: number }; + +export type OracleBaseFragment = { __typename?: 'oracle', account: string, chain: string, status: number, stake: string }; + export type ProposalFragment = { __typename?: 'proposal', content: any, deposit_end_block?: any | null, id: number, proposer_address: string, status?: string | null, submit_block: any, metadata: string, voting_end_block?: any | null, voting_start_block?: any | null, proposal_tally_result?: { __typename?: 'proposal_tally_result', abstain: string, no: string, no_with_veto: string, yes: string } | null }; export type ProposalBaseFragment = { __typename?: 'proposal', id: number, proposer_address: string, content: any, metadata: string, status?: string | null }; @@ -18469,10 +18473,16 @@ export type ProposalDepositFragment = { __typename?: 'proposal_deposit', amount? export type ProposalVoteFragment = { __typename?: 'proposal_vote', voter_address: string, option: string, height: any, block: { __typename?: 'block', timestamp: any, transactions: Array<{ __typename?: 'transaction', hash: string }> } }; +export type RarimocoreParamsFragment = { __typename?: 'rarimocore_params', is_update_required: boolean, key_ecdsa: string, threshold: any, max_violations_count?: number | null }; + export type SlashingParamsFragment = { __typename?: 'slashing_params', params: any }; export type StakingPoolFragment = { __typename?: 'staking_pool', bonded_tokens: string }; +export type TssFragment = { __typename?: 'parties', account: string, delegator?: string | null, status?: number | null, violations_count?: number | null, address: string, committed_global_public_key?: string | null, freeze_end_block?: number | null, pub_key: string, reported_sessions?: any | null }; + +export type TssListFragment = { __typename?: 'parties', account: string, delegator?: string | null, status?: number | null, violations_count?: number | null }; + export type TallyResultFragment = { __typename?: 'proposal_tally_result', abstain: string, no: string, no_with_veto: string, yes: string }; export type TransactionFragment = { __typename?: 'transaction', hash: string, success: boolean, fee: any, signer_infos: any, height: any, messages: any, gas_used?: any | null, raw_log?: string | null, block: { __typename?: 'block', timestamp: any, validator?: { __typename?: 'validator', validator_descriptions: Array<{ __typename?: 'validator_description', avatar_url?: string | null, moniker?: string | null }>, validator_info?: { __typename?: 'validator_info', operator_address: string } | null } | null } }; @@ -18523,6 +18533,26 @@ export type GetLatestTxAndBlocksQueryVariables = Exact<{ export type GetLatestTxAndBlocksQuery = { __typename?: 'query_root', transaction: Array<{ __typename?: 'transaction', height: any, hash: string, success: boolean, signer_infos: any, raw_log?: string | null, block: { __typename?: 'block', timestamp: any, height: any } }>, block: Array<{ __typename?: 'block', height: any, timestamp: any, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', avatar_url?: string | null, moniker?: string | null }> } | null }> }; +export type GetOracleBaseQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; +}>; + + +export type GetOracleBaseQuery = { __typename?: 'query_root', oracle: Array<{ __typename?: 'oracle', account: string, chain: string, status: number, stake: string }> }; + +export type GetOracleByAddressQueryVariables = Exact<{ + address: Scalars['String']['input']; +}>; + + +export type GetOracleByAddressQuery = { __typename?: 'query_root', oracle: Array<{ __typename?: 'oracle', account: string, chain: string, status: number, stake: string, missed_count: number, freeze_end_block: number, violations_count: number, votes_count: number, create_operations_count: number }> }; + +export type GetOracleCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetOracleCountQuery = { __typename?: 'query_root', oracle_aggregate: { __typename?: 'oracle_aggregate', aggregate?: { __typename?: 'oracle_aggregate_fields', count: number } | null } }; + export type GetProposalBaseQueryVariables = Exact<{ limit?: InputMaybe; offset?: InputMaybe; @@ -18575,11 +18605,36 @@ export type GetProposalVotesCountByIdQueryVariables = Exact<{ export type GetProposalVotesCountByIdQuery = { __typename?: 'query_root', proposal: Array<{ __typename?: 'proposal', proposal_votes_aggregate: { __typename?: 'proposal_vote_aggregate', aggregate?: { __typename?: 'proposal_vote_aggregate_fields', count: number } | null } }> }; +export type GetRarimocoreParamsQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetRarimocoreParamsQuery = { __typename?: 'query_root', rarimocore_params: Array<{ __typename?: 'rarimocore_params', is_update_required: boolean, key_ecdsa: string, threshold: any, max_violations_count?: number | null }> }; + export type GetStatisticQueryVariables = Exact<{ [key: string]: never; }>; export type GetStatisticQuery = { __typename?: 'query_root', block: Array<{ __typename?: 'block', timestamp: any, height: any }>, transaction_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, supply: Array<{ __typename?: 'supply', coins: any }>, averageBlockTime: Array<{ __typename?: 'average_block_time_per_minute', averageTime: any }> }; +export type GetTssByAddressQueryVariables = Exact<{ + address: Scalars['String']['input']; +}>; + + +export type GetTssByAddressQuery = { __typename?: 'query_root', parties: Array<{ __typename?: 'parties', account: string, delegator?: string | null, status?: number | null, violations_count?: number | null, address: string, committed_global_public_key?: string | null, freeze_end_block?: number | null, pub_key: string, reported_sessions?: any | null }> }; + +export type GetTssCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetTssCountQuery = { __typename?: 'query_root', parties_aggregate: { __typename?: 'parties_aggregate', aggregate?: { __typename?: 'parties_aggregate_fields', count: number } | null } }; + +export type GetTssListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; +}>; + + +export type GetTssListQuery = { __typename?: 'query_root', parties: Array<{ __typename?: 'parties', account: string, delegator?: string | null, status?: number | null, violations_count?: number | null }> }; + export type GetTransactionBaseQueryVariables = Exact<{ limit?: InputMaybe; offset?: InputMaybe; @@ -18747,6 +18802,27 @@ export const BlockList = gql` } } `; +export const Oracle = gql` + fragment Oracle on oracle { + account + chain + status + stake + missed_count + freeze_end_block + violations_count + votes_count + create_operations_count +} + `; +export const OracleBase = gql` + fragment OracleBase on oracle { + account + chain + status + stake +} + `; export const TallyResult = gql` fragment TallyResult on proposal_tally_result { abstain @@ -18807,6 +18883,14 @@ export const ProposalVote = gql` } } `; +export const RarimocoreParams = gql` + fragment RarimocoreParams on rarimocore_params { + is_update_required + key_ecdsa + threshold + max_violations_count +} + `; export const SlashingParams = gql` fragment SlashingParams on slashing_params { params @@ -18817,6 +18901,27 @@ export const StakingPool = gql` bonded_tokens } `; +export const Tss = gql` + fragment TSS on parties { + account + delegator + status + violations_count + address + committed_global_public_key + freeze_end_block + pub_key + reported_sessions +} + `; +export const TssList = gql` + fragment TSSList on parties { + account + delegator + status + violations_count +} + `; export const Transaction = gql` fragment Transaction on transaction { hash @@ -18974,6 +19079,29 @@ export const GetLatestTxAndBlocks = gql` } ${TransactionBase} ${BlockBase}`; +export const GetOracleBase = gql` + query GetOracleBase($limit: Int, $offset: Int) { + oracle(limit: $limit, offset: $offset) { + ...OracleBase + } +} + ${OracleBase}`; +export const GetOracleByAddress = gql` + query GetOracleByAddress($address: String!) { + oracle(where: {account: {_eq: $address}}) { + ...Oracle + } +} + ${Oracle}`; +export const GetOracleCount = gql` + query GetOracleCount { + oracle_aggregate { + aggregate { + count(columns: account) + } + } +} + `; export const GetProposalBase = gql` query GetProposalBase($limit: Int, $offset: Int) { proposal(limit: $limit, offset: $offset, order_by: {id: desc}) { @@ -19037,6 +19165,13 @@ export const GetProposalVotesCountById = gql` } } `; +export const GetRarimocoreParams = gql` + query GetRarimocoreParams { + rarimocore_params { + ...RarimocoreParams + } +} + ${RarimocoreParams}`; export const GetStatistic = gql` query GetStatistic { block(order_by: {height: desc}, limit: 1) { @@ -19059,6 +19194,29 @@ export const GetStatistic = gql` } } `; +export const GetTssByAddress = gql` + query GetTSSByAddress($address: String!) { + parties(where: {account: {_eq: $address}}) { + ...TSS + } +} + ${Tss}`; +export const GetTssCount = gql` + query GetTSSCount { + parties_aggregate { + aggregate { + count(columns: account) + } + } +} + `; +export const GetTssList = gql` + query GetTSSList($limit: Int, $offset: Int) { + parties(limit: $limit, offset: $offset) { + ...TSSList + } +} + ${TssList}`; export const GetTransactionBase = gql` query GetTransactionBase($limit: Int, $offset: Int) { transaction( diff --git a/src/graphql/queries/GetOracleBase.gql b/src/graphql/queries/GetOracleBase.gql new file mode 100644 index 0000000..6317442 --- /dev/null +++ b/src/graphql/queries/GetOracleBase.gql @@ -0,0 +1,5 @@ +query GetOracleBase($limit: Int, $offset: Int) { + oracle(limit: $limit, offset: $offset) { + ...OracleBase + } +} diff --git a/src/graphql/queries/GetOracleByAddress.gql b/src/graphql/queries/GetOracleByAddress.gql new file mode 100644 index 0000000..753eb02 --- /dev/null +++ b/src/graphql/queries/GetOracleByAddress.gql @@ -0,0 +1,5 @@ +query GetOracleByAddress($address: String!) { + oracle(where: {account: {_eq: $address}}) { + ...Oracle + } +} diff --git a/src/graphql/queries/GetOracleCount.gql b/src/graphql/queries/GetOracleCount.gql new file mode 100644 index 0000000..2e53083 --- /dev/null +++ b/src/graphql/queries/GetOracleCount.gql @@ -0,0 +1,7 @@ +query GetOracleCount { + oracle_aggregate { + aggregate { + count(columns: account) + } + } +} diff --git a/src/graphql/queries/GetRarimocoreParams.gql b/src/graphql/queries/GetRarimocoreParams.gql new file mode 100644 index 0000000..2c4fc41 --- /dev/null +++ b/src/graphql/queries/GetRarimocoreParams.gql @@ -0,0 +1,5 @@ +query GetRarimocoreParams { + rarimocore_params { + ...RarimocoreParams + } +} diff --git a/src/graphql/queries/GetTSSByAddress.gql b/src/graphql/queries/GetTSSByAddress.gql new file mode 100644 index 0000000..72d2d34 --- /dev/null +++ b/src/graphql/queries/GetTSSByAddress.gql @@ -0,0 +1,5 @@ +query GetTSSByAddress($address: String!) { + parties(where: {account: {_eq: $address}}) { + ...TSS + } +} diff --git a/src/graphql/queries/GetTSSCount.gql b/src/graphql/queries/GetTSSCount.gql new file mode 100644 index 0000000..b804dab --- /dev/null +++ b/src/graphql/queries/GetTSSCount.gql @@ -0,0 +1,7 @@ +query GetTSSCount { + parties_aggregate { + aggregate { + count(columns: account) + } + } +} diff --git a/src/graphql/queries/GetTSSList.gql b/src/graphql/queries/GetTSSList.gql new file mode 100644 index 0000000..008f654 --- /dev/null +++ b/src/graphql/queries/GetTSSList.gql @@ -0,0 +1,5 @@ +query GetTSSList($limit: Int, $offset: Int) { + parties(limit: $limit, offset: $offset) { + ...TSSList + } +} diff --git a/src/hooks/useLocalize.ts b/src/hooks/useLocalize.ts index 558079a..aa1b7ca 100644 --- a/src/hooks/useLocalize.ts +++ b/src/hooks/useLocalize.ts @@ -1,15 +1,17 @@ 'use client' -import { BondStatus, ProposalType } from '@rarimo/client' +import { BondStatus, OracleStatus, PartyStatus, ProposalType } from '@rarimo/client' import { AnyObject, Flags, Maybe, Schema } from 'yup' import { createYupInitFn } from '@/helpers' import { useI18n } from '@/locales/client' import { localizeMsgType, + localizeOracleStatus, localizeProposalStatus, localizeProposalType, localizeProposalVoteOption, + localizeTSSStatus, localizeValidatorStatus, } from '@/locales/localizers' @@ -36,6 +38,8 @@ export const useLocalize = () => { localizeProposalVoteOption: (option: unknown) => localizeProposalVoteOption(t, option), localizeProposalType: (type: ProposalType) => localizeProposalType(t, type), localizeMsgType: (type: string) => localizeMsgType(t, type), + localizeTSSStatus: (status: PartyStatus) => localizeTSSStatus(t, status), + localizeOracleStatus: (status: OracleStatus) => localizeOracleStatus(t, status), localizeValidatorStatus: (status: BondStatus, jailed: boolean) => localizeValidatorStatus(t, status, jailed), } diff --git a/src/locales/en.ts b/src/locales/en.ts index 1280586..a700903 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -45,6 +45,11 @@ export default { "validators-lbl": "Validators", "proposals-lbl": "Proposals", }, + "header-bridge-menu": { + "menu-lbl": "Bridge", + "tss-lbl": "TSS", + "oracles-lbl": "Oracles", + }, "footer": { "navigation-links-lbl": "Navigation", "documentation-lbl": "Documentation", @@ -475,4 +480,75 @@ export default { "delegator-lbl": "On behalf of", "tip-lbl": "Please select on behalf of which account you would like to withdraw delegator's rewards.", }, + "tsss": { + "table-lbl": "Threshold Signature Services", + }, + "tss-state": { + "threshold-lbl": "Threshold", + "is-update-required-lbl": "Update required", + "is-update-required-yes-lbl": "Yes", + "is-update-required-no-lbl": "No", + "public-key-lbl": "Public key", + "max-violation-count-lbl": "Max violations", + }, + "tss-list": { + "table-lbl": "Threshold Signature Services", + "account-col-lbl": "Account", + "status-col-lbl": "Status", + "delegator-col-lbl": "Delegator", + "violations-col-lbl": "Violations", + "no-data-title": "There are no TSS", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading TSS", + "error-subtitle": "Please try again later", + }, + "tss-status": { + "active-lbl": "Active", + "frozen-lbl": "Frozen", + "slashed-lbl": "Slashed", + "inactive-lbl": "Inactive", + "unrecognized-lbl": "Unrecognized", + }, + "tss-details": { + "account-col-lbl": "Account:", + "address-col-lbl": "Address:", + "status-col-lbl": "Status:", + "delegator-col-lbl": "Delegator:", + "violations-col-lbl": "Violations:", + "freeze-end-block-col-lbl": "Freeze end block:", + "public-key-col-lbl": "Public key:", + "title": "TSS Details", + "no-data-msg": "There is no TSS with such account address.", + }, + "oracles": { + "account-col-lbl": "Account", + "chain-col-lbl": "Chain", + "status-col-lbl": "Status", + "stake-col-lbl": "Stake", + "table-lbl": "Oracles", + "no-data-title": "There is no existing oracles", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading oracles", + "error-subtitle": "Please try again later", + }, + "oracle-status": { + "active-lbl": "Active", + "freezed-lbl": "Freezed", + "slashed-lbl": "Slashed", + "inactive-lbl": "Inactive", + "unrecognized-lbl": "Unrecognized", + }, + "oracle": { + "account-col-lbl": "Account:", + "chain-col-lbl": "Chain:", + "status-col-lbl": "Status:", + "stake-col-lbl": "Stake:", + "missed-col-lbl": "Missed:", + "votes-col-lbl": "Votes:", + "operations-col-lbl": "Created operations:", + "violations-col-lbl": "Violations:", + "freeze-end-block-col-lbl": "Freeze end block:", + "title": "Oracle Details", + "no-data-msg": "There is no Oracle with such account address.", + }, } as const diff --git a/src/locales/localizers/index.ts b/src/locales/localizers/index.ts index 414c252..1d17fea 100644 --- a/src/locales/localizers/index.ts +++ b/src/locales/localizers/index.ts @@ -1,5 +1,7 @@ export * from './msg-type' +export * from './oracle' export * from './proposal-status' export * from './proposal-type' export * from './proposal-vote-option' +export * from './tss' export * from './validator-status' diff --git a/src/locales/localizers/oracle.ts b/src/locales/localizers/oracle.ts new file mode 100644 index 0000000..ede599a --- /dev/null +++ b/src/locales/localizers/oracle.ts @@ -0,0 +1,12 @@ +import { OracleStatus } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeOracleStatus = (t: TFunction, status: OracleStatus) => + ({ + [OracleStatus.Active]: t('oracle-status.active-lbl'), + [OracleStatus.Freezed]: t('oracle-status.freezed-lbl'), + [OracleStatus.Slashed]: t('oracle-status.slashed-lbl'), + [OracleStatus.Inactive]: t('oracle-status.inactive-lbl'), + [OracleStatus.Unrecognized]: t('oracle-status.unrecognized-lbl'), + })[status] diff --git a/src/locales/localizers/tss.ts b/src/locales/localizers/tss.ts new file mode 100644 index 0000000..b5a08b9 --- /dev/null +++ b/src/locales/localizers/tss.ts @@ -0,0 +1,12 @@ +import { PartyStatus } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeTSSStatus = (t: TFunction, status: PartyStatus) => + ({ + [PartyStatus.Active]: t('tss-status.active-lbl'), + [PartyStatus.Frozen]: t('tss-status.frozen-lbl'), + [PartyStatus.Slashed]: t('tss-status.slashed-lbl'), + [PartyStatus.Inactive]: t('tss-status.inactive-lbl'), + [PartyStatus.Unrecognized]: t('tss-status.unrecognized-lbl'), + })[status] diff --git a/src/types/routes.ts b/src/types/routes.ts index 51ccdba..3e5fa21 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -1,5 +1,7 @@ export enum RoutePaths { Main = '/', + + // Blockchain Blocks = '/blocks', Block = '/blocks/[height]', Transactions = '/transactions', @@ -9,4 +11,10 @@ export enum RoutePaths { Account = '/accounts/[address]', Validators = '/validators', Validator = '/validators/[address]', + + // Bridge + TSSs = '/tss', + TSS = '/tss/[address]', + Oracles = '/oracles', + Oracle = '/oracles/[address]', } diff --git a/yarn.lock b/yarn.lock index 074aa02..790a06e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2489,29 +2489,27 @@ __metadata: languageName: node linkType: hard -"@rarimo/client@npm:^2.0.0-rc.28": - version: 2.0.0-rc.28 - resolution: "@rarimo/client@npm:2.0.0-rc.28" +"@rarimo/client@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client::locator=scan%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@rarimo/client@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client::locator=scan%40workspace%3A." dependencies: "@cosmjs/launchpad": ^0.27.1 "@cosmjs/proto-signing": ^0.31.0 "@cosmjs/stargate": ^0.31.0 "@distributedlab/fetcher": ^1.0.0-rc.6 "@distributedlab/reactivity": ^1.0.0-rc.6 - "@rarimo/shared": ^2.0.0-rc.28 - checksum: 456e2ecb40dfea6e4548bc7e2e27a6d95568035556c0c9cd196100b02f4cacd7e7c5a1d1b14630a70f387da1a491d85dd4433eff07e85449a66109898b94c6fa + "@rarimo/shared": "workspace:^" languageName: node - linkType: hard + linkType: soft -"@rarimo/shared@npm:^2.0.0-rc.28": - version: 2.0.0-rc.28 - resolution: "@rarimo/shared@npm:2.0.0-rc.28" +"@rarimo/shared@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared::locator=scan%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@rarimo/shared@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared::locator=scan%40workspace%3A." dependencies: "@distributedlab/jac": ^1.0.0-rc.6 "@distributedlab/tools": ^1.0.0-rc.6 - checksum: f06876af41b1dd2c9d85b89d67ed098e8296de16d2fa8abd8a704765a6e41d352884009d0b49af18b6ef0f329fe305787a8120563dd0fffcaa4cedbf86a06f8f languageName: node - linkType: hard + linkType: soft "@repeaterjs/repeater@npm:^3.0.4": version: 3.0.4 From 9b7c09b9fc504b0b1eb80f7d2a4785d64a00dc2d Mon Sep 17 00:00:00 2001 From: Semen Loktionov Date: Tue, 28 Nov 2023 17:47:48 +0200 Subject: [PATCH 2/5] add confirmations, operations --- .../[locale]/confirmations/[root]/page.tsx | 34 + src/app/[locale]/confirmations/page.tsx | 16 + src/app/[locale]/operations/[index]/page.tsx | 28 + src/app/[locale]/operations/page.tsx | 16 + src/app/[locale]/oracles/[address]/page.tsx | 6 +- src/app/[locale]/tss/page.tsx | 2 +- src/callers/confirmation.ts | 114 ++ src/callers/index.ts | 2 + src/callers/operation.ts | 76 + src/components/Confirmation/Confirmation.tsx | 111 ++ .../ConfirmationOperationVotes.tsx | 46 + .../Confirmation/ConfirmationOperations.tsx | 41 + .../Confirmation/ConfirmationRow.tsx | 101 ++ src/components/Confirmation/Confirmations.tsx | 126 ++ src/components/Confirmation/index.tsx | 4 + src/components/Header/HeaderBridgeMenu.tsx | 2 + src/components/Operation/Operation.tsx | 162 +++ .../Operation/OperationContentRow.tsx | 42 + src/components/Operation/OperationList.tsx | 111 ++ src/components/Operation/OperationListRow.tsx | 92 ++ src/components/Operation/OperationStatus.tsx | 33 + .../Operation/OperationVoteList.tsx | 112 ++ .../Operation/OperationVoteOption.tsx | 30 + src/components/Operation/OperationVotes.tsx | 45 + .../Operation/OperationVotesRow.tsx | 91 ++ src/components/Operation/Operations.tsx | 46 + src/components/Operation/index.tsx | 4 + src/components/Oracles/OracleStatus.tsx | 2 +- src/components/Proposal/ProposalVotes.tsx | 6 +- .../TSS/{TSSDetails.tsx => TSS.tsx} | 2 +- src/components/TSS/TSSList.tsx | 3 +- src/components/TSS/index.ts | 2 +- .../Validator/ValidatorRedelegationList.tsx | 2 +- src/components/index.ts | 2 + src/graphql/fragments/Confirmation.gql | 11 + src/graphql/fragments/ConfirmationBase.gql | 9 + src/graphql/fragments/Operation.gql | 7 + src/graphql/fragments/OperationVote.gql | 10 + src/graphql/generated.ts | 1285 ++++++++++++++--- src/graphql/queries/GetConfirmationByRoot.gql | 6 + src/graphql/queries/GetConfirmationCount.gql | 7 + src/graphql/queries/GetConfirmationList.gql | 5 + .../queries/GetConfirmationOperationList.gql | 5 + .../GetConfirmationOperationVoteCount.gql | 7 + .../GetConfirmationOperationVoteList.gql | 5 + src/graphql/queries/GetOperationByIndex.gql | 109 ++ src/graphql/queries/GetOperationCount.gql | 7 + src/graphql/queries/GetOperationList.gql | 5 + src/graphql/queries/GetOperationVoteCount.gql | 7 + src/graphql/queries/GetOperationVoteList.gql | 5 + src/hooks/useLocalize.ts | 16 +- src/locales/en.ts | 89 +- src/locales/localizers/index.ts | 3 + src/locales/localizers/msg-type.ts | 2 + src/locales/localizers/op-status.ts | 12 + src/locales/localizers/op-type.ts | 16 + src/locales/localizers/op-vote.ts | 10 + src/locales/localizers/oracle.ts | 1 + src/types/routes.ts | 4 + 59 files changed, 2941 insertions(+), 214 deletions(-) create mode 100644 src/app/[locale]/confirmations/[root]/page.tsx create mode 100644 src/app/[locale]/confirmations/page.tsx create mode 100644 src/app/[locale]/operations/[index]/page.tsx create mode 100644 src/app/[locale]/operations/page.tsx create mode 100644 src/callers/confirmation.ts create mode 100644 src/callers/operation.ts create mode 100644 src/components/Confirmation/Confirmation.tsx create mode 100644 src/components/Confirmation/ConfirmationOperationVotes.tsx create mode 100644 src/components/Confirmation/ConfirmationOperations.tsx create mode 100644 src/components/Confirmation/ConfirmationRow.tsx create mode 100644 src/components/Confirmation/Confirmations.tsx create mode 100644 src/components/Confirmation/index.tsx create mode 100644 src/components/Operation/Operation.tsx create mode 100644 src/components/Operation/OperationContentRow.tsx create mode 100644 src/components/Operation/OperationList.tsx create mode 100644 src/components/Operation/OperationListRow.tsx create mode 100644 src/components/Operation/OperationStatus.tsx create mode 100644 src/components/Operation/OperationVoteList.tsx create mode 100644 src/components/Operation/OperationVoteOption.tsx create mode 100644 src/components/Operation/OperationVotes.tsx create mode 100644 src/components/Operation/OperationVotesRow.tsx create mode 100644 src/components/Operation/Operations.tsx create mode 100644 src/components/Operation/index.tsx rename src/components/TSS/{TSSDetails.tsx => TSS.tsx} (97%) create mode 100644 src/graphql/fragments/Confirmation.gql create mode 100644 src/graphql/fragments/ConfirmationBase.gql create mode 100644 src/graphql/fragments/Operation.gql create mode 100644 src/graphql/fragments/OperationVote.gql create mode 100644 src/graphql/queries/GetConfirmationByRoot.gql create mode 100644 src/graphql/queries/GetConfirmationCount.gql create mode 100644 src/graphql/queries/GetConfirmationList.gql create mode 100644 src/graphql/queries/GetConfirmationOperationList.gql create mode 100644 src/graphql/queries/GetConfirmationOperationVoteCount.gql create mode 100644 src/graphql/queries/GetConfirmationOperationVoteList.gql create mode 100644 src/graphql/queries/GetOperationByIndex.gql create mode 100644 src/graphql/queries/GetOperationCount.gql create mode 100644 src/graphql/queries/GetOperationList.gql create mode 100644 src/graphql/queries/GetOperationVoteCount.gql create mode 100644 src/graphql/queries/GetOperationVoteList.gql create mode 100644 src/locales/localizers/op-status.ts create mode 100644 src/locales/localizers/op-type.ts create mode 100644 src/locales/localizers/op-vote.ts diff --git a/src/app/[locale]/confirmations/[root]/page.tsx b/src/app/[locale]/confirmations/[root]/page.tsx new file mode 100644 index 0000000..2504e6d --- /dev/null +++ b/src/app/[locale]/confirmations/[root]/page.tsx @@ -0,0 +1,34 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getConfirmationByRoot } from '@/callers' +import { + Confirmation, + ConfirmationOperations, + ConfirmationOperationVotes, + PageContainer, +} from '@/components' +import { createMetadata } from '@/config' +import { ConfirmationFragment } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getConfirmation = (root: string) => { + return getServerSideProps(() => getConfirmationByRoot(root)) +} + +export function generateMetadata({ params }: { params: { root: string } }): Metadata { + return createMetadata(`Confirmation ${params.root} Details`) +} + +export default async function ConfirmationPage({ params: { root } }: { params: { root: string } }) { + const { isNotFound, indexes } = await getConfirmation(root) + if (isNotFound) notFound() + + return ( + + + + + + ) +} diff --git a/src/app/[locale]/confirmations/page.tsx b/src/app/[locale]/confirmations/page.tsx new file mode 100644 index 0000000..caebdae --- /dev/null +++ b/src/app/[locale]/confirmations/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { Confirmations, PageContainer } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata(`Confirmations`) +} + +export default function ConfirmationsPage() { + return ( + + + + ) +} diff --git a/src/app/[locale]/operations/[index]/page.tsx b/src/app/[locale]/operations/[index]/page.tsx new file mode 100644 index 0000000..84a36b3 --- /dev/null +++ b/src/app/[locale]/operations/[index]/page.tsx @@ -0,0 +1,28 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getOperationByIndex } from '@/callers' +import { Operation, OperationVotes, PageContainer } from '@/components' +import { createMetadata } from '@/config' +import { GetOperationByIndexQuery } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getOperation = (index: string) => { + return getServerSideProps(() => getOperationByIndex(index)) +} + +export function generateMetadata({ params }: { params: { index: string } }): Metadata { + return createMetadata(`Operation ${params.index} Details`) +} + +export default async function OperationPage({ params: { index } }: { params: { index: string } }) { + const { isNotFound } = await getOperation(index) + if (isNotFound) notFound() + + return ( + + + + + ) +} diff --git a/src/app/[locale]/operations/page.tsx b/src/app/[locale]/operations/page.tsx new file mode 100644 index 0000000..c37499d --- /dev/null +++ b/src/app/[locale]/operations/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { Operations, PageContainer } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata(`Operations`) +} + +export default function OperationsPage() { + return ( + + + + ) +} diff --git a/src/app/[locale]/oracles/[address]/page.tsx b/src/app/[locale]/oracles/[address]/page.tsx index d2d7aea..dd7cf3f 100644 --- a/src/app/[locale]/oracles/[address]/page.tsx +++ b/src/app/[locale]/oracles/[address]/page.tsx @@ -18,11 +18,7 @@ export function generateMetadata({ params }: { params: { address: string } }): M return createMetadata(`Oracle ${params.address} Details`) } -export default async function ProposalPage({ - params: { address }, -}: { - params: { address: string } -}) { +export default async function OraclePage({ params: { address } }: { params: { address: string } }) { const { isNotFound } = await getOracle(address) if (isNotFound) notFound() diff --git a/src/app/[locale]/tss/page.tsx b/src/app/[locale]/tss/page.tsx index d2ca759..f5a0024 100644 --- a/src/app/[locale]/tss/page.tsx +++ b/src/app/[locale]/tss/page.tsx @@ -7,7 +7,7 @@ export function generateMetadata(): Metadata { return createMetadata('TSS') } -export default function TSSPage() { +export default function TSSsPage() { return ( diff --git a/src/callers/confirmation.ts b/src/callers/confirmation.ts new file mode 100644 index 0000000..cd9c2f7 --- /dev/null +++ b/src/callers/confirmation.ts @@ -0,0 +1,114 @@ +import { CONFIG } from '@/config' +import { + apolloClient, + ConfirmationBaseFragment, + ConfirmationFragment, + GetConfirmationByRoot, + GetConfirmationByRootQuery, + GetConfirmationCount, + GetConfirmationCountQuery, + GetConfirmationList, + GetConfirmationListQuery, + GetConfirmationOperationList, + GetConfirmationOperationListQuery, + GetConfirmationOperationVoteCount, + GetConfirmationOperationVoteCountQuery, + GetConfirmationOperationVoteList, + GetConfirmationOperationVoteListQuery, + Operation_Bool_Exp, + OperationFragment, + OperationVoteFragment, + Vote_Bool_Exp, +} from '@/graphql' + +const buildOperationWhere = (indexes: string[]): Operation_Bool_Exp => { + const where: Operation_Bool_Exp = {} + if (!indexes.length) return where + where._or = indexes.map(index => ({ index: { _eq: index } })) + return where +} + +const buildVoteWhere = (indexes: string[]): Vote_Bool_Exp => { + const where: Vote_Bool_Exp = {} + if (!indexes.length) return where + where._or = indexes.map(index => ({ operation: { _eq: index } })) + return where +} + +export const getConfirmationList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, +): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationList, + fetchPolicy: 'network-only', + variables: { limit, offset }, + }) + + return data?.confirmation ?? [] +} + +export const getConfirmationCount = async (): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationCount, + fetchPolicy: 'network-only', + }) + + return data?.confirmation_aggregate.aggregate?.count ?? 0 +} + +export const getConfirmationByRoot = async (root: string): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationByRoot, + fetchPolicy: 'network-only', + variables: { root }, + }) + + return data?.confirmation?.[0] +} + +export const getConfirmationOperationList = async ({ + limit = CONFIG.PAGE_LIMIT, + offset = 0, + indexes, +}: { + limit: number + offset: number + indexes: string[] +}): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationOperationList, + fetchPolicy: 'network-only', + variables: { limit, offset, where: buildOperationWhere(indexes) }, + }) + + return data?.operation ?? [] +} + +export const getConfirmationOperationVotes = async ({ + indexes, + limit = CONFIG.PAGE_LIMIT, + offset = 0, +}: { + indexes: string[] + limit: number + offset: number +}): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationOperationVoteList, + fetchPolicy: 'network-only', + variables: { where: buildVoteWhere(indexes), limit, offset }, + }) + + return data?.vote ?? [] +} + +export const getConfirmationOperationVoteCount = async (operations: string[]): Promise => { + const { data } = await apolloClient.query({ + query: GetConfirmationOperationVoteCount, + fetchPolicy: 'network-only', + variables: { where: buildVoteWhere(operations) }, + }) + + return data?.vote_aggregate?.aggregate?.count ?? 0 +} diff --git a/src/callers/index.ts b/src/callers/index.ts index 791a2c5..c8c1263 100644 --- a/src/callers/index.ts +++ b/src/callers/index.ts @@ -1,4 +1,6 @@ export * from './block' +export * from './confirmation' +export * from './operation' export * from './proposal' export * from './rarimocore' export * from './stats' diff --git a/src/callers/operation.ts b/src/callers/operation.ts new file mode 100644 index 0000000..3a02e48 --- /dev/null +++ b/src/callers/operation.ts @@ -0,0 +1,76 @@ +import { CONFIG } from '@/config' +import { + apolloClient, + GetOperationByIndex, + GetOperationByIndexQuery, + GetOperationCount, + GetOperationCountQuery, + GetOperationList, + GetOperationListQuery, + GetOperationVoteCount, + GetOperationVoteCountQuery, + GetOperationVoteList, + GetOperationVoteListQuery, + OperationFragment, + OperationVoteFragment, +} from '@/graphql' + +export const getOperationList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, +): Promise => { + const { data } = await apolloClient.query({ + query: GetOperationList, + fetchPolicy: 'network-only', + variables: { limit, offset }, + }) + + return data?.operation ?? [] +} + +export const getOperationCount = async (): Promise => { + const { data } = await apolloClient.query({ + query: GetOperationCount, + fetchPolicy: 'network-only', + }) + + return data?.operation_aggregate.aggregate?.count ?? 0 +} + +export const getOperationByIndex = async (index: string): Promise => { + const { data } = await apolloClient.query({ + query: GetOperationByIndex, + fetchPolicy: 'network-only', + variables: { index }, + }) + + return data +} + +export const getOperationVotes = async ({ + operation, + limit = CONFIG.PAGE_LIMIT, + offset = 0, +}: { + operation: string + limit: number + offset: number +}): Promise => { + const { data } = await apolloClient.query({ + query: GetOperationVoteList, + fetchPolicy: 'network-only', + variables: { operation, limit, offset }, + }) + + return data?.vote ?? [] +} + +export const getOperationVoteCount = async (operation: string): Promise => { + const { data } = await apolloClient.query({ + query: GetOperationVoteCount, + fetchPolicy: 'network-only', + variables: { operation }, + }) + + return data?.vote_aggregate?.aggregate?.count ?? 0 +} diff --git a/src/components/Confirmation/Confirmation.tsx b/src/components/Confirmation/Confirmation.tsx new file mode 100644 index 0000000..88bce9c --- /dev/null +++ b/src/components/Confirmation/Confirmation.tsx @@ -0,0 +1,111 @@ +'use client' + +import { time } from '@distributedlab/tools' +import { Link as MuiLink } from '@mui/material' +import Link from 'next/link' + +import { getConfirmationByRoot } from '@/callers' +import { AvatarName } from '@/components/Avatar' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import CopyToClipboardWrapper from '@/components/CopyToClipboardWrapper' +import OverviewTable from '@/components/OverviewTable' +import { + TABLE_BIG_SKELETON_SX, + TABLE_LARGE_SKELETON_SX, + TABLE_MEDIUM_TEXT_SKELETON_SX, + TABLE_SMALL_TEXT_SKELETON_SX, +} from '@/const' +import { ConfirmationFragment } from '@/graphql' +import { generatePath } from '@/helpers' +import { useLoading, useSkeleton } from '@/hooks' +import { useI18n } from '@/locales/client' +import { RoutePaths } from '@/types' + +export default function Confirmation({ root }: { root: string }) { + const t = useI18n() + + const { + data: confirmation, + isLoading, + isLoadingError, + isEmpty, + } = useLoading({} as ConfirmationFragment, () => + getConfirmationByRoot(root), + ) + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('confirmation.root-col-lbl'), + body: withSkeleton( + + {confirmation?.root} + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('confirmation.tx-col-lbl'), + body: withSkeleton( + + + {confirmation?.tx} + + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('confirmation.creator-col-lbl'), + body: withSkeleton( + , + TABLE_LARGE_SKELETON_SX, + ), + }, + { + head: t('confirmation.block-col-lbl'), + body: withSkeleton( + + + {confirmation?.height} + + , + TABLE_SMALL_TEXT_SKELETON_SX, + ), + }, + { + head: t('confirmation.age-col-lbl'), + body: withSkeleton( + time(confirmation?.block?.timestamp, { utc: true }).fromNow, + TABLE_MEDIUM_TEXT_SKELETON_SX, + ), + }, + ] + + return ( + + + + + + + + ) +} diff --git a/src/components/Confirmation/ConfirmationOperationVotes.tsx b/src/components/Confirmation/ConfirmationOperationVotes.tsx new file mode 100644 index 0000000..dab7cc9 --- /dev/null +++ b/src/components/Confirmation/ConfirmationOperationVotes.tsx @@ -0,0 +1,46 @@ +'use client' + +import { getConfirmationOperationVoteCount, getConfirmationOperationVotes } from '@/callers' +import { ContentBox, ContentSection } from '@/components/Content' +import { OperationVoteFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' + +import OperationVoteList from '../Operation/OperationVoteList' + +export default function ConfirmationOperationVotes({ indexes }: { indexes: string[] }) { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + } = useLoading(0, () => getConfirmationOperationVoteCount(indexes)) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getConfirmationOperationVotes({ indexes, limit, offset }), + { + loadArgs: [limit, offset], + }, + ) + return ( + + + + + + ) +} diff --git a/src/components/Confirmation/ConfirmationOperations.tsx b/src/components/Confirmation/ConfirmationOperations.tsx new file mode 100644 index 0000000..9e78dc3 --- /dev/null +++ b/src/components/Confirmation/ConfirmationOperations.tsx @@ -0,0 +1,41 @@ +'use client' + +import { getConfirmationOperationList } from '@/callers' +import { OperationFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' + +import { ContentBox, ContentSection } from '../Content' +import OperationList from '../Operation/OperationList' + +export default function ConfirmationOperations({ indexes }: { indexes: string[] }) { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getConfirmationOperationList({ limit, offset, indexes }), + { + loadArgs: [limit, offset], + }, + ) + + return ( + + + + + + ) +} diff --git a/src/components/Confirmation/ConfirmationRow.tsx b/src/components/Confirmation/ConfirmationRow.tsx new file mode 100644 index 0000000..62f05c1 --- /dev/null +++ b/src/components/Confirmation/ConfirmationRow.tsx @@ -0,0 +1,101 @@ +import { time } from '@distributedlab/tools' +import { Link as MuiLink, Skeleton, TableRow } from '@mui/material' +import { TableCell } from '@mui/material' +import Link from 'next/link' + +import { AvatarName } from '@/components/Avatar' +import { ConfirmationBaseFragment } from '@/graphql' +import { createColumnMap, generatePath } from '@/helpers' +import { useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { ConfirmationColumnIds } from './Confirmations' + +export default function ConfirmationRow({ + row, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + row?: ConfirmationBaseFragment + isLoading: boolean +}) { + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + return ( + + + {isLoading ? ( + + ) : ( + + {withSkeleton(row?.root, { width: '100%' })} + + )} + + + + {withSkeleton(, { + height: 22, + width: '100%', + })} + + + + {isLoading ? ( + + ) : ( + + {withSkeleton(row?.tx, { width: '100%' })} + + )} + + + + {withSkeleton( + + {row?.height} + , + { width: '100%' }, + )} + + + + {withSkeleton(time(row?.block?.timestamp, { utc: true }).fromNow, { + width: '100%', + })} + + + ) +} diff --git a/src/components/Confirmation/Confirmations.tsx b/src/components/Confirmation/Confirmations.tsx new file mode 100644 index 0000000..c3cdb28 --- /dev/null +++ b/src/components/Confirmation/Confirmations.tsx @@ -0,0 +1,126 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { getConfirmationCount, getConfirmationList } from '@/callers' +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { ConfirmationBaseFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' +import { TableColumn } from '@/types' + +import { ContentBox, ContentSection, ContentWrapper } from '../Content' +import ConfirmationRow from './ConfirmationRow' + +export enum ConfirmationColumnIds { + Root = 'root', + Creator = 'creator', + Tx = 'tx', + Block = 'block', + Age = 'age', +} + +export default function Confirmations() { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + } = useLoading(0, getConfirmationCount) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getConfirmationList(limit, offset), + { + loadArgs: [limit, offset], + }, + ) + + const columns: readonly TableColumn[] = [ + { + id: ConfirmationColumnIds.Root, + label: t('confirmations.root-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 100, + maxWidth: 200, + }, + }, + { + id: ConfirmationColumnIds.Creator, + label: t('confirmations.creator-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 100, + maxWidth: 200, + }, + }, + { + id: ConfirmationColumnIds.Tx, + label: t('confirmations.tx-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 100, + maxWidth: 200, + }, + }, + { + id: ConfirmationColumnIds.Block, + label: t('confirmations.block-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 120, + maxWidth: 150, + }, + }, + { + id: ConfirmationColumnIds.Age, + label: t('confirmations.age-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 120, + maxWidth: 150, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as ConfirmationBaseFragment) : data).map( + (row, idx) => , + ) + + return ( + + + + + + + + ) +} diff --git a/src/components/Confirmation/index.tsx b/src/components/Confirmation/index.tsx new file mode 100644 index 0000000..81817fa --- /dev/null +++ b/src/components/Confirmation/index.tsx @@ -0,0 +1,4 @@ +export { default as Confirmation } from './Confirmation' +export { default as ConfirmationOperations } from './ConfirmationOperations' +export { default as ConfirmationOperationVotes } from './ConfirmationOperationVotes' +export { default as Confirmations } from './Confirmations' diff --git a/src/components/Header/HeaderBridgeMenu.tsx b/src/components/Header/HeaderBridgeMenu.tsx index 26d6998..7e562b5 100644 --- a/src/components/Header/HeaderBridgeMenu.tsx +++ b/src/components/Header/HeaderBridgeMenu.tsx @@ -10,6 +10,8 @@ export default function HeaderBridgeMenu(props: Omit diff --git a/src/components/Operation/Operation.tsx b/src/components/Operation/Operation.tsx new file mode 100644 index 0000000..668e00e --- /dev/null +++ b/src/components/Operation/Operation.tsx @@ -0,0 +1,162 @@ +'use client' + +import { time } from '@distributedlab/tools' +import { Chip, Link as MuiLink } from '@mui/material' +import Link from 'next/link' +import { useMemo } from 'react' + +import { getOperationByIndex } from '@/callers' +import { AvatarName } from '@/components/Avatar' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import CopyToClipboardWrapper from '@/components/CopyToClipboardWrapper' +import OverviewTable from '@/components/OverviewTable' +import { + TABLE_BIG_SKELETON_SX, + TABLE_LARGE_SKELETON_SX, + TABLE_MEDIUM_TEXT_SKELETON_SX, + TABLE_SMALL_TEXT_SKELETON_SX, + TABLE_TYPE_BOX_SKELETON_SX, +} from '@/const' +import { GetOperationByIndexQuery } from '@/graphql' +import { generatePath } from '@/helpers' +import { useLoading, useLocalize, useSkeleton } from '@/hooks' +import { useI18n } from '@/locales/client' +import { RoutePaths } from '@/types' + +import OperationContentRow from './OperationContentRow' +import OperationStatus from './OperationStatus' + +export default function Operation({ index }: { index: string }) { + const t = useI18n() + const { localizeOperationType } = useLocalize() + + const { data, isLoading, isLoadingError, isEmpty } = useLoading( + {} as GetOperationByIndexQuery, + () => getOperationByIndex(index), + ) + + const operation = useMemo(() => data?.operation?.[0], [data]) + const confirmation = useMemo(() => data?.confirmation?.[0], [data]) + const tx = useMemo(() => data?.transaction?.[0], [data]) + const operationType = useMemo( + () => localizeOperationType(operation?.operation_type), + [localizeOperationType, operation?.operation_type], + ) + + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('operation.index-col-lbl'), + body: withSkeleton( + + {operation?.index} + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('operation.tx-col-lbl'), + body: withSkeleton( + + + {tx?.hash} + + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('operation.block-col-lbl'), + body: withSkeleton( + + + {tx?.block?.height} + + , + TABLE_SMALL_TEXT_SKELETON_SX, + ), + }, + { + head: t('operation.creator-col-lbl'), + body: withSkeleton( + , + TABLE_LARGE_SKELETON_SX, + ), + }, + ...(confirmation?.root + ? [ + { + head: t('operation.confirmation-col-lbl'), + body: withSkeleton( + + + {confirmation?.root} + + , + TABLE_BIG_SKELETON_SX, + ), + }, + ] + : []), + { + head: t('operation.type-col-lbl'), + body: withSkeleton(, TABLE_TYPE_BOX_SKELETON_SX), + }, + { + head: t('operation.status-col-lbl'), + body: withSkeleton( + , + TABLE_TYPE_BOX_SKELETON_SX, + ), + }, + { + head: t('operation.age-col-lbl'), + body: withSkeleton( + time(operation?.timestamp, { utc: true }).fromNow, + TABLE_MEDIUM_TEXT_SKELETON_SX, + ), + }, + ] + + return ( + + + + + tr:last-child td, & > tr:last-child th, & > tr:nth-last-of-type(-n + 2) td': { + borderBottom: 0, + }, + }} + > + + + + + + ) +} diff --git a/src/components/Operation/OperationContentRow.tsx b/src/components/Operation/OperationContentRow.tsx new file mode 100644 index 0000000..6cd861d --- /dev/null +++ b/src/components/Operation/OperationContentRow.tsx @@ -0,0 +1,42 @@ +'use client' + +import { isObject, mapValues, omit } from 'lodash-es' +import { useMemo } from 'react' + +import JsonViewer from '@/components/JsonViewer' +import TableCollapseRow from '@/components/TableCollapseRow' +import { GetOperationByIndexQuery } from '@/graphql' + +const recursiveOmit = (obj: T, ...keys: string[]): T => { + if (!isObject(obj)) return obj + return mapValues(omit(obj, ...keys), v => (isObject(v) ? omit(v, ...keys) : v)) as T +} + +export default function OperationContentRow({ + operation, + label, +}: { + operation: GetOperationByIndexQuery['operation'][number] + label: string +}) { + const content = useMemo(() => { + const content = + operation?.transfer ?? + operation?.change_parties ?? + operation?.contract_upgrade ?? + operation?.fee_token_management ?? + operation?.identity_default_transfer ?? + operation?.identity_gist_transfer ?? + operation?.identity_state_transfer + + return content ? recursiveOmit(content, '__typename') : null + }, [operation]) + + return content ? ( + + + + ) : ( + <> + ) +} diff --git a/src/components/Operation/OperationList.tsx b/src/components/Operation/OperationList.tsx new file mode 100644 index 0000000..e38978d --- /dev/null +++ b/src/components/Operation/OperationList.tsx @@ -0,0 +1,111 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { ContentWrapper } from '@/components/Content' +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { OperationFragment } from '@/graphql' +import { useI18n } from '@/locales/client' +import { TableColumn, TableListProps } from '@/types' + +import OperationListRow from './OperationListRow' + +export enum OperationColumnIds { + Index = 'index', + Creator = 'creator', + Type = 'type', + Status = 'status', + Date = 'date', +} + +export default function OperationList({ + isLoading, + isLoadingError, + limit, + offset, + list, + count, + handleChangePage, + handleChangeRowsPerPage, + isMinHeighted, +}: TableListProps) { + const t = useI18n() + + const columns: readonly TableColumn[] = [ + { + id: OperationColumnIds.Index, + label: t('operation-list.index-col-lbl'), + sx: { + minWidth: 260, + maxWidth: 260, + }, + }, + { + id: OperationColumnIds.Type, + label: t('operation-list.type-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 220, + }, + }, + { + id: OperationColumnIds.Creator, + label: t('operation-list.creator-col-lbl'), + sx: { + minWidth: 260, + maxWidth: 260, + }, + }, + { + id: OperationColumnIds.Date, + label: t('operation-list.date-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 120, + maxWidth: 150, + }, + }, + { + id: OperationColumnIds.Status, + label: t('operation-list.status-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 150, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as OperationFragment) : list).map( + (row, idx) => , + ) + + return ( + + + + ) +} diff --git a/src/components/Operation/OperationListRow.tsx b/src/components/Operation/OperationListRow.tsx new file mode 100644 index 0000000..9eb0e92 --- /dev/null +++ b/src/components/Operation/OperationListRow.tsx @@ -0,0 +1,92 @@ +'use client' + +import { time } from '@distributedlab/tools' +import { Chip, Link as MuiLink, TableCell, TableRow } from '@mui/material' +import { OpType } from '@rarimo/client' +import Link from 'next/link' +import { useMemo } from 'react' + +import { AvatarName } from '@/components/Avatar' +import { OVERFLOW_SX } from '@/const' +import { OperationFragment } from '@/graphql' +import { abbr, createColumnMap, generatePath } from '@/helpers' +import { useLocalize, useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { OperationColumnIds } from './OperationList' +import OperationStatus from './OperationStatus' + +export default function OperationListRow({ + row, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + row?: OperationFragment + isLoading: boolean +}) { + const { localizeOperationType } = useLocalize() + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + const operationType = useMemo(() => { + return localizeOperationType(row?.operation_type as OpType) + }, [localizeOperationType, row?.operation_type]) + + return ( + + + {withSkeleton( + + {abbr(row?.index, 14, 20)} + , + columnMap[OperationColumnIds.Index]?.sx, + )} + + + + {withSkeleton(, { height: 32, width: '100%' })} + + + + {withSkeleton(, { + width: '100%', + })} + + + + {withSkeleton(time(row?.timestamp, { utc: true }).fromNow, { width: '140px' })} + + + + {withSkeleton(, { + height: 32, + width: '100%', + })} + + + ) +} diff --git a/src/components/Operation/OperationStatus.tsx b/src/components/Operation/OperationStatus.tsx new file mode 100644 index 0000000..42dd595 --- /dev/null +++ b/src/components/Operation/OperationStatus.tsx @@ -0,0 +1,33 @@ +import { Chip } from '@mui/material' +import { OpStatus, opStatusFromJSON } from '@rarimo/client' + +import { useLocalize } from '@/hooks' + +export default function OperationStatus({ status }: { status?: string | number }) { + const { localizeOperationStatus } = useLocalize() + + const getStatusColor = (status?: string | number) => { + if (!status) return 'default' + + switch (opStatusFromJSON(status)) { + case OpStatus.Initialized: + return 'secondary' + case OpStatus.Approved: + return 'primary' + case OpStatus.NotApproved: + return 'error' + case OpStatus.Signed: + return 'success' + default: + return 'default' + } + } + + return ( + + ) +} diff --git a/src/components/Operation/OperationVoteList.tsx b/src/components/Operation/OperationVoteList.tsx new file mode 100644 index 0000000..c664a7e --- /dev/null +++ b/src/components/Operation/OperationVoteList.tsx @@ -0,0 +1,112 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { ContentWrapper } from '@/components/Content' +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { OperationVoteFragment } from '@/graphql' +import { useI18n } from '@/locales/client' +import { TableColumn, TableListProps } from '@/types' + +import OperationVotesRow from './OperationVotesRow' + +export enum OperationVotesColumnIds { + Voter = 'voter', + Tx = 'tx', + Block = 'block', + Age = 'age', + Option = 'option', +} + +export default function OperationVoteList({ + isLoading, + isLoadingError, + limit, + offset, + list, + count, + handleChangePage, + handleChangeRowsPerPage, +}: TableListProps) { + const t = useI18n() + + const columns: readonly TableColumn[] = [ + { + id: OperationVotesColumnIds.Voter, + label: t('operation-vote-list.voter-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 100, + maxWidth: 200, + }, + }, + { + id: OperationVotesColumnIds.Tx, + label: t('operation-vote-list.tx-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 100, + maxWidth: 200, + }, + }, + { + id: OperationVotesColumnIds.Block, + label: t('operation-vote-list.block-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 120, + maxWidth: 150, + }, + }, + { + id: OperationVotesColumnIds.Age, + label: t('operation-vote-list.age-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 120, + maxWidth: 150, + }, + }, + { + id: OperationVotesColumnIds.Option, + label: t('operation-vote-list.option-col-lbl'), + sx: { minWidth: 70, maxWidth: 70 }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as OperationVoteFragment) : list).map( + (row, idx) => ( + + ), + ) + + return ( + + + + ) +} diff --git a/src/components/Operation/OperationVoteOption.tsx b/src/components/Operation/OperationVoteOption.tsx new file mode 100644 index 0000000..161744c --- /dev/null +++ b/src/components/Operation/OperationVoteOption.tsx @@ -0,0 +1,30 @@ +import { Chip } from '@mui/material' +import { OpVoteType, opVoteTypeFromJSON } from '@rarimo/client' +import { useMemo } from 'react' + +import { useLocalize } from '@/hooks' + +export default function OperationVoteOption({ vote }: { vote?: string | number }) { + const { localizeOperationVote } = useLocalize() + + const voteOptionEnum = useMemo(() => opVoteTypeFromJSON(vote!), [vote]) + + const getColor = () => { + switch (voteOptionEnum) { + case OpVoteType.Yes: + return 'success' + case OpVoteType.No: + return 'error' + default: + return 'default' + } + } + + return ( + + ) +} diff --git a/src/components/Operation/OperationVotes.tsx b/src/components/Operation/OperationVotes.tsx new file mode 100644 index 0000000..7869872 --- /dev/null +++ b/src/components/Operation/OperationVotes.tsx @@ -0,0 +1,45 @@ +'use client' + +import { getOperationVoteCount, getOperationVotes } from '@/callers' +import { ContentBox, ContentSection } from '@/components/Content' +import { OperationVoteFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' + +import OperationVoteList from './OperationVoteList' + +export default function OperationVotes({ index }: { index: string }) { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + } = useLoading(0, () => getOperationVoteCount(index)) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getOperationVotes({ operation: index, limit, offset }), + { + loadArgs: [limit, offset], + }, + ) + return ( + + + + + + ) +} diff --git a/src/components/Operation/OperationVotesRow.tsx b/src/components/Operation/OperationVotesRow.tsx new file mode 100644 index 0000000..66d08bf --- /dev/null +++ b/src/components/Operation/OperationVotesRow.tsx @@ -0,0 +1,91 @@ +import { time } from '@distributedlab/tools' +import { Link as MuiLink, Skeleton, TableRow } from '@mui/material' +import { TableCell } from '@mui/material' +import Link from 'next/link' + +import { AvatarName } from '@/components/Avatar' +import { OperationVoteFragment } from '@/graphql' +import { createColumnMap, generatePath } from '@/helpers' +import { useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { OperationVotesColumnIds } from './OperationVoteList' +import OperationVoteOption from './OperationVoteOption' + +export default function OperationVotesRow({ + vote, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + vote?: OperationVoteFragment + isLoading: boolean +}) { + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + return ( + + + {withSkeleton(, { + height: 22, + width: '100%', + })} + + + + {isLoading ? ( + + ) : ( + + {withSkeleton(vote?.tx, { width: '100%' })} + + )} + + + + {withSkeleton( + + {vote?.height} + , + { width: '100%' }, + )} + + + + {withSkeleton(time(vote?.block?.timestamp, { utc: true }).fromNow, { width: '100%' })} + + + {withSkeleton(, { + width: '100%', + height: 32, + })} + + + ) +} diff --git a/src/components/Operation/Operations.tsx b/src/components/Operation/Operations.tsx new file mode 100644 index 0000000..5a0850d --- /dev/null +++ b/src/components/Operation/Operations.tsx @@ -0,0 +1,46 @@ +'use client' + +import { getOperationCount, getOperationList } from '@/callers' +import { OperationFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' + +import { ContentBox, ContentSection } from '../Content' +import OperationList from './OperationList' + +export default function Operations() { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + } = useLoading(0, getOperationCount) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getOperationList(limit, offset), + { + loadArgs: [limit, offset], + }, + ) + + return ( + + + + + + ) +} diff --git a/src/components/Operation/index.tsx b/src/components/Operation/index.tsx new file mode 100644 index 0000000..4d86d28 --- /dev/null +++ b/src/components/Operation/index.tsx @@ -0,0 +1,4 @@ +export { default as Operation } from './Operation' +export { default as OperationList } from './OperationList' +export { default as Operations } from './Operations' +export { default as OperationVotes } from './OperationVotes' diff --git a/src/components/Oracles/OracleStatus.tsx b/src/components/Oracles/OracleStatus.tsx index ecd8e5c..f306e25 100644 --- a/src/components/Oracles/OracleStatus.tsx +++ b/src/components/Oracles/OracleStatus.tsx @@ -11,7 +11,7 @@ export default function OracleStatus({ status }: { status?: string | number }) { const getTSSStatusColor = (status?: string | number) => { switch (oracleStatusFromJSON(status!)) { case OracleStatusEnum.Inactive: - case OracleStatusEnum.Frozen: + case OracleStatusEnum.Freezed: return 'secondary' case OracleStatusEnum.Active: return 'primary' diff --git a/src/components/Proposal/ProposalVotes.tsx b/src/components/Proposal/ProposalVotes.tsx index 831030c..1e9be5b 100644 --- a/src/components/Proposal/ProposalVotes.tsx +++ b/src/components/Proposal/ProposalVotes.tsx @@ -76,14 +76,14 @@ export default function ProposalVotes({ id }: { id: string }) { label: t('proposal-votes.block-height-col-lbl'), sx: { ...OVERFLOW_SX, - minWidth: 40, - maxWidth: 80, + minWidth: 120, + maxWidth: 150, }, }, { id: ProposalVotesColumnIds.Date, label: t('proposal-votes.age-col-lbl'), - sx: { ...OVERFLOW_SX, minWidth: 40, maxWidth: 80 }, + sx: { ...OVERFLOW_SX, minWidth: 120, maxWidth: 150 }, }, { id: ProposalVotesColumnIds.Option, diff --git a/src/components/TSS/TSSDetails.tsx b/src/components/TSS/TSS.tsx similarity index 97% rename from src/components/TSS/TSSDetails.tsx rename to src/components/TSS/TSS.tsx index a4e6018..5b2cd10 100644 --- a/src/components/TSS/TSSDetails.tsx +++ b/src/components/TSS/TSS.tsx @@ -18,7 +18,7 @@ import { abbr } from '@/helpers' import { useLoading, useSkeleton } from '@/hooks' import { useI18n } from '@/locales/client' -export default function TSSDetails({ address }: { address: string }) { +export default function TSS({ address }: { address: string }) { const t = useI18n() const { diff --git a/src/components/TSS/TSSList.tsx b/src/components/TSS/TSSList.tsx index 5afd5f4..6354b4a 100644 --- a/src/components/TSS/TSSList.tsx +++ b/src/components/TSS/TSSList.tsx @@ -27,7 +27,6 @@ export default function TSSList({ count, handleChangePage, handleChangeRowsPerPage, - isMinHeighted = true, }: TableListProps) { const t = useI18n() @@ -82,7 +81,7 @@ export default function TSSList({ ; creator: Scalars['String']['output']; /** An object relationship */ creator_account?: Maybe; + height: Scalars['bigint']['output']; indexes: Scalars['_text']['output']; root: Scalars['String']['output']; signature_ecdsa: Scalars['String']['output']; + /** An object relationship */ + transaction?: Maybe; + tx?: Maybe; }; /** aggregated selection of "confirmation" */ @@ -2121,9 +2127,17 @@ export type Confirmation_Aggregate = { /** aggregate fields of "confirmation" */ export type Confirmation_Aggregate_Fields = { __typename?: 'confirmation_aggregate_fields'; + avg?: Maybe; count: Scalars['Int']['output']; max?: Maybe; min?: Maybe; + stddev?: Maybe; + stddev_pop?: Maybe; + stddev_samp?: Maybe; + sum?: Maybe; + var_pop?: Maybe; + var_samp?: Maybe; + variance?: Maybe; }; @@ -2133,41 +2147,59 @@ export type Confirmation_Aggregate_FieldsCountArgs = { distinct?: InputMaybe; }; +/** aggregate avg on columns */ +export type Confirmation_Avg_Fields = { + __typename?: 'confirmation_avg_fields'; + height?: Maybe; +}; + /** Boolean expression to filter rows from the table "confirmation". All fields are combined with a logical 'AND'. */ export type Confirmation_Bool_Exp = { _and?: InputMaybe>; _not?: InputMaybe; _or?: InputMaybe>; + block?: InputMaybe; creator?: InputMaybe; creator_account?: InputMaybe; + height?: InputMaybe; indexes?: InputMaybe<_Text_Comparison_Exp>; root?: InputMaybe; signature_ecdsa?: InputMaybe; + transaction?: InputMaybe; + tx?: InputMaybe; }; /** aggregate max on columns */ export type Confirmation_Max_Fields = { __typename?: 'confirmation_max_fields'; creator?: Maybe; + height?: Maybe; root?: Maybe; signature_ecdsa?: Maybe; + tx?: Maybe; }; /** aggregate min on columns */ export type Confirmation_Min_Fields = { __typename?: 'confirmation_min_fields'; creator?: Maybe; + height?: Maybe; root?: Maybe; signature_ecdsa?: Maybe; + tx?: Maybe; }; /** Ordering options when selecting data from "confirmation". */ export type Confirmation_Order_By = { + block?: InputMaybe; creator?: InputMaybe; creator_account?: InputMaybe; + height?: InputMaybe; indexes?: InputMaybe; root?: InputMaybe; signature_ecdsa?: InputMaybe; + transaction?: InputMaybe; + tx?: InputMaybe; }; /** select columns of table "confirmation" */ @@ -2175,13 +2207,35 @@ export enum Confirmation_Select_Column { /** column name */ Creator = 'creator', /** column name */ + Height = 'height', + /** column name */ Indexes = 'indexes', /** column name */ Root = 'root', /** column name */ - SignatureEcdsa = 'signature_ecdsa' + SignatureEcdsa = 'signature_ecdsa', + /** column name */ + Tx = 'tx' } +/** aggregate stddev on columns */ +export type Confirmation_Stddev_Fields = { + __typename?: 'confirmation_stddev_fields'; + height?: Maybe; +}; + +/** aggregate stddev_pop on columns */ +export type Confirmation_Stddev_Pop_Fields = { + __typename?: 'confirmation_stddev_pop_fields'; + height?: Maybe; +}; + +/** aggregate stddev_samp on columns */ +export type Confirmation_Stddev_Samp_Fields = { + __typename?: 'confirmation_stddev_samp_fields'; + height?: Maybe; +}; + /** Streaming cursor of the table "confirmation" */ export type Confirmation_Stream_Cursor_Input = { /** Stream column input with initial value */ @@ -2193,9 +2247,35 @@ export type Confirmation_Stream_Cursor_Input = { /** Initial value of the column from where the streaming should start */ export type Confirmation_Stream_Cursor_Value_Input = { creator?: InputMaybe; + height?: InputMaybe; indexes?: InputMaybe; root?: InputMaybe; signature_ecdsa?: InputMaybe; + tx?: InputMaybe; +}; + +/** aggregate sum on columns */ +export type Confirmation_Sum_Fields = { + __typename?: 'confirmation_sum_fields'; + height?: Maybe; +}; + +/** aggregate var_pop on columns */ +export type Confirmation_Var_Pop_Fields = { + __typename?: 'confirmation_var_pop_fields'; + height?: Maybe; +}; + +/** aggregate var_samp on columns */ +export type Confirmation_Var_Samp_Fields = { + __typename?: 'confirmation_var_samp_fields'; + height?: Maybe; +}; + +/** aggregate variance on columns */ +export type Confirmation_Variance_Fields = { + __typename?: 'confirmation_variance_fields'; + height?: Maybe; }; /** columns and relationships of "contract_upgrade" */ @@ -2204,6 +2284,8 @@ export type Contract_Upgrade = { buffer_account: Scalars['String']['output']; chain: Scalars['String']['output']; hash: Scalars['String']['output']; + /** An object relationship */ + network?: Maybe; new_implementation_contract: Scalars['String']['output']; nonce: Scalars['String']['output']; /** An object relationship */ @@ -2257,6 +2339,7 @@ export type Contract_Upgrade_Bool_Exp = { buffer_account?: InputMaybe; chain?: InputMaybe; hash?: InputMaybe; + network?: InputMaybe; new_implementation_contract?: InputMaybe; nonce?: InputMaybe; operation?: InputMaybe; @@ -2296,6 +2379,7 @@ export type Contract_Upgrade_Order_By = { buffer_account?: InputMaybe; chain?: InputMaybe; hash?: InputMaybe; + network?: InputMaybe; new_implementation_contract?: InputMaybe; nonce?: InputMaybe; operation?: InputMaybe; @@ -3386,6 +3470,8 @@ export type Fee_Token_Management = { chain: Scalars['String']['output']; fee_token_amount: Scalars['String']['output']; fee_token_contract: Scalars['String']['output']; + /** An object relationship */ + network?: Maybe; nonce: Scalars['String']['output']; op_type: Scalars['Int']['output']; /** An object relationship */ @@ -3438,6 +3524,7 @@ export type Fee_Token_Management_Bool_Exp = { chain?: InputMaybe; fee_token_amount?: InputMaybe; fee_token_contract?: InputMaybe; + network?: InputMaybe; nonce?: InputMaybe; op_type?: InputMaybe; operation?: InputMaybe; @@ -3474,6 +3561,7 @@ export type Fee_Token_Management_Order_By = { chain?: InputMaybe; fee_token_amount?: InputMaybe; fee_token_contract?: InputMaybe; + network?: InputMaybe; nonce?: InputMaybe; op_type?: InputMaybe; operation?: InputMaybe; @@ -4111,6 +4199,8 @@ export type Identity_Default_Transfer = { gistreplaced_by: Scalars['String']['output']; id: Scalars['String']['output']; /** An object relationship */ + network?: Maybe; + /** An object relationship */ operation?: Maybe; operation_index: Scalars['String']['output']; replaced_gist_hash: Scalars['String']['output']; @@ -4155,6 +4245,7 @@ export type Identity_Default_Transfer_Bool_Exp = { gisthash?: InputMaybe; gistreplaced_by?: InputMaybe; id?: InputMaybe; + network?: InputMaybe; operation?: InputMaybe; operation_index?: InputMaybe; replaced_gist_hash?: InputMaybe; @@ -4212,6 +4303,7 @@ export type Identity_Default_Transfer_Order_By = { gisthash?: InputMaybe; gistreplaced_by?: InputMaybe; id?: InputMaybe; + network?: InputMaybe; operation?: InputMaybe; operation_index?: InputMaybe; replaced_gist_hash?: InputMaybe; @@ -4280,6 +4372,270 @@ export type Identity_Default_Transfer_Stream_Cursor_Value_Input = { state_replaced_by?: InputMaybe; }; +/** columns and relationships of "identity_gist_transfer" */ +export type Identity_Gist_Transfer = { + __typename?: 'identity_gist_transfer'; + chain: Scalars['String']['output']; + contract: Scalars['String']['output']; + gistcreated_at_block: Scalars['String']['output']; + gistcreated_at_timestamp: Scalars['String']['output']; + gisthash: Scalars['String']['output']; + /** An object relationship */ + network?: Maybe; + /** An object relationship */ + operation?: Maybe; + operation_index: Scalars['String']['output']; + replaced_gist_hash: Scalars['String']['output']; +}; + +/** aggregated selection of "identity_gist_transfer" */ +export type Identity_Gist_Transfer_Aggregate = { + __typename?: 'identity_gist_transfer_aggregate'; + aggregate?: Maybe; + nodes: Array; +}; + +/** aggregate fields of "identity_gist_transfer" */ +export type Identity_Gist_Transfer_Aggregate_Fields = { + __typename?: 'identity_gist_transfer_aggregate_fields'; + count: Scalars['Int']['output']; + max?: Maybe; + min?: Maybe; +}; + + +/** aggregate fields of "identity_gist_transfer" */ +export type Identity_Gist_Transfer_Aggregate_FieldsCountArgs = { + columns?: InputMaybe>; + distinct?: InputMaybe; +}; + +/** Boolean expression to filter rows from the table "identity_gist_transfer". All fields are combined with a logical 'AND'. */ +export type Identity_Gist_Transfer_Bool_Exp = { + _and?: InputMaybe>; + _not?: InputMaybe; + _or?: InputMaybe>; + chain?: InputMaybe; + contract?: InputMaybe; + gistcreated_at_block?: InputMaybe; + gistcreated_at_timestamp?: InputMaybe; + gisthash?: InputMaybe; + network?: InputMaybe; + operation?: InputMaybe; + operation_index?: InputMaybe; + replaced_gist_hash?: InputMaybe; +}; + +/** aggregate max on columns */ +export type Identity_Gist_Transfer_Max_Fields = { + __typename?: 'identity_gist_transfer_max_fields'; + chain?: Maybe; + contract?: Maybe; + gistcreated_at_block?: Maybe; + gistcreated_at_timestamp?: Maybe; + gisthash?: Maybe; + operation_index?: Maybe; + replaced_gist_hash?: Maybe; +}; + +/** aggregate min on columns */ +export type Identity_Gist_Transfer_Min_Fields = { + __typename?: 'identity_gist_transfer_min_fields'; + chain?: Maybe; + contract?: Maybe; + gistcreated_at_block?: Maybe; + gistcreated_at_timestamp?: Maybe; + gisthash?: Maybe; + operation_index?: Maybe; + replaced_gist_hash?: Maybe; +}; + +/** Ordering options when selecting data from "identity_gist_transfer". */ +export type Identity_Gist_Transfer_Order_By = { + chain?: InputMaybe; + contract?: InputMaybe; + gistcreated_at_block?: InputMaybe; + gistcreated_at_timestamp?: InputMaybe; + gisthash?: InputMaybe; + network?: InputMaybe; + operation?: InputMaybe; + operation_index?: InputMaybe; + replaced_gist_hash?: InputMaybe; +}; + +/** select columns of table "identity_gist_transfer" */ +export enum Identity_Gist_Transfer_Select_Column { + /** column name */ + Chain = 'chain', + /** column name */ + Contract = 'contract', + /** column name */ + GistcreatedAtBlock = 'gistcreated_at_block', + /** column name */ + GistcreatedAtTimestamp = 'gistcreated_at_timestamp', + /** column name */ + Gisthash = 'gisthash', + /** column name */ + OperationIndex = 'operation_index', + /** column name */ + ReplacedGistHash = 'replaced_gist_hash' +} + +/** Streaming cursor of the table "identity_gist_transfer" */ +export type Identity_Gist_Transfer_Stream_Cursor_Input = { + /** Stream column input with initial value */ + initial_value: Identity_Gist_Transfer_Stream_Cursor_Value_Input; + /** cursor ordering */ + ordering?: InputMaybe; +}; + +/** Initial value of the column from where the streaming should start */ +export type Identity_Gist_Transfer_Stream_Cursor_Value_Input = { + chain?: InputMaybe; + contract?: InputMaybe; + gistcreated_at_block?: InputMaybe; + gistcreated_at_timestamp?: InputMaybe; + gisthash?: InputMaybe; + operation_index?: InputMaybe; + replaced_gist_hash?: InputMaybe; +}; + +/** columns and relationships of "identity_state_transfer" */ +export type Identity_State_Transfer = { + __typename?: 'identity_state_transfer'; + chain: Scalars['String']['output']; + contract: Scalars['String']['output']; + id: Scalars['String']['output']; + /** An object relationship */ + network?: Maybe; + /** An object relationship */ + operation?: Maybe; + operation_index: Scalars['String']['output']; + replaced_state_hash: Scalars['String']['output']; + state_created_at_block: Scalars['String']['output']; + state_created_at_timestamp: Scalars['String']['output']; + state_hash: Scalars['String']['output']; +}; + +/** aggregated selection of "identity_state_transfer" */ +export type Identity_State_Transfer_Aggregate = { + __typename?: 'identity_state_transfer_aggregate'; + aggregate?: Maybe; + nodes: Array; +}; + +/** aggregate fields of "identity_state_transfer" */ +export type Identity_State_Transfer_Aggregate_Fields = { + __typename?: 'identity_state_transfer_aggregate_fields'; + count: Scalars['Int']['output']; + max?: Maybe; + min?: Maybe; +}; + + +/** aggregate fields of "identity_state_transfer" */ +export type Identity_State_Transfer_Aggregate_FieldsCountArgs = { + columns?: InputMaybe>; + distinct?: InputMaybe; +}; + +/** Boolean expression to filter rows from the table "identity_state_transfer". All fields are combined with a logical 'AND'. */ +export type Identity_State_Transfer_Bool_Exp = { + _and?: InputMaybe>; + _not?: InputMaybe; + _or?: InputMaybe>; + chain?: InputMaybe; + contract?: InputMaybe; + id?: InputMaybe; + network?: InputMaybe; + operation?: InputMaybe; + operation_index?: InputMaybe; + replaced_state_hash?: InputMaybe; + state_created_at_block?: InputMaybe; + state_created_at_timestamp?: InputMaybe; + state_hash?: InputMaybe; +}; + +/** aggregate max on columns */ +export type Identity_State_Transfer_Max_Fields = { + __typename?: 'identity_state_transfer_max_fields'; + chain?: Maybe; + contract?: Maybe; + id?: Maybe; + operation_index?: Maybe; + replaced_state_hash?: Maybe; + state_created_at_block?: Maybe; + state_created_at_timestamp?: Maybe; + state_hash?: Maybe; +}; + +/** aggregate min on columns */ +export type Identity_State_Transfer_Min_Fields = { + __typename?: 'identity_state_transfer_min_fields'; + chain?: Maybe; + contract?: Maybe; + id?: Maybe; + operation_index?: Maybe; + replaced_state_hash?: Maybe; + state_created_at_block?: Maybe; + state_created_at_timestamp?: Maybe; + state_hash?: Maybe; +}; + +/** Ordering options when selecting data from "identity_state_transfer". */ +export type Identity_State_Transfer_Order_By = { + chain?: InputMaybe; + contract?: InputMaybe; + id?: InputMaybe; + network?: InputMaybe; + operation?: InputMaybe; + operation_index?: InputMaybe; + replaced_state_hash?: InputMaybe; + state_created_at_block?: InputMaybe; + state_created_at_timestamp?: InputMaybe; + state_hash?: InputMaybe; +}; + +/** select columns of table "identity_state_transfer" */ +export enum Identity_State_Transfer_Select_Column { + /** column name */ + Chain = 'chain', + /** column name */ + Contract = 'contract', + /** column name */ + Id = 'id', + /** column name */ + OperationIndex = 'operation_index', + /** column name */ + ReplacedStateHash = 'replaced_state_hash', + /** column name */ + StateCreatedAtBlock = 'state_created_at_block', + /** column name */ + StateCreatedAtTimestamp = 'state_created_at_timestamp', + /** column name */ + StateHash = 'state_hash' +} + +/** Streaming cursor of the table "identity_state_transfer" */ +export type Identity_State_Transfer_Stream_Cursor_Input = { + /** Stream column input with initial value */ + initial_value: Identity_State_Transfer_Stream_Cursor_Value_Input; + /** cursor ordering */ + ordering?: InputMaybe; +}; + +/** Initial value of the column from where the streaming should start */ +export type Identity_State_Transfer_Stream_Cursor_Value_Input = { + chain?: InputMaybe; + contract?: InputMaybe; + id?: InputMaybe; + operation_index?: InputMaybe; + replaced_state_hash?: InputMaybe; + state_created_at_block?: InputMaybe; + state_created_at_timestamp?: InputMaybe; + state_hash?: InputMaybe; +}; + /** columns and relationships of "inflation" */ export type Inflation = { __typename?: 'inflation'; @@ -5392,6 +5748,8 @@ export type Multisig_Proposal_Variance_Fields = { /** columns and relationships of "multisig_proposal_vote" */ export type Multisig_Proposal_Vote = { __typename?: 'multisig_proposal_vote'; + /** An object relationship */ + block?: Maybe; index: Scalars['String']['output']; option: Scalars['Int']['output']; /** An object relationship */ @@ -5446,6 +5804,7 @@ export type Multisig_Proposal_Vote_Bool_Exp = { _and?: InputMaybe>; _not?: InputMaybe; _or?: InputMaybe>; + block?: InputMaybe; index?: InputMaybe; option?: InputMaybe; proposal?: InputMaybe; @@ -5477,6 +5836,7 @@ export type Multisig_Proposal_Vote_Min_Fields = { /** Ordering options when selecting data from "multisig_proposal_vote". */ export type Multisig_Proposal_Vote_Order_By = { + block?: InputMaybe; index?: InputMaybe; option?: InputMaybe; proposal?: InputMaybe; @@ -5573,6 +5933,154 @@ export type Multisig_Proposal_Vote_Variance_Fields = { submit_block?: Maybe; }; +/** columns and relationships of "network" */ +export type Network = { + __typename?: 'network'; + name: Scalars['String']['output']; + params: Scalars['jsonb']['output']; + type: Scalars['Int']['output']; +}; + + +/** columns and relationships of "network" */ +export type NetworkParamsArgs = { + path?: InputMaybe; +}; + +/** aggregated selection of "network" */ +export type Network_Aggregate = { + __typename?: 'network_aggregate'; + aggregate?: Maybe; + nodes: Array; +}; + +/** aggregate fields of "network" */ +export type Network_Aggregate_Fields = { + __typename?: 'network_aggregate_fields'; + avg?: Maybe; + count: Scalars['Int']['output']; + max?: Maybe; + min?: Maybe; + stddev?: Maybe; + stddev_pop?: Maybe; + stddev_samp?: Maybe; + sum?: Maybe; + var_pop?: Maybe; + var_samp?: Maybe; + variance?: Maybe; +}; + + +/** aggregate fields of "network" */ +export type Network_Aggregate_FieldsCountArgs = { + columns?: InputMaybe>; + distinct?: InputMaybe; +}; + +/** aggregate avg on columns */ +export type Network_Avg_Fields = { + __typename?: 'network_avg_fields'; + type?: Maybe; +}; + +/** Boolean expression to filter rows from the table "network". All fields are combined with a logical 'AND'. */ +export type Network_Bool_Exp = { + _and?: InputMaybe>; + _not?: InputMaybe; + _or?: InputMaybe>; + name?: InputMaybe; + params?: InputMaybe; + type?: InputMaybe; +}; + +/** aggregate max on columns */ +export type Network_Max_Fields = { + __typename?: 'network_max_fields'; + name?: Maybe; + type?: Maybe; +}; + +/** aggregate min on columns */ +export type Network_Min_Fields = { + __typename?: 'network_min_fields'; + name?: Maybe; + type?: Maybe; +}; + +/** Ordering options when selecting data from "network". */ +export type Network_Order_By = { + name?: InputMaybe; + params?: InputMaybe; + type?: InputMaybe; +}; + +/** select columns of table "network" */ +export enum Network_Select_Column { + /** column name */ + Name = 'name', + /** column name */ + Params = 'params', + /** column name */ + Type = 'type' +} + +/** aggregate stddev on columns */ +export type Network_Stddev_Fields = { + __typename?: 'network_stddev_fields'; + type?: Maybe; +}; + +/** aggregate stddev_pop on columns */ +export type Network_Stddev_Pop_Fields = { + __typename?: 'network_stddev_pop_fields'; + type?: Maybe; +}; + +/** aggregate stddev_samp on columns */ +export type Network_Stddev_Samp_Fields = { + __typename?: 'network_stddev_samp_fields'; + type?: Maybe; +}; + +/** Streaming cursor of the table "network" */ +export type Network_Stream_Cursor_Input = { + /** Stream column input with initial value */ + initial_value: Network_Stream_Cursor_Value_Input; + /** cursor ordering */ + ordering?: InputMaybe; +}; + +/** Initial value of the column from where the streaming should start */ +export type Network_Stream_Cursor_Value_Input = { + name?: InputMaybe; + params?: InputMaybe; + type?: InputMaybe; +}; + +/** aggregate sum on columns */ +export type Network_Sum_Fields = { + __typename?: 'network_sum_fields'; + type?: Maybe; +}; + +/** aggregate var_pop on columns */ +export type Network_Var_Pop_Fields = { + __typename?: 'network_var_pop_fields'; + type?: Maybe; +}; + +/** aggregate var_samp on columns */ +export type Network_Var_Samp_Fields = { + __typename?: 'network_var_samp_fields'; + type?: Maybe; +}; + +/** aggregate variance on columns */ +export type Network_Variance_Fields = { + __typename?: 'network_variance_fields'; + type?: Maybe; +}; + /** Boolean expression to compare columns of type "numeric". All fields are combined with logical 'AND'. */ export type Numeric_Comparison_Exp = { _eq?: InputMaybe; @@ -5688,6 +6196,10 @@ export type Operation = { fee_token_management?: Maybe; /** An object relationship */ identity_default_transfer?: Maybe; + /** An object relationship */ + identity_gist_transfer?: Maybe; + /** An object relationship */ + identity_state_transfer?: Maybe; index: Scalars['String']['output']; operation_type: Scalars['Int']['output']; status: Scalars['Int']['output']; @@ -5778,6 +6290,8 @@ export type Operation_Bool_Exp = { creator_account?: InputMaybe; fee_token_management?: InputMaybe; identity_default_transfer?: InputMaybe; + identity_gist_transfer?: InputMaybe; + identity_state_transfer?: InputMaybe; index?: InputMaybe; operation_type?: InputMaybe; status?: InputMaybe; @@ -5831,6 +6345,8 @@ export type Operation_Order_By = { creator_account?: InputMaybe; fee_token_management?: InputMaybe; identity_default_transfer?: InputMaybe; + identity_gist_transfer?: InputMaybe; + identity_state_transfer?: InputMaybe; index?: InputMaybe; operation_type?: InputMaybe; status?: InputMaybe; @@ -5983,6 +6499,8 @@ export type Oracle = { freeze_end_block: Scalars['Int']['output']; index: Scalars['String']['output']; missed_count: Scalars['Int']['output']; + /** An object relationship */ + network?: Maybe; stake: Scalars['String']['output']; status: Scalars['Int']['output']; /** An object relationship */ @@ -6043,6 +6561,7 @@ export type Oracle_Bool_Exp = { freeze_end_block?: InputMaybe; index?: InputMaybe; missed_count?: InputMaybe; + network?: InputMaybe; stake?: InputMaybe; status?: InputMaybe; user?: InputMaybe; @@ -6088,6 +6607,7 @@ export type Oracle_Order_By = { freeze_end_block?: InputMaybe; index?: InputMaybe; missed_count?: InputMaybe; + network?: InputMaybe; stake?: InputMaybe; status?: InputMaybe; user?: InputMaybe; @@ -8900,6 +9420,18 @@ export type Query_Root = { identity_default_transfer_aggregate: Identity_Default_Transfer_Aggregate; /** fetch data from the table: "identity_default_transfer" using primary key columns */ identity_default_transfer_by_pk?: Maybe; + /** fetch data from the table: "identity_gist_transfer" */ + identity_gist_transfer: Array; + /** fetch aggregated fields from the table: "identity_gist_transfer" */ + identity_gist_transfer_aggregate: Identity_Gist_Transfer_Aggregate; + /** fetch data from the table: "identity_gist_transfer" using primary key columns */ + identity_gist_transfer_by_pk?: Maybe; + /** fetch data from the table: "identity_state_transfer" */ + identity_state_transfer: Array; + /** fetch aggregated fields from the table: "identity_state_transfer" */ + identity_state_transfer_aggregate: Identity_State_Transfer_Aggregate; + /** fetch data from the table: "identity_state_transfer" using primary key columns */ + identity_state_transfer_by_pk?: Maybe; /** fetch data from the table: "inflation" */ inflation: Array; /** fetch aggregated fields from the table: "inflation" */ @@ -8948,6 +9480,12 @@ export type Query_Root = { multisig_proposal_vote_aggregate: Multisig_Proposal_Vote_Aggregate; /** fetch data from the table: "multisig_proposal_vote" using primary key columns */ multisig_proposal_vote_by_pk?: Maybe; + /** fetch data from the table: "network" */ + network: Array; + /** fetch aggregated fields from the table: "network" */ + network_aggregate: Network_Aggregate; + /** fetch data from the table: "network" using primary key columns */ + network_by_pk?: Maybe; /** fetch data from the table: "on_chain_item" */ on_chain_item: Array; /** fetch aggregated fields from the table: "on_chain_item" */ @@ -9062,10 +9600,6 @@ export type Query_Root = { token_unit: Array; /** fetch aggregated fields from the table: "token_unit" */ token_unit_aggregate: Token_Unit_Aggregate; - /** fetch data from the table: "tokenmanager_params" */ - tokenmanager_params: Array; - /** fetch aggregated fields from the table: "tokenmanager_params" */ - tokenmanager_params_aggregate: Tokenmanager_Params_Aggregate; /** fetch data from the table: "transaction" */ transaction: Array; /** fetch aggregated fields from the table: "transaction" */ @@ -9723,6 +10257,52 @@ export type Query_RootIdentity_Default_Transfer_By_PkArgs = { }; +export type Query_RootIdentity_Gist_TransferArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootIdentity_Gist_Transfer_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootIdentity_Gist_Transfer_By_PkArgs = { + operation_index: Scalars['String']['input']; +}; + + +export type Query_RootIdentity_State_TransferArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootIdentity_State_Transfer_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootIdentity_State_Transfer_By_PkArgs = { + operation_index: Scalars['String']['input']; +}; + + export type Query_RootInflationArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -9917,6 +10497,29 @@ export type Query_RootMultisig_Proposal_Vote_By_PkArgs = { }; +export type Query_RootNetworkArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootNetwork_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Query_RootNetwork_By_PkArgs = { + name: Scalars['String']['input']; +}; + + export type Query_RootOn_Chain_ItemArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -10378,24 +10981,6 @@ export type Query_RootToken_Unit_AggregateArgs = { }; -export type Query_RootTokenmanager_ParamsArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - -export type Query_RootTokenmanager_Params_AggregateArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - export type Query_RootTransactionArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -11615,6 +12200,22 @@ export type Subscription_Root = { identity_default_transfer_by_pk?: Maybe; /** fetch data from the table in a streaming manner: "identity_default_transfer" */ identity_default_transfer_stream: Array; + /** fetch data from the table: "identity_gist_transfer" */ + identity_gist_transfer: Array; + /** fetch aggregated fields from the table: "identity_gist_transfer" */ + identity_gist_transfer_aggregate: Identity_Gist_Transfer_Aggregate; + /** fetch data from the table: "identity_gist_transfer" using primary key columns */ + identity_gist_transfer_by_pk?: Maybe; + /** fetch data from the table in a streaming manner: "identity_gist_transfer" */ + identity_gist_transfer_stream: Array; + /** fetch data from the table: "identity_state_transfer" */ + identity_state_transfer: Array; + /** fetch aggregated fields from the table: "identity_state_transfer" */ + identity_state_transfer_aggregate: Identity_State_Transfer_Aggregate; + /** fetch data from the table: "identity_state_transfer" using primary key columns */ + identity_state_transfer_by_pk?: Maybe; + /** fetch data from the table in a streaming manner: "identity_state_transfer" */ + identity_state_transfer_stream: Array; /** fetch data from the table: "inflation" */ inflation: Array; /** fetch aggregated fields from the table: "inflation" */ @@ -11679,6 +12280,14 @@ export type Subscription_Root = { multisig_proposal_vote_by_pk?: Maybe; /** fetch data from the table in a streaming manner: "multisig_proposal_vote" */ multisig_proposal_vote_stream: Array; + /** fetch data from the table: "network" */ + network: Array; + /** fetch aggregated fields from the table: "network" */ + network_aggregate: Network_Aggregate; + /** fetch data from the table: "network" using primary key columns */ + network_by_pk?: Maybe; + /** fetch data from the table in a streaming manner: "network" */ + network_stream: Array; /** fetch data from the table: "on_chain_item" */ on_chain_item: Array; /** fetch aggregated fields from the table: "on_chain_item" */ @@ -11837,12 +12446,6 @@ export type Subscription_Root = { token_unit_aggregate: Token_Unit_Aggregate; /** fetch data from the table in a streaming manner: "token_unit" */ token_unit_stream: Array; - /** fetch data from the table: "tokenmanager_params" */ - tokenmanager_params: Array; - /** fetch aggregated fields from the table: "tokenmanager_params" */ - tokenmanager_params_aggregate: Tokenmanager_Params_Aggregate; - /** fetch data from the table in a streaming manner: "tokenmanager_params" */ - tokenmanager_params_stream: Array; /** fetch data from the table: "transaction" */ transaction: Array; /** fetch aggregated fields from the table: "transaction" */ @@ -12601,6 +13204,66 @@ export type Subscription_RootIdentity_Default_Transfer_StreamArgs = { }; +export type Subscription_RootIdentity_Gist_TransferArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootIdentity_Gist_Transfer_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootIdentity_Gist_Transfer_By_PkArgs = { + operation_index: Scalars['String']['input']; +}; + + +export type Subscription_RootIdentity_Gist_Transfer_StreamArgs = { + batch_size: Scalars['Int']['input']; + cursor: Array>; + where?: InputMaybe; +}; + + +export type Subscription_RootIdentity_State_TransferArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootIdentity_State_Transfer_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootIdentity_State_Transfer_By_PkArgs = { + operation_index: Scalars['String']['input']; +}; + + +export type Subscription_RootIdentity_State_Transfer_StreamArgs = { + batch_size: Scalars['Int']['input']; + cursor: Array>; + where?: InputMaybe; +}; + + export type Subscription_RootInflationArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -12851,6 +13514,36 @@ export type Subscription_RootMultisig_Proposal_Vote_StreamArgs = { }; +export type Subscription_RootNetworkArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootNetwork_AggregateArgs = { + distinct_on?: InputMaybe>; + limit?: InputMaybe; + offset?: InputMaybe; + order_by?: InputMaybe>; + where?: InputMaybe; +}; + + +export type Subscription_RootNetwork_By_PkArgs = { + name: Scalars['String']['input']; +}; + + +export type Subscription_RootNetwork_StreamArgs = { + batch_size: Scalars['Int']['input']; + cursor: Array>; + where?: InputMaybe; +}; + + export type Subscription_RootOn_Chain_ItemArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -13461,33 +14154,8 @@ export type Subscription_RootToken_Unit_AggregateArgs = { export type Subscription_RootToken_Unit_StreamArgs = { batch_size: Scalars['Int']['input']; - cursor: Array>; - where?: InputMaybe; -}; - - -export type Subscription_RootTokenmanager_ParamsArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - -export type Subscription_RootTokenmanager_Params_AggregateArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - -export type Subscription_RootTokenmanager_Params_StreamArgs = { - batch_size: Scalars['Int']['input']; - cursor: Array>; - where?: InputMaybe; + cursor: Array>; + where?: InputMaybe; }; @@ -14952,146 +15620,6 @@ export type Token_Unit_Variance_Order_By = { exponent?: InputMaybe; }; -/** columns and relationships of "tokenmanager_params" */ -export type Tokenmanager_Params = { - __typename?: 'tokenmanager_params'; - height: Scalars['bigint']['output']; - params: Scalars['jsonb']['output']; -}; - - -/** columns and relationships of "tokenmanager_params" */ -export type Tokenmanager_ParamsParamsArgs = { - path?: InputMaybe; -}; - -/** aggregated selection of "tokenmanager_params" */ -export type Tokenmanager_Params_Aggregate = { - __typename?: 'tokenmanager_params_aggregate'; - aggregate?: Maybe; - nodes: Array; -}; - -/** aggregate fields of "tokenmanager_params" */ -export type Tokenmanager_Params_Aggregate_Fields = { - __typename?: 'tokenmanager_params_aggregate_fields'; - avg?: Maybe; - count: Scalars['Int']['output']; - max?: Maybe; - min?: Maybe; - stddev?: Maybe; - stddev_pop?: Maybe; - stddev_samp?: Maybe; - sum?: Maybe; - var_pop?: Maybe; - var_samp?: Maybe; - variance?: Maybe; -}; - - -/** aggregate fields of "tokenmanager_params" */ -export type Tokenmanager_Params_Aggregate_FieldsCountArgs = { - columns?: InputMaybe>; - distinct?: InputMaybe; -}; - -/** aggregate avg on columns */ -export type Tokenmanager_Params_Avg_Fields = { - __typename?: 'tokenmanager_params_avg_fields'; - height?: Maybe; -}; - -/** Boolean expression to filter rows from the table "tokenmanager_params". All fields are combined with a logical 'AND'. */ -export type Tokenmanager_Params_Bool_Exp = { - _and?: InputMaybe>; - _not?: InputMaybe; - _or?: InputMaybe>; - height?: InputMaybe; - params?: InputMaybe; -}; - -/** aggregate max on columns */ -export type Tokenmanager_Params_Max_Fields = { - __typename?: 'tokenmanager_params_max_fields'; - height?: Maybe; -}; - -/** aggregate min on columns */ -export type Tokenmanager_Params_Min_Fields = { - __typename?: 'tokenmanager_params_min_fields'; - height?: Maybe; -}; - -/** Ordering options when selecting data from "tokenmanager_params". */ -export type Tokenmanager_Params_Order_By = { - height?: InputMaybe; - params?: InputMaybe; -}; - -/** select columns of table "tokenmanager_params" */ -export enum Tokenmanager_Params_Select_Column { - /** column name */ - Height = 'height', - /** column name */ - Params = 'params' -} - -/** aggregate stddev on columns */ -export type Tokenmanager_Params_Stddev_Fields = { - __typename?: 'tokenmanager_params_stddev_fields'; - height?: Maybe; -}; - -/** aggregate stddev_pop on columns */ -export type Tokenmanager_Params_Stddev_Pop_Fields = { - __typename?: 'tokenmanager_params_stddev_pop_fields'; - height?: Maybe; -}; - -/** aggregate stddev_samp on columns */ -export type Tokenmanager_Params_Stddev_Samp_Fields = { - __typename?: 'tokenmanager_params_stddev_samp_fields'; - height?: Maybe; -}; - -/** Streaming cursor of the table "tokenmanager_params" */ -export type Tokenmanager_Params_Stream_Cursor_Input = { - /** Stream column input with initial value */ - initial_value: Tokenmanager_Params_Stream_Cursor_Value_Input; - /** cursor ordering */ - ordering?: InputMaybe; -}; - -/** Initial value of the column from where the streaming should start */ -export type Tokenmanager_Params_Stream_Cursor_Value_Input = { - height?: InputMaybe; - params?: InputMaybe; -}; - -/** aggregate sum on columns */ -export type Tokenmanager_Params_Sum_Fields = { - __typename?: 'tokenmanager_params_sum_fields'; - height?: Maybe; -}; - -/** aggregate var_pop on columns */ -export type Tokenmanager_Params_Var_Pop_Fields = { - __typename?: 'tokenmanager_params_var_pop_fields'; - height?: Maybe; -}; - -/** aggregate var_samp on columns */ -export type Tokenmanager_Params_Var_Samp_Fields = { - __typename?: 'tokenmanager_params_var_samp_fields'; - height?: Maybe; -}; - -/** aggregate variance on columns */ -export type Tokenmanager_Params_Variance_Fields = { - __typename?: 'tokenmanager_params_variance_fields'; - height?: Maybe; -}; - /** columns and relationships of "transaction" */ export type Transaction = { __typename?: 'transaction'; @@ -18306,9 +18834,15 @@ export type Violation_Report_Variance_Fields = { /** columns and relationships of "vote" */ export type Vote = { __typename?: 'vote'; + /** An object relationship */ + block?: Maybe; + height: Scalars['bigint']['output']; operation: Scalars['String']['output']; /** An object relationship */ operation_info?: Maybe; + /** An object relationship */ + transaction?: Maybe; + tx?: Maybe; validator: Scalars['String']['output']; /** An object relationship */ validator_info?: Maybe; @@ -18348,6 +18882,7 @@ export type Vote_Aggregate_FieldsCountArgs = { /** aggregate avg on columns */ export type Vote_Avg_Fields = { __typename?: 'vote_avg_fields'; + height?: Maybe; vote?: Maybe; }; @@ -18356,8 +18891,12 @@ export type Vote_Bool_Exp = { _and?: InputMaybe>; _not?: InputMaybe; _or?: InputMaybe>; + block?: InputMaybe; + height?: InputMaybe; operation?: InputMaybe; operation_info?: InputMaybe; + transaction?: InputMaybe; + tx?: InputMaybe; validator?: InputMaybe; validator_info?: InputMaybe; vote?: InputMaybe; @@ -18366,7 +18905,9 @@ export type Vote_Bool_Exp = { /** aggregate max on columns */ export type Vote_Max_Fields = { __typename?: 'vote_max_fields'; + height?: Maybe; operation?: Maybe; + tx?: Maybe; validator?: Maybe; vote?: Maybe; }; @@ -18374,15 +18915,21 @@ export type Vote_Max_Fields = { /** aggregate min on columns */ export type Vote_Min_Fields = { __typename?: 'vote_min_fields'; + height?: Maybe; operation?: Maybe; + tx?: Maybe; validator?: Maybe; vote?: Maybe; }; /** Ordering options when selecting data from "vote". */ export type Vote_Order_By = { + block?: InputMaybe; + height?: InputMaybe; operation?: InputMaybe; operation_info?: InputMaybe; + transaction?: InputMaybe; + tx?: InputMaybe; validator?: InputMaybe; validator_info?: InputMaybe; vote?: InputMaybe; @@ -18390,9 +18937,13 @@ export type Vote_Order_By = { /** select columns of table "vote" */ export enum Vote_Select_Column { + /** column name */ + Height = 'height', /** column name */ Operation = 'operation', /** column name */ + Tx = 'tx', + /** column name */ Validator = 'validator', /** column name */ Vote = 'vote' @@ -18401,18 +18952,21 @@ export enum Vote_Select_Column { /** aggregate stddev on columns */ export type Vote_Stddev_Fields = { __typename?: 'vote_stddev_fields'; + height?: Maybe; vote?: Maybe; }; /** aggregate stddev_pop on columns */ export type Vote_Stddev_Pop_Fields = { __typename?: 'vote_stddev_pop_fields'; + height?: Maybe; vote?: Maybe; }; /** aggregate stddev_samp on columns */ export type Vote_Stddev_Samp_Fields = { __typename?: 'vote_stddev_samp_fields'; + height?: Maybe; vote?: Maybe; }; @@ -18426,7 +18980,9 @@ export type Vote_Stream_Cursor_Input = { /** Initial value of the column from where the streaming should start */ export type Vote_Stream_Cursor_Value_Input = { + height?: InputMaybe; operation?: InputMaybe; + tx?: InputMaybe; validator?: InputMaybe; vote?: InputMaybe; }; @@ -18434,24 +18990,28 @@ export type Vote_Stream_Cursor_Value_Input = { /** aggregate sum on columns */ export type Vote_Sum_Fields = { __typename?: 'vote_sum_fields'; + height?: Maybe; vote?: Maybe; }; /** aggregate var_pop on columns */ export type Vote_Var_Pop_Fields = { __typename?: 'vote_var_pop_fields'; + height?: Maybe; vote?: Maybe; }; /** aggregate var_samp on columns */ export type Vote_Var_Samp_Fields = { __typename?: 'vote_var_samp_fields'; + height?: Maybe; vote?: Maybe; }; /** aggregate variance on columns */ export type Vote_Variance_Fields = { __typename?: 'vote_variance_fields'; + height?: Maybe; vote?: Maybe; }; @@ -18461,6 +19021,14 @@ export type BlockBaseFragment = { __typename?: 'block', height: any, timestamp: export type BlockListFragment = { __typename?: 'block', height: any, timestamp: any, total_gas?: any | null, transactions_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', moniker?: string | null, avatar_url?: string | null }> } | null }; +export type ConfirmationFragment = { __typename?: 'confirmation', creator: string, height: any, tx?: string | null, root: string, indexes: any, signature_ecdsa: string, block?: { __typename?: 'block', timestamp: any } | null }; + +export type ConfirmationBaseFragment = { __typename?: 'confirmation', root: string, creator: string, height: any, tx?: string | null, block?: { __typename?: 'block', timestamp: any } | null }; + +export type OperationFragment = { __typename?: 'operation', index: string, operation_type: number, status: number, creator: string, timestamp: any }; + +export type OperationVoteFragment = { __typename?: 'vote', operation: string, height: any, tx?: string | null, validator: string, vote: number, block?: { __typename?: 'block', timestamp: any } | null }; + export type OracleFragment = { __typename?: 'oracle', account: string, chain: string, status: number, stake: string, missed_count: number, freeze_end_block: number, violations_count: number, votes_count: number, create_operations_count: number }; export type OracleBaseFragment = { __typename?: 'oracle', account: string, chain: string, status: number, stake: string }; @@ -18525,6 +19093,51 @@ export type GetBlockListQueryVariables = Exact<{ export type GetBlockListQuery = { __typename?: 'query_root', block: Array<{ __typename?: 'block', height: any, timestamp: any, total_gas?: any | null, transactions_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', moniker?: string | null, avatar_url?: string | null }> } | null }> }; +export type GetConfirmationByRootQueryVariables = Exact<{ + root: Scalars['String']['input']; +}>; + + +export type GetConfirmationByRootQuery = { __typename?: 'query_root', confirmation: Array<{ __typename?: 'confirmation', creator: string, height: any, tx?: string | null, root: string, indexes: any, signature_ecdsa: string, block?: { __typename?: 'block', timestamp: any } | null }> }; + +export type GetConfirmationCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetConfirmationCountQuery = { __typename?: 'query_root', confirmation_aggregate: { __typename?: 'confirmation_aggregate', aggregate?: { __typename?: 'confirmation_aggregate_fields', count: number } | null } }; + +export type GetConfirmationListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; +}>; + + +export type GetConfirmationListQuery = { __typename?: 'query_root', confirmation: Array<{ __typename?: 'confirmation', root: string, creator: string, height: any, tx?: string | null, block?: { __typename?: 'block', timestamp: any } | null }> }; + +export type GetConfirmationOperationListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; + where: Operation_Bool_Exp; +}>; + + +export type GetConfirmationOperationListQuery = { __typename?: 'query_root', operation: Array<{ __typename?: 'operation', index: string, operation_type: number, status: number, creator: string, timestamp: any }> }; + +export type GetConfirmationOperationVoteCountQueryVariables = Exact<{ + where: Vote_Bool_Exp; +}>; + + +export type GetConfirmationOperationVoteCountQuery = { __typename?: 'query_root', vote_aggregate: { __typename?: 'vote_aggregate', aggregate?: { __typename?: 'vote_aggregate_fields', count: number } | null } }; + +export type GetConfirmationOperationVoteListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; + where: Vote_Bool_Exp; +}>; + + +export type GetConfirmationOperationVoteListQuery = { __typename?: 'query_root', vote: Array<{ __typename?: 'vote', operation: string, height: any, tx?: string | null, validator: string, vote: number, block?: { __typename?: 'block', timestamp: any } | null }> }; + export type GetLatestTxAndBlocksQueryVariables = Exact<{ limit?: InputMaybe; offset?: InputMaybe; @@ -18533,6 +19146,42 @@ export type GetLatestTxAndBlocksQueryVariables = Exact<{ export type GetLatestTxAndBlocksQuery = { __typename?: 'query_root', transaction: Array<{ __typename?: 'transaction', height: any, hash: string, success: boolean, signer_infos: any, raw_log?: string | null, block: { __typename?: 'block', timestamp: any, height: any } }>, block: Array<{ __typename?: 'block', height: any, timestamp: any, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', avatar_url?: string | null, moniker?: string | null }> } | null }> }; +export type GetOperationByIndexQueryVariables = Exact<{ + index: Scalars['String']['input']; +}>; + + +export type GetOperationByIndexQuery = { __typename?: 'query_root', operation: Array<{ __typename?: 'operation', index: string, creator: string, operation_type: number, status: number, timestamp: any, change_parties?: { __typename?: 'change_parties', new_public_key: string, operation_index: string, parties: any, signature: string } | null, contract_upgrade?: { __typename?: 'contract_upgrade', buffer_account: string, chain: string, hash: string, new_implementation_contract: string, nonce: string, operation_index: string, target_contract: string, type: number, network?: { __typename?: 'network', name: string, params: any, type: number } | null } | null, fee_token_management?: { __typename?: 'fee_token_management', chain: string, fee_token_amount: string, fee_token_contract: string, nonce: string, op_type: number, operation_index: string, receiver: string, network?: { __typename?: 'network', name: string, params: any, type: number } | null } | null, identity_default_transfer?: { __typename?: 'identity_default_transfer', chain: string, contract: string, gistcreated_at_block: string, gistcreated_at_timestamp: string, gisthash: string, gistreplaced_by: string, id: string, operation_index: string, replaced_gist_hash: string, replaced_state_hash: string, state_created_at_block: string, state_created_at_timestamp: string, state_hash: string, state_replaced_by: string, network?: { __typename?: 'network', name: string, params: any, type: number } | null } | null, identity_gist_transfer?: { __typename?: 'identity_gist_transfer', chain: string, contract: string, gistcreated_at_block: string, gistcreated_at_timestamp: string, gisthash: string, operation_index: string, replaced_gist_hash: string, network?: { __typename?: 'network', name: string, params: any, type: number } | null } | null, identity_state_transfer?: { __typename?: 'identity_state_transfer', chain: string, contract: string, id: string, operation_index: string, replaced_state_hash: string, state_created_at_block: string, state_created_at_timestamp: string, state_hash: string } | null, transfer?: { __typename?: 'transfer', amount: string, bundle_data?: string | null, bundle_salt?: string | null, event_id: string, from: any, item_meta?: any | null, operation_index: string, origin: string, receiver: string, to: any, tx: string } | null }>, confirmation: Array<{ __typename?: 'confirmation', creator: string, height: any, tx?: string | null, root: string, indexes: any, signature_ecdsa: string, block?: { __typename?: 'block', timestamp: any } | null }>, transaction: Array<{ __typename?: 'transaction', height: any, hash: string, success: boolean, signer_infos: any, raw_log?: string | null, block: { __typename?: 'block', timestamp: any, height: any } }> }; + +export type GetOperationCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetOperationCountQuery = { __typename?: 'query_root', operation_aggregate: { __typename?: 'operation_aggregate', aggregate?: { __typename?: 'operation_aggregate_fields', count: number } | null } }; + +export type GetOperationListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; +}>; + + +export type GetOperationListQuery = { __typename?: 'query_root', operation: Array<{ __typename?: 'operation', index: string, operation_type: number, status: number, creator: string, timestamp: any }> }; + +export type GetOperationVoteCountQueryVariables = Exact<{ + operation: Scalars['String']['input']; +}>; + + +export type GetOperationVoteCountQuery = { __typename?: 'query_root', vote_aggregate: { __typename?: 'vote_aggregate', aggregate?: { __typename?: 'vote_aggregate_fields', count: number } | null } }; + +export type GetOperationVoteListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; + operation: Scalars['String']['input']; +}>; + + +export type GetOperationVoteListQuery = { __typename?: 'query_root', vote: Array<{ __typename?: 'vote', operation: string, height: any, tx?: string | null, validator: string, vote: number, block?: { __typename?: 'block', timestamp: any } | null }> }; + export type GetOracleBaseQueryVariables = Exact<{ limit?: InputMaybe; offset?: InputMaybe; @@ -18802,6 +19451,51 @@ export const BlockList = gql` } } `; +export const Confirmation = gql` + fragment Confirmation on confirmation { + creator + height + tx + root + indexes + signature_ecdsa + block { + timestamp + } +} + `; +export const ConfirmationBase = gql` + fragment ConfirmationBase on confirmation { + root + creator + height + tx + block { + timestamp + } +} + `; +export const Operation = gql` + fragment Operation on operation { + index + operation_type + status + creator + timestamp +} + `; +export const OperationVote = gql` + fragment OperationVote on vote { + operation + height + tx + validator + vote + block { + timestamp + } +} + `; export const Oracle = gql` fragment Oracle on oracle { account @@ -19064,6 +19758,57 @@ export const GetBlockList = gql` } } ${BlockList}`; +export const GetConfirmationByRoot = gql` + query GetConfirmationByRoot($root: String!) { + confirmation(where: {root: {_eq: $root}}) { + ...Confirmation + } +} + ${Confirmation}`; +export const GetConfirmationCount = gql` + query GetConfirmationCount { + confirmation_aggregate { + aggregate { + count(columns: root) + } + } +} + `; +export const GetConfirmationList = gql` + query GetConfirmationList($limit: Int, $offset: Int) { + confirmation(limit: $limit, offset: $offset) { + ...ConfirmationBase + } +} + ${ConfirmationBase}`; +export const GetConfirmationOperationList = gql` + query GetConfirmationOperationList($limit: Int, $offset: Int, $where: operation_bool_exp!) { + operation( + order_by: {timestamp: desc} + limit: $limit + offset: $offset + where: $where + ) { + ...Operation + } +} + ${Operation}`; +export const GetConfirmationOperationVoteCount = gql` + query GetConfirmationOperationVoteCount($where: vote_bool_exp!) { + vote_aggregate(where: $where) { + aggregate { + count(columns: operation) + } + } +} + `; +export const GetConfirmationOperationVoteList = gql` + query GetConfirmationOperationVoteList($limit: Int, $offset: Int, $where: vote_bool_exp!) { + vote(order_by: {height: desc}, where: $where, limit: $limit, offset: $offset) { + ...OperationVote + } +} + ${OperationVote}`; export const GetLatestTxAndBlocks = gql` query GetLatestTxAndBlocks($limit: Int, $offset: Int) { transaction( @@ -19079,6 +19824,154 @@ export const GetLatestTxAndBlocks = gql` } ${TransactionBase} ${BlockBase}`; +export const GetOperationByIndex = gql` + query GetOperationByIndex($index: String!) { + operation(where: {index: {_eq: $index}}) { + index + creator + operation_type + status + timestamp + change_parties { + new_public_key + operation_index + parties + signature + } + contract_upgrade { + buffer_account + chain + hash + new_implementation_contract + nonce + operation_index + target_contract + type + network { + name + params + type + } + } + fee_token_management { + chain + fee_token_amount + fee_token_contract + nonce + op_type + operation_index + receiver + network { + name + params + type + } + } + identity_default_transfer { + chain + contract + gistcreated_at_block + gistcreated_at_timestamp + gisthash + gistreplaced_by + id + operation_index + replaced_gist_hash + replaced_state_hash + state_created_at_block + state_created_at_timestamp + state_hash + state_replaced_by + network { + name + params + type + } + } + identity_gist_transfer { + chain + contract + gistcreated_at_block + gistcreated_at_timestamp + gisthash + operation_index + replaced_gist_hash + network { + name + params + type + } + } + identity_state_transfer { + chain + contract + id + operation_index + replaced_state_hash + state_created_at_block + state_created_at_timestamp + state_hash + } + transfer { + amount + bundle_data + bundle_salt + event_id + from + item_meta + operation_index + origin + receiver + to + tx + } + } + confirmation(where: {root: {_in: [$index]}}) { + ...Confirmation + } + transaction(where: {raw_log: {_regex: $index, _iregex: "new_operation"}}) { + ...TransactionBase + } +} + ${Confirmation} +${TransactionBase}`; +export const GetOperationCount = gql` + query GetOperationCount { + operation_aggregate { + aggregate { + count(columns: index) + } + } +} + `; +export const GetOperationList = gql` + query GetOperationList($limit: Int, $offset: Int) { + operation(order_by: {timestamp: desc}, limit: $limit, offset: $offset) { + ...Operation + } +} + ${Operation}`; +export const GetOperationVoteCount = gql` + query GetOperationVoteCount($operation: String!) { + vote_aggregate(where: {operation: {_eq: $operation}}) { + aggregate { + count(columns: operation) + } + } +} + `; +export const GetOperationVoteList = gql` + query GetOperationVoteList($limit: Int, $offset: Int, $operation: String!) { + vote( + order_by: {height: desc} + where: {operation: {_eq: $operation}} + limit: $limit + offset: $offset + ) { + ...OperationVote + } +} + ${OperationVote}`; export const GetOracleBase = gql` query GetOracleBase($limit: Int, $offset: Int) { oracle(limit: $limit, offset: $offset) { diff --git a/src/graphql/queries/GetConfirmationByRoot.gql b/src/graphql/queries/GetConfirmationByRoot.gql new file mode 100644 index 0000000..1a8cadf --- /dev/null +++ b/src/graphql/queries/GetConfirmationByRoot.gql @@ -0,0 +1,6 @@ +query GetConfirmationByRoot($root: String!) { + confirmation(where: {root: {_eq: $root}}) { + ...Confirmation + } +} + diff --git a/src/graphql/queries/GetConfirmationCount.gql b/src/graphql/queries/GetConfirmationCount.gql new file mode 100644 index 0000000..fa47cb9 --- /dev/null +++ b/src/graphql/queries/GetConfirmationCount.gql @@ -0,0 +1,7 @@ +query GetConfirmationCount { + confirmation_aggregate { + aggregate { + count(columns: root) + } + } +} diff --git a/src/graphql/queries/GetConfirmationList.gql b/src/graphql/queries/GetConfirmationList.gql new file mode 100644 index 0000000..c3bc289 --- /dev/null +++ b/src/graphql/queries/GetConfirmationList.gql @@ -0,0 +1,5 @@ +query GetConfirmationList($limit: Int, $offset: Int) { + confirmation(limit: $limit, offset: $offset) { + ...ConfirmationBase + } +} diff --git a/src/graphql/queries/GetConfirmationOperationList.gql b/src/graphql/queries/GetConfirmationOperationList.gql new file mode 100644 index 0000000..9717555 --- /dev/null +++ b/src/graphql/queries/GetConfirmationOperationList.gql @@ -0,0 +1,5 @@ +query GetConfirmationOperationList($limit: Int, $offset: Int, $where: operation_bool_exp!) { + operation(order_by: { timestamp: desc }, limit: $limit, offset: $offset, where: $where) { + ...Operation + } +} diff --git a/src/graphql/queries/GetConfirmationOperationVoteCount.gql b/src/graphql/queries/GetConfirmationOperationVoteCount.gql new file mode 100644 index 0000000..8cece7e --- /dev/null +++ b/src/graphql/queries/GetConfirmationOperationVoteCount.gql @@ -0,0 +1,7 @@ +query GetConfirmationOperationVoteCount($where: vote_bool_exp!) { + vote_aggregate(where: $where) { + aggregate { + count(columns: operation) + } + } +} diff --git a/src/graphql/queries/GetConfirmationOperationVoteList.gql b/src/graphql/queries/GetConfirmationOperationVoteList.gql new file mode 100644 index 0000000..a2d430b --- /dev/null +++ b/src/graphql/queries/GetConfirmationOperationVoteList.gql @@ -0,0 +1,5 @@ +query GetConfirmationOperationVoteList($limit: Int, $offset: Int, $where: vote_bool_exp!) { + vote(order_by: {height: desc}, where: $where, limit: $limit, offset: $offset) { + ...OperationVote + } +} diff --git a/src/graphql/queries/GetOperationByIndex.gql b/src/graphql/queries/GetOperationByIndex.gql new file mode 100644 index 0000000..c5971db --- /dev/null +++ b/src/graphql/queries/GetOperationByIndex.gql @@ -0,0 +1,109 @@ +query GetOperationByIndex($index: String!) { + operation(where: {index: {_eq: $index}}) { + index + creator + operation_type + status + timestamp + change_parties { + new_public_key + operation_index + parties + signature + } + contract_upgrade { + buffer_account + chain + hash + new_implementation_contract + nonce + operation_index + target_contract + type + network { + name + params + type + } + } + fee_token_management { + chain + fee_token_amount + fee_token_contract + nonce + op_type + operation_index + receiver + network { + name + params + type + } + } + identity_default_transfer { + chain + contract + gistcreated_at_block + gistcreated_at_timestamp + gisthash + gistreplaced_by + id + operation_index + replaced_gist_hash + replaced_state_hash + state_created_at_block + state_created_at_timestamp + state_hash + state_replaced_by + network { + name + params + type + } + } + identity_gist_transfer { + chain + contract + gistcreated_at_block + gistcreated_at_timestamp + gisthash + operation_index + replaced_gist_hash + network { + name + params + type + } + } + identity_state_transfer { + chain + contract + id + operation_index + replaced_state_hash + state_created_at_block + state_created_at_timestamp + state_hash + } + transfer { + amount + bundle_data + bundle_salt + event_id + from + item_meta + operation_index + origin + receiver + to + tx + } + } + confirmation(where: {root: {_in: [$index]}}) { + ...Confirmation + } + transaction(where: {raw_log: {_regex: $index, _iregex: "new_operation"}}) { + ...TransactionBase + } +} + diff --git a/src/graphql/queries/GetOperationCount.gql b/src/graphql/queries/GetOperationCount.gql new file mode 100644 index 0000000..043492f --- /dev/null +++ b/src/graphql/queries/GetOperationCount.gql @@ -0,0 +1,7 @@ +query GetOperationCount { + operation_aggregate { + aggregate { + count(columns: index) + } + } +} diff --git a/src/graphql/queries/GetOperationList.gql b/src/graphql/queries/GetOperationList.gql new file mode 100644 index 0000000..662d98e --- /dev/null +++ b/src/graphql/queries/GetOperationList.gql @@ -0,0 +1,5 @@ +query GetOperationList($limit: Int, $offset: Int) { + operation(order_by: { timestamp: desc }, limit: $limit, offset: $offset) { + ...Operation + } +} diff --git a/src/graphql/queries/GetOperationVoteCount.gql b/src/graphql/queries/GetOperationVoteCount.gql new file mode 100644 index 0000000..c2466bb --- /dev/null +++ b/src/graphql/queries/GetOperationVoteCount.gql @@ -0,0 +1,7 @@ +query GetOperationVoteCount($operation: String!) { + vote_aggregate(where: { operation: { _eq: $operation } }) { + aggregate { + count(columns: operation) + } + } +} diff --git a/src/graphql/queries/GetOperationVoteList.gql b/src/graphql/queries/GetOperationVoteList.gql new file mode 100644 index 0000000..5778415 --- /dev/null +++ b/src/graphql/queries/GetOperationVoteList.gql @@ -0,0 +1,5 @@ +query GetOperationVoteList($limit: Int, $offset: Int, $operation: String!) { + vote(order_by: {height: desc}, where: {operation: {_eq: $operation}}, limit: $limit, offset: $offset) { + ...OperationVote + } +} diff --git a/src/hooks/useLocalize.ts b/src/hooks/useLocalize.ts index aa1b7ca..5e2b21f 100644 --- a/src/hooks/useLocalize.ts +++ b/src/hooks/useLocalize.ts @@ -1,12 +1,23 @@ 'use client' -import { BondStatus, OracleStatus, PartyStatus, ProposalType } from '@rarimo/client' +import { + BondStatus, + OpStatus, + OpType, + OpVoteType, + OracleStatus, + PartyStatus, + ProposalType, +} from '@rarimo/client' import { AnyObject, Flags, Maybe, Schema } from 'yup' import { createYupInitFn } from '@/helpers' import { useI18n } from '@/locales/client' import { localizeMsgType, + localizeOperationStatus, + localizeOperationType, + localizeOperationVote, localizeOracleStatus, localizeProposalStatus, localizeProposalType, @@ -42,6 +53,9 @@ export const useLocalize = () => { localizeOracleStatus: (status: OracleStatus) => localizeOracleStatus(t, status), localizeValidatorStatus: (status: BondStatus, jailed: boolean) => localizeValidatorStatus(t, status, jailed), + localizeOperationType: (type: OpType) => localizeOperationType(t, type), + localizeOperationStatus: (status: OpStatus) => localizeOperationStatus(t, status), + localizeOperationVote: (type: OpVoteType) => localizeOperationVote(t, type), } return { diff --git a/src/locales/en.ts b/src/locales/en.ts index a700903..9c0b696 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -49,6 +49,8 @@ export default { "menu-lbl": "Bridge", "tss-lbl": "TSS", "oracles-lbl": "Oracles", + "operations-lbl": "Operations", + "confirmations-lbl": "Confirmations", }, "footer": { "navigation-links-lbl": "Navigation", @@ -192,6 +194,8 @@ export default { "unknown-lbl": "Unknown", "ethereum-tx-lbl": "Ethereum Tx", "create-identity-default-transfer-op-lbl": "Create Identity Transfer", + "create-identity-gist-transfer-op-lbl": "Create Identity GIST Transfer", + "create-identity-state-transfer-op-lbl": "Create Identity State Transfer", }, "proposal-status": { "unspecified-lbl": "Unknown", @@ -320,7 +324,7 @@ export default { "table-lbl": "Proposal Votes", "no-data-title": "There is no votes for this proposal", "no-data-subtitle": "It will appear for a while", - "error-title": "There was an error while loading deposits", + "error-title": "There was an error while loading votes", "error-subtitle": "Please try again later", }, "proposal": { @@ -534,6 +538,7 @@ export default { "oracle-status": { "active-lbl": "Active", "freezed-lbl": "Freezed", + "jailed-lbl": "Jailed", "slashed-lbl": "Slashed", "inactive-lbl": "Inactive", "unrecognized-lbl": "Unrecognized", @@ -549,6 +554,86 @@ export default { "violations-col-lbl": "Violations:", "freeze-end-block-col-lbl": "Freeze end block:", "title": "Oracle Details", - "no-data-msg": "There is no Oracle with such account address.", + "no-data-msg": "There is no oracle with such account address.", + }, + "operation-list": { + "table-lbl": "Operations", + "no-data-title": "There are no operations", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading operations", + "error-subtitle": "Please try again later", + "index-col-lbl": "Index", + "creator-col-lbl": "Creator", + "type-col-lbl": "Type", + "status-col-lbl": "Status", + "date-col-lbl": "Age", + }, + "operation-type": { + "transfer-lbl": "Transfer", + "change-parties-lbl": "Change Parties", + "fee-token-management-lbl": "Fee Token Management", + "contract-upgrade-lbl": "Contract Upgrade", + "identity-default-transfer-lbl": "Identity Default Transfer", + "identity-aggregated-transfer-lbl": "Identity Aggregated Transfer", + "identity-gist-transfer-lbl": "Identity Gist Transfer", + "identity-state-transfer-lbl": "Identity State Transfer", + "unrecognized-lbl": "Unknown", + }, + "operation-status": { + "initialized": "Initialized", + "approved": "Approved", + "not-approved": "Not Approved", + "signed": "Signed", + "unrecognized": "Unknown", + }, + "operation-vote-type": { + "yes": "Yes", + "no": "No", + "unrecognized": "Unknown", + }, + "operation": { + "index-col-lbl": "Index:", + "type-col-lbl": "Operation Type:", + "status-col-lbl": "Status:", + "creator-col-lbl": "Creator:", + "block-col-lbl": "Block:", + "tx-col-lbl": "Transaction hash:", + "age-col-lbl": "Age:", + "confirmation-col-lbl": "Confirmation:", + "title": "Operation Details", + "no-data-msg": "There is no operation with such index.", + }, + "operation-vote-list": { + "table-lbl": "Votes", + "voter-col-lbl": "Voter's account ID", + "tx-col-lbl": "Transaction hash", + "option-col-lbl": "Option", + "block-col-lbl": "Block", + "age-col-lbl": "Age", + "no-data-title": "There is no votes for this operation", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading votes", + "error-subtitle": "Please try again later", + }, + "confirmations": { + "table-lbl": "Confirmations", + "no-data-title": "There are no confirmations", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading confirmations", + "error-subtitle": "Please try again later", + "root-col-lbl": "Root", + "creator-col-lbl": "Creator", + "block-col-lbl": "Block", + "tx-col-lbl": "Transaction hash", + "age-col-lbl": "Age", + }, + "confirmation": { + "root-col-lbl": "Root:", + "creator-col-lbl": "Creator:", + "age-col-lbl": "Age:", + "block-col-lbl": "Block:", + "tx-col-lbl": "Transaction hash:", + "title": "Confirmation Details", + "no-data-msg": "There is no confirmation with such index.", }, } as const diff --git a/src/locales/localizers/index.ts b/src/locales/localizers/index.ts index 1d17fea..6bf8f76 100644 --- a/src/locales/localizers/index.ts +++ b/src/locales/localizers/index.ts @@ -1,4 +1,7 @@ export * from './msg-type' +export * from './op-status' +export * from './op-type' +export * from './op-vote' export * from './oracle' export * from './proposal-status' export * from './proposal-type' diff --git a/src/locales/localizers/msg-type.ts b/src/locales/localizers/msg-type.ts index 6e135f9..2deb952 100644 --- a/src/locales/localizers/msg-type.ts +++ b/src/locales/localizers/msg-type.ts @@ -61,4 +61,6 @@ export const localizeMsgType = (t: TFunction, type: string) => [MessageTypeUrls.OracleVote]: t('message-types.oracle-vote-lbl'), [MessageTypeUrls.OracleUnjail]: t('message-types.oracle-unjail-lbl'), [MessageTypeUrls.CreateIdentityDefaultTransferOp]: t('message-types.create-identity-default-transfer-op-lbl'), + [MessageTypeUrls.CreateIdentityGISTTransferOp]: t('message-types.create-identity-gist-transfer-op-lbl'), + [MessageTypeUrls.CreateIdentityStateTransferOp]: t('message-types.create-identity-state-transfer-op-lbl'), })[type] diff --git a/src/locales/localizers/op-status.ts b/src/locales/localizers/op-status.ts new file mode 100644 index 0000000..8fa31c4 --- /dev/null +++ b/src/locales/localizers/op-status.ts @@ -0,0 +1,12 @@ +import { OpStatus } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeOperationStatus = (t: TFunction, type: OpStatus) => + ({ + [OpStatus.Initialized]: t('operation-status.initialized'), + [OpStatus.Approved]: t('operation-status.approved'), + [OpStatus.NotApproved]: t('operation-status.not-approved'), + [OpStatus.Signed]: t('operation-status.signed'), + [OpStatus.Unrecognized]: t('operation-status.unrecognized'), + })[type] diff --git a/src/locales/localizers/op-type.ts b/src/locales/localizers/op-type.ts new file mode 100644 index 0000000..3bfc812 --- /dev/null +++ b/src/locales/localizers/op-type.ts @@ -0,0 +1,16 @@ +import { OpType } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeOperationType = (t: TFunction, type: OpType) => + ({ + [OpType.Transfer]: t('operation-type.transfer-lbl'), + [OpType.ChangeParties]: t('operation-type.change-parties-lbl'), + [OpType.FeeTokenManagement]: t('operation-type.fee-token-management-lbl'), + [OpType.ContractUpgrade]: t('operation-type.contract-upgrade-lbl'), + [OpType.IdentityDefaultTransfer]: t('operation-type.identity-default-transfer-lbl'), + [OpType.IdentityAggregatedTransfer]: t('operation-type.identity-aggregated-transfer-lbl'), + [OpType.IdentityGistTransfer]: t('operation-type.identity-gist-transfer-lbl'), + [OpType.IdentityStateTransfer]: t('operation-type.identity-state-transfer-lbl'), + [OpType.Unrecognized]: t('operation-type.unrecognized-lbl'), + })[type] diff --git a/src/locales/localizers/op-vote.ts b/src/locales/localizers/op-vote.ts new file mode 100644 index 0000000..ca0d2f2 --- /dev/null +++ b/src/locales/localizers/op-vote.ts @@ -0,0 +1,10 @@ +import { OpVoteType } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeOperationVote = (t: TFunction, type: OpVoteType) => + ({ + [OpVoteType.Yes]: t('operation-vote-type.yes'), + [OpVoteType.No]: t('operation-vote-type.no'), + [OpVoteType.Unrecognized]: t('operation-vote-type.unrecognized'), + })[type] diff --git a/src/locales/localizers/oracle.ts b/src/locales/localizers/oracle.ts index ede599a..f161b27 100644 --- a/src/locales/localizers/oracle.ts +++ b/src/locales/localizers/oracle.ts @@ -6,6 +6,7 @@ export const localizeOracleStatus = (t: TFunction, status: OracleStatus) => ({ [OracleStatus.Active]: t('oracle-status.active-lbl'), [OracleStatus.Freezed]: t('oracle-status.freezed-lbl'), + [OracleStatus.Jailed]: t('oracle-status.jailed-lbl'), [OracleStatus.Slashed]: t('oracle-status.slashed-lbl'), [OracleStatus.Inactive]: t('oracle-status.inactive-lbl'), [OracleStatus.Unrecognized]: t('oracle-status.unrecognized-lbl'), diff --git a/src/types/routes.ts b/src/types/routes.ts index 3e5fa21..b8eb60c 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -17,4 +17,8 @@ export enum RoutePaths { TSS = '/tss/[address]', Oracles = '/oracles', Oracle = '/oracles/[address]', + Operations = '/operations', + Operation = '/operations/[index]', + Confirmations = '/confirmations', + Confirmation = '/confirmations/[root]', } From 26d44cdfee76287b387f0731b9967d30616036da Mon Sep 17 00:00:00 2001 From: Semen Loktionov Date: Thu, 30 Nov 2023 17:15:39 +0200 Subject: [PATCH 3/5] add network --- src/app/[locale]/networks/[name]/page.tsx | 27 +++++ src/app/[locale]/networks/page.tsx | 16 +++ src/callers/index.ts | 1 + src/callers/network.ts | 43 ++++++++ src/components/Confirmation/Confirmation.tsx | 1 - src/components/Header/HeaderBridgeMenu.tsx | 1 + src/components/Network/Network.tsx | 76 +++++++++++++ src/components/Network/NetworkParameters.tsx | 27 +++++ src/components/Network/Networks.tsx | 106 +++++++++++++++++++ src/components/Network/NetworksRow.tsx | 83 +++++++++++++++ src/components/Network/index.ts | 2 + src/components/index.ts | 1 + src/graphql/fragments/Network.gql | 5 + src/graphql/generated.ts | 52 +++++++++ src/graphql/queries/GetNetworkByName.gql | 6 ++ src/graphql/queries/GetNetworkCount.gql | 7 ++ src/graphql/queries/GetNetworkList.gql | 5 + src/hooks/useLocalize.ts | 6 ++ src/locales/en.ts | 33 ++++++ src/locales/localizers/index.ts | 1 + src/locales/localizers/network-type.ts | 21 ++++ src/types/routes.ts | 2 + 22 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 src/app/[locale]/networks/[name]/page.tsx create mode 100644 src/app/[locale]/networks/page.tsx create mode 100644 src/callers/network.ts create mode 100644 src/components/Network/Network.tsx create mode 100644 src/components/Network/NetworkParameters.tsx create mode 100644 src/components/Network/Networks.tsx create mode 100644 src/components/Network/NetworksRow.tsx create mode 100644 src/components/Network/index.ts create mode 100644 src/graphql/fragments/Network.gql create mode 100644 src/graphql/queries/GetNetworkByName.gql create mode 100644 src/graphql/queries/GetNetworkCount.gql create mode 100644 src/graphql/queries/GetNetworkList.gql create mode 100644 src/locales/localizers/network-type.ts diff --git a/src/app/[locale]/networks/[name]/page.tsx b/src/app/[locale]/networks/[name]/page.tsx new file mode 100644 index 0000000..0e1dd14 --- /dev/null +++ b/src/app/[locale]/networks/[name]/page.tsx @@ -0,0 +1,27 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getNetworkByName } from '@/callers' +import { Network, PageContainer } from '@/components' +import { createMetadata } from '@/config' +import { NetworkFragment } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getNetwork = (name: string) => { + return getServerSideProps(() => getNetworkByName(name)) +} + +export function generateMetadata({ params }: { params: { name: string } }): Metadata { + return createMetadata(`Network ${params.name} Details`) +} + +export default async function NetworkPage({ params: { name } }: { params: { name: string } }) { + const { isNotFound } = await getNetwork(name) + if (isNotFound) notFound() + + return ( + + + + ) +} diff --git a/src/app/[locale]/networks/page.tsx b/src/app/[locale]/networks/page.tsx new file mode 100644 index 0000000..5d52a89 --- /dev/null +++ b/src/app/[locale]/networks/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { Networks, PageContainer } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata(`Networks`) +} + +export default function NetworksPage() { + return ( + + + + ) +} diff --git a/src/callers/index.ts b/src/callers/index.ts index c8c1263..93ed0d8 100644 --- a/src/callers/index.ts +++ b/src/callers/index.ts @@ -1,5 +1,6 @@ export * from './block' export * from './confirmation' +export * from './network' export * from './operation' export * from './proposal' export * from './rarimocore' diff --git a/src/callers/network.ts b/src/callers/network.ts new file mode 100644 index 0000000..7ab1c06 --- /dev/null +++ b/src/callers/network.ts @@ -0,0 +1,43 @@ +import { CONFIG } from '@/config' +import { + apolloClient, + GetNetworkByName, + GetNetworkByNameQuery, + GetNetworkCount, + GetNetworkCountQuery, + GetNetworkList, + GetNetworkListQuery, + NetworkFragment, +} from '@/graphql' + +export const getNetworkList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, +): Promise => { + const { data } = await apolloClient.query({ + query: GetNetworkList, + fetchPolicy: 'network-only', + variables: { limit, offset }, + }) + + return data?.network ?? [] +} + +export const getNetworkCount = async (): Promise => { + const { data } = await apolloClient.query({ + query: GetNetworkCount, + fetchPolicy: 'network-only', + }) + + return data?.network_aggregate.aggregate?.count ?? 0 +} + +export const getNetworkByName = async (name: string): Promise => { + const { data } = await apolloClient.query({ + query: GetNetworkByName, + fetchPolicy: 'network-only', + variables: { name }, + }) + + return data?.network?.[0] +} diff --git a/src/components/Confirmation/Confirmation.tsx b/src/components/Confirmation/Confirmation.tsx index 88bce9c..8bb646b 100644 --- a/src/components/Confirmation/Confirmation.tsx +++ b/src/components/Confirmation/Confirmation.tsx @@ -102,7 +102,6 @@ export default function Confirmation({ root }: { root: string }) { isEmpty={isEmpty} isLoadingError={isLoadingError} rows={rows} - sx={{}} /> diff --git a/src/components/Header/HeaderBridgeMenu.tsx b/src/components/Header/HeaderBridgeMenu.tsx index 7e562b5..fca6e77 100644 --- a/src/components/Header/HeaderBridgeMenu.tsx +++ b/src/components/Header/HeaderBridgeMenu.tsx @@ -12,6 +12,7 @@ export default function HeaderBridgeMenu(props: Omit diff --git a/src/components/Network/Network.tsx b/src/components/Network/Network.tsx new file mode 100644 index 0000000..cda6a80 --- /dev/null +++ b/src/components/Network/Network.tsx @@ -0,0 +1,76 @@ +'use client' + +import { Chip } from '@mui/material' +import { useMemo } from 'react' + +import { getNetworkByName } from '@/callers' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import JsonViewer from '@/components/JsonViewer' +import OverviewTable from '@/components/OverviewTable' +import TableCollapseRow from '@/components/TableCollapseRow' +import { TABLE_BIG_SKELETON_SX, TABLE_TYPE_BOX_SKELETON_SX } from '@/const' +import { NetworkFragment } from '@/graphql' +import { useLoading, useLocalize, useSkeleton } from '@/hooks' +import { useI18n } from '@/locales/client' + +export default function Network({ name }: { name: string }) { + const t = useI18n() + const { localizeNetworkType } = useLocalize() + + const { + data: network, + isLoading, + isLoadingError, + isEmpty, + } = useLoading({} as NetworkFragment, () => getNetworkByName(name)) + + const networkType = useMemo( + () => localizeNetworkType(network?.type), + [localizeNetworkType, network?.type], + ) + + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('network.name-col-lbl'), + body: withSkeleton(network?.name, TABLE_BIG_SKELETON_SX), + }, + { + head: t('network.type-col-lbl'), + body: withSkeleton(, TABLE_TYPE_BOX_SKELETON_SX), + }, + ] + + return ( + + + + tr > th': { + width: '500px', + }, + }} + /> + tr:last-child td, & > tr:last-child th, & > tr:nth-last-of-type(-n + 2) td': { + borderBottom: 0, + }, + }} + > + + + + + + + + ) +} diff --git a/src/components/Network/NetworkParameters.tsx b/src/components/Network/NetworkParameters.tsx new file mode 100644 index 0000000..c0bca59 --- /dev/null +++ b/src/components/Network/NetworkParameters.tsx @@ -0,0 +1,27 @@ +import { Chip, Stack, SxProps } from '@mui/material' +import { NetworkParams, networkParamTypeFromJSON } from '@rarimo/client' + +import { useLocalize } from '@/hooks' + +export default function NetworkParameters({ + params = [], + sx = {}, +}: { + params?: NetworkParams[] + sx?: SxProps +}) { + const { localizeNetworkParamType } = useLocalize() + + return ( + + {params.map((item, idx) => ( + + ))} + + ) +} diff --git a/src/components/Network/Networks.tsx b/src/components/Network/Networks.tsx new file mode 100644 index 0000000..2ef14dd --- /dev/null +++ b/src/components/Network/Networks.tsx @@ -0,0 +1,106 @@ +'use client' + +import { TableCell } from '@mui/material' + +import { getNetworkCount, getNetworkList } from '@/callers' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { NetworkFragment } from '@/graphql' +import { useLoading, useTablePagination } from '@/hooks' +import { useI18n } from '@/locales/client' +import { TableColumn } from '@/types' + +import NetworksRow from './NetworksRow' + +export enum NetworkColumnIds { + Name = 'name', + Type = 'type', + Parameters = 'parameters', +} + +export default function Networks() { + const t = useI18n() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage } = useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + } = useLoading(0, getNetworkCount) + + const { data, isLoading, isLoadingError } = useLoading( + [], + () => getNetworkList(limit, offset), + { + loadArgs: [limit, offset], + }, + ) + + const columns: readonly TableColumn[] = [ + { + id: NetworkColumnIds.Name, + label: t('networks.name-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 200, + maxWidth: 200, + }, + }, + { + id: NetworkColumnIds.Type, + label: t('networks.type-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 150, + maxWidth: 150, + }, + }, + { + id: NetworkColumnIds.Parameters, + label: t('networks.params-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 220, + maxWidth: 220, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as NetworkFragment) : data).map((row, idx) => ( + + )) + + return ( + + + + + + + + ) +} diff --git a/src/components/Network/NetworksRow.tsx b/src/components/Network/NetworksRow.tsx new file mode 100644 index 0000000..e71d18b --- /dev/null +++ b/src/components/Network/NetworksRow.tsx @@ -0,0 +1,83 @@ +import { Chip, Link as MuiLink, Skeleton, TableRow } from '@mui/material' +import { TableCell } from '@mui/material' +import { NetworkType } from '@rarimo/client' +import Link from 'next/link' +import { useMemo } from 'react' + +import { NetworkFragment } from '@/graphql' +import { createColumnMap, generatePath } from '@/helpers' +import { useLocalize, useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import NetworkParameters from './NetworkParameters' +import { NetworkColumnIds } from './Networks' + +export default function NetworksRow({ + row, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + row?: NetworkFragment + isLoading: boolean +}) { + const { localizeNetworkType } = useLocalize() + + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + const networkType = useMemo( + () => localizeNetworkType(row?.type as NetworkType), + [localizeNetworkType, row?.type], + ) + + return ( + + + {isLoading ? ( + + ) : ( + + {withSkeleton(row?.name, { width: '100%' })} + + )} + + + + {withSkeleton(, { + width: '100%', + height: 32, + })} + + + + {withSkeleton( + , + { + width: '100%', + height: 32, + }, + )} + + + ) +} diff --git a/src/components/Network/index.ts b/src/components/Network/index.ts new file mode 100644 index 0000000..d032697 --- /dev/null +++ b/src/components/Network/index.ts @@ -0,0 +1,2 @@ +export { default as Network } from './Network' +export { default as Networks } from './Networks' diff --git a/src/components/index.ts b/src/components/index.ts index 1745b83..9f46f62 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -9,6 +9,7 @@ export * from './TSS' export * from './Oracles' export * from './Operation' export * from './Confirmation' +export * from './Network' export { default as Avatar } from './Avatar/Avatar' export { default as AvatarName } from './Avatar/AvatarName' diff --git a/src/graphql/fragments/Network.gql b/src/graphql/fragments/Network.gql new file mode 100644 index 0000000..a04ce1d --- /dev/null +++ b/src/graphql/fragments/Network.gql @@ -0,0 +1,5 @@ +fragment Network on network { + name + params + type +} diff --git a/src/graphql/generated.ts b/src/graphql/generated.ts index 565b041..f9cf9b9 100644 --- a/src/graphql/generated.ts +++ b/src/graphql/generated.ts @@ -19025,6 +19025,8 @@ export type ConfirmationFragment = { __typename?: 'confirmation', creator: strin export type ConfirmationBaseFragment = { __typename?: 'confirmation', root: string, creator: string, height: any, tx?: string | null, block?: { __typename?: 'block', timestamp: any } | null }; +export type NetworkFragment = { __typename?: 'network', name: string, params: any, type: number }; + export type OperationFragment = { __typename?: 'operation', index: string, operation_type: number, status: number, creator: string, timestamp: any }; export type OperationVoteFragment = { __typename?: 'vote', operation: string, height: any, tx?: string | null, validator: string, vote: number, block?: { __typename?: 'block', timestamp: any } | null }; @@ -19146,6 +19148,26 @@ export type GetLatestTxAndBlocksQueryVariables = Exact<{ export type GetLatestTxAndBlocksQuery = { __typename?: 'query_root', transaction: Array<{ __typename?: 'transaction', height: any, hash: string, success: boolean, signer_infos: any, raw_log?: string | null, block: { __typename?: 'block', timestamp: any, height: any } }>, block: Array<{ __typename?: 'block', height: any, timestamp: any, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', avatar_url?: string | null, moniker?: string | null }> } | null }> }; +export type GetNetworkByNameQueryVariables = Exact<{ + name: Scalars['String']['input']; +}>; + + +export type GetNetworkByNameQuery = { __typename?: 'query_root', network: Array<{ __typename?: 'network', name: string, params: any, type: number }> }; + +export type GetNetworkCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetNetworkCountQuery = { __typename?: 'query_root', network_aggregate: { __typename?: 'network_aggregate', aggregate?: { __typename?: 'network_aggregate_fields', count: number } | null } }; + +export type GetNetworkListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; +}>; + + +export type GetNetworkListQuery = { __typename?: 'query_root', network: Array<{ __typename?: 'network', name: string, params: any, type: number }> }; + export type GetOperationByIndexQueryVariables = Exact<{ index: Scalars['String']['input']; }>; @@ -19475,6 +19497,13 @@ export const ConfirmationBase = gql` } } `; +export const Network = gql` + fragment Network on network { + name + params + type +} + `; export const Operation = gql` fragment Operation on operation { index @@ -19824,6 +19853,29 @@ export const GetLatestTxAndBlocks = gql` } ${TransactionBase} ${BlockBase}`; +export const GetNetworkByName = gql` + query GetNetworkByName($name: String!) { + network(where: {name: {_eq: $name}}) { + ...Network + } +} + ${Network}`; +export const GetNetworkCount = gql` + query GetNetworkCount { + network_aggregate { + aggregate { + count(columns: name) + } + } +} + `; +export const GetNetworkList = gql` + query GetNetworkList($limit: Int, $offset: Int) { + network(limit: $limit, offset: $offset) { + ...Network + } +} + ${Network}`; export const GetOperationByIndex = gql` query GetOperationByIndex($index: String!) { operation(where: {index: {_eq: $index}}) { diff --git a/src/graphql/queries/GetNetworkByName.gql b/src/graphql/queries/GetNetworkByName.gql new file mode 100644 index 0000000..76298c4 --- /dev/null +++ b/src/graphql/queries/GetNetworkByName.gql @@ -0,0 +1,6 @@ +query GetNetworkByName($name: String!) { + network(where: {name: {_eq: $name}}) { + ...Network + } +} + diff --git a/src/graphql/queries/GetNetworkCount.gql b/src/graphql/queries/GetNetworkCount.gql new file mode 100644 index 0000000..0f38e83 --- /dev/null +++ b/src/graphql/queries/GetNetworkCount.gql @@ -0,0 +1,7 @@ +query GetNetworkCount { + network_aggregate { + aggregate { + count(columns: name) + } + } +} diff --git a/src/graphql/queries/GetNetworkList.gql b/src/graphql/queries/GetNetworkList.gql new file mode 100644 index 0000000..ccd1fc4 --- /dev/null +++ b/src/graphql/queries/GetNetworkList.gql @@ -0,0 +1,5 @@ +query GetNetworkList($limit: Int, $offset: Int) { + network(limit: $limit, offset: $offset) { + ...Network + } +} diff --git a/src/hooks/useLocalize.ts b/src/hooks/useLocalize.ts index 5e2b21f..696beaa 100644 --- a/src/hooks/useLocalize.ts +++ b/src/hooks/useLocalize.ts @@ -2,6 +2,8 @@ import { BondStatus, + NetworkParamType, + NetworkType, OpStatus, OpType, OpVoteType, @@ -15,6 +17,8 @@ import { createYupInitFn } from '@/helpers' import { useI18n } from '@/locales/client' import { localizeMsgType, + localizeNetworkParamType, + localizeNetworkType, localizeOperationStatus, localizeOperationType, localizeOperationVote, @@ -56,6 +60,8 @@ export const useLocalize = () => { localizeOperationType: (type: OpType) => localizeOperationType(t, type), localizeOperationStatus: (status: OpStatus) => localizeOperationStatus(t, status), localizeOperationVote: (type: OpVoteType) => localizeOperationVote(t, type), + localizeNetworkType: (type: NetworkType) => localizeNetworkType(t, type), + localizeNetworkParamType: (type: NetworkParamType) => localizeNetworkParamType(t, type), } return { diff --git a/src/locales/en.ts b/src/locales/en.ts index 9c0b696..e6a84ed 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -51,6 +51,7 @@ export default { "oracles-lbl": "Oracles", "operations-lbl": "Operations", "confirmations-lbl": "Confirmations", + "networks-lbl": "Networks", }, "footer": { "navigation-links-lbl": "Navigation", @@ -636,4 +637,36 @@ export default { "title": "Confirmation Details", "no-data-msg": "There is no confirmation with such index.", }, + "networks": { + "table-lbl": "Networks", + "no-data-title": "There are no networks", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading networks", + "error-subtitle": "Please try again later", + "name-col-lbl": "Name", + "type-col-lbl": "Type", + "params-col-lbl": "Parameters", + }, + "network-type": { + "evm-lbl": "EVM", + "solana-lbl": "Solana", + "near-lbl": "Near", + "other-lbl": "Other", + "rarimo-lbl": "Rarimo", + "unrecognized-lbl": "Unknown", + }, + "network-param-type": { + "bridge-lbl": "Bridge", + "fee-lbl": "Fee", + "identity-lbl": "Identity", + "unrecognized-lbl": "Unknown", + }, + "network": { + "name-col-lbl": "Name:", + "type-col-lbl": "Type:", + "params-col-lbl": "Parameters:", + "title": "Network Details", + "no-data-msg": "There is no network with such name.", + "parameters-col-lbl": "Parameters", + }, } as const diff --git a/src/locales/localizers/index.ts b/src/locales/localizers/index.ts index 6bf8f76..971ad4f 100644 --- a/src/locales/localizers/index.ts +++ b/src/locales/localizers/index.ts @@ -1,4 +1,5 @@ export * from './msg-type' +export * from './network-type' export * from './op-status' export * from './op-type' export * from './op-vote' diff --git a/src/locales/localizers/network-type.ts b/src/locales/localizers/network-type.ts new file mode 100644 index 0000000..a077678 --- /dev/null +++ b/src/locales/localizers/network-type.ts @@ -0,0 +1,21 @@ +import { NetworkParamType, NetworkType } from '@rarimo/client' + +import { TFunction } from '@/types' + +export const localizeNetworkType = (t: TFunction, type: NetworkType) => + ({ + [NetworkType.EVM]: t('network-type.evm-lbl'), + [NetworkType.Solana]: t('network-type.solana-lbl'), + [NetworkType.Near]: t('network-type.near-lbl'), + [NetworkType.Other]: t('network-type.other-lbl'), + [NetworkType.Rarimo]: t('network-type.rarimo-lbl'), + [NetworkType.Unrecognized]: t('network-type.unrecognized-lbl'), + })[type] + +export const localizeNetworkParamType = (t: TFunction, type: NetworkParamType) => + ({ + [NetworkParamType.Bridge]: t('network-param-type.bridge-lbl'), + [NetworkParamType.Fee]: t('network-param-type.fee-lbl'), + [NetworkParamType.Identity]: t('network-param-type.identity-lbl'), + [NetworkParamType.Unrecognized]: t('network-param-type.unrecognized-lbl'), + })[type] diff --git a/src/types/routes.ts b/src/types/routes.ts index b8eb60c..9981116 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -21,4 +21,6 @@ export enum RoutePaths { Operation = '/operations/[index]', Confirmations = '/confirmations', Confirmation = '/confirmations/[root]', + Networks = '/networks', + Network = '/networks/[name]', } From caed826e5c36ce37cc0a919ee15325070ea88214 Mon Sep 17 00:00:00 2001 From: Semen Loktionov Date: Fri, 1 Dec 2023 12:57:42 +0200 Subject: [PATCH 4/5] add supported tokens --- .../supported-tokens/[index]/page.tsx | 31 +++++ src/app/[locale]/supported-tokens/page.tsx | 16 +++ src/callers/collection.ts | 57 +++++++++ src/callers/index.ts | 1 + src/components/Header/HeaderBridgeMenu.tsx | 1 + .../SupportedToken/SupportedToken.tsx | 106 ++++++++++++++++ .../SupportedToken/SupportedTokenList.tsx | 97 +++++++++++++++ .../SupportedToken/SupportedTokenListRow.tsx | 98 +++++++++++++++ .../SupportedToken/SupportedTokens.tsx | 116 ++++++++++++++++++ src/components/SupportedToken/index.ts | 2 + src/components/index.ts | 1 + src/graphql/fragments/Collection.gql | 13 ++ src/graphql/fragments/CollectionBase.gql | 5 + src/graphql/generated.ts | 72 +++++++++++ src/graphql/queries/GetCollectionByIndex.gql | 6 + src/graphql/queries/GetCollectionCount.gql | 7 ++ src/graphql/queries/GetCollectionList.gql | 5 + src/locales/en.ts | 26 ++++ src/types/routes.ts | 2 + 19 files changed, 662 insertions(+) create mode 100644 src/app/[locale]/supported-tokens/[index]/page.tsx create mode 100644 src/app/[locale]/supported-tokens/page.tsx create mode 100644 src/callers/collection.ts create mode 100644 src/components/SupportedToken/SupportedToken.tsx create mode 100644 src/components/SupportedToken/SupportedTokenList.tsx create mode 100644 src/components/SupportedToken/SupportedTokenListRow.tsx create mode 100644 src/components/SupportedToken/SupportedTokens.tsx create mode 100644 src/components/SupportedToken/index.ts create mode 100644 src/graphql/fragments/Collection.gql create mode 100644 src/graphql/fragments/CollectionBase.gql create mode 100644 src/graphql/queries/GetCollectionByIndex.gql create mode 100644 src/graphql/queries/GetCollectionCount.gql create mode 100644 src/graphql/queries/GetCollectionList.gql diff --git a/src/app/[locale]/supported-tokens/[index]/page.tsx b/src/app/[locale]/supported-tokens/[index]/page.tsx new file mode 100644 index 0000000..db5ce85 --- /dev/null +++ b/src/app/[locale]/supported-tokens/[index]/page.tsx @@ -0,0 +1,31 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' + +import { getCollectionByIndex } from '@/callers' +import { PageContainer, SupportedToken } from '@/components' +import { createMetadata } from '@/config' +import { CollectionFragment } from '@/graphql' +import { getServerSideProps } from '@/helpers' + +const getCollection = (index: string) => { + return getServerSideProps(() => getCollectionByIndex(index)) +} + +export function generateMetadata({ params }: { params: { index: string } }): Metadata { + return createMetadata(`Supported Token ${params.index} Details`) +} + +export default async function SupportedTokenPage({ + params: { index }, +}: { + params: { index: string } +}) { + const { isNotFound } = await getCollection(index) + if (isNotFound) notFound() + + return ( + + + + ) +} diff --git a/src/app/[locale]/supported-tokens/page.tsx b/src/app/[locale]/supported-tokens/page.tsx new file mode 100644 index 0000000..5471727 --- /dev/null +++ b/src/app/[locale]/supported-tokens/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from 'next' + +import { PageContainer, SupportedTokens } from '@/components' +import { createMetadata } from '@/config' + +export function generateMetadata(): Metadata { + return createMetadata(`Supported Tokens`) +} + +export default function SupportedTokensPage() { + return ( + + + + ) +} diff --git a/src/callers/collection.ts b/src/callers/collection.ts new file mode 100644 index 0000000..15ee11a --- /dev/null +++ b/src/callers/collection.ts @@ -0,0 +1,57 @@ +import { TokenType } from '@rarimo/client' + +import { CONFIG } from '@/config' +import { + apolloClient, + Collection_Bool_Exp, + CollectionBaseFragment, + CollectionFragment, + GetCollectionByIndex, + GetCollectionByIndexQuery, + GetCollectionCount, + GetCollectionCountQuery, + GetCollectionList, + GetCollectionListQuery, +} from '@/graphql' + +const createCollectionWhere = (tokenTypes: TokenType[]): Collection_Bool_Exp => { + return { + _or: tokenTypes.map(type => ({ + collection_data: { token_type: { _eq: type } }, + })), + } +} + +export const getCollectionList = async ( + limit: number = CONFIG.PAGE_LIMIT, + offset = 0, + filters: TokenType[] = [], +): Promise => { + const { data } = await apolloClient.query({ + query: GetCollectionList, + fetchPolicy: 'network-only', + variables: { limit, offset, where: createCollectionWhere(filters) }, + }) + + return data?.collection ?? [] +} + +export const getCollectionCount = async (filters: TokenType[] = []): Promise => { + const { data } = await apolloClient.query({ + query: GetCollectionCount, + fetchPolicy: 'network-only', + variables: { where: createCollectionWhere(filters) }, + }) + + return data?.collection_aggregate.aggregate?.count ?? 0 +} + +export const getCollectionByIndex = async (index: string): Promise => { + const { data } = await apolloClient.query({ + query: GetCollectionByIndex, + fetchPolicy: 'network-only', + variables: { index }, + }) + + return data.collection?.[0] +} diff --git a/src/callers/index.ts b/src/callers/index.ts index 93ed0d8..9f5128d 100644 --- a/src/callers/index.ts +++ b/src/callers/index.ts @@ -1,4 +1,5 @@ export * from './block' +export * from './collection' export * from './confirmation' export * from './network' export * from './operation' diff --git a/src/components/Header/HeaderBridgeMenu.tsx b/src/components/Header/HeaderBridgeMenu.tsx index fca6e77..c9161eb 100644 --- a/src/components/Header/HeaderBridgeMenu.tsx +++ b/src/components/Header/HeaderBridgeMenu.tsx @@ -13,6 +13,7 @@ export default function HeaderBridgeMenu(props: Omit diff --git a/src/components/SupportedToken/SupportedToken.tsx b/src/components/SupportedToken/SupportedToken.tsx new file mode 100644 index 0000000..0ed3304 --- /dev/null +++ b/src/components/SupportedToken/SupportedToken.tsx @@ -0,0 +1,106 @@ +'use client' + +import { Link as MuiLink } from '@mui/material' +import Link from 'next/link' + +import { getCollectionByIndex } from '@/callers' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import CopyToClipboardWrapper from '@/components/CopyToClipboardWrapper' +import JsonViewer from '@/components/JsonViewer' +import OverviewTable from '@/components/OverviewTable' +import TableCollapseRow from '@/components/TableCollapseRow' +import { + TABLE_BIG_SKELETON_SX, + TABLE_MEDIUM_TEXT_SKELETON_SX, + TABLE_SMALL_TEXT_SKELETON_SX, +} from '@/const' +import { CollectionFragment } from '@/graphql' +import { generatePath } from '@/helpers' +import { useLoading, useSkeleton } from '@/hooks' +import { useI18n } from '@/locales/client' +import { RoutePaths } from '@/types' + +export default function SupportedToken({ index }: { index: string }) { + const t = useI18n() + + const { + data: collection, + isLoading, + isLoadingError, + isEmpty, + } = useLoading({} as CollectionFragment, () => getCollectionByIndex(index)) + + const withSkeleton = useSkeleton(isLoading) + + const rows = [ + { + head: t('supported-token.index-col-lbl'), + body: withSkeleton( + + {collection?.index} + , + TABLE_BIG_SKELETON_SX, + ), + }, + { + head: t('supported-token.name-col-lbl'), + body: withSkeleton(collection?.meta?.name ?? '', TABLE_MEDIUM_TEXT_SKELETON_SX), + }, + { + head: t('supported-token.symbol-col-lbl'), + body: withSkeleton(collection?.meta?.symbol ?? '', TABLE_SMALL_TEXT_SKELETON_SX), + }, + ...(collection?.meta?.metadata_uri + ? [ + { + head: t('supported-token.metadata-uri-col-lbl'), + body: withSkeleton( + + + {collection?.meta?.metadata_uri} + + , + TABLE_BIG_SKELETON_SX, + ), + }, + ] + : []), + ] + + return ( + + + + tr > th': { + width: '500px', + }, + }} + /> + tr:last-child td, & > tr:last-child th, & > tr:nth-last-of-type(-n + 2) td': { + borderBottom: 0, + }, + }} + > + + + + + + + + ) +} diff --git a/src/components/SupportedToken/SupportedTokenList.tsx b/src/components/SupportedToken/SupportedTokenList.tsx new file mode 100644 index 0000000..31e8f6b --- /dev/null +++ b/src/components/SupportedToken/SupportedTokenList.tsx @@ -0,0 +1,97 @@ +import { TableCell } from '@mui/material' + +import TableWithPagination from '@/components/TableWithPagination' +import { OVERFLOW_SX } from '@/const' +import { CollectionBaseFragment } from '@/graphql' +import { useI18n } from '@/locales/client' +import { TableColumn, TableListProps } from '@/types' + +import SupportedTokenListRow from './SupportedTokenListRow' + +export enum CollectionColumnIds { + Index = 'index', + Name = 'name', + Symbol = 'symbol', + Chains = 'chains', +} + +export default function SupportedTokenList({ + isLoading, + isLoadingError, + limit, + offset, + list, + count, + handleChangePage, + handleChangeRowsPerPage, +}: TableListProps) { + const t = useI18n() + + const columns: readonly TableColumn[] = [ + { + id: CollectionColumnIds.Index, + label: t('supported-token-list.index-col-lbl'), + sx: { + minWidth: 200, + maxWidth: 200, + }, + }, + { + id: CollectionColumnIds.Name, + label: t('supported-token-list.name-col-lbl'), + sx: { + minWidth: 150, + maxWidth: 150, + }, + }, + { + id: CollectionColumnIds.Symbol, + label: t('supported-token-list.symbol-col-lbl'), + sx: { + minWidth: 80, + maxWidth: 80, + }, + }, + { + id: CollectionColumnIds.Chains, + label: t('supported-token-list.chains-col-lbl'), + sx: { + ...OVERFLOW_SX, + minWidth: 200, + maxWidth: 200, + }, + align: 'right', + }, + ] + + const headCells = columns.map(column => ( + + {column.label} + + )) + + const rows = (isLoading ? new Array(limit).fill({} as CollectionBaseFragment) : list).map( + (row, idx) => ( + + ), + ) + + return ( + + ) +} diff --git a/src/components/SupportedToken/SupportedTokenListRow.tsx b/src/components/SupportedToken/SupportedTokenListRow.tsx new file mode 100644 index 0000000..8829d61 --- /dev/null +++ b/src/components/SupportedToken/SupportedTokenListRow.tsx @@ -0,0 +1,98 @@ +'use client' + +import { Chip, Link as MuiLink, Stack, TableCell, TableRow } from '@mui/material' +import { CollectionDataIndex, CollectionMetadata } from '@rarimo/client' +import Link from 'next/link' +import { useMemo } from 'react' + +import { OVERFLOW_SX } from '@/const' +import { CollectionBaseFragment } from '@/graphql' +import { createColumnMap, generatePath } from '@/helpers' +import { useSkeleton } from '@/hooks' +import { RoutePaths, TableColumn } from '@/types' + +import { CollectionColumnIds } from './SupportedTokenList' + +export default function SupportedTokenListRow({ + row, + columns, + isLoading, +}: { + columns: readonly TableColumn[] + row?: CollectionBaseFragment + isLoading: boolean +}) { + const columnMap = createColumnMap(columns) + const withSkeleton = useSkeleton(isLoading) + + const metadata = useMemo(() => { + return row?.meta as CollectionMetadata | undefined + }, [row]) + + const chains = useMemo(() => { + const datas = (row?.data as CollectionDataIndex[]) || ([] as CollectionDataIndex[]) + return datas?.map(i => i.chain) + }, [row]) + + return ( + + + {withSkeleton( + + {row?.index} + , + columnMap[CollectionColumnIds.Index]?.sx, + )} + + + + {withSkeleton(metadata?.name, { width: '100%' })} + + + + {withSkeleton(metadata?.symbol, { width: '100%' })} + + + + {withSkeleton( + + {chains.map((item, idx) => ( + + ))} + , + { + width: '100%', + height: 32, + }, + )} + + + ) +} diff --git a/src/components/SupportedToken/SupportedTokens.tsx b/src/components/SupportedToken/SupportedTokens.tsx new file mode 100644 index 0000000..5738ba3 --- /dev/null +++ b/src/components/SupportedToken/SupportedTokens.tsx @@ -0,0 +1,116 @@ +'use client' + +import { Box, Tab, Tabs, useTheme } from '@mui/material' +import { TokenType } from '@rarimo/client' +import { useMemo } from 'react' + +import { getCollectionCount, getCollectionList } from '@/callers' +import { ContentBox, ContentSection, ContentWrapper } from '@/components/Content' +import { CollectionBaseFragment } from '@/graphql' +import { useLoading, useTablePagination, useTabsFilter } from '@/hooks' +import { useI18n } from '@/locales/client' + +import SupportedTokenList from './SupportedTokenList' + +enum Filters { + FT = 'ft', + NFT = 'nft', +} + +const FILTERS_MAP = { + [Filters.FT]: 0, + [Filters.NFT]: 1, +} + +export default function SupportedTokens() { + const t = useI18n() + const theme = useTheme() + + const { limit, offset, handleChangePage, handleChangeRowsPerPage, setOffset } = + useTablePagination() + + const { + data: count, + isLoading: isLoadingCount, + isLoadingError: isLoadingCountError, + reload: reloadCount, + } = useLoading(0, () => getCollectionCount(filters)) + + const { + data: list, + isLoading, + isLoadingError, + reload: reloadList, + } = useLoading( + [] as CollectionBaseFragment[], + () => getCollectionList(limit, offset, filters), + { loadArgs: [limit, offset] }, + ) + + const { filter, handleFilterChange } = useTabsFilter({ + queryKey: 'type', + defaultValue: FILTERS_MAP[Filters.FT], + handler: async () => { + setOffset(0) + await reloadCount() + await reloadList() + }, + }) + + const filters = useMemo( + () => + ({ + [FILTERS_MAP[Filters.FT]]: [ + TokenType.Native, + TokenType.Erc20, + TokenType.NearFt, + TokenType.MetaplexFt, + ], + [FILTERS_MAP[Filters.NFT]]: [ + TokenType.Erc721, + TokenType.Erc1155, + TokenType.NearNft, + TokenType.MetaplexNft, + ], + })[filter], + + [filter], + ) + + const tabs = [ + { + label: t('supported-tokens.ft-filter-lbl'), + value: FILTERS_MAP[Filters.FT], + }, + { + label: t('supported-tokens.nft-filter-lbl'), + value: FILTERS_MAP[Filters.NFT], + }, + ] + + return ( + + + + + + {tabs.map((tab, idx) => ( + + ))} + + + + + + + ) +} diff --git a/src/components/SupportedToken/index.ts b/src/components/SupportedToken/index.ts new file mode 100644 index 0000000..592457c --- /dev/null +++ b/src/components/SupportedToken/index.ts @@ -0,0 +1,2 @@ +export { default as SupportedToken } from './SupportedToken' +export { default as SupportedTokens } from './SupportedTokens' diff --git a/src/components/index.ts b/src/components/index.ts index 9f46f62..8a5b354 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -10,6 +10,7 @@ export * from './Oracles' export * from './Operation' export * from './Confirmation' export * from './Network' +export * from './SupportedToken' export { default as Avatar } from './Avatar/Avatar' export { default as AvatarName } from './Avatar/AvatarName' diff --git a/src/graphql/fragments/Collection.gql b/src/graphql/fragments/Collection.gql new file mode 100644 index 0000000..bf12a26 --- /dev/null +++ b/src/graphql/fragments/Collection.gql @@ -0,0 +1,13 @@ +fragment Collection on collection { + data + index + meta + collection_data { + collection + decimals + index + index_key + token_type + wrapped + } +} diff --git a/src/graphql/fragments/CollectionBase.gql b/src/graphql/fragments/CollectionBase.gql new file mode 100644 index 0000000..dc5db9b --- /dev/null +++ b/src/graphql/fragments/CollectionBase.gql @@ -0,0 +1,5 @@ +fragment CollectionBase on collection { + index + data + meta +} diff --git a/src/graphql/generated.ts b/src/graphql/generated.ts index f9cf9b9..b5ea781 100644 --- a/src/graphql/generated.ts +++ b/src/graphql/generated.ts @@ -19021,6 +19021,10 @@ export type BlockBaseFragment = { __typename?: 'block', height: any, timestamp: export type BlockListFragment = { __typename?: 'block', height: any, timestamp: any, total_gas?: any | null, transactions_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', moniker?: string | null, avatar_url?: string | null }> } | null }; +export type CollectionFragment = { __typename?: 'collection', data: any, index: string, meta: any, collection_data?: { __typename?: 'collection_data', collection?: string | null, decimals: number, index: any, index_key: string, token_type: number, wrapped: boolean } | null }; + +export type CollectionBaseFragment = { __typename?: 'collection', index: string, data: any, meta: any }; + export type ConfirmationFragment = { __typename?: 'confirmation', creator: string, height: any, tx?: string | null, root: string, indexes: any, signature_ecdsa: string, block?: { __typename?: 'block', timestamp: any } | null }; export type ConfirmationBaseFragment = { __typename?: 'confirmation', root: string, creator: string, height: any, tx?: string | null, block?: { __typename?: 'block', timestamp: any } | null }; @@ -19095,6 +19099,29 @@ export type GetBlockListQueryVariables = Exact<{ export type GetBlockListQuery = { __typename?: 'query_root', block: Array<{ __typename?: 'block', height: any, timestamp: any, total_gas?: any | null, transactions_aggregate: { __typename?: 'transaction_aggregate', aggregate?: { __typename?: 'transaction_aggregate_fields', count: number } | null }, validator?: { __typename?: 'validator', validator_info?: { __typename?: 'validator_info', operator_address: string } | null, validator_descriptions: Array<{ __typename?: 'validator_description', moniker?: string | null, avatar_url?: string | null }> } | null }> }; +export type GetCollectionByIndexQueryVariables = Exact<{ + index: Scalars['String']['input']; +}>; + + +export type GetCollectionByIndexQuery = { __typename?: 'query_root', collection: Array<{ __typename?: 'collection', data: any, index: string, meta: any, collection_data?: { __typename?: 'collection_data', collection?: string | null, decimals: number, index: any, index_key: string, token_type: number, wrapped: boolean } | null }> }; + +export type GetCollectionCountQueryVariables = Exact<{ + where: Collection_Bool_Exp; +}>; + + +export type GetCollectionCountQuery = { __typename?: 'query_root', collection_aggregate: { __typename?: 'collection_aggregate', aggregate?: { __typename?: 'collection_aggregate_fields', count: number } | null } }; + +export type GetCollectionListQueryVariables = Exact<{ + limit?: InputMaybe; + offset?: InputMaybe; + where: Collection_Bool_Exp; +}>; + + +export type GetCollectionListQuery = { __typename?: 'query_root', collection: Array<{ __typename?: 'collection', index: string, data: any, meta: any }> }; + export type GetConfirmationByRootQueryVariables = Exact<{ root: Scalars['String']['input']; }>; @@ -19473,6 +19500,28 @@ export const BlockList = gql` } } `; +export const Collection = gql` + fragment Collection on collection { + data + index + meta + collection_data { + collection + decimals + index + index_key + token_type + wrapped + } +} + `; +export const CollectionBase = gql` + fragment CollectionBase on collection { + index + data + meta +} + `; export const Confirmation = gql` fragment Confirmation on confirmation { creator @@ -19787,6 +19836,29 @@ export const GetBlockList = gql` } } ${BlockList}`; +export const GetCollectionByIndex = gql` + query GetCollectionByIndex($index: String!) { + collection(where: {index: {_eq: $index}}) { + ...Collection + } +} + ${Collection}`; +export const GetCollectionCount = gql` + query GetCollectionCount($where: collection_bool_exp!) { + collection_aggregate(where: $where) { + aggregate { + count(columns: index) + } + } +} + `; +export const GetCollectionList = gql` + query GetCollectionList($limit: Int, $offset: Int, $where: collection_bool_exp!) { + collection(limit: $limit, offset: $offset, where: $where) { + ...CollectionBase + } +} + ${CollectionBase}`; export const GetConfirmationByRoot = gql` query GetConfirmationByRoot($root: String!) { confirmation(where: {root: {_eq: $root}}) { diff --git a/src/graphql/queries/GetCollectionByIndex.gql b/src/graphql/queries/GetCollectionByIndex.gql new file mode 100644 index 0000000..310a152 --- /dev/null +++ b/src/graphql/queries/GetCollectionByIndex.gql @@ -0,0 +1,6 @@ +query GetCollectionByIndex($index: String!) { + collection(where: {index: {_eq: $index}}) { + ...Collection + } +} + diff --git a/src/graphql/queries/GetCollectionCount.gql b/src/graphql/queries/GetCollectionCount.gql new file mode 100644 index 0000000..5d43588 --- /dev/null +++ b/src/graphql/queries/GetCollectionCount.gql @@ -0,0 +1,7 @@ +query GetCollectionCount($where: collection_bool_exp!) { + collection_aggregate(where: $where) { + aggregate { + count(columns: index) + } + } +} diff --git a/src/graphql/queries/GetCollectionList.gql b/src/graphql/queries/GetCollectionList.gql new file mode 100644 index 0000000..0d68c6e --- /dev/null +++ b/src/graphql/queries/GetCollectionList.gql @@ -0,0 +1,5 @@ +query GetCollectionList($limit: Int, $offset: Int, $where: collection_bool_exp!) { + collection(limit: $limit, offset: $offset, where: $where) { + ...CollectionBase + } +} diff --git a/src/locales/en.ts b/src/locales/en.ts index e6a84ed..54e1c31 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -52,6 +52,7 @@ export default { "operations-lbl": "Operations", "confirmations-lbl": "Confirmations", "networks-lbl": "Networks", + "supported-tokens-lbl": "Supported Tokens", }, "footer": { "navigation-links-lbl": "Navigation", @@ -669,4 +670,29 @@ export default { "no-data-msg": "There is no network with such name.", "parameters-col-lbl": "Parameters", }, + "supported-tokens": { + "table-lbl": "Supported Tokens", + "nft-filter-lbl": "Non-fungible", + "ft-filter-lbl": "Fungible", + }, + "supported-token-list": { + "index-col-lbl": "Index", + "name-col-lbl": "Name", + "symbol-col-lbl": "Symbol", + "chains-col-lbl": "Chains", + "table-lbl": "Supported tokens", + "no-data-title": "There are no supported tokens", + "no-data-subtitle": "It will appear for a while", + "error-title": "There was an error while loading supported tokens", + "error-subtitle": "Please try again later", + }, + "supported-token": { + "title": "Supported Token", + "no-data-msg": "There are no supported token with such index", + "index-col-lbl": "Index:", + "name-col-lbl": "Name:", + "symbol-col-lbl": "Symbol:", + "chains-col-lbl": "Chains", + "metadata-uri-col-lbl": "Metadata URI:", + }, } as const diff --git a/src/types/routes.ts b/src/types/routes.ts index 9981116..455baf8 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -23,4 +23,6 @@ export enum RoutePaths { Confirmation = '/confirmations/[root]', Networks = '/networks', Network = '/networks/[name]', + SupportedTokens = '/supported-tokens', + SupportedToken = '/supported-tokens/[index]', } From 766315f7ba33d386222022fa62ec28fbfb2641fd Mon Sep 17 00:00:00 2001 From: Semen Loktionov Date: Fri, 1 Dec 2023 13:19:40 +0200 Subject: [PATCH 5/5] update sdk ver --- CHANGELOG.md | 12 +++++++++++- package.json | 24 +++--------------------- yarn.lock | 22 ++++++++++++---------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 710df40..20c9e10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. +## [1.0.6] - 2023-12-01 +### Added +- TSS pages +- Oracle pages +- Operation pages +- Confirmation pages +- Network pages +- Supported token pages + ## [1.0.5] - 2023-11-02 ### Added - Ability to delegate, undelegate and vote proposal via authorization grants @@ -39,7 +48,8 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic - Initiated project -[Unreleased]: https://gitlab.com/rarimo/scan/compare/1.0.5...HEAD +[Unreleased]: https://gitlab.com/rarimo/scan/compare/1.0.6...HEAD +[1.0.6]: https://gitlab.com/rarimo/scan/compare/1.0.5...1.0.6 [1.0.5]: https://gitlab.com/rarimo/scan/compare/1.0.4...1.0.5 [1.0.4]: https://gitlab.com/rarimo/scan/compare/1.0.3...1.0.4 [1.0.3]: https://gitlab.com/rarimo/scan/compare/1.0.2...1.0.3 diff --git a/package.json b/package.json index 496ef6f..6496499 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan", - "version": "1.0.5", + "version": "1.0.6", "private": true, "gitHooks": { "pre-commit": "yarn lint", @@ -27,7 +27,7 @@ "@hookform/resolvers": "^3.3.1", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.3", - "@rarimo/client": "^2.0.0-rc.28", + "@rarimo/client": "^2.0.0-rc.32", "graphql": "^16.7.1", "graphql-tag": "^2.12.6", "lodash-es": "^4.17.21", @@ -72,23 +72,5 @@ "stylelint-scss": "^5.0.1", "yorkie": "^2.0.0" }, - "packageManager": "yarn@3.6.1", - "resolutions": { - "rarimo-js-sdk-monorepo-root": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk", - "@rarimo/auth-zkp-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/auth-zkp-iden3", - "@rarimo/bridge": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/bridge", - "@rarimo/client": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client", - "@rarimo/identity-gen-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/identity-gen-iden3", - "@rarimo/nft-checkout": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/nft-checkout", - "@rarimo/provider": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/provider", - "@rarimo/providers-evm": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-evm", - "@rarimo/providers-near": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-near", - "@rarimo/providers-solana": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/providers-solana", - "@rarimo/react-nft-checkout": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/react-nft-checkout", - "@rarimo/react-provider": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/react-provider", - "@rarimo/shared": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared", - "@rarimo/shared-zkp-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared-zkp-iden3", - "@rarimo/swap": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/swap", - "@rarimo/zkp-gen-iden3": "portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/zkp-gen-iden3" - } + "packageManager": "yarn@3.6.1" } diff --git a/yarn.lock b/yarn.lock index 790a06e..b43c001 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2489,27 +2489,29 @@ __metadata: languageName: node linkType: hard -"@rarimo/client@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client::locator=scan%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@rarimo/client@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/client::locator=scan%40workspace%3A." +"@rarimo/client@npm:^2.0.0-rc.32": + version: 2.0.0-rc.32 + resolution: "@rarimo/client@npm:2.0.0-rc.32" dependencies: "@cosmjs/launchpad": ^0.27.1 "@cosmjs/proto-signing": ^0.31.0 "@cosmjs/stargate": ^0.31.0 "@distributedlab/fetcher": ^1.0.0-rc.6 "@distributedlab/reactivity": ^1.0.0-rc.6 - "@rarimo/shared": "workspace:^" + "@rarimo/shared": ^2.0.0-rc.32 + checksum: b3df7590410b017d4699ee925f82f554908bbf1c1eb4db0d602aa26d7dbaa13967caa71608e970c5dd5e506cea9283ad697cc0633ab1e4ac472103126e821584 languageName: node - linkType: soft + linkType: hard -"@rarimo/shared@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared::locator=scan%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@rarimo/shared@portal:/Users/napalmpapalam/Projects/RARIMO/js-sdk/packages/shared::locator=scan%40workspace%3A." +"@rarimo/shared@npm:^2.0.0-rc.32": + version: 2.0.0-rc.32 + resolution: "@rarimo/shared@npm:2.0.0-rc.32" dependencies: "@distributedlab/jac": ^1.0.0-rc.6 "@distributedlab/tools": ^1.0.0-rc.6 + checksum: 0ac84807695d3d594e2453cd86ca221881a78229237c72d1d968138e9505977de95e149891b59ee3d87845d6e65fe35bd719dd760c30f2a94de2d87bf4c0ae11 languageName: node - linkType: soft + linkType: hard "@repeaterjs/repeater@npm:^3.0.4": version: 3.0.4 @@ -9609,7 +9611,7 @@ __metadata: "@hookform/resolvers": ^3.3.1 "@mui/icons-material": ^5.14.3 "@mui/material": ^5.14.3 - "@rarimo/client": ^2.0.0-rc.28 + "@rarimo/client": ^2.0.0-rc.32 "@types/lodash-es": ^4 "@types/negotiator": ^0 "@types/node": 20.4.5