@@ -17,7 +17,7 @@ import {
17
17
import { Input } from '@/components/ui/input'
18
18
import { Table , TableBody , TableCell , TableHead , TableHeader , TableRow } from '@/components/ui/table'
19
19
20
- import { createSuiteAction } from './actions'
20
+ import { createSuiteAction , importSuiteAction } from './actions'
21
21
import { loader , type TSuite } from './loader'
22
22
23
23
export const dynamic = 'force-dynamic'
@@ -36,14 +36,21 @@ export default async function Page() {
36
36
37
37
{ /* Suites List */ }
38
38
39
- < SectionHeader title = "Test Suites" actions = { [ < CreateSuiteDialog key = "create-suite-dialog" /> ] } />
39
+ < SectionHeader
40
+ title = "Test Suites"
41
+ actions = { [
42
+ //
43
+ < CreateSuiteDialog key = "create-suite-dialog" /> ,
44
+ < ImportSuiteDialog key = "import-suite-dialog" /> ,
45
+ ] }
46
+ />
40
47
41
48
< Table >
42
49
< TableHeader >
43
50
< TableRow >
44
51
< TableHead > Name</ TableHead >
45
52
< TableHead > Tests</ TableHead >
46
- < TableHead > Created</ TableHead >
53
+ < TableHead > Created At </ TableHead >
47
54
< TableHead > Cron</ TableHead >
48
55
< TableHead > Last Run</ TableHead >
49
56
< TableHead > { /* Actions */ } </ TableHead >
@@ -63,7 +70,7 @@ export default async function Page() {
63
70
< TableCell > { suite . tests . length } tests</ TableCell >
64
71
< TableCell > { formatDate ( suite . createdAt ) } </ TableCell >
65
72
< TableCell > { getCronLabel ( suite . cronCadence ) } </ TableCell >
66
- < TableCell > { suite . lastCronRunAt ? formatDate ( suite . lastCronRunAt ) : 'Never' } </ TableCell >
73
+ < TableCell > { getLastRunLabel ( suite ) } </ TableCell >
67
74
< TableCell className = "text-right" >
68
75
< Link href = { `/suite/${ suite . id } ` } > View</ Link >
69
76
</ TableCell >
@@ -117,3 +124,43 @@ function getCronLabel(cronCadence: TSuite['cronCadence']) {
117
124
return 'Never'
118
125
}
119
126
}
127
+
128
+ function ImportSuiteDialog ( ) {
129
+ return (
130
+ < Dialog >
131
+ < DialogTrigger asChild >
132
+ < Button variant = "outline" className = "ml-auto" >
133
+ < Plus className = "w-4 h-4" />
134
+ Import Suite
135
+ </ Button >
136
+ </ DialogTrigger >
137
+ < DialogContent >
138
+ < DialogHeader >
139
+ < DialogTitle > Import a test suite</ DialogTitle >
140
+ < DialogDescription > Import a test suite from a JSON file.</ DialogDescription >
141
+
142
+ < form action = { importSuiteAction } className = "space-y-4" >
143
+ < div >
144
+ < label htmlFor = "file" className = "block text-sm font-medium text-gray-700 mb-1" >
145
+ Suite File
146
+ </ label >
147
+ < Input type = "file" id = "file" name = "file" accept = ".json" required />
148
+ </ div >
149
+
150
+ < div className = "flex justify-end gap-2" >
151
+ < Button type = "submit" > Import</ Button >
152
+ </ div >
153
+ </ form >
154
+ </ DialogHeader >
155
+ </ DialogContent >
156
+ </ Dialog >
157
+ )
158
+ }
159
+
160
+ function getLastRunLabel ( suite : { runs : { createdAt : Date } [ ] } ) {
161
+ if ( suite . runs . length === 0 ) {
162
+ return 'Never'
163
+ }
164
+
165
+ return formatDate ( suite . runs [ 0 ] . createdAt )
166
+ }
0 commit comments