fix scheduler flickering

Alessandro committed Dec 22, 2025 at 06:07 UTC 745d4ebd318924904591d58ff0cc08e53b4c1b4a
1 file changed +19 -9
webui/components/settings/scheduler/scheduler-store.js
+19 -9
@@ -549,12 +549,11 @@ const schedulerStoreModel = {
549 startPolling() {
550 if (this.pollingInterval) return;
551 this.fetchTasks();
552 - // Poll every 5 seconds - balances responsiveness with performance
552 this.pollingInterval = setInterval(() => {
553 if (this.pollingActive) {
554 this.fetchTasks();
555 }
557 - }, 5000);
556 + }, 2000);
557 },
558
559 stopPolling() {
@@ -568,7 +567,8 @@ const schedulerStoreModel = {
567 // Data fetching -------------------------------------------------------------
568 async fetchTasks({ manual = false } = {}) {
569 if (this.isCreating || this.isEditing) return;
571 - this.isLoading = true;
570 + if (manual) this.isLoading = true;
571 +
572 try {
573 const { ok, error, tasks } = await schedulerApi.listTasks();
574 if (!ok) {
@@ -577,12 +577,22 @@ const schedulerStoreModel = {
577 this.hasNoTasks = true;
578 return;
579 }
580 - // Only update if data actually changed - prevents DOM thrashing during polling
581 - const newJson = JSON.stringify(tasks);
582 - if (newJson !== JSON.stringify(this.tasks)) {
583 - this.tasks = tasks;
584 - }
585 - this.hasNoTasks = tasks.length === 0;
580 +
581 + // Smart merge: preserve object references to prevent UI flickering
582 + const taskMap = new Map(this.tasks.map((t) => [t.uuid, t]));
583 + this.tasks = tasks.map((newTask) => {
584 + const existing = taskMap.get(newTask.uuid);
585 + if (existing) {
586 + // Update existing object in-place if different
587 + if (JSON.stringify(existing) !== JSON.stringify(newTask)) {
588 + Object.assign(existing, newTask);
589 + }
590 + return existing; // Return the SAME object reference
591 + }
592 + return newTask; // New object
593 + });
594 +
595 + this.hasNoTasks = this.tasks.length === 0;
596 } catch (error) {
597 if (manual) this.notifyError(`Failed to fetch tasks: ${error.message}`);
598 this.tasks = [];