11<template >
2- <v-container >
3- <v-row >
4- <v-col cols =" 12" >
5- <h2 class =" text-h6 font-weight-medium" >Batch #{{ batchIndex }}</h2 >
6- <v-divider class =" my-4" ></v-divider >
7- </v-col >
8- </v-row >
9-
10- <v-row v-if =" loading" >
11- <v-col cols =" 12" class =" text-center" >
12- <v-progress-circular indeterminate color =" primary" ></v-progress-circular >
13- </v-col >
14- </v-row >
15-
16- <v-row v-else-if =" batch" >
17- <v-col cols =" 12" md =" 6" >
18- <v-card >
19- <v-card-title >Batch Information</v-card-title >
20- <v-card-text >
21- <v-table density =" compact" >
22- <tbody >
23- <tr >
24- <td class =" font-weight-medium" >Batch Index</td >
25- <td >#{{ batch.batchIndex.toLocaleString() }}</td >
26- </tr >
27- <tr >
28- <td class =" font-weight-medium" >L1 Block</td >
29- <td >
30- <a :href =" l1BlockUrl" target =" _blank" rel =" noopener noreferrer" class =" text-decoration-none" >
31- {{ batch.l1BlockNumber.toLocaleString() }}
32- <v-icon size =" x-small" class =" ml-1" >mdi-open-in-new</v-icon >
33- </a >
34- </td >
35- </tr >
36- <tr >
37- <td class =" font-weight-medium" >L1 Transaction</td >
38- <td >
39- <a :href =" l1TransactionUrl" target =" _blank" rel =" noopener noreferrer" class =" text-decoration-none text-truncate" style =" max-width : 200px ; display : inline-block ; font-family : monospace ;" >
40- {{ batch.l1TransactionHash }}
41- <v-icon size =" x-small" class =" ml-1" >mdi-open-in-new</v-icon >
42- </a >
43- </td >
44- </tr >
45- <tr >
46- <td class =" font-weight-medium" >L2 Block Range</td >
47- <td v-if =" batch.l2BlockStart !== null" >
48- {{ batch.l2BlockStart.toLocaleString() }} - {{ batch.l2BlockEnd.toLocaleString() }}
49- </td >
50- <td v-else class =" text-medium-emphasis" >Pending</td >
51- </tr >
52- <tr >
53- <td class =" font-weight-medium" >Timestamp</td >
54- <td >{{ $dt.shortDate(batch.timestamp) }} ({{ $dt.fromNow(batch.timestamp) }})</td >
55- </tr >
56- <tr >
57- <td class =" font-weight-medium" >Status</td >
58- <td >
59- <v-chip :color =" statusColors[batch.status]" >
60- {{ statusLabels[batch.status] }}
61- </v-chip >
62- </td >
63- </tr >
64- <tr v-if =" batch.blobHash" >
65- <td class =" font-weight-medium" >Blob Hash</td >
66- <td style =" font-family : monospace ;" >
67- <a :href =" blobViewerUrl" target =" _blank" rel =" noopener noreferrer" class =" text-decoration-none" >
68- {{ batch.blobHash }}
69- <v-icon size =" x-small" class =" ml-1" >mdi-open-in-new</v-icon >
70- </a >
71- </td >
72- </tr >
73- <tr v-if =" batch.dataContainer" >
74- <td class =" font-weight-medium" >Data Container</td >
75- <td >
76- <v-chip size =" small" :color =" batch.dataContainer === 'in_blob4844' ? 'primary' : 'secondary'" >
77- {{ dataContainerLabels[batch.dataContainer] }}
78- </v-chip >
79- </td >
80- </tr >
81- <tr v-if =" batch.txCount" >
82- <td class =" font-weight-medium" >Transaction Count</td >
83- <td >{{ batch.txCount.toLocaleString() }}</td >
84- </tr >
85- </tbody >
86- </v-table >
87- </v-card-text >
88- </v-card >
89- </v-col >
90- </v-row >
91-
92- <v-row v-if =" batch && batch.l2BlockStart !== null" >
93- <v-col cols =" 12" >
94- <v-card class =" mt-4" >
95- <v-card-title >Transactions in Batch</v-card-title >
96- <v-card-text >
97- <TransactionsList :opBatchIndex =" parseInt(batchIndex)" :withCount =" true" />
98- </v-card-text >
99- </v-card >
100- </v-col >
101- </v-row >
2+ <v-container fluid >
3+ <h2 class =" text-h6 font-weight-medium" >
4+ Batch <span class =" text-grey-darken-1" >#{{ $route.params.batchIndex }}</span >
5+ </h2 >
6+ <v-divider class =" my-4" ></v-divider >
7+
8+ <template v-if =" loading " >
9+ <v-card >
10+ <v-card-text >
11+ <v-skeleton-loader type =" list-item-three-line" ></v-skeleton-loader >
12+ <v-skeleton-loader type =" list-item-three-line" ></v-skeleton-loader >
13+ <v-skeleton-loader type =" list-item-three-line" ></v-skeleton-loader >
14+ </v-card-text >
15+ </v-card >
16+ </template >
17+ <template v-else-if =" batch && ! loading " >
18+ <BaseChipGroup v-model =" selectedTab" mandatory >
19+ <v-chip label size =" small" value =" overview" >Overview</v-chip >
20+ <v-chip label size =" small" value =" transactions" >Transactions</v-chip >
21+ </BaseChipGroup >
22+
23+ <OpBatchOverview
24+ v-if =" selectedTab === 'overview'"
25+ :batch =" batch"
26+ />
27+
28+ <OpBatchTransactions
29+ v-if =" selectedTab === 'transactions'"
30+ :batchIndex =" Number(batch.batchIndex)"
31+ />
32+ </template >
33+ <template v-else >
34+ <v-card >
35+ <v-card-text >
36+ <p >Couldn't find batch #{{ $route.params.batchIndex }}</p >
37+ </v-card-text >
38+ </v-card >
39+ </template >
10240 </v-container >
10341</template >
10442
10543<script setup>
106- import { ref , computed , onMounted , inject } from ' vue' ;
107- import TransactionsList from ' @/components/TransactionsList.vue' ;
44+ import { ref , onMounted , inject , watch } from ' vue' ;
45+ import { useRouter } from ' vue-router' ;
46+ import BaseChipGroup from ' ./base/BaseChipGroup.vue' ;
47+ import OpBatchOverview from ' ./OpBatchOverview.vue' ;
48+ import OpBatchTransactions from ' ./OpBatchTransactions.vue' ;
10849
10950const props = defineProps ({
11051 batchIndex: {
@@ -114,59 +55,59 @@ const props = defineProps({
11455});
11556
11657const $server = inject (' $server' );
117- const $dt = inject ( ' $dt ' );
58+ const router = useRouter ( );
11859
119- const loading = ref (true );
120- const batch = ref (null );
60+ const selectedTab = ref (' overview' );
12161
122- const blobViewerUrl = computed (() => {
123- if (! batch .value ? .blobHash ) return ' ' ;
124- const explorer = batch .value .parentChainExplorer || ' https://etherscan.io' ;
125- return ` ${ explorer} /blob/${ batch .value .blobHash } ` ;
126- });
62+ // Reactive data
63+ const loading = ref (false );
64+ const batch = ref (null );
65+ const error = ref (null );
12766
128- const l1TransactionUrl = computed (() => {
129- if (! batch .value ? .l1TransactionHash ) return ' ' ;
130- const explorer = batch .value .parentChainExplorer || ' https://etherscan.io' ;
131- return ` ${ explorer} /tx/${ batch .value .l1TransactionHash } ` ;
132- });
67+ // Methods
68+ function loadBatch () {
69+ loading .value = true ;
70+ error .value = null ;
13371
134- const l1BlockUrl = computed (() => {
135- if ( ! batch .value ? . l1BlockNumber ) return ' ' ;
136- const explorer = batch . value . parentChainExplorer || ' https://etherscan.io ' ;
137- return ` ${ explorer } /block/ ${ batch . value . l1BlockNumber } ` ;
138- });
72+ $server . getOpBatchDetail ( props . batchIndex )
73+ . then ( response => batch .value = response . data )
74+ . catch ( console . log )
75+ . finally (() => loading . value = false ) ;
76+ }
13977
140- const statusColors = {
141- pending: ' warning' ,
142- confirmed: ' info' ,
143- finalized: ' success'
78+ const checkUrlHash = () => {
79+ if (window .location .hash === ' #transactions' ) {
80+ selectedTab .value = ' transactions' ;
81+ } else {
82+ selectedTab .value = ' overview' ;
83+ }
14484};
14585
146- const statusLabels = {
147- pending: ' Pending' ,
148- confirmed: ' Confirmed' ,
149- finalized: ' Finalized'
150- };
86+ // Watch with optimization
87+ watch (() => props .batchIndex , (batchIndex ) => {
88+ // Reset state when hash changes
89+ if (batchIndex !== props .batchIndex ) {
90+ batch .value = null ;
91+ }
15192
152- const dataContainerLabels = {
153- in_blob4844: ' EIP-4844 Blob' ,
154- in_calldata: ' Calldata'
155- };
93+ loadBatch (batchIndex);
94+ }, { immediate: true });
15695
157- async function loadBatch () {
158- loading .value = true ;
159- try {
160- const { data } = await $server .getOpBatchDetail (props .batchIndex );
161- batch .value = data;
162- } catch (error) {
163- console .error (' Error loading batch:' , error);
164- } finally {
165- loading .value = false ;
96+ watch (() => selectedTab .value , (newTab ) => {
97+ const currentPath = router .currentRoute .value .fullPath .split (' #' )[0 ];
98+ let hash = ' ' ;
99+
100+ if (newTab === ' transactions' ) {
101+ hash = ' #transactions' ;
166102 }
167- }
103+
104+ router .replace (currentPath + hash);
105+ });
168106
169107onMounted (() => {
170- loadBatch ();
108+ checkUrlHash ();
109+ router .afterEach (() => {
110+ checkUrlHash ();
111+ });
171112});
172113 </script >
0 commit comments