Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,23 +1,121 @@
// modules/ui/UIManager.js
import { Modal } from './components/Modal.js';
import { Lightbox } from './components/Lightbox.js';
import { Logger } from '../../core/logger.js';
/**
* @typedef {Object} UIComponentProps
* @property {string} [content] - HTML content for the component
* @property {Function} [onClose] - Callback when component closes
*/
/**
* Available UI components
* @type {Object<string, Function>}
*/
const components = {
modal: Modal,
lightbox: Lightbox,
};
/**
* Active component instances (singletons)
* @type {Object<string, Object>}
*/
const activeInstances = {};
/**
* UI Manager for creating and managing UI components
* @namespace UIManager
*/
export const UIManager = {
/**
* Open a UI component (reuses existing instance for singletons)
* @param {string} type - Component type (e.g., 'modal', 'lightbox')
* @param {UIComponentProps} [props={}] - Component properties
* @returns {Object|null} Component instance or null if type unknown
*/
open(type, props = {}) {
const Component = components[type];
if (!Component) {
console.warn(`[UIManager] Unknown type: ${type}`);
Logger.warn(`[UIManager] Unknown type: ${type}`);
return null;
}
// For lightbox, reuse existing instance for efficiency
if (type === 'lightbox') {
if (activeInstances.lightbox) {
Logger.info('[UIManager] Reusing existing lightbox instance');
// Update content and reopen
activeInstances.lightbox.updateContent(props.content || '');
// Always call open() to ensure it's shown, regardless of current state
activeInstances.lightbox.open();
return activeInstances.lightbox;
} else {
Logger.info('[UIManager] Creating new lightbox instance');
// Create new instance and store it
const instance = new Component({
...props,
onClose: () => {
// Don't delete the instance, just close it for reuse
Logger.info('[UIManager] Lightbox closed, instance kept for reuse');
if (props.onClose) props.onClose();
}
});
activeInstances.lightbox = instance;
instance.open();
return instance;
}
}
// For other components, create new instances
const instance = new Component(props);
instance.open();
return instance;
},
/**
* Close a UI component instance
* @param {Object} instance - Component instance to close
*/
close(instance) {
if (instance?.close) instance.close();
},
/**
* Close a component by type
* @param {string} type - Component type to close
*/
closeByType(type) {
if (activeInstances[type]) {
this.close(activeInstances[type]);
}
},
/**
* Check if a component is currently open
* @param {string} type - Component type to check
* @returns {boolean}
*/
isOpen(type) {
return activeInstances[type]?.isOpen() || false;
},
/**
* Destroy all active instances (cleanup)
*/
destroyAll() {
Object.values(activeInstances).forEach(instance => {
if (instance?.destroy) {
instance.destroy();
}
});
Object.keys(activeInstances).forEach(key => {
delete activeInstances[key];
});
}
};

View File

@@ -3,39 +3,125 @@ import {useEvent} from "../../../core/useEvent";
export class Dialog {
constructor({content = '', className = '', onClose = null} = {}) {
this.onClose = onClose;
this.className = className;
this.isOpenState = false;
this.dialog = document.createElement('dialog');
this.dialog.className = className;
this.dialog.innerHTML = `
<form method="dialog" class="${className}-content">
${content}
<button class="${className}-close" value="close">×</button>
</form>
`;
this.eventCleanup = []; // Track cleanup functions
this.updateContent(content);
this.bindEvents();
}
useEvent(this.dialog, 'click', (e) => {
const isOutside = !e.target.closest(className+'-content');
/**
* Bind event handlers to the dialog
*/
bindEvents() {
// Clean up any existing event listeners first
this.cleanupEvents();
// Store references to bound event handlers for cleanup
this.clickHandler = (e) => {
const isOutside = !e.target.closest('.' + this.className + '-content');
if (isOutside) this.close();
})
};
useEvent(this.dialog, 'cancel', (e) => {
this.cancelHandler = (e) => {
e.preventDefault();
this.close();
})
};
// Use direct event listeners instead of useEvent to avoid module-based cleanup issues
this.dialog.addEventListener('click', this.clickHandler);
this.dialog.addEventListener('cancel', this.cancelHandler);
// Store cleanup functions
this.eventCleanup = [
() => this.dialog.removeEventListener('click', this.clickHandler),
() => this.dialog.removeEventListener('cancel', this.cancelHandler)
];
}
open()
{
document.body.appendChild(this.dialog);
/**
* Clean up existing event listeners
*/
cleanupEvents() {
this.eventCleanup.forEach(cleanup => cleanup());
this.eventCleanup = [];
}
/**
* Update the content of the dialog without recreating it
* @param {string} content - New HTML content
*/
updateContent(content) {
this.dialog.innerHTML = `
<form method="dialog" class="${this.className}-content">
${content}
<button class="${this.className}-close" value="close">×</button>
</form>
`;
// No need to rebind events - they're attached to the dialog element itself
// which doesn't get replaced by innerHTML
}
open() {
// Always ensure dialog is in DOM
if (!this.dialog.parentElement) {
document.body.appendChild(this.dialog);
}
// Force close if somehow already open
if (this.dialog.hasAttribute('open') || this.dialog.open) {
this.dialog.close?.() || this.dialog.removeAttribute('open');
}
// Now open fresh
this.dialog.showModal?.() || this.dialog.setAttribute('open', '');
document.documentElement.dataset[`${this.dialog.className}Open`] = 'true';
this.isOpenState = true;
}
close()
{
this.dialog.close?.() || this.dialog.removeAttribute('open');
this.dialog.remove();
delete document.documentElement.dataset[`${this.dialog.className}Open`];
this.onClose?.();
close() {
if (this.isOpenState) {
this.dialog.close?.() || this.dialog.removeAttribute('open');
delete document.documentElement.dataset[`${this.dialog.className}Open`];
this.isOpenState = false;
// Keep dialog in DOM for reuse, just hide it
// Don't remove from DOM to enable singleton pattern
this.onClose?.();
}
}
/**
* Check if dialog is currently open (checks both state and DOM)
* @returns {boolean}
*/
isOpen() {
// Check both our internal state and the actual DOM state
const domIsOpen = this.dialog && (this.dialog.hasAttribute('open') || this.dialog.open);
// Sync our internal state with DOM reality
if (domIsOpen !== this.isOpenState) {
this.isOpenState = domIsOpen;
}
return this.isOpenState;
}
/**
* Destroy the dialog completely (for cleanup)
*/
destroy() {
if (this.isOpenState) {
this.close();
}
this.cleanupEvents();
if (this.dialog.parentElement) {
this.dialog.remove();
}
}
}

View File

@@ -1,9 +1,10 @@
import { UIManager } from './UIManager.js';
import { Logger } from '../../core/logger.js';
export function init() {
/*UIManager.open('modal', {
content: '<p>Hallo!</p><button class="modal-close">OK</button>',
onClose: () => console.log('Modal wurde geschlossen')
onClose: () => Logger.info('Modal wurde geschlossen')
});*/
}