Skip to content

Commit ba6907f

Browse files
authored
fix: transaction table (#71)
* chore: fix inner transaction rendering in non lazy table * fix: support viewing an inner transaction group * chore: fix build
1 parent f28f847 commit ba6907f

31 files changed

+160
-216
lines changed

src/features/accounts/components/labels.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const accountJsonLabel = 'Acount JSON'
1+
export const accountJsonLabel = 'Account JSON'
22
export const accountActivityLabel = 'Activity'
33

44
export const accountLiveTransactionsTabLabel = 'Live Transactions'

src/features/blocks/components/block-details.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { useMemo } from 'react'
44
import { cn } from '@/features/common/utils'
55
import { dateFormatter } from '@/utils/format'
66
import { BlockLink } from './block-link'
7-
import { TransactionsTable } from './transactions'
87
import { Block } from '../models'
98
import { Badge } from '@/features/common/components/badge'
109
import { RenderInlineAsyncAtom } from '@/features/common/components/render-inline-async-atom'
10+
import { TransactionsTable } from '@/features/transactions/components/transactions-table'
11+
import { transactionsTableColumnsWithoutRound } from '@/features/transactions/components/transactions-table-columns'
1112

1213
type Props = {
1314
block: Block
@@ -72,7 +73,7 @@ export function BlockDetails({ block }: Props) {
7273
<Card className={cn('p-4')}>
7374
<CardContent className={cn('text-sm space-y-2')}>
7475
<h1 className={cn('text-2xl text-primary font-bold')}>{transactionsLabel}</h1>
75-
<TransactionsTable transactions={block.transactions} />
76+
<TransactionsTable transactions={block.transactions} columns={transactionsTableColumnsWithoutRound} />
7677
</CardContent>
7778
</Card>
7879
</div>

src/features/blocks/components/transactions.tsx

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/features/blocks/data/block-result.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { BlockResult, Round } from './types'
66
import { groupResultsAtom } from '@/features/groups/data'
77
import { GroupId, GroupResult } from '@/features/groups/data/types'
88
import { atomsInAtom } from '@/features/common/data'
9+
import { flattenTransactionResult } from '@/features/transactions/utils/flatten-transaction-result'
910

1011
export const getBlockAndExtractData = async (round: Round) => {
1112
// We use indexer instead of algod, as algod might not have the full history of blocks
@@ -15,17 +16,12 @@ export const getBlockAndExtractData = async (round: Round) => {
1516
.then((result) => {
1617
const [transactionIds, groupResults] = ((result.transactions ?? []) as TransactionResult[]).reduce(
1718
(acc, t) => {
19+
// Accumulate transactions
1820
acc[0].push(t.id)
19-
if (t.group) {
20-
const group: GroupResult = acc[1].get(t.group) ?? {
21-
id: t.group,
22-
round: result.round as number,
23-
timestamp: new Date(result.timestamp * 1000).toISOString(),
24-
transactionIds: [],
25-
}
26-
group.transactionIds.push(t.id)
27-
acc[1].set(t.group, group)
28-
}
21+
22+
// Accumulate group results
23+
accumulateGroupsFromTransaction(acc[1], t, result.round, result.timestamp)
24+
2925
return acc
3026
},
3127
[[], new Map()] as [string[], Map<GroupId, GroupResult>]
@@ -45,6 +41,30 @@ export const getBlockAndExtractData = async (round: Round) => {
4541
return result
4642
}
4743

44+
export const accumulateGroupsFromTransaction = (
45+
acc: Map<GroupId, GroupResult>,
46+
transaction: TransactionResult,
47+
round: number,
48+
roundTime: number
49+
) => {
50+
// Inner transactions can be part of a group, just like regular transactions.
51+
// In this scenario we add the root transaction id to the group, as inner transactions don't have ids on the network.
52+
flattenTransactionResult(transaction).forEach((txn) => {
53+
if (txn.group) {
54+
const group: GroupResult = acc.get(txn.group) ?? {
55+
id: txn.group,
56+
round,
57+
timestamp: new Date(roundTime * 1000).toISOString(),
58+
transactionIds: [],
59+
}
60+
if (!group.transactionIds.find((id) => id === transaction.id)) {
61+
group.transactionIds.push(transaction.id)
62+
}
63+
acc.set(txn.group, group)
64+
}
65+
})
66+
}
67+
4868
export const addStateExtractedFromBlocksAtom = atom(
4969
null,
5070
(get, set, blockResults: BlockResult[], transactionResults: TransactionResult[], groupResults: GroupResult[]) => {

src/features/blocks/data/latest-blocks.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { flattenTransactionResult } from '@/features/transactions/utils/flatten-
1414
import { distinct } from '@/utils/distinct'
1515
import { assetResultsAtom } from '@/features/assets/data'
1616
import { BlockSummary } from '../models'
17-
import { blockResultsAtom, addStateExtractedFromBlocksAtom } from './block-result'
17+
import { blockResultsAtom, addStateExtractedFromBlocksAtom, accumulateGroupsFromTransaction } from './block-result'
1818
import { GroupId, GroupResult } from '@/features/groups/data/types'
1919
import { AssetId } from '@/features/assets/data/types'
2020
import { BalanceChangeRole } from '@algorandfoundation/algokit-subscriber/types/subscription'
@@ -121,17 +121,7 @@ const subscribeToBlocksEffect = atomEffect((get, set) => {
121121
acc[1].push(transaction)
122122

123123
// Accumulate group results
124-
if (t.group) {
125-
const roundTime = transaction['round-time']
126-
const group: GroupResult = acc[2].get(t.group) ?? {
127-
id: t.group,
128-
round: round,
129-
timestamp: (roundTime ? new Date(roundTime * 1000) : new Date()).toISOString(),
130-
transactionIds: [],
131-
}
132-
group.transactionIds.push(t.id)
133-
acc[2].set(t.group, group)
134-
}
124+
accumulateGroupsFromTransaction(acc[2], transaction, round, transaction['round-time'] ?? new Date().getTime() / 1000)
135125

136126
// Accumulate stale asset ids
137127
const staleAssetIds = flattenTransactionResult(t)

src/features/common/components/data-table.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
import { ColumnDef, flexRender, getCoreRowModel, useReactTable, getPaginationRowModel } from '@tanstack/react-table'
1+
import { ColumnDef, flexRender, getCoreRowModel, useReactTable, getPaginationRowModel, getExpandedRowModel } from '@tanstack/react-table'
22
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/features/common/components/table'
33
import { DataTablePagination } from './data-table-pagination'
44

55
interface DataTableProps<TData, TValue> {
66
columns: ColumnDef<TData, TValue>[]
77
data: TData[]
8+
getSubRows?: (row: TData) => TData[]
89
}
910

10-
export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
11+
export function DataTable<TData, TValue>({ columns, data, getSubRows }: DataTableProps<TData, TValue>) {
1112
const table = useReactTable({
1213
data,
14+
paginateExpandedRows: false,
15+
state: {
16+
expanded: true,
17+
},
18+
getSubRows: getSubRows,
1319
columns,
1420
getCoreRowModel: getCoreRowModel(),
21+
getExpandedRowModel: getExpandedRowModel(),
1522
getPaginationRowModel: getPaginationRowModel(),
1623
})
1724

src/features/groups/components/group-details.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useMemo } from 'react'
66
import { Badge } from '@/features/common/components/badge'
77
import { dateFormatter } from '@/utils/format'
88
import { BlockLink } from '@/features/blocks/components/block-link'
9-
import { GroupVisualTabs } from './group-visual-tabs'
9+
import { GroupTransactionsViewTabs } from './group-transactions-view-tabs'
1010

1111
type Props = {
1212
group: Group
@@ -60,7 +60,7 @@ export function GroupDetails({ group }: Props) {
6060
<CardContent className={cn('text-sm space-y-2')}>
6161
<h1 className={cn('text-2xl text-primary font-bold')}>{transactionsLabel}</h1>
6262
</CardContent>
63-
<GroupVisualTabs group={group} />
63+
<GroupTransactionsViewTabs group={group} />
6464
</Card>
6565
</div>
6666
)

src/features/groups/components/group-visual-tabs.tsx renamed to src/features/groups/components/group-transactions-view-tabs.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { OverflowAutoTabsContent, Tabs, TabsList, TabsTrigger } from '@/features
33
import { Group } from '../models'
44
import { TransactionsGraph } from '@/features/transactions/components/transactions-graph'
55
import { TransactionsTable } from '@/features/transactions/components/transactions-table'
6+
import { transactionsTableColumnsWithoutRound } from '@/features/transactions/components/transactions-table-columns'
67

78
type Props = {
89
group: Group
@@ -14,7 +15,7 @@ export const groupVisual = 'View Group'
1415
export const groupVisualGraphLabel = 'Graph'
1516
export const groupVisualTableLabel = 'Table'
1617

17-
export function GroupVisualTabs({ group }: Props) {
18+
export function GroupTransactionsViewTabs({ group }: Props) {
1819
return (
1920
<Tabs defaultValue={graphTabId}>
2021
<TabsList aria-label={groupVisual}>
@@ -29,7 +30,7 @@ export function GroupVisualTabs({ group }: Props) {
2930
<TransactionsGraph transactions={group.transactions} />
3031
</OverflowAutoTabsContent>
3132
<OverflowAutoTabsContent value={tableTabId}>
32-
<TransactionsTable transactions={group.transactions} />
33+
<TransactionsTable transactions={group.transactions} columns={transactionsTableColumnsWithoutRound} />
3334
</OverflowAutoTabsContent>
3435
</Tabs>
3536
)
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
import { Group } from '../models'
22
import { GroupResult } from '../data/types'
3-
import { Transaction } from '@/features/transactions/models'
3+
import { InnerTransaction, Transaction, TransactionType } from '@/features/transactions/models'
44
import { asTransactionsSummary } from '@/features/transactions/mappers'
5+
import { flattenInnerTransactions } from '@/utils/flatten-inner-transactions'
56

67
export const asGroup = (groupResult: GroupResult, transactions: Transaction[]): Group => {
8+
// The transactions passed in are always parent transactions.
9+
// The group can be an inner transaction group, so we want to filter any transactions that aren't related to the group.
10+
const transactionsInGroup = transactions.reduce(
11+
(acc, txn) => {
12+
if (txn.group === groupResult.id) {
13+
// transaction in the group is at the root level, no need to search further
14+
acc.push(txn)
15+
} else if (txn.type === TransactionType.ApplicationCall && txn.innerTransactions.length > 0) {
16+
const txns = flattenInnerTransactions(txn)
17+
txns.forEach((flat) => {
18+
if (flat.transaction.group === groupResult.id) {
19+
acc.push(flat.transaction)
20+
}
21+
})
22+
}
23+
return acc
24+
},
25+
[] as (Transaction | InnerTransaction)[]
26+
)
27+
728
return {
829
id: groupResult.id,
930
round: groupResult.round,
10-
transactions,
31+
transactions: transactionsInGroup,
1132
timestamp: groupResult.timestamp,
12-
transactionsSummary: asTransactionsSummary(transactions),
33+
transactionsSummary: asTransactionsSummary(transactionsInGroup),
1334
}
1435
}

src/features/groups/pages/group-page.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { executeComponentTest } from '@/tests/test-component'
22
import { getByRole, render, waitFor } from '@/tests/testing-library'
33
import { useParams } from 'react-router-dom'
44
import { describe, expect, it, vi } from 'vitest'
5-
import { GroupPage, blockInvalidRoundMessage, blockNotFoundMessage, groupFailedToLoadMessage } from './group-page'
5+
import { GroupPage, blockInvalidRoundMessage, groupNotFoundMessage, groupFailedToLoadMessage } from './group-page'
66
import { indexer } from '@/features/common/data'
77
import { HttpError } from '@/tests/errors'
88
import { groupResultMother } from '@/tests/object-mother/group-result'
@@ -14,7 +14,7 @@ import { transactionResultMother } from '@/tests/object-mother/transaction-resul
1414
import { assetResultMother } from '@/tests/object-mother/asset-result'
1515
import { algoAssetResult } from '@/features/assets/data'
1616
import { transactionResultsAtom } from '@/features/transactions/data'
17-
import { groupVisual, groupVisualGraphLabel, groupVisualTableLabel } from '../components/group-visual-tabs'
17+
import { groupVisual, groupVisualGraphLabel, groupVisualTableLabel } from '../components/group-transactions-view-tabs'
1818
import { tableAssertion } from '@/tests/assertions/table-assertion'
1919
import { assetResultsAtom } from '@/features/assets/data'
2020

@@ -40,7 +40,7 @@ describe('block-page', () => {
4040
return executeComponentTest(
4141
() => render(<GroupPage />),
4242
async (component) => {
43-
await waitFor(() => expect(component.getByText(blockNotFoundMessage)).toBeTruthy())
43+
await waitFor(() => expect(component.getByText(groupNotFoundMessage)).toBeTruthy())
4444
}
4545
)
4646
})
@@ -117,10 +117,10 @@ describe('block-page', () => {
117117
// This table has 10+ row, we only test the first 2 rows
118118
rows: [
119119
{
120-
cells: ['INDQXWQ...', 'AACC...EN4A', '1201559522', 'Application Call'],
120+
cells: ['INDQXWQ...', '/oRSr2u...', 'AACC...EN4A', '1201559522', 'Application Call', ''],
121121
},
122122
{
123-
cells: ['Inner 1', 'AACC...EN4A', '2PIF...RNMM', 'Payment', '2.770045'],
123+
cells: ['Inner 1', 'aWpPwlo...', 'AACC...EN4A', '2PIF...RNMM', 'Payment', '2.770045'],
124124
},
125125
],
126126
})

0 commit comments

Comments
 (0)