6262 q-dialog( v-model ='logsDialog' maximized )
6363 q-card.fit.column.no-wrap ( style ='overflow: hidden;' )
6464 q-toolbar.bg-info.text-white ( bordered dense style ='height: 28px; line-height: 28px;' )
65- q-toolbar-title Logs de la tâche "{{ selectedCronName }}"
65+ q-toolbar-title
66+ span Logs de la tâche "{{ selectedCronName }}"
67+ span.q-ml-sm.text-caption ( v-if ='logsDialog && selectedCronName' ) (Actualisation dans {{ logsAutoRefreshCountdown }}s)
6668 q-space
69+ q-btn(
70+ flat
71+ round
72+ dense
73+ icon ='mdi-play-circle-outline'
74+ :loading ='logsRunLoading'
75+ :disable ='!selectedCronName'
76+ @click ='runSelectedCronImmediately'
77+ )
78+ q-tooltip.text-body2 ( anchor ='top middle' self ='bottom middle' ) Exécuter immédiatement
79+ q-separator.q-mx-xs ( vertical inset )
6780 q-btn( flat round dense icon ='mdi-refresh' : loading= 'logsLoading' @click ='loadCronLogs' )
81+ q-tooltip.text-body2 ( anchor ='top middle' self ='bottom middle' ) Actualiser les logs
6882 q-btn( flat round dense icon ='mdi-close' v-close-popup )
83+ q-tooltip.text-body2 ( anchor ='top middle' self ='bottom middle' ) Fermer
6984 q-separator
7085 q-card-section.col.q-pa-none ( ref ='logsContainer' style ='min-height: 0; overflow: auto;' )
7186 q-inner-loading( :showing ='logsLoading' )
@@ -156,6 +171,10 @@ export default defineNuxtComponent({
156171 const logsMonacoEditor = ref <any >(null )
157172 const logsScrollDispose = ref <null | (() => void )>(null )
158173 const logsLoadingMore = ref (false )
174+ const logsRunLoading = ref (false )
175+ const logsAutoRefreshMs = ref (60_000 )
176+ const logsAutoRefreshTimer = ref <ReturnType <typeof setInterval > | null >(null )
177+ const logsAutoRefreshCountdown = ref (5 )
159178 const cronToggleLoading = reactive <Record <string , boolean >>({})
160179 const cronRunLoading = reactive <Record <string , boolean >>({})
161180 const logsMonacoOptions = computed (() => ({
@@ -209,6 +228,10 @@ export default defineNuxtComponent({
209228 logsMonacoEditor ,
210229 logsScrollDispose ,
211230 logsLoadingMore ,
231+ logsRunLoading ,
232+ logsAutoRefreshMs ,
233+ logsAutoRefreshTimer ,
234+ logsAutoRefreshCountdown ,
212235 cronToggleLoading ,
213236 cronRunLoading ,
214237 logsMonacoOptions ,
@@ -217,13 +240,16 @@ export default defineNuxtComponent({
217240 watch: {
218241 logsDialog(isOpen : boolean ): void {
219242 if (isOpen ) {
243+ this .startLogsAutoRefresh ()
220244 return
221245 }
222246
247+ this .stopLogsAutoRefresh ()
223248 this .resetLogsViewerState ()
224249 },
225250 },
226251 beforeUnmount(): void {
252+ this .stopLogsAutoRefresh ()
227253 this .resetLogsViewerState ()
228254 },
229255 computed: {
@@ -247,6 +273,36 @@ export default defineNuxtComponent({
247273 },
248274 },
249275 methods: {
276+ startLogsAutoRefresh(): void {
277+ if (this .logsAutoRefreshTimer || ! this .logsDialog ) {
278+ return
279+ }
280+
281+ const refreshSeconds = Math .max (Math .round (this .logsAutoRefreshMs / 1000 ), 1 )
282+ this .logsAutoRefreshCountdown = refreshSeconds
283+ this .logsAutoRefreshTimer = setInterval (() => {
284+ if (! this .logsDialog || ! this .selectedCronName || this .logsLoading || this .logsLoadingMore ) {
285+ return
286+ }
287+
288+ if (this .logsAutoRefreshCountdown > 1 ) {
289+ this .logsAutoRefreshCountdown -= 1
290+ return
291+ }
292+
293+ this .logsAutoRefreshCountdown = refreshSeconds
294+ void this .loadCronLogs ()
295+ }, 1000 )
296+ },
297+ stopLogsAutoRefresh(): void {
298+ if (! this .logsAutoRefreshTimer ) {
299+ return
300+ }
301+
302+ clearInterval (this .logsAutoRefreshTimer )
303+ this .logsAutoRefreshTimer = null
304+ this .logsAutoRefreshCountdown = Math .max (Math .round (this .logsAutoRefreshMs / 1000 ), 1 )
305+ },
250306 resetLogsViewerState(): void {
251307 if (this .logsScrollDispose ) {
252308 this .logsScrollDispose ()
@@ -272,6 +328,7 @@ export default defineNuxtComponent({
272328 this .selectedCronName = cronTask ?.name || ' '
273329 this .logsDialog = true
274330 await this .loadCronLogs ()
331+ this .startLogsAutoRefresh ()
275332 },
276333 async toggleCronEnabled(cronTask : any ): Promise <void > {
277334 const name = cronTask ?.name
@@ -315,7 +372,7 @@ export default defineNuxtComponent({
315372 this .$q .notify ({
316373 message: ` Exécution immédiate lancée pour "${name }". ` ,
317374 color: ' positive' ,
318- position: ' top-right ' ,
375+ position: ' bottom-center ' ,
319376 icon: ' mdi-play-circle-outline' ,
320377 })
321378 await this .refresh ()
@@ -330,6 +387,31 @@ export default defineNuxtComponent({
330387 this .cronRunLoading [name ] = false
331388 }
332389 },
390+ async runSelectedCronImmediately(): Promise <void > {
391+ if (! this .selectedCronName ) {
392+ return
393+ }
394+
395+ this .logsRunLoading = true
396+ try {
397+ await this .$http .post (` /core/cron/${encodeURIComponent (this .selectedCronName )}/run-immediately ` )
398+ this .$q .notify ({
399+ message: ` Exécution immédiate lancée pour "${this .selectedCronName }". ` ,
400+ color: ' positive' ,
401+ position: ' bottom' ,
402+ icon: ' mdi-play-circle-outline' ,
403+ })
404+ } catch (error : any ) {
405+ this .$q .notify ({
406+ message: error ?.response ?._data ?.message || ` Impossible de lancer immédiatement "${this .selectedCronName }". ` ,
407+ color: ' negative' ,
408+ position: ' bottom' ,
409+ icon: ' mdi-alert-circle-outline' ,
410+ })
411+ } finally {
412+ this .logsRunLoading = false
413+ }
414+ },
333415 async loadCronLogs(): Promise <void > {
334416 if (! this .selectedCronName ) {
335417 return
@@ -358,6 +440,9 @@ export default defineNuxtComponent({
358440 })
359441 } finally {
360442 this .logsLoading = false
443+ if (this .logsDialog && this .selectedCronName ) {
444+ this .logsAutoRefreshCountdown = Math .max (Math .round (this .logsAutoRefreshMs / 1000 ), 1 )
445+ }
361446 }
362447 },
363448 onLogsEditorLoad(editor : any ): void {
0 commit comments