11<template >
22 <div class =" tw-flex tw-flex-col tw-flex-1 tw-min-h-0" >
3+ <!-- Loading spinner -->
4+ <div
5+ v-if =" loading"
6+ class =" tw-flex tw-flex-1 tw-items-center tw-justify-center tw-min-h-[200px]"
7+ >
8+ <div class =" tw-flex tw-flex-col tw-items-center tw-gap-3" >
9+ <svg
10+ class =" tw-animate-spin tw-h-8 tw-w-8 tw-text-blue-500"
11+ xmlns =" http://www.w3.org/2000/svg"
12+ fill =" none"
13+ viewBox =" 0 0 24 24"
14+ >
15+ <circle
16+ class =" tw-opacity-25"
17+ cx =" 12"
18+ cy =" 12"
19+ r =" 10"
20+ stroke =" currentColor"
21+ stroke-width =" 4"
22+ />
23+ <path
24+ class =" tw-opacity-75"
25+ fill =" currentColor"
26+ d =" M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
27+ />
28+ </svg >
29+ <span class =" tw-text-sm tw-text-gray-500" >{{ $t('Loading...') }}</span >
30+ </div >
31+ </div >
32+
33+ <!-- Table content -->
334 <base-table
35+ v-else
436 :columns =" columns"
537 :data =" data"
6- />
38+ >
39+ <!-- Custom case_number cell with link to case -->
40+ <template #cell-case_number =" { value } " >
41+ <a
42+ v-if =" value"
43+ :href =" `/cases/${value}`"
44+ class =" tw-text-blue-600 hover:tw-text-blue-800 hover:tw-underline tw-font-medium"
45+ >
46+ #{{ value }}
47+ </a >
48+ <span v-else class =" tw-text-gray-400" >-</span >
49+ </template >
50+
51+ <!-- Custom status cell with colored badge -->
52+ <template #cell-status =" { value } " >
53+ <span
54+ class =" tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium"
55+ :class =" getStatusClasses(value)"
56+ >
57+ {{ formatStatus(value) }}
58+ </span >
59+ </template >
60+
61+ <!-- Custom tokens_used cell with hover popover -->
62+ <template #cell-tokens_used =" { value , item } " >
63+ <div class =" tw-relative tw-group tw-inline-block" >
64+ <span class =" tw-cursor-help tw-border-b tw-border-dotted tw-border-gray-400" >
65+ {{ value }}
66+ </span >
67+ <!-- Popover tooltip -->
68+ <div
69+ class ="
70+ tw-absolute tw-z-50 tw-bottom-full tw-left-1/2 tw--translate-x-1/2 tw-mb-2
71+ tw-hidden group-hover:tw-block
72+ tw-bg-gray-900 tw-text-white tw-text-xs tw-rounded-lg tw-py-2 tw-px-3
73+ tw-whitespace-nowrap tw-shadow-lg
74+ "
75+ >
76+ <div class =" tw-flex tw-flex-col tw-gap-1" >
77+ <div class =" tw-flex tw-justify-between tw-gap-4" >
78+ <span class =" tw-text-gray-400" >{{ $t('Input') }}:</span >
79+ <span class =" tw-font-medium" >{{ item.input_tokens }}</span >
80+ </div >
81+ <div class =" tw-flex tw-justify-between tw-gap-4" >
82+ <span class =" tw-text-gray-400" >{{ $t('Output') }}:</span >
83+ <span class =" tw-font-medium" >{{ item.output_tokens }}</span >
84+ </div >
85+ </div >
86+ <!-- Arrow -->
87+ <div
88+ class ="
89+ tw-absolute tw-top-full tw-left-1/2 tw--translate-x-1/2
90+ tw-border-4 tw-border-transparent tw-border-t-gray-900
91+ "
92+ />
93+ </div >
94+ </div >
95+ </template >
96+ </base-table >
797 <pagination
98+ v-if =" !loading"
899 class =" tw-mt-3 tw-shrink-0"
9100 :page =" page"
10101 :total-pages =" totalPages"
@@ -39,6 +130,7 @@ export default {
39130 page: 1 ,
40131 totalPages: 1 ,
41132 perPage: 15 ,
133+ loading: false ,
42134 };
43135 },
44136 computed: {
@@ -83,19 +175,23 @@ export default {
83175 design: [
84176 { key: ' flow_genie_name' , label: this .$t (' FlowGenie Name' ) },
85177 { key: ' user_name' , label: this .$t (' User' ) },
178+ { key: ' model' , label: this .$t (' Model' ) },
86179 { key: ' status' , label: this .$t (' Status' ) },
87180 { key: ' duration' , label: this .$t (' Execution Time' ) },
181+ { key: ' llm_calls' , label: this .$t (' LLM Calls' ) },
88182 { key: ' tools' , label: this .$t (' Tools' ) },
89183 { key: ' tokens_used' , label: this .$t (' Tokens Used' ) },
90184 { key: ' created_at' , label: this .$t (' Date' ), format: dateFormatter },
91185 ],
92186 execution: [
93- { key: ' process_request_id' , label: this .$t (' Request ID' ) },
94- { key: ' node_id' , label: this .$t (' Node ID' ) },
187+ { key: ' case_number' , label: this .$t (' Case #' ) },
188+ { key: ' process_name' , label: this .$t (' Process' ) },
189+ { key: ' node_name' , label: this .$t (' Node' ) },
95190 { key: ' flow_genie_name' , label: this .$t (' FlowGenie Name' ) },
96191 { key: ' user_name' , label: this .$t (' User' ) },
97192 { key: ' status' , label: this .$t (' Status' ) },
98193 { key: ' duration' , label: this .$t (' Execution Time' ) },
194+ { key: ' llm_calls' , label: this .$t (' LLM Calls' ) },
99195 { key: ' tools' , label: this .$t (' Tools' ) },
100196 { key: ' tokens_used' , label: this .$t (' Tokens Used' ) },
101197 { key: ' created_at' , label: this .$t (' Date' ), format: dateFormatter },
@@ -141,6 +237,7 @@ export default {
141237 this .fetchData ();
142238 },
143239 async fetchData (params = {}) {
240+ this .loading = true ;
144241 try {
145242 const response = await ProcessMaker .apiClient .get (this .apiEndpoint , {
146243 params: {
@@ -160,6 +257,8 @@ export default {
160257 // eslint-disable-next-line no-console
161258 console .log (error);
162259 this .data = [];
260+ } finally {
261+ this .loading = false ;
163262 }
164263 },
165264 handlePageChange (newPage ) {
@@ -170,6 +269,22 @@ export default {
170269 this .page = 1 ;
171270 this .fetchData (params);
172271 },
272+ getStatusClasses (status ) {
273+ const statusClasses = {
274+ completed: ' tw-bg-green-100 tw-text-green-800' ,
275+ error: ' tw-bg-red-100 tw-text-red-800' ,
276+ processing: ' tw-bg-yellow-100 tw-text-yellow-800' ,
277+ };
278+ return statusClasses[status] || ' tw-bg-gray-100 tw-text-gray-800' ;
279+ },
280+ formatStatus (status ) {
281+ const statusLabels = {
282+ completed: this .$t (' Completed' ),
283+ error: this .$t (' Error' ),
284+ processing: this .$t (' Processing' ),
285+ };
286+ return statusLabels[status] || status;
287+ },
173288 },
174289};
175290< / script>
0 commit comments