@@ -5,8 +5,13 @@ import {
55} from 'antd' ;
66import { ArrowLeftOutlined } from '@ant-design/icons' ;
77import dayjs from 'dayjs' ;
8+ import relativeTime from 'dayjs/plugin/relativeTime' ;
9+ import 'dayjs/locale/zh-cn' ;
10+ import { useLocale } from '../../hooks/useLocale' ;
811import { getPITRStatus } from '../../api/pitr' ;
912
13+ dayjs . extend ( relativeTime ) ;
14+
1015const { Title, Text } = Typography ;
1116
1217const stateColors : Record < string , 'processing' | 'success' | 'error' | 'default' > = {
@@ -20,9 +25,19 @@ const stateColors: Record<string, 'processing' | 'success' | 'error' | 'default'
2025 cancelled : 'default' ,
2126} ;
2227
28+ function fmtTime ( ts : string | undefined | null ) : string {
29+ if ( ! ts ) return '-' ;
30+ const d = dayjs ( ts ) ;
31+ if ( ! d . isValid ( ) || d . year ( ) < 2000 ) return '-' ;
32+ const daysDiff = dayjs ( ) . diff ( d , 'day' ) ;
33+ if ( daysDiff < 7 ) return d . locale ( 'zh-cn' ) . fromNow ( ) ;
34+ return d . format ( 'YYYY年M月D日 HH:mm' ) ;
35+ }
36+
2337export default function PITRDetailPage ( ) {
2438 const { id } = useParams < { id : string } > ( ) ;
2539 const navigate = useNavigate ( ) ;
40+ const { t } = useLocale ( ) ;
2641
2742 const { data : operation , isLoading, error } = useQuery ( {
2843 queryKey : [ 'pitr-status' , id ] ,
@@ -38,18 +53,18 @@ export default function PITRDetailPage() {
3853 } ) ;
3954
4055 if ( isLoading ) {
41- return < div style = { { textAlign : 'center' , padding : 48 } } > < Spin size = "large" tip = "Loading operation..." /> </ div > ;
56+ return < div style = { { textAlign : 'center' , padding : 48 } } > < Spin size = "large" tip = { t ( 'pitr.loadingPreview' ) } /> </ div > ;
4257 }
4358
4459 if ( error || ! operation ) {
4560 return (
4661 < Card >
4762 < div style = { { textAlign : 'center' , padding : 48 } } >
48- < Typography . Text type = "danger" > Failed to load operation details. </ Typography . Text >
63+ < Typography . Text type = "danger" > { t ( 'common.error' ) } </ Typography . Text >
4964 < br /> < br />
5065 < Space >
51- < Button onClick = { ( ) => navigate ( - 1 ) } > Go Back </ Button >
52- < Button onClick = { ( ) => navigate ( '/audit' ) } > Audit Log </ Button >
66+ < Button onClick = { ( ) => navigate ( - 1 ) } > { t ( 'pitr.stepBack' ) } </ Button >
67+ < Button onClick = { ( ) => navigate ( '/audit' ) } > { t ( 'audit.title' ) } </ Button >
5368 </ Space >
5469 </ div >
5570 </ Card >
@@ -69,43 +84,43 @@ export default function PITRDetailPage() {
6984 < Card >
7085 < div style = { { display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' , marginBottom : 24 } } >
7186 < div >
72- < Title level = { 4 } style = { { margin : 0 } } > PITR Operation Detail </ Title >
87+ < Title level = { 4 } style = { { margin : 0 } } > { t ( 'pitr.detail' ) } </ Title >
7388 < Text type = "secondary" > ID: { operation . id } </ Text >
7489 </ div >
7590 < Badge status = { stateColor } text = { operation . state } />
7691 </ div >
7792
7893 < Descriptions bordered column = { 1 } >
79- < Descriptions . Item label = "Operation ID" > { operation . id } </ Descriptions . Item >
80- < Descriptions . Item label = "Agent ID" > { operation . agentId } </ Descriptions . Item >
81- < Descriptions . Item label = "Target Table" > { operation . targetTable } </ Descriptions . Item >
82- < Descriptions . Item label = "Recovery Time" >
94+ < Descriptions . Item label = { t ( 'audit.operationId' ) } > { operation . id } </ Descriptions . Item >
95+ < Descriptions . Item label = { t ( 'audit.agentId' ) } > { operation . agentId } </ Descriptions . Item >
96+ < Descriptions . Item label = { t ( 'pitr.targetTable' ) } > { operation . targetTable } </ Descriptions . Item >
97+ < Descriptions . Item label = { t ( 'pitr.recoveryTime' ) } >
8398 { dayjs ( operation . recoveryTime ) . format ( 'YYYY-MM-DD HH:mm:ss' ) }
8499 </ Descriptions . Item >
85- < Descriptions . Item label = "Mode" > { operation . mode } </ Descriptions . Item >
86- < Descriptions . Item label = "State" >
100+ < Descriptions . Item label = { t ( 'pitr.mode' ) } > { operation . mode } </ Descriptions . Item >
101+ < Descriptions . Item label = { t ( 'pitr.state' ) } >
87102 < Tag color = { stateColor } > { operation . state } </ Tag >
88103 </ Descriptions . Item >
89- < Descriptions . Item label = "Created At" >
104+ < Descriptions . Item label = { t ( 'pitr.createdAt' ) } >
90105 { dayjs ( operation . createdAt ) . format ( 'YYYY-MM-DD HH:mm:ss' ) }
91106 </ Descriptions . Item >
92- < Descriptions . Item label = "Updated At " >
107+ < Descriptions . Item label = "更新时间 " >
93108 { dayjs ( operation . updatedAt ) . format ( 'YYYY-MM-DD HH:mm:ss' ) }
94109 </ Descriptions . Item >
95110 </ Descriptions >
96111
97112 { operation . preflightResult && (
98- < Card size = "small" title = "Preflight Results" style = { { marginTop : 16 } } >
113+ < Card size = "small" title = { t ( 'pitr.preflightCompleted' ) } style = { { marginTop : 16 } } >
99114 < Descriptions bordered column = { 1 } size = "small" >
100- < Descriptions . Item label = "Binlog Files" >
115+ < Descriptions . Item label = { t ( 'pitr.binlogFiles' ) } >
101116 { operation . preflightResult . binlogFiles ?. join ( ', ' ) || '-' }
102117 </ Descriptions . Item >
103- < Descriptions . Item label = "Earliest Time" >
118+ < Descriptions . Item label = { t ( 'pitr.earliestTime' ) } >
104119 { operation . preflightResult . earliestTime
105120 ? dayjs ( operation . preflightResult . earliestTime ) . format ( 'YYYY-MM-DD HH:mm:ss' )
106121 : '-' }
107122 </ Descriptions . Item >
108- < Descriptions . Item label = "Estimated Size" >
123+ < Descriptions . Item label = { t ( 'pitr.estimatedSize' ) } >
109124 { operation . preflightResult . estimatedSize
110125 ? `${ ( operation . preflightResult . estimatedSize / 1024 / 1024 ) . toFixed ( 1 ) } MB`
111126 : '-' }
@@ -115,16 +130,16 @@ export default function PITRDetailPage() {
115130 ) }
116131
117132 { operation . parseResult && (
118- < Card size = "small" title = "Parse Results" style = { { marginTop : 16 } } >
133+ < Card size = "small" title = { t ( 'pitr.estimatedChanges' ) } style = { { marginTop : 16 } } >
119134 < Descriptions bordered column = { 1 } size = "small" >
120- < Descriptions . Item label = "Rows Affected" >
135+ < Descriptions . Item label = { t ( 'pitr.rowsAffected' ) } >
121136 { operation . parseResult . rowsAffected ?. toLocaleString ( ) || '0' }
122137 </ Descriptions . Item >
123138 </ Descriptions >
124139
125140 { operation . parseResult . reverseSql && operation . parseResult . reverseSql . length > 0 ? (
126141 < div style = { { marginTop : 16 } } >
127- < Text strong style = { { marginBottom : 8 , display : 'block' } } > Reverse SQL </ Text >
142+ < Text strong style = { { marginBottom : 8 , display : 'block' } } > { t ( 'pitr.sampleSql' ) } </ Text >
128143 < Table
129144 dataSource = { operation . parseResult . reverseSql }
130145 rowKey = "sequence"
@@ -138,7 +153,7 @@ export default function PITRDetailPage() {
138153 width : 40 ,
139154 } ,
140155 {
141- title : 'Type' ,
156+ title : { t ( 'pitr.mode' ) } ,
142157 dataIndex : 'sqlType' ,
143158 key : 'sqlType' ,
144159 width : 80 ,
@@ -148,13 +163,13 @@ export default function PITRDetailPage() {
148163 } ,
149164 } ,
150165 {
151- title : 'Table' ,
166+ title : { t ( 'pitr.targetTable' ) } ,
152167 dataIndex : 'tableName' ,
153168 key : 'tableName' ,
154169 width : 120 ,
155170 } ,
156171 {
157- title : 'Reverse SQL' ,
172+ title : { t ( 'pitr.sampleSql' ) } ,
158173 dataIndex : 'reverseSql' ,
159174 key : 'reverseSql' ,
160175 ellipsis : true ,
@@ -165,7 +180,7 @@ export default function PITRDetailPage() {
165180 ) ,
166181 } ,
167182 {
168- title : 'Rows' ,
183+ title : { t ( 'pitr.rowsAffected' ) } ,
169184 dataIndex : 'rowsAffected' ,
170185 key : 'rowsAffected' ,
171186 width : 60 ,
@@ -175,7 +190,7 @@ export default function PITRDetailPage() {
175190 </ div >
176191 ) : operation . parseResult . sqlSample ? (
177192 < div style = { { marginTop : 16 } } >
178- < Text strong style = { { marginBottom : 8 , display : 'block' } } > SQL Sample </ Text >
193+ < Text strong style = { { marginBottom : 8 , display : 'block' } } > { t ( 'pitr.sampleSql' ) } </ Text >
179194 < pre style = { {
180195 background : '#f5f5f5' ,
181196 padding : 8 ,
@@ -190,22 +205,22 @@ export default function PITRDetailPage() {
190205 </ div >
191206 ) : (
192207 < div style = { { marginTop : 16 } } >
193- < Text type = "secondary" > No reverse SQL available </ Text >
208+ < Text type = "secondary" > { t ( 'common.noData' ) } </ Text >
194209 </ div >
195210 ) }
196211 </ Card >
197212 ) }
198213
199214 { operation . execResult && (
200- < Card size = "small" title = "Execution Results" style = { { marginTop : 16 } } >
215+ < Card size = "small" title = { t ( 'pitr.executingRecovery' ) } style = { { marginTop : 16 } } >
201216 < Descriptions bordered column = { 1 } size = "small" >
202- < Descriptions . Item label = "Rows Restored" >
217+ < Descriptions . Item label = { t ( 'pitr.rowsRestored' ) } >
203218 { operation . execResult . rowsRestored ?. toLocaleString ( ) || '0' }
204219 </ Descriptions . Item >
205- < Descriptions . Item label = "Duration" >
220+ < Descriptions . Item label = { t ( 'pitr.duration' ) } >
206221 { operation . execResult . duration || '-' }
207222 </ Descriptions . Item >
208- < Descriptions . Item label = "Executed At" >
223+ < Descriptions . Item label = { t ( 'pitr.createdAt' ) } >
209224 { operation . execResult . executedAt
210225 ? dayjs ( operation . execResult . executedAt ) . format ( 'YYYY-MM-DD HH:mm:ss' )
211226 : '-' }
@@ -215,21 +230,21 @@ export default function PITRDetailPage() {
215230 ) }
216231
217232 { operation . error && (
218- < Card size = "small" title = "Error" style = { { marginTop : 16 } } >
233+ < Card size = "small" title = { t ( 'common.error' ) } style = { { marginTop : 16 } } >
219234 < Text type = "danger" > { operation . error } </ Text >
220235 </ Card >
221236 ) }
222237
223238 { operation . progress && (
224- < Card size = "small" title = "Progress" style = { { marginTop : 16 } } >
239+ < Card size = "small" title = { t ( 'pitr.batchProgress' ) } style = { { marginTop : 16 } } >
225240 < Descriptions bordered column = { 1 } size = "small" >
226- < Descriptions . Item label = "Batches" >
241+ < Descriptions . Item label = { t ( 'pitr.batches' ) } >
227242 { operation . progress . batchesComplete } / { operation . progress . batchesTotal }
228243 </ Descriptions . Item >
229- < Descriptions . Item label = "Rows Restored" >
244+ < Descriptions . Item label = { t ( 'pitr.rowsRestored' ) } >
230245 { operation . progress . rowsRestored ?. toLocaleString ( ) || '0' }
231246 </ Descriptions . Item >
232- < Descriptions . Item label = "Estimated Remaining" >
247+ < Descriptions . Item label = { t ( 'pitr.estRemaining' ) } >
233248 { operation . progress . estimatedRemaining || '-' }
234249 </ Descriptions . Item >
235250 </ Descriptions >
0 commit comments