fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -6,6 +6,8 @@
*/
import { UIManager } from '../ui/UIManager.js';
import { ToastQueue } from './ToastQueue.js';
import { ModalManager } from './ModalManager.js';
export class LiveComponentUIHelper {
constructor(liveComponentManager) {
@@ -13,6 +15,11 @@ export class LiveComponentUIHelper {
this.uiManager = UIManager;
this.activeDialogs = new Map(); // componentId → dialog instances
this.activeNotifications = new Map(); // componentId → notification instances
this.toastQueue = new ToastQueue(5); // Max 5 toasts
// Use ModalManager with native <dialog> element
// Native <dialog> provides automatic backdrop, focus management, and ESC handling
this.modalManager = new ModalManager();
}
/**
@@ -34,27 +41,29 @@ export class LiveComponentUIHelper {
onConfirm = null
} = options;
// Create dialog content
const dialogContent = this.createDialogContent(title, content, buttons, {
onClose,
onConfirm
});
// Show modal via UIManager
const modal = this.uiManager.open('modal', {
content: dialogContent,
className: `livecomponent-dialog livecomponent-dialog--${size}`,
onClose: () => {
if (onClose) {
onClose();
}
this.activeDialogs.delete(componentId);
}
// Use ModalManager for better stack management
const modal = this.modalManager.open(componentId, {
title: title,
content: content,
size: size,
buttons: buttons,
closeOnBackdrop: closeOnBackdrop,
closeOnEscape: closeOnEscape
});
// Store reference
this.activeDialogs.set(componentId, modal);
// Setup onClose callback
if (onClose && modal.dialog) {
const originalClose = modal.close;
modal.close = () => {
originalClose.call(modal);
onClose();
this.activeDialogs.delete(componentId);
};
}
return modal;
}
@@ -142,11 +151,9 @@ export class LiveComponentUIHelper {
* @param {string} componentId - Component ID
*/
closeDialog(componentId) {
const dialog = this.activeDialogs.get(componentId);
if (dialog && typeof dialog.close === 'function') {
dialog.close();
this.activeDialogs.delete(componentId);
}
// Use ModalManager to close
this.modalManager.close(componentId);
this.activeDialogs.delete(componentId);
}
/**
@@ -164,74 +171,20 @@ export class LiveComponentUIHelper {
action = null
} = options;
// Create notification element
const notification = document.createElement('div');
notification.className = `livecomponent-notification livecomponent-notification--${type} livecomponent-notification--${position}`;
notification.setAttribute('role', 'alert');
notification.setAttribute('aria-live', 'polite');
notification.innerHTML = `
<div class="notification-content">
<span class="notification-message">${message}</span>
${action ? `<button class="notification-action">${action.text}</button>` : ''}
<button class="notification-close" aria-label="Close">×</button>
</div>
`;
// Add styles
notification.style.cssText = `
position: fixed;
${position.includes('top') ? 'top' : 'bottom'}: 1rem;
${position.includes('left') ? 'left' : 'right'}: 1rem;
max-width: 400px;
padding: 1rem;
background: ${this.getNotificationColor(type)};
color: white;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
z-index: 10000;
opacity: 0;
transform: translateY(${position.includes('top') ? '-20px' : '20px'});
transition: opacity 0.3s ease, transform 0.3s ease;
`;
// Add to DOM
document.body.appendChild(notification);
// Animate in
requestAnimationFrame(() => {
notification.style.opacity = '1';
notification.style.transform = 'translateY(0)';
// Use ToastQueue for better management
const toast = this.toastQueue.add(componentId, {
message: message,
type: type,
duration: duration,
position: position
});
// Setup close button
const closeBtn = notification.querySelector('.notification-close');
closeBtn.addEventListener('click', () => {
this.hideNotification(notification);
});
// Setup action button
if (action) {
const actionBtn = notification.querySelector('.notification-action');
actionBtn.addEventListener('click', () => {
if (action.handler) {
action.handler();
}
this.hideNotification(notification);
});
// Store reference for compatibility
if (toast) {
this.activeNotifications.set(componentId, toast);
}
// Auto-hide after duration
if (duration > 0) {
setTimeout(() => {
this.hideNotification(notification);
}, duration);
}
// Store reference
this.activeNotifications.set(componentId, notification);
return notification;
return toast;
}
/**
@@ -240,31 +193,17 @@ export class LiveComponentUIHelper {
* @param {HTMLElement|string} notificationOrComponentId - Notification element or component ID
*/
hideNotification(notificationOrComponentId) {
const notification = typeof notificationOrComponentId === 'string'
? this.activeNotifications.get(notificationOrComponentId)
: notificationOrComponentId;
const componentId = typeof notificationOrComponentId === 'string'
? notificationOrComponentId
: notificationOrComponentId.dataset?.componentId;
if (!notification) {
if (!componentId) {
return;
}
// Animate out
notification.style.opacity = '0';
notification.style.transform = `translateY(${notification.classList.contains('livecomponent-notification--top') ? '-20px' : '20px'})`;
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
// Remove from map
for (const [componentId, notif] of this.activeNotifications.entries()) {
if (notif === notification) {
this.activeNotifications.delete(componentId);
break;
}
}
}, 300);
// Use ToastQueue to remove
this.toastQueue.remove(componentId);
this.activeNotifications.delete(componentId);
}
/**