@@ -5,6 +5,7 @@ import { JobStatus } from '../types/job'
55
66const queueStore = useQueueStore ()
77const error = ref <string | null >(null )
8+ const isLoading = ref (false )
89
910// Mock data for charts
1011const processingRateData = ref ([42 , 50 , 65 , 59 , 80 , 81 , 56 , 55 , 72 , 64 , 61 , 68 , 75 , 62 , 44 , 35 , 41 , 48 ])
@@ -30,39 +31,52 @@ const queueActivityData = computed(() => {
3031 }))
3132})
3233
34+ // Mock data for groups and batches
35+ const groupData = ref ([
36+ { name: ' Daily Reports' , jobCount: 45 , completionRate: 78 , activeJobs: 3 },
37+ { name: ' User Notifications' , jobCount: 128 , completionRate: 62 , activeJobs: 12 },
38+ { name: ' Data Exports' , jobCount: 34 , completionRate: 91 , activeJobs: 1 },
39+ ])
40+
41+ const recentBatches = ref ([
42+ { id: ' batch_abc123' , name: ' Weekly Newsletter' , jobCount: 15 , completedJobs: 12 , status: ' active' },
43+ { id: ' batch_def456' , name: ' Image Processing' , jobCount: 24 , completedJobs: 24 , status: ' completed' },
44+ { id: ' batch_ghi789' , name: ' User Import' , jobCount: 120 , completedJobs: 98 , status: ' active' },
45+ ])
46+
3347onMounted (async () => {
48+ await fetchDashboardData ()
49+ })
50+
51+ async function fetchDashboardData(forceRefresh = false ) {
52+ error .value = null
53+ isLoading .value = true
54+
3455 try {
3556 await Promise .all ([
36- queueStore .fetchQueueStats (),
37- queueStore .fetchQueues (),
57+ queueStore .fetchQueueStats (forceRefresh ),
58+ queueStore .fetchQueues (forceRefresh ),
3859 ])
3960
4061 // Generate processing rate data (last 18 minutes)
4162 processingRateData .value = Array .from ({ length: 18 }, () =>
4263 Math .max (20 , Math .floor (Math .random () * queueStore .stats .processingRate * 1.5 )))
64+
65+ // In a real implementation, you would fetch groups and batches data here
66+ // await queueStore.fetchGroups(forceRefresh)
67+ // await queueStore.fetchBatches(forceRefresh)
4368 }
4469 catch (err ) {
4570 error .value = ' Failed to load dashboard data'
4671 console .error (' Dashboard data loading error:' , err )
4772 }
48- })
73+ finally {
74+ isLoading .value = false
75+ }
76+ }
4977
5078async function refreshData() {
51- error .value = null
52- try {
53- await Promise .all ([
54- queueStore .fetchQueueStats (true ),
55- queueStore .fetchQueues (true ),
56- ])
57-
58- // Generate new processing rate data
59- processingRateData .value = Array .from ({ length: 18 }, () =>
60- Math .max (20 , Math .floor (Math .random () * queueStore .stats .processingRate * 1.5 )))
61- }
62- catch (err ) {
63- error .value = ' Failed to refresh dashboard data'
64- console .error (' Dashboard data refresh error:' , err )
65- }
79+ await fetchDashboardData (true )
6680}
6781 </script >
6882
@@ -75,14 +89,18 @@ async function refreshData() {
7589 Dashboard Overview
7690 </h2 >
7791 </div >
78- <button class =" btn btn-primary flex items-center" :disabled =" queueStore.isLoadingStats || queueStore.isLoadingQueues" @click =" refreshData" >
79- <span v-if =" queueStore.isLoadingStats || queueStore.isLoadingQueues" class =" loader mr-2" />
92+ <button
93+ class =" btn btn-primary flex items-center"
94+ :disabled =" isLoading || queueStore.isLoadingStats || queueStore.isLoadingQueues"
95+ @click =" refreshData"
96+ >
97+ <span v-if =" isLoading || queueStore.isLoadingStats || queueStore.isLoadingQueues" class =" loader mr-2" />
8098 <span v-else class =" i-carbon-refresh mr-2" />
81- {{ queueStore.isLoadingStats || queueStore.isLoadingQueues ? 'Loading...' : 'Refresh' }}
99+ {{ isLoading || queueStore.isLoadingStats || queueStore.isLoadingQueues ? 'Loading...' : 'Refresh' }}
82100 </button >
83101 </div >
84102
85- <div v-if =" queueStore.isLoadingStats && !queueStore.hasStats" class =" card p-8 text-center bg-white rounded-xl shadow-md" >
103+ <div v-if =" isLoading && !queueStore.hasStats" class =" card p-8 text-center bg-white rounded-xl shadow-md" >
86104 <div class =" flex justify-center items-center space-x-3" >
87105 <div class =" w-5 h-5 rounded-full bg-indigo-600 animate-pulse" />
88106 <div class =" w-5 h-5 rounded-full bg-indigo-600 animate-pulse" style =" animation-delay : 0.2s " />
@@ -182,7 +200,7 @@ async function refreshData() {
182200 </h3 >
183201 </div >
184202 <div class =" p-2 h-64 bg-white rounded-lg" >
185- <div v-if =" queueStore.isLoadingStats && !queueStore.hasStats" class =" flex h-full items-center justify-center" >
203+ <div v-if =" isLoading && !queueStore.hasStats" class =" flex h-full items-center justify-center" >
186204 <div class =" loader mr-2" />
187205 <span class =" text-gray-500" >Loading chart data...</span >
188206 </div >
@@ -217,7 +235,7 @@ async function refreshData() {
217235 </h3 >
218236 </div >
219237 <div class =" p-2 h-64 bg-white rounded-lg flex justify-center items-center" >
220- <div v-if =" queueStore.isLoadingStats && !queueStore.hasStats" class =" flex items-center" >
238+ <div v-if =" isLoading && !queueStore.hasStats" class =" flex items-center" >
221239 <div class =" loader mr-2" />
222240 <span class =" text-gray-500" >Loading chart data...</span >
223241 </div >
@@ -278,6 +296,155 @@ async function refreshData() {
278296 </div >
279297 </div >
280298
299+ <!-- Group Activity Section -->
300+ <div class =" card p-5 rounded-xl shadow hover:shadow-lg transition-shadow mb-8" >
301+ <div class =" flex items-center mb-6" >
302+ <span class =" i-carbon-group text-xl text-indigo-600 mr-2" />
303+ <h3 class =" text-lg font-medium text-gray-800" >
304+ Job Groups
305+ </h3 >
306+ </div >
307+
308+ <div v-if =" isLoading" class =" py-8 text-center" >
309+ <div class =" loader mx-auto mb-4" />
310+ <p class =" text-gray-500" >
311+ Loading group data...
312+ </p >
313+ </div >
314+
315+ <div v-else-if =" groupData.length === 0" class =" py-8 text-center text-gray-500" >
316+ No group data available
317+ </div >
318+
319+ <div v-else >
320+ <div class =" grid grid-cols-1 md:grid-cols-3 gap-4 mb-4" >
321+ <div v-for =" group in groupData" :key =" group.name" class =" p-4 bg-white rounded-lg border border-gray-100 shadow-sm" >
322+ <div class =" flex justify-between items-start mb-2" >
323+ <h4 class =" font-medium text-gray-800" >
324+ {{ group.name }}
325+ </h4 >
326+ <span class =" text-xs px-2 py-1 rounded bg-blue-100 text-blue-700" >{{ group.activeJobs }} active</span >
327+ </div >
328+
329+ <div class =" mt-3" >
330+ <div class =" flex justify-between text-xs mb-1" >
331+ <span >Completion</span >
332+ <span >{{ group.completionRate }}%</span >
333+ </div >
334+ <div class =" h-1.5 w-full bg-gray-200 rounded-full overflow-hidden" >
335+ <div
336+ class =" h-full bg-indigo-500 rounded-full"
337+ :style =" { width: `${group.completionRate}%` }"
338+ />
339+ </div >
340+ </div >
341+
342+ <div class =" mt-3 text-sm text-gray-600" >
343+ {{ group.jobCount }} total jobs
344+ </div >
345+ </div >
346+ </div >
347+
348+ <div class =" text-right mt-4" >
349+ <router-link to =" /groups" class =" btn btn-outline text-sm" >
350+ <span class =" i-carbon-list-checked mr-2" />
351+ View All Groups
352+ </router-link >
353+ </div >
354+ </div >
355+ </div >
356+
357+ <!-- Recent Batches Section -->
358+ <div class =" card p-5 rounded-xl shadow hover:shadow-lg transition-shadow mb-8" >
359+ <div class =" flex items-center mb-6" >
360+ <span class =" i-carbon-batch-job text-xl text-indigo-600 mr-2" />
361+ <h3 class =" text-lg font-medium text-gray-800" >
362+ Recent Batches
363+ </h3 >
364+ </div >
365+
366+ <div v-if =" isLoading" class =" py-8 text-center" >
367+ <div class =" loader mx-auto mb-4" />
368+ <p class =" text-gray-500" >
369+ Loading batch data...
370+ </p >
371+ </div >
372+
373+ <div v-else-if =" recentBatches.length === 0" class =" py-8 text-center text-gray-500" >
374+ No batch data available
375+ </div >
376+
377+ <div v-else >
378+ <div class =" overflow-x-auto" >
379+ <table class =" w-full" >
380+ <thead >
381+ <tr class =" text-left border-b border-gray-200" >
382+ <th class =" pb-3 font-medium text-gray-500" >
383+ Batch Name
384+ </th >
385+ <th class =" pb-3 font-medium text-gray-500" >
386+ Status
387+ </th >
388+ <th class =" pb-3 font-medium text-gray-500" >
389+ Progress
390+ </th >
391+ <th class =" pb-3 font-medium text-gray-500 text-right" >
392+ Jobs
393+ </th >
394+ </tr >
395+ </thead >
396+ <tbody >
397+ <tr v-for =" batch in recentBatches" :key =" batch.id" class =" border-b border-gray-100" >
398+ <td class =" py-3" >
399+ <div class =" font-medium text-gray-800" >
400+ {{ batch.name }}
401+ </div >
402+ <div class =" text-xs text-gray-500" >
403+ {{ batch.id }}
404+ </div >
405+ </td >
406+ <td class =" py-3" >
407+ <span
408+ class =" px-2 py-1 text-xs rounded-full"
409+ :class =" {
410+ 'bg-blue-100 text-blue-700': batch.status === 'active',
411+ 'bg-emerald-100 text-emerald-700': batch.status === 'completed',
412+ 'bg-amber-100 text-amber-700': batch.status === 'waiting',
413+ 'bg-red-100 text-red-700': batch.status === 'failed',
414+ }"
415+ >
416+ {{ batch.status }}
417+ </span >
418+ </td >
419+ <td class =" py-3" >
420+ <div class =" flex items-center" >
421+ <div class =" w-32 bg-gray-200 rounded-full h-2 mr-3" >
422+ <div
423+ class =" bg-indigo-500 h-2 rounded-full"
424+ :style =" { width: `${(batch.completedJobs / batch.jobCount) * 100}%` }"
425+ />
426+ </div >
427+ <span class =" text-sm" >{{ Math.round((batch.completedJobs / batch.jobCount) * 100) }}%</span >
428+ </div >
429+ </td >
430+ <td class =" py-3 text-right" >
431+ <span class =" font-medium" >{{ batch.completedJobs }}</span >
432+ <span class =" text-gray-500" >/{{ batch.jobCount }}</span >
433+ </td >
434+ </tr >
435+ </tbody >
436+ </table >
437+ </div >
438+
439+ <div class =" text-right mt-4" >
440+ <router-link to =" /batches" class =" btn btn-outline text-sm" >
441+ <span class =" i-carbon-list mr-2" />
442+ View All Batches
443+ </router-link >
444+ </div >
445+ </div >
446+ </div >
447+
281448 <!-- Queue Activity -->
282449 <div class =" card p-5 rounded-xl shadow hover:shadow-lg transition-shadow" >
283450 <div class =" flex items-center mb-6" >
@@ -287,7 +454,7 @@ async function refreshData() {
287454 </h3 >
288455 </div >
289456
290- <div v-if =" queueStore.isLoadingQueues && !queueStore.hasQueues" class =" py-8 text-center" >
457+ <div v-if =" isLoading && !queueStore.hasQueues" class =" py-8 text-center" >
291458 <div class =" loader mx-auto mb-4" />
292459 <p class =" text-gray-500" >
293460 Loading queue data...
0 commit comments