@@ -28,7 +28,7 @@ import {
2828 PaginationNext ,
2929 PaginationPrevious ,
3030} from "@/components/ui/pagination" ;
31- import { Loader2 , RefreshCw , ArrowLeft } from "lucide-react" ;
31+ import { Loader2 , RefreshCw , ArrowLeft , ChevronDown , ChevronUp } from "lucide-react" ;
3232import { getTasks , getSessionConfigs } from "@/api/models/space" ;
3333import { Task } from "@/types" ;
3434import ReactCodeMirror from "@uiw/react-codemirror" ;
@@ -54,6 +54,7 @@ export default function TasksPage() {
5454
5555 const [ detailDialogOpen , setDetailDialogOpen ] = useState ( false ) ;
5656 const [ selectedTask , setSelectedTask ] = useState < Task | null > ( null ) ;
57+ const [ isDataExpanded , setIsDataExpanded ] = useState ( false ) ;
5758
5859 const totalPages = Math . ceil ( allTasks . length / PAGE_SIZE ) ;
5960 const paginatedTasks = allTasks . slice (
@@ -351,19 +352,29 @@ export default function TasksPage() {
351352 </ div >
352353
353354 { /* Task Detail Dialog */ }
354- < Dialog open = { detailDialogOpen } onOpenChange = { setDetailDialogOpen } >
355+ < Dialog
356+ open = { detailDialogOpen }
357+ onOpenChange = { ( open ) => {
358+ setDetailDialogOpen ( open ) ;
359+ if ( ! open ) {
360+ setIsDataExpanded ( false ) ;
361+ }
362+ } }
363+ >
355364 < DialogContent className = "max-w-4xl max-h-[90vh] flex flex-col" >
356- < DialogHeader >
357- < DialogTitle > { t ( "taskDetail" ) || "Task Detail" } </ DialogTitle >
365+ < DialogHeader className = "flex-shrink-0" >
366+ < DialogTitle >
367+ { t ( "taskDetail" ) || "Task Detail" }
368+ </ DialogTitle >
358369 </ DialogHeader >
359370 { selectedTask && (
360- < div className = "rounded-md border bg-card p-6 overflow-y-auto flex-1 " >
371+ < div className = "flex-1 overflow-y-auto min-h-0 " >
361372 { /* Task header */ }
362- < div className = "border-b pb-4" >
363- < h3 className = "text-xl font-semibold mb -2 font-mono " >
364- { selectedTask . id }
365- </ h3 >
366- < div className = "flex items-center gap-2" >
373+ < div className = "border-b pb-4 space-y-3 mb-4 " >
374+ < div className = "flex items-center gap -2 flex-wrap " >
375+ < span className = "inline-flex items-center justify-center rounded-md bg-secondary border border-border px-2 py-1 text-xs font-medium" >
376+ { t ( "order" ) || "Order" } : { selectedTask . order }
377+ </ span >
367378 < span
368379 className = { `inline-flex items-center rounded-md border px-2 py-1 text-xs font-medium ${ getStatusColor (
369380 selectedTask . status
@@ -384,75 +395,129 @@ export default function TasksPage() {
384395 </ div >
385396 </ div >
386397
387- { /* Task details in grid */ }
388- < div className = "grid grid-cols-2 gap-4 mt-6" >
389- < div >
390- < p className = "text-sm font-medium text-muted-foreground mb-1" >
391- { t ( "sessionId" ) || "Session ID" }
392- </ p >
393- < p className = "text-sm bg-muted px-2 py-1 rounded font-mono" >
394- { selectedTask . session_id }
395- </ p >
396- </ div >
397- < div >
398- < p className = "text-sm font-medium text-muted-foreground mb-1" >
399- { t ( "projectId" ) || "Project ID" }
400- </ p >
401- < p className = "text-sm bg-muted px-2 py-1 rounded font-mono" >
402- { selectedTask . project_id }
403- </ p >
404- </ div >
405- < div >
406- < p className = "text-sm font-medium text-muted-foreground mb-1" >
407- { t ( "order" ) || "Order" }
408- </ p >
409- < p className = "text-sm bg-muted px-2 py-1 rounded" >
410- { selectedTask . order }
411- </ p >
412- </ div >
413- < div >
414- < p className = "text-sm font-medium text-muted-foreground mb-1" >
415- { t ( "createdAt" ) }
416- </ p >
417- < p className = "text-sm bg-muted px-2 py-1 rounded" >
418- { new Date ( selectedTask . created_at ) . toLocaleString ( ) }
419- </ p >
420- </ div >
421- < div >
422- < p className = "text-sm font-medium text-muted-foreground mb-1" >
423- { t ( "updatedAt" ) }
424- </ p >
425- < p className = "text-sm bg-muted px-2 py-1 rounded" >
426- { new Date ( selectedTask . updated_at ) . toLocaleString ( ) }
427- </ p >
398+ { /* Task details - reordered */ }
399+ < div className = "space-y-4" >
400+ { /* 1. Task Description */ }
401+ { selectedTask . data ?. task_description != null && (
402+ < div >
403+ < p className = "text-sm font-medium text-muted-foreground mb-1" >
404+ Task Description
405+ </ p >
406+ < p className = "text-sm bg-muted px-2 py-1 rounded whitespace-pre-wrap" >
407+ { typeof selectedTask . data . task_description === "string"
408+ ? selectedTask . data . task_description
409+ : JSON . stringify ( selectedTask . data . task_description , null , 2 ) }
410+ </ p >
411+ </ div >
412+ ) }
413+
414+ { /* 2. Progresses */ }
415+ { selectedTask . data ?. progresses != null &&
416+ Array . isArray ( selectedTask . data . progresses ) &&
417+ selectedTask . data . progresses . length > 0 && (
418+ < div >
419+ < p className = "text-sm font-medium text-muted-foreground mb-2" >
420+ Progresses
421+ </ p >
422+ < div className = "space-y-1.5" >
423+ { selectedTask . data . progresses . map (
424+ ( progress : unknown , index : number ) => (
425+ < div
426+ key = { index }
427+ className = "text-sm bg-muted px-3 py-1.5 rounded border-l-2 border-primary/30"
428+ >
429+ { typeof progress === "string" ? progress : String ( progress ) }
430+ </ div >
431+ )
432+ ) }
433+ </ div >
434+ </ div >
435+ ) }
436+
437+ { /* 3. User Preferences */ }
438+ { selectedTask . data ?. user_preferences != null &&
439+ Array . isArray ( selectedTask . data . user_preferences ) &&
440+ selectedTask . data . user_preferences . length > 0 && (
441+ < div >
442+ < p className = "text-sm font-medium text-muted-foreground mb-2" >
443+ User Preferences
444+ </ p >
445+ < div className = "space-y-1" >
446+ { selectedTask . data . user_preferences . map (
447+ ( pref : unknown , index : number ) => (
448+ < div
449+ key = { index }
450+ className = "text-sm bg-muted px-3 py-2 rounded border-l-2 border-primary/20"
451+ >
452+ { typeof pref === "string" ? pref : String ( pref ) }
453+ </ div >
454+ )
455+ ) }
456+ </ div >
457+ </ div >
458+ ) }
459+
460+ { /* 4. Created At & Updated At */ }
461+ < div className = "grid grid-cols-2 gap-4" >
462+ < div >
463+ < p className = "text-sm font-medium text-muted-foreground mb-1" >
464+ { t ( "createdAt" ) }
465+ </ p >
466+ < p className = "text-sm bg-muted px-2 py-1 rounded" >
467+ { new Date ( selectedTask . created_at ) . toLocaleString ( ) }
468+ </ p >
469+ </ div >
470+ < div >
471+ < p className = "text-sm font-medium text-muted-foreground mb-1" >
472+ { t ( "updatedAt" ) }
473+ </ p >
474+ < p className = "text-sm bg-muted px-2 py-1 rounded" >
475+ { new Date ( selectedTask . updated_at ) . toLocaleString ( ) }
476+ </ p >
477+ </ div >
428478 </ div >
429- </ div >
430479
431- { /* Task data */ }
432- < div className = "border-t pt-6 mt-6" >
433- < p className = "text-sm font-medium text-muted-foreground mb-3" >
434- { t ( "taskData" ) || "Task Data" }
435- </ p >
436- < div className = "border rounded-md overflow-hidden" >
437- < ReactCodeMirror
438- value = { JSON . stringify ( selectedTask . data , null , 2 ) }
439- height = "400px"
440- theme = { resolvedTheme === "dark" ? okaidia : "light" }
441- extensions = { [ json ( ) , EditorView . lineWrapping ] }
442- editable = { false }
443- basicSetup = { {
444- lineNumbers : true ,
445- foldGutter : true ,
446- } }
447- />
480+ { /* 5. Task data - Collapsible */ }
481+ < div className = "border-t pt-4 mt-4" >
482+ < button
483+ onClick = { ( ) => setIsDataExpanded ( ! isDataExpanded ) }
484+ className = "flex items-center gap-2 w-full text-left mb-3 hover:opacity-80 transition-opacity"
485+ >
486+ < p className = "text-sm font-medium text-muted-foreground" >
487+ { t ( "taskData" ) || "Task Data" }
488+ </ p >
489+ { isDataExpanded ? (
490+ < ChevronUp className = "h-4 w-4 text-muted-foreground" />
491+ ) : (
492+ < ChevronDown className = "h-4 w-4 text-muted-foreground" />
493+ ) }
494+ </ button >
495+ { isDataExpanded && (
496+ < div className = "border rounded-md overflow-hidden" >
497+ < ReactCodeMirror
498+ value = { JSON . stringify ( selectedTask . data , null , 2 ) }
499+ height = "400px"
500+ theme = { resolvedTheme === "dark" ? okaidia : "light" }
501+ extensions = { [ json ( ) , EditorView . lineWrapping ] }
502+ editable = { false }
503+ basicSetup = { {
504+ lineNumbers : true ,
505+ foldGutter : true ,
506+ } }
507+ />
508+ </ div >
509+ ) }
448510 </ div >
449511 </ div >
450512 </ div >
451513 ) }
452- < DialogFooter >
514+ < DialogFooter className = "flex-shrink-0" >
453515 < Button
454516 variant = "outline"
455- onClick = { ( ) => setDetailDialogOpen ( false ) }
517+ onClick = { ( ) => {
518+ setDetailDialogOpen ( false ) ;
519+ setIsDataExpanded ( false ) ;
520+ } }
456521 >
457522 { t ( "close" ) }
458523 </ Button >
0 commit comments