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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/api/blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,57 @@ export const blocks = {
}
}

totalCount
}
highSecuritySets: highSecuritySetsConnection(
orderBy: timestamp_DESC
first: $limit
where: {
block: { height_eq: $height }
OR: { block: { hash_eq: $hash } }
}
) {
edges {
node {
extrinsicHash
timestamp
delay
block {
height
}
who {
id
}
interceptor {
id
}
}
}

totalCount
}
errorEvents: errorEventsConnection(
orderBy: timestamp_DESC
first: $limit
where: {
block: { height_eq: $height }
OR: { block: { hash_eq: $hash } }
}
) {
edges {
node {
errorDocs
errorModule
errorName
errorType
extrinsicHash
timestamp
block {
height
}
}
}

totalCount
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/api/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ export const search = (fetcher: DataFetcher) => ({
}
timestamp
}
errorEvents(
limit: $limit
where: {
errorType_containsInsensitive: $keyword
OR: { errorName_containsInsensitive: $keyword }
}
) {
extrinsicHash
}
}
`;

Expand Down
56 changes: 56 additions & 0 deletions src/components/common/table-columns/BLOCK_ERROR_EVENT_COLUMNS.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createColumnHelper } from '@tanstack/react-table';

import { LinkWithCopy } from '@/components/ui/composites/link-with-copy/LinkWithCopy';
import { TimestampDisplay } from '@/components/ui/timestamp-display';
import { RESOURCES } from '@/constants/resources';
import type { BlockErrorEvent } from '@/schemas';
import { formatTxAddress } from '@/utils/formatter';

const columnHelper = createColumnHelper<BlockErrorEvent>();

export const BLOCK_ERROR_EVENT_COLUMNS = [
columnHelper.accessor('node.extrinsicHash', {
id: 'extrinsicHash',
header: 'Extrinsic Hash',
cell: (props) =>
props.getValue() ? (
<LinkWithCopy
href={`${RESOURCES.errors}/${props.getValue()}`}
text={formatTxAddress(props.getValue() ?? '-')}
textCopy={props.getValue() ?? ''}
/>
) : (
'Is not available'
),
enableSorting: false
}),
columnHelper.accessor('node.block.height', {
id: 'block_height',
header: 'Block',
cell: (props) => (
<LinkWithCopy
href={`${RESOURCES.blocks}/${props.getValue()}`}
text={props.getValue().toString()}
/>
),
enableSorting: true
}),
columnHelper.accessor('node.timestamp', {
id: 'timestamp',
header: 'Timestamp',
cell: (props) => <TimestampDisplay timestamp={props.getValue()} />,
enableSorting: true
}),
columnHelper.accessor('node.errorType', {
id: 'errorType',
header: 'Type',
cell: (props) => props.getValue(),
enableSorting: true
}),
columnHelper.accessor('node.errorName', {
id: 'errorName',
header: 'Name',
cell: (props) => props.getValue() ?? '-',
enableSorting: true
})
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { createColumnHelper } from '@tanstack/react-table';

import { LinkWithCopy } from '@/components/ui/composites/link-with-copy/LinkWithCopy';
import { TimestampDisplay } from '@/components/ui/timestamp-display';
import { RESOURCES } from '@/constants/resources';
import type { BlockHighSecuritySet } from '@/schemas';
import { formatDuration, formatTxAddress } from '@/utils/formatter';

const columnHelper = createColumnHelper<BlockHighSecuritySet>();

export const BLOCK_HIGH_SECURITY_SET_COLUMNS = [
columnHelper.accessor('node.extrinsicHash', {
id: 'tx-hash',
header: 'Hash',
cell: (props) =>
props.getValue() ? (
<LinkWithCopy
href={`${RESOURCES.highSecuritySets}/${props.getValue()}`}
text={formatTxAddress(props.getValue() ?? '-')}
textCopy={props.getValue() ?? ''}
/>
) : (
'Is not available'
),
enableSorting: false
}),
columnHelper.accessor('node.block.height', {
id: 'block_height',
header: 'Block',
cell: (props) => (
<LinkWithCopy
href={`${RESOURCES.blocks}/${props.getValue()}`}
text={props.getValue().toString()}
/>
),
enableSorting: true
}),
columnHelper.accessor('node.timestamp', {
id: 'timestamp',
header: 'Timestamp',
cell: (props) => <TimestampDisplay timestamp={props.getValue()} />,
enableSorting: true
}),
columnHelper.accessor('node.who.id', {
id: 'who',
header: 'Beneficiary',
cell: (props) => (
<LinkWithCopy
href={`${RESOURCES.accounts}/${props.getValue()}`}
text={formatTxAddress(props.getValue())}
textCopy={props.getValue()}
/>
),
enableSorting: false
}),
columnHelper.accessor('node.interceptor.id', {
id: 'interceptor',
header: 'Guardian',
cell: (props) => (
<LinkWithCopy
href={`${RESOURCES.accounts}/${props.getValue()}`}
text={formatTxAddress(props.getValue())}
textCopy={props.getValue()}
/>
),
enableSorting: false
}),
columnHelper.accessor('node.delay', {
id: 'delay',
header: 'Reversible Time',
cell: (props) => formatDuration(props.getValue()),
enableSorting: true
})
];
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import type { BlockResponse } from '@/schemas';
import { formatOption } from '@/utils/formatter';

import { BlockErrorEvents } from '../block-error-events/BlockErrorEvents';
import { BlockHighSecuritySets } from '../block-high-security-sets/BlockHighSecuritySets';
import { BlockReversibleTransactions } from '../block-reversible-transactions/BlockReversibleTransactions';
import { BlockTransactions } from '../block-transactions/BlockTransactions';

Expand All @@ -23,7 +25,9 @@ export interface BlockDataTabsProps {

const TAB_OPTIONS = {
immediate: 'immediate-transactions',
reversible: 'reversible-transactions'
reversible: 'reversible-transactions',
highSecuritySets: 'high-security-sets',
errorEvents: 'error-events'
} as const;
const TAB_LIST = Object.values(TAB_OPTIONS);

Expand Down Expand Up @@ -66,6 +70,12 @@ export const BlockDataTabs: React.FC<BlockDataTabsProps> = ({ query }) => {
<TabsContent value={TAB_OPTIONS.reversible}>
<BlockReversibleTransactions query={query} />
</TabsContent>
<TabsContent value={TAB_OPTIONS.highSecuritySets}>
<BlockHighSecuritySets query={query} />
</TabsContent>
<TabsContent value={TAB_OPTIONS.errorEvents}>
<BlockErrorEvents query={query} />
</TabsContent>
</Tabs>
</ContentContainer>
</SectionContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { QueryResult } from '@apollo/client';
import { Link } from '@tanstack/react-router';
import React from 'react';

import { Button } from '@/components/ui/button';
import { DataTable } from '@/components/ui/composites/data-table/DataTable';
import { ContentContainer } from '@/components/ui/content-container';
import type { BlockResponse } from '@/schemas';

import { useBlockErrorEvents } from './hook';

interface Props {
query: QueryResult<BlockResponse>;
}

export const BlockErrorEvents: React.FC<Props> = ({ query }) => {
const { getStatus, table, error } = useBlockErrorEvents(query);

return (
<ContentContainer className="flex flex-col gap-4 px-0">
<h2>Recent Error Events</h2>

<DataTable
table={table}
fetch={{
status: getStatus(),
errorFallback: <p>Error: {error && error.message}</p>
}}
/>

{!query.loading && query.data?.errorEvents.totalCount !== 0 && (
<Button variant="link" className="mx-auto w-fit">
<Link to="/errors" search={{ block: query.data?.blocks[0]?.height }}>
See all error events
</Link>
</Button>
)}
</ContentContainer>
);
};
40 changes: 40 additions & 0 deletions src/components/features/block-details/block-error-events/hook.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { QueryResult } from '@apollo/client';
import { getCoreRowModel, useReactTable } from '@tanstack/react-table';
import { useMemo } from 'react';

import { BLOCK_ERROR_EVENT_COLUMNS } from '@/components/common/table-columns/BLOCK_ERROR_EVENT_COLUMNS';
import type { BlockResponse, BlockErrorEvent } from '@/schemas';

export const useBlockErrorEvents = (query: QueryResult<BlockResponse>) => {
const { data, error: fetchError, loading } = query;
const blockColumns = useMemo(() => BLOCK_ERROR_EVENT_COLUMNS, []);

const table = useReactTable<BlockErrorEvent>({
data: data?.errorEvents?.edges ?? [],
columns: blockColumns,
getCoreRowModel: getCoreRowModel(),
enableSorting: false
});

const success = !loading && !fetchError;
const error = !loading && fetchError;

const getStatus = () => {
switch (true) {
case success:
return 'success';
case !!error:
return 'error';
case !!loading:
return 'loading';
default:
return 'idle';
}
};

return {
table,
getStatus,
error
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { QueryResult } from '@apollo/client';
import { Link } from '@tanstack/react-router';
import React from 'react';

import { Button } from '@/components/ui/button';
import { DataTable } from '@/components/ui/composites/data-table/DataTable';
import { ContentContainer } from '@/components/ui/content-container';
import type { BlockResponse } from '@/schemas';

import { useBlockHighSecuritySets } from './hook';

interface Props {
query: QueryResult<BlockResponse>;
}

export const BlockHighSecuritySets: React.FC<Props> = ({ query }) => {
const { getStatus, table, error } = useBlockHighSecuritySets(query);

return (
<ContentContainer className="flex flex-col gap-4 px-0">
<h2>Recent High Security Sets</h2>

<DataTable
table={table}
fetch={{
status: getStatus(),
errorFallback: <p>Error: {error && error.message}</p>
}}
/>

{!query.loading && query.data?.highSecuritySets.totalCount !== 0 && (
<Button variant="link" className="mx-auto w-fit">
<Link
to="/high-security-sets"
search={{ block: query.data?.blocks[0]?.height }}
>
See all high security sets
</Link>
</Button>
)}
</ContentContainer>
);
};
Loading