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

@@ -82,7 +82,7 @@
<div class="admin-section">
<h2>PHP Erweiterungen</h2>
<div class="extensions-list">
<?php foreach($stats['loadedExtensions'] as $extension): ?>
<?php foreach ($stats['loadedExtensions'] as $extension): ?>
<span class="extension-badge"><?= $extension ?></span>
<?php endforeach; ?>
</div>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $title ?></title>
<title>{{ title }}</title>
<link rel="stylesheet" href="/css/admin.css">
</head>
<body class="admin-page">
@@ -42,18 +42,18 @@
</tr>
</thead>
<tbody>
<?php foreach($env as $key => $value): ?>
<tr>
<td><?= $key ?></td>
<td><?= is_array($value) ? json_encode($value) : $value ?></td>
</tr>
<?php endforeach; ?>
<for var="envVar" in="env">
<tr>
<td>{{ envVar.key }}</td>
<td>{{ envVar.value }}</td>
</tr>
</for>
</tbody>
</table>
</div>
<div class="admin-footer">
<p>&copy; <?= date('Y') ?> Framework Admin</p>
<p>&copy; {{ current_year }} Framework Admin</p>
</div>
<script>

View File

@@ -0,0 +1,250 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Manager</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<h1>Image Manager</h1>
<div class="row">
<!-- Image Slots Section -->
<div class="col-md-6">
<h2>Image Slots</h2>
<div id="image-slots" class="list-group">
<for var="slot" in="slots">
<div class="list-group-item slot-item" data-slot-id="{{ slot.id }}">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5>{{ slot.slotName }}</h5>
<small class="text-muted">ID: {{ slot.id }}</small>
</div>
<div class="slot-image-container" style="width: 100px; height: 100px;">
<div class="border border-dashed d-flex align-items-center justify-content-center h-100"
ondrop="handleDrop(event, '{{ slot.id }}')"
ondragover="handleDragOver(event)"
ondragleave="handleDragLeave(event)">
<span class="text-muted">Drop image here or click to select</span>
</div>
</div>
</div>
</div>
</for>
</div>
</div>
<!-- Available Images Section -->
<div class="col-md-6">
<h2>Available Images</h2>
<!-- Search Bar -->
<div class="mb-3">
<input type="text"
id="image-search"
class="form-control"
placeholder="Search images..."
onkeyup="searchImages()">
</div>
<!-- Images Grid -->
<div id="images-grid" class="row g-2">
<for var="image" in="images">
<div class="col-md-4 image-item"
data-filename="{{ image.originalFilename }}"
data-alt="{{ image.altText }}">
<div class="card">
<img src="/media/images/{{ image.path }}"
alt="{{ image.altText }}"
class="card-img-top"
style="height: 150px; object-fit: cover; cursor: move;"
draggable="true"
ondragstart="handleDragStart(event, '{{ image.ulid }}')"
onclick="selectImage('{{ image.ulid }}')">
<div class="card-body p-2">
<small class="text-truncate d-block">
{{ image.originalFilename }}
</small>
<small class="text-muted">
{{ image.width }}x{{ image.height }} {{ image.fileSize }}KB
</small>
</div>
</div>
</div>
</for>
</div>
</div>
</div>
</div>
<!-- Image Selection Modal -->
<div class="modal fade" id="imageSelectModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Select Image for <span id="modal-slot-name"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div id="modal-images" class="row g-2">
<!-- Images will be loaded here -->
</div>
</div>
</div>
</div>
</div>
<script>
// Current dragging image
let draggedImageUlid = null;
let selectedSlotId = null;
// Handle drag start
function handleDragStart(event, imageUlid) {
draggedImageUlid = imageUlid;
event.dataTransfer.effectAllowed = 'copy';
}
// Handle drag over
function handleDragOver(event) {
event.preventDefault();
event.currentTarget.classList.add('bg-light');
}
// Handle drag leave
function handleDragLeave(event) {
event.currentTarget.classList.remove('bg-light');
}
// Handle drop
async function handleDrop(event, slotId) {
event.preventDefault();
event.currentTarget.classList.remove('bg-light');
if (draggedImageUlid) {
await assignImageToSlot(slotId, draggedImageUlid);
}
}
// Assign image to slot
async function assignImageToSlot(slotId, imageUlid) {
try {
const response = await fetch(`/api/image-slots/${slotId}/image`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ image_ulid: imageUlid })
});
if (response.ok) {
location.reload(); // Simple reload for now
} else {
alert('Failed to assign image');
}
} catch (error) {
console.error('Error:', error);
alert('Error assigning image');
}
}
// Remove image from slot
async function removeImage(slotId) {
if (!confirm('Remove image from this slot?')) return;
try {
const response = await fetch(`/api/image-slots/${slotId}/image`, {
method: 'DELETE'
});
if (response.ok) {
location.reload();
} else {
alert('Failed to remove image');
}
} catch (error) {
console.error('Error:', error);
alert('Error removing image');
}
}
// Select image (click handler)
function selectImage(imageUlid) {
// Find which slot was clicked if any
const clickedSlot = document.querySelector('.slot-item.selecting');
if (clickedSlot) {
const slotId = clickedSlot.dataset.slotId;
assignImageToSlot(slotId, imageUlid);
clickedSlot.classList.remove('selecting');
}
}
// Search images
function searchImages() {
const searchTerm = document.getElementById('image-search').value.toLowerCase();
const imageItems = document.querySelectorAll('.image-item');
imageItems.forEach(item => {
const filename = item.dataset.filename.toLowerCase();
const alt = item.dataset.alt.toLowerCase();
if (filename.includes(searchTerm) || alt.includes(searchTerm)) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
}
// Add click handler to slots for selection mode
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.slot-item').forEach(slot => {
const container = slot.querySelector('.slot-image-container');
if (container && !container.querySelector('img')) {
container.style.cursor = 'pointer';
container.addEventListener('click', function() {
// Remove previous selection
document.querySelectorAll('.slot-item').forEach(s => s.classList.remove('selecting'));
// Mark as selecting
slot.classList.add('selecting');
// Highlight available images
document.getElementById('images-grid').classList.add('selecting-mode');
});
}
});
});
// Add some CSS
const style = document.createElement('style');
style.textContent = `
.slot-item.selecting {
border: 2px solid #0d6efd;
background-color: #e7f1ff;
}
.selecting-mode .card {
cursor: pointer;
}
.selecting-mode .card:hover {
border-color: #0d6efd;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}
.border-dashed {
border-style: dashed !important;
}
.object-fit-cover {
object-fit: cover;
}
`;
document.head.appendChild(style);
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $title ?></title>
<title>{{ title }}</title>
<link rel="stylesheet" href="/css/admin.css">
</head>
<body class="admin-page">
@@ -25,68 +25,68 @@
<div class="dashboard-stats">
<div class="stat-box">
<h3>Aktueller Speicherverbrauch</h3>
<div class="stat-value"><?= $performance['currentMemoryUsage'] ?></div>
<div class="stat-value">{{ performance.currentMemoryUsage }}</div>
</div>
<div class="stat-box">
<h3>Maximaler Speicherverbrauch</h3>
<div class="stat-value"><?= $performance['peakMemoryUsage'] ?></div>
<div class="stat-value">{{ performance.peakMemoryUsage }}</div>
</div>
<div class="stat-box">
<h3>Speicherlimit</h3>
<div class="stat-value"><?= $performance['memoryLimit'] ?></div>
<div class="stat-value">{{ performance.memoryLimit }}</div>
</div>
<div class="stat-box">
<h3>Speicherauslastung</h3>
<div class="stat-value">
<div class="progress-bar">
<div class="progress" style="width: <?= $performance['memoryUsagePercentage'] ?>%"></div>
<div class="progress" style="width: {{ performance.memoryUsagePercentage }}%"></div>
</div>
<div class="progress-value"><?= $performance['memoryUsagePercentage'] ?>%</div>
<div class="progress-value">{{ performance.memoryUsagePercentage }}%</div>
</div>
</div>
<div class="stat-box">
<h3>Systemlast (1/5/15 min)</h3>
<div class="stat-value">
<?= $performance['loadAverage'][0] ?> /
<?= $performance['loadAverage'][1] ?> /
<?= $performance['loadAverage'][2] ?>
{{ performance.loadAverage.0 }} /
{{ performance.loadAverage.1 }} /
{{ performance.loadAverage.2 }}
</div>
</div>
<div class="stat-box">
<h3>OPCache aktiviert</h3>
<div class="stat-value"><?= $performance['opcacheEnabled'] ?></div>
<div class="stat-value">{{ performance.opcacheEnabled }}</div>
</div>
<?php if (isset($performance['opcacheMemoryUsage'])): ?>
<div class="stat-box">
<h3>OPCache Speicherverbrauch</h3>
<div class="stat-value"><?= $performance['opcacheMemoryUsage'] ?></div>
</div>
<div if="performance.opcacheMemoryUsage">
<div class="stat-box">
<h3>OPCache Speicherverbrauch</h3>
<div class="stat-value">{{ performance.opcacheMemoryUsage }}</div>
</div>
<div class="stat-box">
<h3>OPCache Cache Hits</h3>
<div class="stat-value"><?= $performance['opcacheCacheHits'] ?></div>
</div>
<div class="stat-box">
<h3>OPCache Cache Hits</h3>
<div class="stat-value">{{ performance.opcacheCacheHits }}</div>
</div>
<div class="stat-box">
<h3>OPCache Miss Rate</h3>
<div class="stat-value"><?= $performance['opcacheMissRate'] ?></div>
<div class="stat-box">
<h3>OPCache Miss Rate</h3>
<div class="stat-value">{{ performance.opcacheMissRate }}</div>
</div>
</div>
<?php endif; ?>
<div class="stat-box">
<h3>Ausführungszeit</h3>
<div class="stat-value"><?= $performance['executionTime'] ?></div>
<div class="stat-value">{{ performance.executionTime }}</div>
</div>
<div class="stat-box">
<h3>Geladene Dateien</h3>
<div class="stat-value"><?= $performance['includedFiles'] ?></div>
<div class="stat-value">{{ performance.includedFiles }}</div>
</div>
</div>
@@ -97,17 +97,17 @@
</div>
<div class="file-list" id="fileList">
<?php foreach(get_included_files() as $file): ?>
<div class="file-item">
<?= $file ?>
</div>
<?php endforeach; ?>
<for var="file" in="performance.files">
<div class="file-item">
{{ file }}
</div>
</for>
</div>
</div>
</div>
<div class="admin-footer">
<p>&copy; <?= date('Y') ?> Framework Admin</p>
<p>&copy; {{ current_year }} Framework Admin</p>
</div>
<script>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $title ?></title>
<title>{{ title }}</title>
<link rel="stylesheet" href="/css/admin.css">
</head>
<body class="admin-page">
@@ -22,72 +22,61 @@
</div>
<div class="admin-content">
<?php if (isset($redis['status']) && $redis['status'] === 'Verbunden'): ?>
<div class="dashboard-stats">
<div class="stat-box">
<h3>Status</h3>
<div class="stat-value status-connected"><?= $redis['status'] ?></div>
</div>
<div class="stat-box">
<h3>Version</h3>
<div class="stat-value"><?= $redis['version'] ?></div>
</div>
<div class="stat-box">
<h3>Uptime</h3>
<div class="stat-value"><?= $redis['uptime'] ?></div>
</div>
<div class="stat-box">
<h3>Speicherverbrauch</h3>
<div class="stat-value"><?= $redis['memory'] ?></div>
</div>
<div class="stat-box">
<h3>Max. Speicherverbrauch</h3>
<div class="stat-value"><?= $redis['peak_memory'] ?></div>
</div>
<div class="stat-box">
<h3>Verbundene Clients</h3>
<div class="stat-value"><?= $redis['clients'] ?></div>
</div>
<div class="stat-box">
<h3>Anzahl Schlüssel</h3>
<div class="stat-value"><?= $redis['keys'] ?></div>
</div>
<div class="dashboard-stats">
<div class="stat-box">
<h3>Status</h3>
<div class="stat-value status-connected">{{ redis.status }}</div>
</div>
<div class="admin-section">
<h2>Schlüssel (max. 50 angezeigt)</h2>
<div class="admin-tools">
<input type="text" id="keyFilter" placeholder="Schlüssel filtern..." class="search-input">
</div>
<div class="stat-box">
<h3>Version</h3>
<div class="stat-value">{{ redis.version }}</div>
</div>
<div class="key-list" id="keyList">
<?php if (empty($redis['key_sample'])): ?>
<div class="empty-message">Keine Schlüssel vorhanden</div>
<?php else: ?>
<?php foreach($redis['key_sample'] as $key): ?>
<div class="key-item">
<?= $key ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="stat-box">
<h3>Uptime</h3>
<div class="stat-value">{{ redis.uptime }}</div>
</div>
<?php else: ?>
<div class="error-message">
<h2>Redis-Verbindung fehlgeschlagen</h2>
<p><?= $redis['status'] ?? 'Unbekannter Fehler' ?></p>
<div class="stat-box">
<h3>Speicherverbrauch</h3>
<div class="stat-value">{{ redis.memory }}</div>
</div>
<?php endif; ?>
<div class="stat-box">
<h3>Max. Speicherverbrauch</h3>
<div class="stat-value">{{ redis.peak_memory }}</div>
</div>
<div class="stat-box">
<h3>Verbundene Clients</h3>
<div class="stat-value">{{ redis.clients }}</div>
</div>
<div class="stat-box">
<h3>Anzahl Schlüssel</h3>
<div class="stat-value">{{ redis.keys }}</div>
</div>
</div>
<div class="admin-section">
<h2>Schlüssel (max. 50 angezeigt)</h2>
<div class="admin-tools">
<input type="text" id="keyFilter" placeholder="Schlüssel filtern..." class="search-input">
</div>
<div class="key-list" id="keyList">
<for var="key" in="redis.key_sample">
<div class="key-item">
{{ key }}
</div>
</for>
</div>
</div>
</div>
<div class="admin-footer">
<p>&copy; <?= date('Y') ?> Framework Admin</p>
<p>&copy; {{ current_year }} Framework Admin</p>
</div>
<script>

View File

@@ -37,7 +37,7 @@
</tr>
</thead>
<tbody>
<?php foreach($routes as $route): ?>
<?php foreach ($routes as $route): ?>
<tr>
<td><?= $route->path ?></td>
<td><?= $route->method ?></td>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $title ?></title>
<title>{{ title }}</title>
<link rel="stylesheet" href="/css/admin.css">
</head>
<body class="admin-page">
@@ -24,31 +24,26 @@
<div class="admin-content">
<div class="admin-tools">
<input type="text" id="serviceFilter" placeholder="Dienste filtern..." class="search-input">
<span class="services-count"><?= count($services) ?> Dienste insgesamt</span>
<span class="services-count">{{ servicesCount }} Dienste insgesamt</span>
</div>
<div class="service-list" id="serviceList">
<?php foreach($services as $service): ?>
<for var="service" in="services">
<div class="service-item">
<div class="service-name"><?= $service ?></div>
<?php
$parts = explode('\\', $service);
$category = $parts[1] ?? 'Unknown';
$subCategory = $parts[2] ?? '';
?>
<div class="service-name">{{ service.name }}</div>
<div class="service-category">
<span class="category-badge"><?= $category ?></span>
<?php if ($subCategory): ?>
<span class="subcategory-badge"><?= $subCategory ?></span>
<?php endif; ?>
<span class="category-badge">{{ service.category }}</span>
<if condition="service.subCategory">
<span class="subcategory-badge">{{ service.subCategory }}</span>
</if>
</div>
</div>
<?php endforeach; ?>
</for>
</div>
</div>
<div class="admin-footer">
<p>&copy; <?= date('Y') ?> Framework Admin</p>
<p>&copy; {{ date('Y') }} Framework Admin</p>
</div>
<script>
@@ -65,7 +60,7 @@
});
document.querySelector('.services-count').textContent =
visibleCount + ' von ' + <?= count($services) ?> + ' Diensten';
visibleCount + ' von ' + {{ servicesCount }} + ' Diensten';
});
</script>
</body>