@@ -3,11 +3,17 @@ import { useVirtualizer } from '@tanstack/react-virtual';
3
3
import type { MirrorJob } from '@/lib/db/schema' ;
4
4
import Fuse from 'fuse.js' ;
5
5
import { Button } from '../ui/button' ;
6
- import { RefreshCw } from 'lucide-react' ;
6
+ import { RefreshCw , Check , X , Loader2 , Import } from 'lucide-react' ;
7
7
import { Card } from '../ui/card' ;
8
8
import { formatDate , getStatusColor } from '@/lib/utils' ;
9
9
import { Skeleton } from '../ui/skeleton' ;
10
10
import type { FilterParams } from '@/types/filter' ;
11
+ import {
12
+ Tooltip ,
13
+ TooltipContent ,
14
+ TooltipProvider ,
15
+ TooltipTrigger ,
16
+ } from '../ui/tooltip' ;
11
17
12
18
type MirrorJobWithKey = MirrorJob & { _rowKey : string } ;
13
19
@@ -73,7 +79,7 @@ export default function ActivityList({
73
79
count : filteredActivities . length ,
74
80
getScrollElement : ( ) => parentRef . current ,
75
81
estimateSize : ( idx ) =>
76
- expandedItems . has ( filteredActivities [ idx ] . _rowKey ) ? 217 : 120 ,
82
+ expandedItems . has ( filteredActivities [ idx ] . _rowKey ) ? 217 : 100 ,
77
83
overscan : 5 ,
78
84
measureElement : ( el ) => el . getBoundingClientRect ( ) . height + 8 ,
79
85
} ) ;
@@ -155,34 +161,121 @@ export default function ActivityList({
155
161
} }
156
162
className = 'border-b px-4 pt-4'
157
163
>
158
- < div className = 'flex items-start gap-4' >
159
- < div className = 'relative mt-2' >
164
+ < div className = 'flex items-start gap-3 sm:gap- 4' >
165
+ < div className = 'relative mt-2 flex-shrink-0 ' >
160
166
< div
161
167
className = { `h-2 w-2 rounded-full ${ getStatusColor (
162
168
activity . status ,
163
169
) } `}
164
170
/>
165
171
</ div >
166
172
167
- < div className = 'flex-1' >
168
- < div className = 'mb-1 flex flex-col sm:flex-row sm:items-center sm:justify-between' >
169
- < p className = 'font-medium' > { activity . message } </ p >
170
- < p className = 'text-sm text-muted-foreground' >
173
+ < div className = 'flex-1 min-w-0' >
174
+ < div className = 'mb-1 flex items-start justify-between gap-2' >
175
+ < div className = 'flex-1 min-w-0' >
176
+ { /* Mobile: Show simplified status-based message */ }
177
+ < div className = 'block sm:hidden' >
178
+ < p className = 'font-medium flex items-center gap-1.5' >
179
+ { activity . status === 'synced' ? (
180
+ < >
181
+ < Check className = 'h-4 w-4 text-teal-600 dark:text-teal-400' />
182
+ < span className = 'text-teal-600 dark:text-teal-400' > Sync successful</ span >
183
+ </ >
184
+ ) : activity . status === 'mirrored' ? (
185
+ < >
186
+ < Check className = 'h-4 w-4 text-emerald-600 dark:text-emerald-400' />
187
+ < span className = 'text-emerald-600 dark:text-emerald-400' > Mirror successful</ span >
188
+ </ >
189
+ ) : activity . status === 'failed' ? (
190
+ < >
191
+ < X className = 'h-4 w-4 text-rose-600 dark:text-rose-400' />
192
+ < span className = 'text-rose-600 dark:text-rose-400' > Operation failed</ span >
193
+ </ >
194
+ ) : activity . status === 'syncing' ? (
195
+ < >
196
+ < Loader2 className = 'h-4 w-4 text-indigo-600 dark:text-indigo-400 animate-spin' />
197
+ < span className = 'text-indigo-600 dark:text-indigo-400' > Syncing in progress</ span >
198
+ </ >
199
+ ) : activity . status === 'mirroring' ? (
200
+ < >
201
+ < Loader2 className = 'h-4 w-4 text-yellow-600 dark:text-yellow-400 animate-spin' />
202
+ < span className = 'text-yellow-600 dark:text-yellow-400' > Mirroring in progress</ span >
203
+ </ >
204
+ ) : activity . status === 'imported' ? (
205
+ < >
206
+ < Import className = 'h-4 w-4 text-blue-600 dark:text-blue-400' />
207
+ < span className = 'text-blue-600 dark:text-blue-400' > Imported</ span >
208
+ </ >
209
+ ) : (
210
+ < span > { activity . message } </ span >
211
+ ) }
212
+ </ p >
213
+ </ div >
214
+ { /* Desktop: Show status with icon and full message in tooltip */ }
215
+ < div className = 'hidden sm:block' >
216
+ < TooltipProvider >
217
+ < Tooltip >
218
+ < TooltipTrigger asChild >
219
+ < p className = 'font-medium flex items-center gap-1.5 cursor-help' >
220
+ { activity . status === 'synced' ? (
221
+ < >
222
+ < Check className = 'h-4 w-4 text-teal-600 dark:text-teal-400 flex-shrink-0' />
223
+ < span className = 'text-teal-600 dark:text-teal-400' > Sync successful</ span >
224
+ </ >
225
+ ) : activity . status === 'mirrored' ? (
226
+ < >
227
+ < Check className = 'h-4 w-4 text-emerald-600 dark:text-emerald-400 flex-shrink-0' />
228
+ < span className = 'text-emerald-600 dark:text-emerald-400' > Mirror successful</ span >
229
+ </ >
230
+ ) : activity . status === 'failed' ? (
231
+ < >
232
+ < X className = 'h-4 w-4 text-rose-600 dark:text-rose-400 flex-shrink-0' />
233
+ < span className = 'text-rose-600 dark:text-rose-400' > Operation failed</ span >
234
+ </ >
235
+ ) : activity . status === 'syncing' ? (
236
+ < >
237
+ < Loader2 className = 'h-4 w-4 text-indigo-600 dark:text-indigo-400 animate-spin flex-shrink-0' />
238
+ < span className = 'text-indigo-600 dark:text-indigo-400' > Syncing in progress</ span >
239
+ </ >
240
+ ) : activity . status === 'mirroring' ? (
241
+ < >
242
+ < Loader2 className = 'h-4 w-4 text-yellow-600 dark:text-yellow-400 animate-spin flex-shrink-0' />
243
+ < span className = 'text-yellow-600 dark:text-yellow-400' > Mirroring in progress</ span >
244
+ </ >
245
+ ) : activity . status === 'imported' ? (
246
+ < >
247
+ < Import className = 'h-4 w-4 text-blue-600 dark:text-blue-400 flex-shrink-0' />
248
+ < span className = 'text-blue-600 dark:text-blue-400' > Imported</ span >
249
+ </ >
250
+ ) : (
251
+ < span className = 'truncate' > { activity . message } </ span >
252
+ ) }
253
+ </ p >
254
+ </ TooltipTrigger >
255
+ < TooltipContent side = "bottom" align = "start" className = "max-w-[400px]" >
256
+ < p className = "whitespace-pre-wrap break-words" > { activity . message } </ p >
257
+ </ TooltipContent >
258
+ </ Tooltip >
259
+ </ TooltipProvider >
260
+ </ div >
261
+ </ div >
262
+ < p className = 'text-sm text-muted-foreground whitespace-nowrap flex-shrink-0 ml-2' >
171
263
{ formatDate ( activity . timestamp ) }
172
264
</ p >
173
265
</ div >
174
266
175
- { activity . repositoryName && (
176
- < p className = 'mb-2 text-sm text-muted-foreground' >
177
- Repository: { activity . repositoryName }
178
- </ p >
179
- ) }
180
-
181
- { activity . organizationName && (
182
- < p className = 'mb-2 text-sm text-muted-foreground' >
183
- Organization: { activity . organizationName }
184
- </ p >
185
- ) }
267
+ < div className = 'flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3' >
268
+ { activity . repositoryName && (
269
+ < p className = 'text-sm text-muted-foreground truncate' >
270
+ < span className = 'font-medium' > Repo:</ span > { activity . repositoryName }
271
+ </ p >
272
+ ) }
273
+ { activity . organizationName && (
274
+ < p className = 'text-sm text-muted-foreground truncate' >
275
+ < span className = 'font-medium' > Org:</ span > { activity . organizationName }
276
+ </ p >
277
+ ) }
278
+ </ div >
186
279
187
280
{ activity . details && (
188
281
< div className = 'mt-2' >
@@ -199,7 +292,7 @@ export default function ActivityList({
199
292
} )
200
293
}
201
294
>
202
- { isExpanded ? 'Hide Details' : 'Show Details' }
295
+ { isExpanded ? 'Hide Details' : activity . status === 'failed' ? 'Show Error Details' : 'Show Details' }
203
296
</ Button >
204
297
205
298
{ isExpanded && (
0 commit comments