@@ -11,108 +11,258 @@ import {
1111 DropdownMenuTrigger ,
1212} from "@/components/ui/dropdown-menu"
1313import { ColumnDef } from "@tanstack/react-table"
14- import { ArrowUpDown , Filter } from 'lucide-react'
14+ import { ArrowUpDown , Edit , Filter , Trash2 } from 'lucide-react'
1515import { JobStatus } from "./jobs-management"
1616
17- export const columns : ColumnDef < JobStatus > [ ] = [
18- {
19- accessorKey : "name" ,
20- header : ( { column } ) => (
21- < Button
22- variant = "ghost"
23- onClick = { ( ) => column . toggleSorting ( column . getIsSorted ( ) === "asc" ) }
24- >
25- Name
26- < ArrowUpDown className = "ml-2 h-4 w-4" />
27- </ Button >
28- ) ,
29- } ,
30- {
31- accessorKey : "namespace" ,
32- header : "Namespace" ,
33- } ,
34- {
35- accessorKey : "queue" ,
36- header : "Queue" ,
37- cell : ( { row } ) => {
38- const queue = row . getValue ( "queue" ) as string ;
39- return (
40- < Badge
41- className = "bg-blue-100 text-blue-800 hover:bg-blue-100/60 "
17+ interface CreateColumnsOptions {
18+ availableNamespaces : string [ ]
19+ availableQueues : string [ ]
20+ availableStatuses : string [ ]
21+ onEdit ?: ( job : JobStatus ) => void
22+ onDelete ?: ( job : JobStatus ) => void
23+ }
24+
25+ export const createColumns = ( {
26+ availableNamespaces,
27+ availableQueues,
28+ availableStatuses,
29+ onEdit,
30+ onDelete
31+ } : CreateColumnsOptions ) : ColumnDef < JobStatus > [ ] => [
32+ {
33+ accessorKey : "name" ,
34+ header : ( { column } ) => (
35+ < Button
36+ variant = "ghost"
37+ onClick = { ( ) => column . toggleSorting ( column . getIsSorted ( ) === "asc" ) }
4238 >
43- { queue . charAt ( 0 ) . toUpperCase ( ) + queue . slice ( 1 ) }
44- </ Badge >
45- ) ;
39+ Name
40+ < ArrowUpDown className = "ml-2 h-4 w-4" />
41+ </ Button >
42+ ) ,
4643 } ,
47- } ,
48- {
49- accessorKey : "createdAt" ,
50- header : ( { column } ) => (
51- < Button
52- variant = "ghost"
53- onClick = { ( ) => column . toggleSorting ( column . getIsSorted ( ) === "asc" ) }
54- >
55- Creation Time
56- < ArrowUpDown className = "ml-2 h-4 w-4" />
57- </ Button >
58- ) ,
59- cell : ( { row } ) => {
60- const createdAt = row . getValue ( "createdAt" ) as Date
61- return new Intl . DateTimeFormat ( "en-US" , {
62- dateStyle : "medium" ,
63- timeStyle : "short" ,
64- } ) . format ( createdAt )
44+ {
45+ accessorKey : "namespace" ,
46+ header : ( { column } ) => (
47+ < div className = "flex items-center" >
48+ Namespace
49+ < DropdownMenu >
50+ < DropdownMenuTrigger asChild >
51+ < Button variant = "ghost" size = "sm" className = "ml-2 h-8 p-1" >
52+ < Filter className = "h-4 w-4" />
53+ </ Button >
54+ </ DropdownMenuTrigger >
55+ < DropdownMenuContent align = "start" >
56+ < DropdownMenuLabel > Filter by Namespace</ DropdownMenuLabel >
57+ < DropdownMenuSeparator />
58+ < DropdownMenuCheckboxItem
59+ checked = { ! column . getFilterValue ( ) }
60+ onCheckedChange = { ( checked ) => {
61+ if ( checked ) column . setFilterValue ( undefined )
62+ } }
63+ >
64+ All
65+ </ DropdownMenuCheckboxItem >
66+ { availableNamespaces . map ( ( namespace ) => (
67+ < DropdownMenuCheckboxItem
68+ key = { namespace }
69+ checked = { column . getFilterValue ( ) === namespace }
70+ onCheckedChange = { ( checked ) => {
71+ column . setFilterValue ( checked ? namespace : undefined )
72+ } }
73+ >
74+ { namespace }
75+ </ DropdownMenuCheckboxItem >
76+ ) ) }
77+ </ DropdownMenuContent >
78+ </ DropdownMenu >
79+ </ div >
80+ ) ,
81+ cell : ( { row } ) => {
82+ const namespace = row . getValue ( "namespace" ) as string ;
83+ return (
84+ < Badge
85+ className = "bg-purple-100 text-purple-800 hover:bg-purple-100/60"
86+ >
87+ { namespace }
88+ </ Badge >
89+ ) ;
90+ } ,
91+ filterFn : ( row , columnId , filterValue ) => {
92+ return row . getValue ( columnId ) === filterValue
93+ } ,
6594 } ,
66- } ,
67- {
68- accessorKey : "status" ,
69- header : ( { column } ) => (
70- < div className = "flex items-center" >
71- Status
72- < DropdownMenu >
73- < DropdownMenuTrigger asChild >
74- < Button variant = "ghost" size = "sm" className = "ml-2 h-8 p-1" >
75- < Filter className = "h-4 w-4" />
76- </ Button >
77- </ DropdownMenuTrigger >
78- < DropdownMenuContent align = "start" >
79- < DropdownMenuLabel > Filter by Status</ DropdownMenuLabel >
80- < DropdownMenuSeparator />
81- { [ "pending" , "running" , "completed" , "failed" ] . map ( ( status ) => (
95+ {
96+ accessorKey : "queue" ,
97+ header : ( { column } ) => (
98+ < div className = "flex items-center" >
99+ Queue
100+ < DropdownMenu >
101+ < DropdownMenuTrigger asChild >
102+ < Button variant = "ghost" size = "sm" className = "ml-2 h-8 p-1" >
103+ < Filter className = "h-4 w-4" />
104+ </ Button >
105+ </ DropdownMenuTrigger >
106+ < DropdownMenuContent align = "start" >
107+ < DropdownMenuLabel > Filter by Queue</ DropdownMenuLabel >
108+ < DropdownMenuSeparator />
82109 < DropdownMenuCheckboxItem
83- key = { status }
84- checked = { column . getFilterValue ( ) === status }
110+ checked = { ! column . getFilterValue ( ) }
85111 onCheckedChange = { ( checked ) => {
86- column . setFilterValue ( checked ? status : undefined )
112+ if ( checked ) column . setFilterValue ( undefined )
87113 } }
88114 >
89- { status . charAt ( 0 ) . toUpperCase ( ) + status . slice ( 1 ) }
115+ All
90116 </ DropdownMenuCheckboxItem >
91- ) ) }
92- </ DropdownMenuContent >
93- </ DropdownMenu >
94- </ div >
95- ) ,
96- cell : ( { row } ) => {
97- const status = row . getValue ( "status" ) as string
98- return (
99- < Badge
100- className = {
101- status === "completed"
102- ? "bg-green-100 text-green-800"
103- : status === "running"
104- ? "bg-blue-100 text-blue-800"
105- : status === "pending"
106- ? "bg-yellow-100 text-yellow-800"
107- : "bg-red-100 text-red-800"
108- }
117+ { availableQueues . map ( ( queue ) => (
118+ < DropdownMenuCheckboxItem
119+ key = { queue }
120+ checked = { column . getFilterValue ( ) === queue }
121+ onCheckedChange = { ( checked ) => {
122+ column . setFilterValue ( checked ? queue : undefined )
123+ } }
124+ >
125+ { queue }
126+ </ DropdownMenuCheckboxItem >
127+ ) ) }
128+ </ DropdownMenuContent >
129+ </ DropdownMenu >
130+ </ div >
131+ ) ,
132+ cell : ( { row } ) => {
133+ const queue = row . getValue ( "queue" ) as string ;
134+ return (
135+ < Badge
136+ className = "bg-blue-100 text-blue-800 hover:bg-blue-100/60 "
137+ >
138+ { queue }
139+ </ Badge >
140+ ) ;
141+ } ,
142+ filterFn : ( row , columnId , filterValue ) => {
143+ return row . getValue ( columnId ) === filterValue
144+ } ,
145+ } ,
146+ {
147+ accessorKey : "createdAt" ,
148+ header : ( { column } ) => (
149+ < Button
150+ variant = "ghost"
151+ onClick = { ( ) => column . toggleSorting ( column . getIsSorted ( ) === "asc" ) }
109152 >
110- { status }
111- </ Badge >
112- )
153+ Creation Time
154+ < ArrowUpDown className = "ml-2 h-4 w-4" />
155+ </ Button >
156+ ) ,
157+ cell : ( { row } ) => {
158+ const createdAt = row . getValue ( "createdAt" ) as Date
159+ return new Intl . DateTimeFormat ( "en-US" , {
160+ dateStyle : "medium" ,
161+ timeStyle : "short" ,
162+ } ) . format ( createdAt )
163+ } ,
113164 } ,
114- filterFn : ( row , columnId , filterValue ) => {
115- return row . getValue ( columnId ) === filterValue
165+ {
166+ accessorKey : "status" ,
167+ header : ( { column } ) => (
168+ < div className = "flex items-center" >
169+ Status
170+ < DropdownMenu >
171+ < DropdownMenuTrigger asChild >
172+ < Button variant = "ghost" size = "sm" className = "ml-2 h-8 p-1" >
173+ < Filter className = "h-4 w-4" />
174+ </ Button >
175+ </ DropdownMenuTrigger >
176+ < DropdownMenuContent align = "start" >
177+ < DropdownMenuLabel > Filter by Status</ DropdownMenuLabel >
178+ < DropdownMenuSeparator />
179+ < DropdownMenuCheckboxItem
180+ checked = { ! column . getFilterValue ( ) }
181+ onCheckedChange = { ( checked ) => {
182+ if ( checked ) column . setFilterValue ( undefined )
183+ } }
184+ >
185+ All
186+ </ DropdownMenuCheckboxItem >
187+ { availableStatuses . map ( ( status ) => (
188+ < DropdownMenuCheckboxItem
189+ key = { status }
190+ checked = { column . getFilterValue ( ) === status }
191+ onCheckedChange = { ( checked ) => {
192+ column . setFilterValue ( checked ? status : undefined )
193+ } }
194+ >
195+ { status . charAt ( 0 ) . toUpperCase ( ) + status . slice ( 1 ) }
196+ </ DropdownMenuCheckboxItem >
197+ ) ) }
198+ </ DropdownMenuContent >
199+ </ DropdownMenu >
200+ </ div >
201+ ) ,
202+ cell : ( { row } ) => {
203+ const status = row . getValue ( "status" ) as string
204+ return (
205+ < Badge
206+ className = {
207+ status === "completed"
208+ ? "bg-green-100 text-green-800"
209+ : status === "running"
210+ ? "bg-blue-100 text-blue-800"
211+ : status === "pending"
212+ ? "bg-yellow-100 text-yellow-800"
213+ : "bg-red-100 text-red-800"
214+ }
215+ >
216+ { status }
217+ </ Badge >
218+ )
219+ } ,
220+ filterFn : ( row , columnId , filterValue ) => {
221+ return row . getValue ( columnId ) === filterValue
222+ } ,
116223 } ,
117- } ,
118- ]
224+ {
225+ id : "actions" ,
226+ header : "Actions" ,
227+ cell : ( { row } ) => {
228+ const job = row . original
229+
230+ return (
231+ < div className = "flex items-center gap-2" >
232+ { onEdit && (
233+ < Button
234+ variant = "ghost"
235+ size = "sm"
236+ onClick = { ( e ) => {
237+ e . stopPropagation ( )
238+ onEdit ( job )
239+ } }
240+ className = "h-8 w-8 p-0"
241+ >
242+ < Edit className = "h-4 w-4" />
243+ </ Button >
244+ ) }
245+ { onDelete && (
246+ < Button
247+ variant = "ghost"
248+ size = "sm"
249+ onClick = { ( e ) => {
250+ e . stopPropagation ( )
251+ onDelete ( job )
252+ } }
253+ className = "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50"
254+ >
255+ < Trash2 className = "h-4 w-4" />
256+ </ Button >
257+ ) }
258+ </ div >
259+ )
260+ } ,
261+ } ,
262+ ]
263+
264+ export const columns = createColumns ( {
265+ availableNamespaces : [ ] ,
266+ availableQueues : [ ] ,
267+ availableStatuses : [ ]
268+ } )
0 commit comments