From 9ded4efe09b8d98158087ebdb82f5a4813fbe594 Mon Sep 17 00:00:00 2001 From: Hoang Dinh Date: Tue, 18 Jun 2024 15:07:27 +1000 Subject: [PATCH] chore: enhance the transaction visual UI (#104) --- src/assets/svg/circle.svg | 6 - src/assets/svg/pointer-left.svg | 4 +- src/assets/svg/pointer-right.svg | 8 +- .../common/components/display-algo.tsx | 2 +- .../components/display-asset-amount.tsx | 17 +- src/features/common/components/svg/circle.tsx | 21 - .../common/components/svg/pointer-left.tsx | 9 +- .../common/components/svg/pointer-right.tsx | 8 +- ...5EZY7V6FFNI6WUD5FHRVDV6NCU6HD424BJGGA.html | 1965 ++++++++-------- ...S4VYR4ZDZ3RXIET5CNYQVJUO5OXXPMHAMJCCQ.html | 463 ++-- ...XC3EXFGZQHYKI6FQOZU2DOKHQCAWYEIHJBKEA.html | 1011 ++++---- ...7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA.html | 87 +- ...ICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA.html | 178 +- ...emQhwQliJO18b64Nl1QIkjA39ZszRCeSCI%3D.html | 2033 +++++++++-------- ...C7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ.html | 69 +- ...ZUMUFIYQLSDC26HGLTFD7EATQDY37FHCIYBBQ.html | 192 +- ...IHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA.html | 87 +- .../components/graph-config.tsx | 5 +- .../components/horizontal.tsx | 123 +- .../components/transactions-graph.tsx | 6 +- .../components/vertical-title.tsx | 55 +- .../transactions-graph/mappers/index.ts | 220 +- .../transactions-graph/models/index.ts | 33 +- 23 files changed, 3548 insertions(+), 3054 deletions(-) delete mode 100644 src/assets/svg/circle.svg delete mode 100644 src/features/common/components/svg/circle.tsx diff --git a/src/assets/svg/circle.svg b/src/assets/svg/circle.svg deleted file mode 100644 index 24f1d6648..000000000 --- a/src/assets/svg/circle.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/svg/pointer-left.svg b/src/assets/svg/pointer-left.svg index 324960593..0758d46e8 100644 --- a/src/assets/svg/pointer-left.svg +++ b/src/assets/svg/pointer-left.svg @@ -1,4 +1,4 @@  - - + + diff --git a/src/assets/svg/pointer-right.svg b/src/assets/svg/pointer-right.svg index f5113d485..2f8cfd7ea 100644 --- a/src/assets/svg/pointer-right.svg +++ b/src/assets/svg/pointer-right.svg @@ -1,4 +1,4 @@ - - - - + + + + \ No newline at end of file diff --git a/src/features/common/components/display-algo.tsx b/src/features/common/components/display-algo.tsx index ec9cedee7..41eb67a17 100644 --- a/src/features/common/components/display-algo.tsx +++ b/src/features/common/components/display-algo.tsx @@ -9,7 +9,7 @@ export type Props = { export function DisplayAlgo({ className, amount }: Props) { return ( -
+
{amount.algos}
diff --git a/src/features/common/components/display-asset-amount.tsx b/src/features/common/components/display-asset-amount.tsx index e0187b93f..b5d2a4468 100644 --- a/src/features/common/components/display-asset-amount.tsx +++ b/src/features/common/components/display-asset-amount.tsx @@ -11,9 +11,16 @@ type Props = { asset: AssetSummary | AsyncMaybeAtom isFrozen?: boolean className?: string + linkClassName?: string } -const Amount = ({ asset, amount, isFrozen }: { asset: AssetSummary; amount: number | bigint; isFrozen?: boolean }) => { +type AmountProps = { + asset: AssetSummary + amount: number | bigint + isFrozen?: boolean + linkClassName?: string +} +const Amount = ({ asset, amount, isFrozen, linkClassName }: AmountProps) => { // asset decimals value must be from 0 to 19 so it is safe to use .toString() here // the amount is uint64, should be safe to be .toString() const amountToDisplay = new Decimal(amount.toString()).div(new Decimal(10).pow(asset.decimals)).toString() @@ -22,7 +29,7 @@ const Amount = ({ asset, amount, isFrozen }: { asset: AssetSummary; amount: numb
{amountToDisplay} {asset.unitName ? ( - + {asset.unitName} ) : undefined} @@ -31,15 +38,15 @@ const Amount = ({ asset, amount, isFrozen }: { asset: AssetSummary; amount: numb ) } -export const DisplayAssetAmount = ({ amount, asset, isFrozen, className }: Props) => { +export const DisplayAssetAmount = ({ amount, asset, isFrozen, className, linkClassName }: Props) => { return (
{'read' in asset ? ( - {(asset) => } + {(asset) => } ) : ( - + )}
) diff --git a/src/features/common/components/svg/circle.tsx b/src/features/common/components/svg/circle.tsx deleted file mode 100644 index 2a44643cf..000000000 --- a/src/features/common/components/svg/circle.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { SVGProps } from 'react' -const SvgCircle = (props: SVGProps) => ( - - - - - -) -export default SvgCircle diff --git a/src/features/common/components/svg/pointer-left.tsx b/src/features/common/components/svg/pointer-left.tsx index 6e4c2c586..0282044cc 100644 --- a/src/features/common/components/svg/pointer-left.tsx +++ b/src/features/common/components/svg/pointer-left.tsx @@ -2,18 +2,19 @@ import type { SVGProps } from 'react' const SvgPointerLeft = (props: SVGProps) => ( ) diff --git a/src/features/common/components/svg/pointer-right.tsx b/src/features/common/components/svg/pointer-right.tsx index b1ef5bd6f..7c11fad31 100644 --- a/src/features/common/components/svg/pointer-right.tsx +++ b/src/features/common/components/svg/pointer-right.tsx @@ -2,14 +2,14 @@ import type { SVGProps } from 'react' const SvgPointerRight = (props: SVGProps) => ( - + ) export default SvgPointerRight diff --git a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.INDQXWQXHF22SO45EZY7V6FFNI6WUD5FHRVDV6NCU6HD424BJGGA.html b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.INDQXWQXHF22SO45EZY7V6FFNI6WUD5FHRVDV6NCU6HD424BJGGA.html index 9995c7943..348ca5c5e 100644 --- a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.INDQXWQXHF22SO45EZY7V6FFNI6WUD5FHRVDV6NCU6HD424BJGGA.html +++ b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.INDQXWQXHF22SO45EZY7V6FFNI6WUD5FHRVDV6NCU6HD424BJGGA.html @@ -1,7 +1,7 @@
- - + +
- AACC...EN4A - - +
+ 1 +
+
+
+
- - AACC...EN4A - - + + + + + +
+ +
+
+ 1 +
+
+
@@ -66,16 +177,34 @@ - - + +
- 2PIF...RNMM - - +
+ 4 +
+
+
+
- - 2PIF...RNMM - - - + + + + +
+
+ + + 2PIF...RNMM + + +
+
+
+ 4 +
+
+
+
- - FCHE...IYSM - - - + + + + +
+
+ + + FCHE...IYSM + + +
+
+
+ 6 +
+
+ +
- - EOXL...GCE4 - - + + + + + +
+
+ + + EOXL...GCE4 + + +
+
+
+ 7 +
+
+ @@ -142,16 +450,34 @@ - - +
+ + + FCHE...IYSM + + +
+
- FCHE...IYSM - - +
+ 6 +
+
+
- - +
+ + + EOXL...GCE4 + + +
+
- EOXL...GCE4 - - +
+ 7 +
+
+
- - 645869114 - - +
+ + 645869114 + +
+
+
+
- - IWT4...4RVY - - + + + + +
+
+ + + IWT4...4RVY + + +
+
+
+ 8 +
+
+
@@ -210,7 +604,7 @@
@@ -312,52 +706,39 @@
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -403,7 +773,7 @@ >
- - - - - +
+ 1 +
- Payment
- 2.770045 - - - - - + + + + +
- - - - - + 4 +
@@ -534,7 +882,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -639,7 +963,7 @@ >
- - - - - + style="grid-column-start: 2; grid-column-end: 6;" + > +
+ 1 +
- Transfer
-
-
- - 0.586582 - - +
+
- USDC - + + 0.586582 + + + USDC + +
- - - - - + 4 +
@@ -766,7 +1069,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.586582 - - +
+
- USDC - + + 0.586582 + + + USDC + +
- - - - - + 6 +
@@ -889,7 +1170,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -994,7 +1251,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 146.5 - - +
- - - - - + 6 +
@@ -1121,7 +1357,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 146.5 - - +
- - - - - + 7 +
@@ -1243,7 +1457,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -1348,7 +1538,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.00017647 - - +
+
- goETH - + + 0.00017647 + + + goETH + +
- - - - - + 7 +
@@ -1475,7 +1644,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.00017647 - - +
+
- goETH - + + 0.00017647 + + + goETH + +
- - - - - + 8 +
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
- - - - - +
+ 1 +
- Payment
- 2.78626 - - - - - + + + + +
- - - - - + 8 +
- - - - - +
+ 1 +
- Payment
- 0 - - - - - + + + + +
- - - - - + 1 +
diff --git a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.KMNBSQ4ZFX252G7S4VYR4ZDZ3RXIET5CNYQVJUO5OXXPMHAMJCCQ.html b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.KMNBSQ4ZFX252G7S4VYR4ZDZ3RXIET5CNYQVJUO5OXXPMHAMJCCQ.html index 45cbce22a..5fdbaa299 100644 --- a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.KMNBSQ4ZFX252G7S4VYR4ZDZ3RXIET5CNYQVJUO5OXXPMHAMJCCQ.html +++ b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.KMNBSQ4ZFX252G7S4VYR4ZDZ3RXIET5CNYQVJUO5OXXPMHAMJCCQ.html @@ -1,7 +1,7 @@
- - + +
- W2IZ...NCEY - - +
+ 1 +
+
+
- - 971368268 - - + +
+
+
- - 2ZPN...DJJ4 - - + + + + +
+ +
+
+ 2 +
+
+
@@ -57,24 +125,74 @@ class="text-l font-semibold" >
- - 971350278 - - + +
+
+
- - NOEN...BZJI - - + + + + +
+ +
+
+ 3 +
+
+
@@ -88,7 +206,7 @@
@@ -158,52 +276,39 @@
- - - - - + 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -245,7 +339,7 @@ >
- - - - - + 1 +
- Payment
- 236.706032 - - - - - + + + + +
- - - - - + 2 +
@@ -372,7 +445,7 @@ >
- - - - - + 2 +
- App Call -
- - - - - + App Call +
+
+
diff --git a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.WYEGSIGWZHTR6VYXC3EXFGZQHYKI6FQOZU2DOKHQCAWYEIHJBKEA.html b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.WYEGSIGWZHTR6VYXC3EXFGZQHYKI6FQOZU2DOKHQCAWYEIHJBKEA.html index df5b09c64..165e6a141 100644 --- a/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.WYEGSIGWZHTR6VYXC3EXFGZQHYKI6FQOZU2DOKHQCAWYEIHJBKEA.html +++ b/src/features/transactions-graph/components/__snapshots__/application-transaction-graph.WYEGSIGWZHTR6VYXC3EXFGZQHYKI6FQOZU2DOKHQCAWYEIHJBKEA.html @@ -1,7 +1,7 @@
- - + +
- BULA...KO4I - - +
+ 1 +
+
+
- - 1667658418 - - + +
+
+
- - AIIW...JPVE - - + + + + +
+ +
+
+ 2 +
+
+
@@ -57,24 +125,74 @@ class="text-l font-semibold" >
- - 1284326447 - - + +
+
+
- - JP3E...NXPI - - + + + + +
+ +
+
+ 3 +
+
+
@@ -84,16 +202,34 @@ - - + +
- TRCE...RMUM - - +
+ 4 +
+
+
+
- - TRCE...RMUM - - + + + + + +
+ +
+
+ 4 +
+
+
@@ -144,7 +373,7 @@
@@ -230,52 +459,39 @@
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -319,7 +524,7 @@ >
- - - - - +
+ 2 +
- App Call -
- - - - - + App Call +
+
+
@@ -423,7 +604,7 @@ >
- - - - - +
+ 2 +
- App Call -
- - - - - + App Call +
+
+
@@ -527,7 +684,7 @@ >
- - - - - +
+ 1 +
- Payment
- 0.0011 - - - - - + + + + +
- - - - - + 2 +
@@ -656,7 +792,7 @@ >
- - - - - +
+ 2 +
- Transfer
-
-
- - 1.048576 - - +
+
- ORA - + + 1.048576 + + + ORA + +
- - - - - + 4 +
@@ -778,7 +892,7 @@ >
- - - - - +
+ 2 +
- App Call -
- - - - - + App Call +
+
+
- - - - - +
+ 2 +
- Payment
- 0.732252 - - - - - + + + + +
- - - - - + 4 +
diff --git a/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.563MNGEL2OF4IBA7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA.html b/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.563MNGEL2OF4IBA7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA.html index 0f3d243c8..ae97899df 100644 --- a/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.563MNGEL2OF4IBA7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA.html +++ b/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.563MNGEL2OF4IBA7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA.html @@ -1,7 +1,7 @@
- - + +
- SMO6...ALKU - - +
+ 1 +
+
+
@@ -89,53 +107,40 @@
- - - - -
+
USDt diff --git a/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.JBDSQEI37W5KWPQICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA.html b/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.JBDSQEI37W5KWPQICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA.html index fbbe8816d..1e5ebfb22 100644 --- a/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.JBDSQEI37W5KWPQICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA.html +++ b/src/features/transactions-graph/components/__snapshots__/asset-transfer-graph.JBDSQEI37W5KWPQICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA.html @@ -1,7 +1,7 @@
- - + +
- 6MO6...HSJM - - +
+ 1 +
+
+
- - + +
- OCD5...4IFA - - +
+ 2 +
+
+
@@ -113,47 +149,34 @@
- - - - - + 1 +
- Transfer
-
-
- - 0.3 - - +
- - - - - + 2 +
diff --git a/src/features/transactions-graph/components/__snapshots__/group-graph.%2FoRSr2uMFemQhwQliJO18b64Nl1QIkjA39ZszRCeSCI%3D.html b/src/features/transactions-graph/components/__snapshots__/group-graph.%2FoRSr2uMFemQhwQliJO18b64Nl1QIkjA39ZszRCeSCI%3D.html index af446c975..9eb22f3e3 100644 --- a/src/features/transactions-graph/components/__snapshots__/group-graph.%2FoRSr2uMFemQhwQliJO18b64Nl1QIkjA39ZszRCeSCI%3D.html +++ b/src/features/transactions-graph/components/__snapshots__/group-graph.%2FoRSr2uMFemQhwQliJO18b64Nl1QIkjA39ZszRCeSCI%3D.html @@ -1,7 +1,7 @@
- - + +
- AACC...EN4A - - +
+ 1 +
+
+
+
- - AACC...EN4A - - + + + + + +
+ +
+
+ 1 +
+
+
@@ -66,16 +177,34 @@ - - + +
- 2PIF...RNMM - - +
+ 4 +
+
+
+
- - 2PIF...RNMM - - - + + + + +
+ +
+
+ 4 +
+
+
+
- - FCHE...IYSM - - - + + + + +
+ +
+
+ 6 +
+
+
+
- - EOXL...GCE4 - - + + + + + +
+ +
+
+ 7 +
+
+
@@ -142,16 +450,34 @@ - - + +
- FCHE...IYSM - - +
+ 6 +
+
+
- - + +
- EOXL...GCE4 - - +
+ 7 +
+
+
- - 645869114 - - + +
+
+
- - IWT4...4RVY - - + + + + +
+ +
+
+ 8 +
+
+
@@ -210,7 +604,7 @@
@@ -312,52 +706,39 @@
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -403,7 +773,7 @@ >
- - - - - +
+ 1 +
- Payment
- 2.770045 - - - - - + + + + +
- - - - - + 4 +
@@ -534,7 +882,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -639,7 +963,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.586582 - - +
+
- USDC - + + 0.586582 + + + USDC + +
- - - - - + 4 +
@@ -766,7 +1069,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.586582 - - +
+
- USDC - + + 0.586582 + + + USDC + +
- - - - - + 6 +
@@ -889,7 +1170,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -994,7 +1251,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 146.5 - - +
- - - - - + 6 +
@@ -1121,7 +1357,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 146.5 - - +
- - - - - + 7 +
@@ -1243,7 +1457,7 @@ >
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
@@ -1348,7 +1538,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.00017647 - - +
+
- goETH - + + 0.00017647 + + + goETH + +
- - - - - + 7 +
@@ -1475,7 +1644,7 @@ >
- - - - - +
+ 1 +
- Transfer
-
-
- - 0.00017647 - - +
+
- goETH - + + 0.00017647 + + + goETH + +
- - - - - + 8 +
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
- - - - - +
+ 1 +
- Payment
- 2.78626 - - - - - + + + + +
- - - - - + 8 +
- - - - - +
+ 1 +
- Payment
- 0 - - - - - + + + + +
- - - - - + 1 +
@@ -1971,47 +2052,34 @@
- - - - - +
+ 1 +
- App Call -
- - - - - + App Call +
+
+
diff --git a/src/features/transactions-graph/components/__snapshots__/key-reg-graph.VE767RE4HGQM7GFC7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ.html b/src/features/transactions-graph/components/__snapshots__/key-reg-graph.VE767RE4HGQM7GFC7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ.html index 52ee91171..13ce742bc 100644 --- a/src/features/transactions-graph/components/__snapshots__/key-reg-graph.VE767RE4HGQM7GFC7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ.html +++ b/src/features/transactions-graph/components/__snapshots__/key-reg-graph.VE767RE4HGQM7GFC7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ.html @@ -1,7 +1,7 @@
- - + +
- 65NE...YLNI - - +
+ 1 +
+
+
@@ -89,26 +107,11 @@
- - - - - +
diff --git a/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.FBORGSDC4ULLWHWZUMUFIYQLSDC26HGLTFD7EATQDY37FHCIYBBQ.html b/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.FBORGSDC4ULLWHWZUMUFIYQLSDC26HGLTFD7EATQDY37FHCIYBBQ.html index 98f6b87bd..c329e8096 100644 --- a/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.FBORGSDC4ULLWHWZUMUFIYQLSDC26HGLTFD7EATQDY37FHCIYBBQ.html +++ b/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.FBORGSDC4ULLWHWZUMUFIYQLSDC26HGLTFD7EATQDY37FHCIYBBQ.html @@ -1,7 +1,7 @@
- - + +
- M3IA...OXXM - - +
+ 1 +
+
+
- - + +
- KIZL...U5BQ - - +
+ 2 +
+
+
@@ -113,47 +149,34 @@
- - - - - + 1 +
- Payment
- 236.07 - - - - - + + + + +
- - - - - + 2 +
diff --git a/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.ILDCD5Z64CYSLEZIHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA.html b/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.ILDCD5Z64CYSLEZIHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA.html index ef8ecc20e..bae39dc07 100644 --- a/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.ILDCD5Z64CYSLEZIHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA.html +++ b/src/features/transactions-graph/components/__snapshots__/payment-transaction-graph.ILDCD5Z64CYSLEZIHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA.html @@ -1,7 +1,7 @@
- - + +
- TDV4...QNHM - - +
+ 1 +
+
+
@@ -89,56 +107,43 @@
- - - - -
+
0
)) } +const colorClassMap = { + [TransactionType.Payment]: { border: 'border-payment', text: 'text-payment' }, + [TransactionType.AssetTransfer]: { border: 'border-asset-transfer', text: 'text-asset-transfer' }, + [TransactionType.AppCall]: { border: 'border-application-call', text: 'text-application-call' }, + [TransactionType.AssetConfig]: { border: 'border-asset-config', text: 'text-asset-config' }, + [TransactionType.AssetFreeze]: { border: 'border-asset-freeze', text: 'text-asset-freeze' }, + [TransactionType.KeyReg]: { border: 'border-key-registration', text: 'text-key-registration' }, + [TransactionType.StateProof]: { border: 'border-state-proof', text: 'text-state-proof' }, +} + +function Circle({ className, text }: { className?: string; text?: string | number }) { + return ( +
+ {text} +
+ ) +} const RenderTransactionVector = fixedForwardRef( ( @@ -51,51 +70,63 @@ const RenderTransactionVector = fixedForwardRef( }, ref?: React.LegacyRef ) => { - const color = graphConfig.defaultTransactionColor + const colorClass = colorClassMap[transaction.type] return (
- +
- {vector.direction === 'rightToLeft' && } -
- {vector.direction === 'leftToRight' && } + {vector.direction === 'rightToLeft' && } +
+ {vector.direction === 'leftToRight' && }
-
- {transaction.type === TransactionType.Payment && ( - <> - Payment - - - )} - {transaction.type === TransactionType.AssetTransfer && ( - <> - Transfer - - - )} - {transaction.type === TransactionType.AppCall && <>App Call} - {transaction.type === TransactionType.AssetConfig && <>Asset Config} - {transaction.type === TransactionType.AssetFreeze && <>Asset Freeze} +
+
+ {transaction.type === TransactionType.Payment && ( + <> + Payment + + + )} + {transaction.type === TransactionType.AssetTransfer && ( + <> + Transfer + + + )} + {transaction.type === TransactionType.AppCall && <>App Call} + {transaction.type === TransactionType.AssetConfig && <>Asset Config} + {transaction.type === TransactionType.AssetFreeze && <>Asset Freeze} +
- - +
) } @@ -112,7 +143,7 @@ const RenderTransactionSelfLoop = fixedForwardRef( }, ref?: React.LegacyRef ) => { - const color = graphConfig.defaultTransactionColor + const colorClass = colorClassMap[transaction.type] return (
- +
-
+
{transaction.type === TransactionType.Payment && ( )} @@ -168,7 +198,7 @@ const RenderTransactionPoint = fixedForwardRef( }, ref?: React.LegacyRef ) => { - const color = graphConfig.defaultTransactionColor + const colorClass = colorClassMap[transaction.type] return (
- +
) } @@ -202,16 +231,16 @@ export function Horizontal({ horizontal, verticals }: Props) {
{verticals.map((_, index) => { - if (visualization.type === 'vector' && (index < visualization.from || index > visualization.to)) { + if (visualization.type === 'vector' && (index < visualization.fromVerticalIndex || index > visualization.toVerticalIndex)) { return
} - if (visualization.type === 'point' && index > visualization.from) return
+ if (visualization.type === 'point' && index > visualization.fromVerticalIndex) return
// The `index > transactionRepresentation.from + 1` is here // because a self-loop vector is rendered across 2 grid cells (see RenderTransactionSelfLoop). // Therefore, we skip this cell so that we won't cause overflowing - if (visualization.type === 'selfLoop' && index > visualization.from + 1) return
+ if (visualization.type === 'selfLoop' && index > visualization.fromVerticalIndex + 1) return
- if (index === visualization.from) + if (index === visualization.fromVerticalIndex) return ( diff --git a/src/features/transactions-graph/components/transactions-graph.tsx b/src/features/transactions-graph/components/transactions-graph.tsx index 17466faa9..087656758 100644 --- a/src/features/transactions-graph/components/transactions-graph.tsx +++ b/src/features/transactions-graph/components/transactions-graph.tsx @@ -24,9 +24,9 @@ export function TransactionsGraph({ transactionsGraphData }: Props) { }} >
{/* The first header cell is empty */}
- {verticals.map((swimlane, index) => ( + {verticals.map((vertical, index) => (
- +
))}
@@ -60,7 +60,7 @@ export function TransactionsGraph({ transactionsGraphData }: Props) { .filter((a) => a.type !== 'Placeholder') // Don't need to draw for the empty vertical .map((_, index) => (
-
+
))}
diff --git a/src/features/transactions-graph/components/vertical-title.tsx b/src/features/transactions-graph/components/vertical-title.tsx index cf9bb26f7..0ecbd79a6 100644 --- a/src/features/transactions-graph/components/vertical-title.tsx +++ b/src/features/transactions-graph/components/vertical-title.tsx @@ -3,21 +3,62 @@ import { AccountLink } from '@/features/accounts/components/account-link' import { ApplicationLink } from '@/features/applications/components/application-link' import { AssetIdLink } from '@/features/assets/components/asset-link' import { TransactionGraphVertical } from '@/features/transactions-graph' +import { KeyIcon, LinkIcon } from 'lucide-react' + +export function AccountNumber({ number }: { number: number }) { + return ( +
+ {number} +
+ ) +} export function VerticalTitle({ vertical }: { vertical: TransactionGraphVertical }) { return ( - {vertical.type === 'Account' && } + {vertical.type === 'Account' && ( + }> + + + )} {vertical.type === 'Application' && ( -
- - - {vertical.accounts.map(({ address }, index) => ( - +
+ + + + } + rightComponent={} + > + + + {vertical.rekeyedAccounts.map(({ accountAddress, accountNumber }) => ( + } + rightComponent={} + > + + ))}
)} - {vertical.type === 'Asset' && } + {vertical.type === 'Asset' && } ) } + +type TitleWrapperProps = { + leftComponent?: React.ReactNode + children: React.ReactNode + rightComponent?: React.ReactNode +} +function TitleWrapper({ leftComponent, children, rightComponent }: TitleWrapperProps) { + return ( +
+
{leftComponent}
+
{children}
+
{rightComponent}
+
+ ) +} diff --git a/src/features/transactions-graph/mappers/index.ts b/src/features/transactions-graph/mappers/index.ts index 2202c6e54..4b98b328c 100644 --- a/src/features/transactions-graph/mappers/index.ts +++ b/src/features/transactions-graph/mappers/index.ts @@ -1,10 +1,11 @@ import { + TransactionGraphAccountVertical, TransactionGraphApplicationVertical, - TransactionGraphVertical, - TransactionGraphPointVisualization, TransactionGraphHorizontal, + TransactionGraphPointVisualization, TransactionGraphSelfLoopVisualization, TransactionGraphVectorVisualization, + TransactionGraphVertical, TransactionGraphVisualization, TransactionsGraphData, } from '@/features/transactions-graph' @@ -18,6 +19,7 @@ export const asTransactionsGraphData = (transactions: Transaction[]): Transactio const verticals: TransactionGraphVertical[] = [ ...getVerticalsForTransactions(flattenedTransactions.map((t) => t.transaction)), { + id: -1, type: 'Placeholder', }, // an empty account to make room to show transactions with the same sender and receiver ] @@ -30,20 +32,69 @@ export const asTransactionsGraphData = (transactions: Transaction[]): Transactio } const getVerticalsForTransactions = (transactions: Transaction[] | InnerTransaction[]): TransactionGraphVertical[] => { - const verticals = transactions.flatMap(getVerticalsForTransaction) + const transactionsVerticals = transactions.flatMap(asRawTransactionGraphVerticals) + const mergedVerticals = mergeRawTransactionGraphVerticals(transactionsVerticals) + return indexTransactionsVerticals(mergedVerticals) +} + +const indexTransactionsVerticals = (rawVerticals: TransactionGraphVertical[]): TransactionGraphVertical[] => { + const uniqueAddresses = rawVerticals + .flatMap((vertical) => { + switch (vertical.type) { + case 'Account': + return [vertical.accountAddress] + case 'Asset': + return [] + case 'Application': + return [vertical.linkedAccount.accountAddress, ...vertical.rekeyedAccounts.map((account) => account.accountNumber)] + } + }) + .filter(distinct((x) => x)) + + return rawVerticals.map((vertical, index) => { + switch (vertical.type) { + case 'Account': + return { + ...vertical, + id: index, + accountNumber: uniqueAddresses.indexOf(vertical.accountAddress) + 1, + } + case 'Asset': + return { ...vertical, id: index } + case 'Application': + return { + ...vertical, + id: index, + linkedAccount: { + accountNumber: uniqueAddresses.indexOf(vertical.linkedAccount.accountAddress) + 1, + accountAddress: vertical.linkedAccount.accountAddress, + }, + rekeyedAccounts: vertical.rekeyedAccounts.map((account) => ({ + ...account, + accountNumber: uniqueAddresses.indexOf(account.accountAddress) + 1, + })), + } + default: + throw new Error(`Unknown vertical type "${vertical.type}"`) + } + }) +} + +const mergeRawTransactionGraphVerticals = (verticals: TransactionGraphVertical[]): TransactionGraphVertical[] => { return verticals.reduce((acc, current, _, array) => { if (current.type === 'Account') { if ( acc.some( (c) => - (c.type === 'Account' && c.address === current.address) || + (c.type === 'Account' && c.accountAddress === current.accountAddress) || // An application has its own account too - (c.type === 'Application' && c.address === current.address) + (c.type === 'Application' && c.linkedAccount.accountAddress === current.accountAddress) ) ) { return acc } - const app = array.find((a) => a.type === 'Application' && a.address === current.address) + // An application has its own account too + const app = array.find((a) => a.type === 'Application' && a.linkedAccount.accountAddress === current.accountAddress) if (app) { return [...acc, app] } @@ -51,16 +102,17 @@ const getVerticalsForTransactions = (transactions: Transaction[] | InnerTransact return [...acc, current] } if (current.type === 'Application') { - const index = acc.findIndex((c) => c.type === 'Application' && c.id === current.id) + const index = acc.findIndex((c) => c.type === 'Application' && c.applicationId === current.applicationId) // An application can send transactions on behalf of multiple accounts // We merge all the accounts, so we only show one application on the graph if (index > -1) { const applicationVertical = { + id: -1, type: 'Application' as const, - id: current.id, - address: current.address, - accounts: [...(acc[index] as TransactionGraphApplicationVertical).accounts, ...current.accounts].filter( - distinct((x) => x.address) + applicationId: current.applicationId, + linkedAccount: current.linkedAccount, + rekeyedAccounts: [...(acc[index] as TransactionGraphApplicationVertical).rekeyedAccounts, ...current.rekeyedAccounts].filter( + distinct((x) => x.accountAddress) ), } acc.splice(index, 1, applicationVertical) @@ -70,7 +122,7 @@ const getVerticalsForTransactions = (transactions: Transaction[] | InnerTransact } } if (current.type === 'Asset') { - if (acc.some((c) => c.type === 'Asset' && c.id === current.id)) { + if (acc.some((c) => c.type === 'Asset' && c.assetId === current.assetId)) { return acc } return [...acc, current] @@ -78,43 +130,55 @@ const getVerticalsForTransactions = (transactions: Transaction[] | InnerTransact }, []) } -const getVerticalsForTransaction = (transaction: Transaction | InnerTransaction): TransactionGraphVertical[] => { +const asRawTransactionGraphVerticals = (transaction: Transaction | InnerTransaction): TransactionGraphVertical[] => { const verticals: TransactionGraphVertical[] = [ { + id: -1, + accountNumber: -1, type: 'Account', - address: transaction.sender, + accountAddress: transaction.sender, }, ] if (transaction.type === TransactionType.Payment || transaction.type === TransactionType.AssetTransfer) { verticals.push({ + id: -1, + accountNumber: -1, type: 'Account', - address: transaction.receiver, + accountAddress: transaction.receiver, }) } if (transaction.type === TransactionType.AppCall) { verticals.push({ + id: -1, type: 'Application', - id: transaction.applicationId, - address: getApplicationAddress(transaction.applicationId), - accounts: transaction.innerTransactions + applicationId: transaction.applicationId, + linkedAccount: { + accountNumber: -1, + accountAddress: getApplicationAddress(transaction.applicationId), + }, + rekeyedAccounts: transaction.innerTransactions .flatMap((innerTransaction) => innerTransaction.sender) .filter((address) => address !== getApplicationAddress(transaction.applicationId)) .filter(distinct((x) => x)) .map((address) => ({ - address, + accountNumber: -1, + accountAddress: address, })), }) } if (transaction.type === TransactionType.AssetConfig) { verticals.push({ + id: -1, type: 'Asset', - id: transaction.assetId.toString(), + assetId: transaction.assetId, }) } if (transaction.type === TransactionType.AssetFreeze) { verticals.push({ + id: -1, + accountNumber: -1, type: 'Account', - address: transaction.address.toString(), + accountAddress: transaction.address, }) } return verticals @@ -153,70 +217,142 @@ const getHorizontalsForTransaction = ( return [thisRow] } +type TransactionVisualisationFromTo = { + verticalId: number + accountNumber?: number +} +// Fallback value, it should never happen, just to make TypeScript happy +const fallbackFromTo: TransactionVisualisationFromTo = { + verticalId: -1, + accountNumber: undefined, +} const getTransactionVisualization = ( transaction: Transaction | InnerTransaction, verticals: TransactionGraphVertical[], parent?: TransactionGraphHorizontal ): TransactionGraphVisualization => { - const calculateTo = () => { + const calculateTo = (): TransactionVisualisationFromTo => { if (transaction.type === TransactionType.AssetTransfer || transaction.type === TransactionType.Payment) { - return verticals.findIndex( - (c) => - (c.type === 'Account' && transaction.receiver === c.address) || (c.type === 'Application' && transaction.receiver === c.address) + const accountVertical = verticals.find( + (c): c is TransactionGraphAccountVertical => c.type === 'Account' && transaction.receiver === c.accountAddress ) + if (accountVertical) { + return { + verticalId: accountVertical.id, + accountNumber: accountVertical.accountNumber, + } + } + + const applicationVertical = verticals.find( + (c): c is TransactionGraphApplicationVertical => c.type === 'Application' && transaction.receiver === c.linkedAccount.accountAddress + ) + if (applicationVertical) { + return { + verticalId: applicationVertical.id, + accountNumber: applicationVertical.linkedAccount.accountNumber, + } + } + + return fallbackFromTo } if (transaction.type === TransactionType.AppCall) { - return verticals.findIndex((c) => c.type === 'Application' && transaction.applicationId === c.id) + return { + verticalId: verticals.find((c) => c.type === 'Application' && transaction.applicationId === c.applicationId)?.id ?? -1, + } } if (transaction.type === TransactionType.AssetConfig) { - return verticals.findIndex((c) => c.type === 'Asset' && transaction.assetId.toString() === c.id) + return { + verticalId: verticals.find((c) => c.type === 'Asset' && transaction.assetId === c.assetId)?.id ?? -1, + } } if (transaction.type === TransactionType.AssetFreeze) { - return verticals.findIndex((c) => c.type === 'Account' && transaction.address.toString() === c.address) + const accountVertical = verticals.find( + (c): c is TransactionGraphAccountVertical => c.type === 'Account' && transaction.address === c.accountAddress + ) + if (accountVertical) { + return { + verticalId: accountVertical.id, + accountNumber: accountVertical.accountNumber, + } + } } throw new Error('Unsupported transaction type') } - const calculateFrom = () => { - // If the transaction is child, the parent transaction must be an application call - // The "from" must be the parent application call transaction + + const calculateFrom = (): TransactionVisualisationFromTo => { if (!parent) { - return verticals.findIndex( - (c) => - (c.type === 'Account' && transaction.sender === c.address) || - (c.type === 'Application' && c.accounts.map((a) => a.address).includes(transaction.sender)) + // If the transaction is not a child, it is sent an individual account or an application account + const accountVertical = verticals.find( + (c): c is TransactionGraphAccountVertical => c.type === 'Account' && transaction.sender === c.accountAddress ) + if (accountVertical) { + return { + verticalId: accountVertical.id, + accountNumber: accountVertical.accountNumber, + } + } + + const applicationVertical = verticals.find( + (c): c is TransactionGraphApplicationVertical => c.type === 'Application' && transaction.sender === c.linkedAccount.accountAddress + ) + if (applicationVertical) { + return { + verticalId: applicationVertical.id, + accountNumber: applicationVertical.linkedAccount.accountNumber, + } + } + return fallbackFromTo } + // If the transaction is child, the parent transaction must be an application call + // The "from" must be the parent application call transaction const parentAppCallTransaction = parent.transaction as AppCallTransaction - return verticals.findIndex((c) => c.type === 'Application' && c.id === parentAppCallTransaction.applicationId) + const applicationVertical = verticals.find( + (c): c is TransactionGraphApplicationVertical => + c.type === 'Application' && c.applicationId === parentAppCallTransaction.applicationId + ) + if (applicationVertical) { + return { + verticalId: applicationVertical.id, + accountNumber: + applicationVertical.linkedAccount.accountAddress === transaction.sender + ? applicationVertical.linkedAccount.accountNumber + : applicationVertical.rekeyedAccounts.find((account) => account.accountAddress === transaction.sender)?.accountNumber, + } + } + return fallbackFromTo } const from = calculateFrom() if (transaction.type === TransactionType.KeyReg || transaction.type === TransactionType.StateProof) { return { - from: from, + fromVerticalIndex: from.verticalId, + fromAccountIndex: from.accountNumber, type: 'point', } satisfies TransactionGraphPointVisualization } const to = calculateTo() - if (from === to) { + if (from.verticalId === to.verticalId) { return { - from: from, + fromVerticalIndex: from.verticalId, + fromAccountIndex: from.accountNumber, type: 'selfLoop', } satisfies TransactionGraphSelfLoopVisualization } - const direction = from < to ? 'leftToRight' : 'rightToLeft' + const direction = from.verticalId < to.verticalId ? 'leftToRight' : 'rightToLeft' return { - from: Math.min(from, to), - to: Math.max(from, to), + fromVerticalIndex: Math.min(from.verticalId, to.verticalId), + fromAccountIndex: from.accountNumber, + toVerticalIndex: Math.max(from.verticalId, to.verticalId), + toAccountIndex: to.accountNumber, direction: direction, type: 'vector', } satisfies TransactionGraphVectorVisualization diff --git a/src/features/transactions-graph/models/index.ts b/src/features/transactions-graph/models/index.ts index 1f7e8e4e3..ac9b9c901 100644 --- a/src/features/transactions-graph/models/index.ts +++ b/src/features/transactions-graph/models/index.ts @@ -1,5 +1,7 @@ import { InnerTransaction, Transaction } from '@/features/transactions/models' import { Address } from '@/features/accounts/data/types' +import { ApplicationId } from '@/features/applications/data/types' +import { AssetId } from '@/features/assets/data/types' export type TransactionsGraphData = { horizontals: TransactionGraphHorizontal[] @@ -21,39 +23,48 @@ export type TransactionGraphVisualization = export type TransactionGraphVectorVisualization = { type: 'vector' - from: number - to: number + fromVerticalIndex: number + fromAccountIndex?: number + toAccountIndex?: number + toVerticalIndex: number direction: 'leftToRight' | 'rightToLeft' } export type TransactionGraphSelfLoopVisualization = { type: 'selfLoop' - from: number + fromVerticalIndex: number + fromAccountIndex?: number } export type TransactionGraphPointVisualization = { type: 'point' - from: number + fromVerticalIndex: number + fromAccountIndex?: number } export type TransactionGraphAccountVertical = { + id: number + accountNumber: number type: 'Account' - address: string + accountAddress: Address } export type TransactionGraphApplicationVertical = { - type: 'Application' id: number - address: Address - accounts: { - address: Address + type: 'Application' + applicationId: ApplicationId + linkedAccount: { accountNumber: number; accountAddress: Address } + rekeyedAccounts: { + accountNumber: number + accountAddress: Address }[] } export type TransactionGraphAssetVertical = { + id: number type: 'Asset' - id: string + assetId: AssetId } export type TransactionGraphVertical = | TransactionGraphAccountVertical | TransactionGraphApplicationVertical | TransactionGraphAssetVertical - | { type: 'Placeholder' } + | { id: -1; type: 'Placeholder' }