Commit: f0438c2

Commit Details

SHAf0438c2cbc2d838bb66a4d8129dd25b5d48d28ee
Treeb8e53d050248c8b632fa3de86003489acae4670b
Author<f69e50@finnacloud.com> 1766443042 +0300
Committer<f69e50@finnacloud.com> 1766443042 +0300
Message
increment once more
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJyCIeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKtrgP/04FZPSa4Hmx9WpR
gOamzjIXc+1+pBvGQDairLZU6rtDSgNkoryrsqOOLIXZWkkxZ70q8/aXQBFThr+t
YyDIz85u9GiwPOV8o1X4sxzF7bupOd6YmOOPqS2vco1aibpB8w9N9EwlMzW95Otw
vnQ/h0kz8MTp0wfXeRJqvLg8DVPnLgW70ly1TZQe19jEA4NwBZOyK2ksTis8iycX
HUM4WW8Velo8O+OtygAbwISr2dILKvkclTLn9kgfpN5esvBvJu4K+xA5T5alDchc
PY3FFeZteQf3GX4v0EH8K3c/q8OcQFMxuRGO31uYGqNbjbOB7zdZVs3N0B1m1efv
vhCgZ6gyxlz0kiozgO6Sx5WFOzHuTlguCK+x0JOtzCokRL/VLiPzmW5Umt280eJz
AlD7u7Dah3khoqDkzXfCL1lxch9tRMVMUYWRMayxC3iculCFM6OCLgzY9hay5y1j
WP1ZOdy/x9jKPoLv5USnw0KlH4rZIHH+aDMDEzWmWUWYDpShylG7sKafXg75bnho
5LbAfCucnDrkjN+rx1dxaKrZswQlIJ8iZ5Q6DzHnDzl4TaFcN1E3exS+xp46H7va
SbR94UfpCyjpTQ2hHdOS7XHINFUDIzWF3mUZ8gqyEANiqpgJ+RcOGX66s69oILpr
vD20SIdMHWDqJH3G6GMNsg1g5/QU
=YrcG
-----END PGP SIGNATURE-----

✓ Verified

File: src/main/resources/static/js/notifications.js

1 // Notification System - Replaces alerts and confirms
2
3 /**
4 * Show a notification message
5 * @param {string} message - The message to display
6 * @param {string} type - 'success', 'error', 'warning', 'info'
7 * @param {number} duration - Auto-close duration in ms (0 = don't auto-close)
8 */
9 function showNotification(message, type = 'info', duration = 5000) {
10 const container = document.getElementById('notificationContainer');
11 if (!container) {
12 console.warn('Notification container not found');
13 return;
14 }
15
16 const notification = document.createElement('div');
17 notification.className = `notification ${type}`;
18
19 const titles = {
20 success: 'Success',
21 error: 'Error',
22 warning: 'Warning',
23 info: 'Info'
24 };
25
26 notification.innerHTML = `
27 <div class="notification-content">
28 <div class="notification-title">${titles[type] || 'Notification'}</div>
29 <div class="notification-message">${escapeHtml(message)}</div>
30 </div>
31 <button class="notification-close" onclick="this.parentElement.remove()" aria-label="Close">&times;</button>
32 `;
33
34 container.appendChild(notification);
35
36 // Auto-remove after duration
37 if (duration > 0) {
38 setTimeout(() => {
39 if (notification.parentElement) {
40 notification.style.animation = 'slideInRight 0.3s ease-out reverse';
41 setTimeout(() => notification.remove(), 300);
42 }
43 }, duration);
44 }
45
46 return notification;
47 }
48
49 /**
50 * Show a confirmation dialog
51 * @param {string} message - The message to display
52 * @param {string} title - The dialog title
53 * @returns {Promise<boolean>} - Resolves to true if confirmed, false if cancelled
54 */
55 function showConfirm(message, title = 'Confirm') {
56 return new Promise((resolve) => {
57 const overlay = document.createElement('div');
58 overlay.className = 'confirm-dialog-overlay';
59
60 overlay.innerHTML = `
61 <div class="confirm-dialog">
62 <div class="confirm-dialog-title">${escapeHtml(title)}</div>
63 <div class="confirm-dialog-message">${escapeHtml(message)}</div>
64 <div class="confirm-dialog-actions">
65 <button class="btn-cancel" onclick="this.closest('.confirm-dialog-overlay').remove(); window.__confirmResolve__(false);">Cancel</button>
66 <button class="btn-confirm" onclick="this.closest('.confirm-dialog-overlay').remove(); window.__confirmResolve__(true);">Confirm</button>
67 </div>
68 </div>
69 `;
70
71 document.body.appendChild(overlay);
72
73 // Store resolve function globally temporarily
74 window.__confirmResolve__ = resolve;
75
76 // Close on overlay click (outside dialog)
77 overlay.addEventListener('click', (e) => {
78 if (e.target === overlay) {
79 overlay.remove();
80 resolve(false);
81 }
82 });
83 });
84 }
85
86 function escapeHtml(text) {
87 const div = document.createElement('div');
88 div.textContent = text;
89 return div.innerHTML;
90 }
91
92 /**
93 * Show a prompt dialog with input field
94 * @param {string} message - The message to display
95 * @param {string} title - The dialog title
96 * @param {string} defaultValue - Default input value
97 * @param {string} placeholder - Input placeholder
98 * @returns {Promise<string|null>} - Resolves to input value if confirmed, null if cancelled
99 */
100 function showPrompt(message, title = 'Input', defaultValue = '', placeholder = '') {
101 return new Promise((resolve) => {
102 const overlay = document.createElement('div');
103 overlay.className = 'confirm-dialog-overlay';
104
105 overlay.innerHTML = `
106 <div class="confirm-dialog" style="max-width: 500px;">
107 <div class="confirm-dialog-title">${escapeHtml(title)}</div>
108 <div class="confirm-dialog-message">${escapeHtml(message)}</div>
109 <div style="margin-bottom: 1.5rem;">
110 <input type="text" id="promptInput" class="form-group input" style="width: 100%; padding: 0.875rem; border: 2px solid var(--border-color); border-radius: 10px; font-size: 1rem;" value="${escapeHtml(defaultValue)}" placeholder="${escapeHtml(placeholder)}" autofocus>
111 </div>
112 <div class="confirm-dialog-actions">
113 <button class="btn-cancel" onclick="this.closest('.confirm-dialog-overlay').remove(); window.__promptResolve__(null);">Cancel</button>
114 <button class="btn-confirm" onclick="const input = document.getElementById('promptInput'); this.closest('.confirm-dialog-overlay').remove(); window.__promptResolve__(input.value);">Confirm</button>
115 </div>
116 </div>
117 `;
118
119 document.body.appendChild(overlay);
120
121 // Store resolve function globally temporarily
122 window.__promptResolve__ = resolve;
123
124 // Focus input
125 setTimeout(() => {
126 const input = document.getElementById('promptInput');
127 if (input) {
128 input.focus();
129 input.select();
130 }
131 }, 100);
132
133 // Handle Enter key
134 const input = document.getElementById('promptInput');
135 if (input) {
136 input.addEventListener('keypress', (e) => {
137 if (e.key === 'Enter') {
138 overlay.remove();
139 resolve(input.value);
140 }
141 });
142 }
143
144 // Close on overlay click (outside dialog)
145 overlay.addEventListener('click', (e) => {
146 if (e.target === overlay) {
147 overlay.remove();
148 resolve(null);
149 }
150 });
151
152 // Handle Escape key
153 const handleEscape = (e) => {
154 if (e.key === 'Escape') {
155 overlay.remove();
156 resolve(null);
157 document.removeEventListener('keydown', handleEscape);
158 }
159 };
160 document.addEventListener('keydown', handleEscape);
161 });
162 }
163
164 // Make functions globally available
165 window.showNotification = showNotification;
166 window.showConfirm = showConfirm;
167 window.showPrompt = showPrompt;
168