Rafael Uzarowski commited on
Commit
7447d12
·
unverified ·
1 Parent(s): afd821e

feat: frontend-only notifications and test button for them

Browse files
webui/components/notifications/notification-icons.html CHANGED
@@ -29,6 +29,13 @@
29
  title="Create Test Notification">
30
  <div class="notification-icon">🧪</div>
31
  </button>
 
 
 
 
 
 
 
32
  </div>
33
  </body>
34
  </html>
 
29
  title="Create Test Notification">
30
  <div class="notification-icon">🧪</div>
31
  </button>
32
+
33
+ <!-- Test Frontend Error Button (for development) -->
34
+ <button class="notification-test-button frontend-error"
35
+ @click="toastFrontendError('Backend connection failed', 'Connection Error')"
36
+ title="Test Frontend Error Toast">
37
+ <div class="notification-icon">⚠️</div>
38
+ </button>
39
  </div>
40
  </body>
41
  </html>
webui/css/notification.css CHANGED
@@ -109,6 +109,17 @@
109
  font-size: 1.2rem;
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
 
112
  /* Light Mode Styles */
113
  .light-mode .notification-toggle {
114
  background: rgba(0, 0, 0, 0.05);
@@ -140,6 +151,16 @@
140
  border-color: rgba(33, 150, 243, 0.5);
141
  }
142
 
 
 
 
 
 
 
 
 
 
 
143
  /* Animations */
144
  @keyframes pulse {
145
  0%, 100% { transform: scale(1); }
 
109
  font-size: 1.2rem;
110
  }
111
 
112
+ /* Frontend Error Test Button - distinct orange/red styling */
113
+ .notification-test-button.frontend-error {
114
+ background: rgba(255, 152, 0, 0.15);
115
+ border-color: rgba(255, 152, 0, 0.4);
116
+ }
117
+
118
+ .notification-test-button.frontend-error:hover {
119
+ background: rgba(255, 152, 0, 0.25);
120
+ border-color: rgba(255, 152, 0, 0.6);
121
+ }
122
+
123
  /* Light Mode Styles */
124
  .light-mode .notification-toggle {
125
  background: rgba(0, 0, 0, 0.05);
 
151
  border-color: rgba(33, 150, 243, 0.5);
152
  }
153
 
154
+ .light-mode .notification-test-button.frontend-error {
155
+ background: rgba(255, 152, 0, 0.15);
156
+ border-color: rgba(255, 152, 0, 0.4);
157
+ }
158
+
159
+ .light-mode .notification-test-button.frontend-error:hover {
160
+ background: rgba(255, 152, 0, 0.25);
161
+ border-color: rgba(255, 152, 0, 0.6);
162
+ }
163
+
164
  /* Animations */
165
  @keyframes pulse {
166
  0%, 100% { transform: scale(1); }
webui/js/notificationStore.js CHANGED
@@ -366,9 +366,96 @@ const model = {
366
  // Legacy method for backward compatibility
367
  toggleNotifications() {
368
  this.openModal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  }
370
  };
371
 
372
  // Create and export the store
373
  const store = createStore("notificationStore", model);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  export { store };
 
366
  // Legacy method for backward compatibility
367
  toggleNotifications() {
368
  this.openModal();
369
+ },
370
+
371
+ // NEW: Add frontend-only toast directly to stack (for connection errors, etc.)
372
+ addFrontendToast(type, message, title = "", display_time = 5) {
373
+ const timestamp = new Date().toISOString();
374
+ const notification = {
375
+ id: `frontend-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
376
+ type: type,
377
+ title: title,
378
+ message: message,
379
+ detail: "",
380
+ timestamp: timestamp,
381
+ display_time: display_time,
382
+ read: false,
383
+ frontend: true // Mark as frontend-only
384
+ };
385
+
386
+ // Create toast object with auto-dismiss timer
387
+ const toast = {
388
+ ...notification,
389
+ toastId: `toast-${notification.id}`,
390
+ addedAt: Date.now(),
391
+ autoRemoveTimer: null
392
+ };
393
+
394
+ // Add to bottom of stack (newest at bottom)
395
+ this.toastStack.push(toast);
396
+
397
+ // Enforce max stack limit (remove oldest from top)
398
+ if (this.toastStack.length > this.maxToastStack) {
399
+ const removed = this.toastStack.shift(); // Remove from top
400
+ if (removed.autoRemoveTimer) {
401
+ clearTimeout(removed.autoRemoveTimer);
402
+ }
403
+ }
404
+
405
+ // Set auto-dismiss timer
406
+ toast.autoRemoveTimer = setTimeout(() => {
407
+ this.removeFromToastStack(toast.toastId);
408
+ }, notification.display_time * 1000);
409
+
410
+ console.log(`Frontend toast added: ${notification.type} - ${notification.message}`);
411
+ return notification.id;
412
+ },
413
+
414
+ // NEW: Convenience methods for frontend-only notifications
415
+ frontendError(message, title = "Connection Error", display_time = 8) {
416
+ return this.addFrontendToast('error', message, title, display_time);
417
+ },
418
+
419
+ frontendWarning(message, title = "Warning", display_time = 5) {
420
+ return this.addFrontendToast('warning', message, title, display_time);
421
+ },
422
+
423
+ frontendInfo(message, title = "Info", display_time = 3) {
424
+ return this.addFrontendToast('info', message, title, display_time);
425
  }
426
  };
427
 
428
  // Create and export the store
429
  const store = createStore("notificationStore", model);
430
+
431
+ // NEW: Global function for frontend error toasts (replaces toastFetchError)
432
+ window.toastFrontendError = function(message, title = "Connection Error") {
433
+ if (window.Alpine && window.Alpine.store && window.Alpine.store('notificationStore')) {
434
+ return window.Alpine.store('notificationStore').frontendError(message, title);
435
+ } else {
436
+ // Fallback if Alpine/store not ready
437
+ console.error('Frontend Error:', title, '-', message);
438
+ return null;
439
+ }
440
+ };
441
+
442
+ // NEW: Additional global convenience functions
443
+ window.toastFrontendWarning = function(message, title = "Warning") {
444
+ if (window.Alpine && window.Alpine.store && window.Alpine.store('notificationStore')) {
445
+ return window.Alpine.store('notificationStore').frontendWarning(message, title);
446
+ } else {
447
+ console.warn('Frontend Warning:', title, '-', message);
448
+ return null;
449
+ }
450
+ };
451
+
452
+ window.toastFrontendInfo = function(message, title = "Info") {
453
+ if (window.Alpine && window.Alpine.store && window.Alpine.store('notificationStore')) {
454
+ return window.Alpine.store('notificationStore').frontendInfo(message, title);
455
+ } else {
456
+ console.log('Frontend Info:', title, '-', message);
457
+ return null;
458
+ }
459
+ };
460
+
461
  export { store };