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

@@ -12,6 +12,7 @@ use App\Framework\View\Contracts\StaticComponent;
use App\Framework\View\Dom\ElementNode;
use App\Framework\View\Dom\Node;
use App\Framework\View\Dom\TextNode;
use App\Framework\View\ValueObjects\UIDataAttribute;
#[ComponentName('admin-sidebar')]
final readonly class AdminSidebar implements StaticComponent
@@ -53,8 +54,9 @@ final readonly class AdminSidebar implements StaticComponent
$header = $this->buildHeader();
$navigation = $this->buildNavigation();
$footer = $this->buildFooter();
$resizeHandle = '<div class="admin-sidebar__resize-handle" aria-label="Resize sidebar"></div>';
return $header . $navigation . $footer;
return $header . $navigation . $footer . $resizeHandle;
}
private function buildHeader(): string
@@ -92,23 +94,37 @@ final readonly class AdminSidebar implements StaticComponent
private function renderSection(NavigationSection $section): string
{
$html = '<div class="admin-nav__section">';
$sectionId = $this->generateSectionId($section->name);
// Use name attribute for exclusive accordion behavior
$html = '<details class="admin-nav__section" name="admin-nav-sections" ' . UIDataAttribute::SECTION_ID->value() . '="' . $this->escape($sectionId) . '">';
if ($section->name !== '') {
$html .= '<h2 class="admin-nav__section-title">' . htmlspecialchars($section->name) . '</h2>';
$chevronIcon = '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>';
$html .= '<summary class="admin-nav__section-toggle">';
$html .= '<h2>' . htmlspecialchars($section->name) . '</h2>';
$html .= $chevronIcon;
$html .= '</summary>';
}
$html .= '<ul class="admin-nav__list" role="list">';
$html .= '<ul role="list">';
foreach ($section->items as $item) {
$html .= $this->renderItem($item);
}
$html .= '</ul></div>';
$html .= '</ul></details>';
return $html;
}
/**
* Generate a section ID from section name
*/
private function generateSectionId(string $name): string
{
return strtolower(preg_replace('/[^a-zA-Z0-9]+/', '-', trim($name)));
}
private function renderItem(NavigationItem $item): string
{
$activeState = $item->isActive($this->currentPath)
@@ -118,8 +134,8 @@ final readonly class AdminSidebar implements StaticComponent
$iconHtml = $this->renderIcon($item->icon);
return <<<HTML
<li class="admin-nav__item">
<a href="{$this->escape($item->url)}" class="admin-nav__link" {$activeState}>
<li>
<a href="{$this->escape($item->url)}" {$activeState}>
{$iconHtml}
<span>{$this->escape($item->name)}</span>
</a>
@@ -137,7 +153,7 @@ final readonly class AdminSidebar implements StaticComponent
$svgIcon = $this->getSvgIcon($icon);
if ($svgIcon !== null) {
return '<svg class="admin-nav__icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">' . $svgIcon . '</svg>';
return '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">' . $svgIcon . '</svg>';
}
// Fallback to emoji or text
@@ -183,19 +199,24 @@ final readonly class AdminSidebar implements StaticComponent
private function buildFallbackNavigation(): string
{
// Fallback to old hardcoded navigation for backward compatibility
$sectionId = $this->generateSectionId('Dashboard');
$chevronIcon = '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>';
return <<<HTML
<nav class="admin-nav">
<div class="admin-nav__section">
<h2 class="admin-nav__section-title">Dashboard</h2>
<ul class="admin-nav__list" role="list">
<li class="admin-nav__item">
<a href="/admin" class="admin-nav__link" {$this->getActiveState('/admin')}>
<details class="admin-nav__section" name="admin-nav-sections" data-section-id="{$sectionId}">
<summary class="admin-nav__section-toggle">
<h2>Dashboard</h2>
{$chevronIcon}
</summary>
<ul role="list">
<li>
<a href="/admin" {$this->getActiveState('/admin')}>
<span class="admin-nav__icon">📊</span>
<span>Overview</span>
</a>
</li>
</ul>
</div>
</details>
</nav>
HTML;
}
@@ -239,20 +260,33 @@ final readonly class AdminSidebar implements StaticComponent
if (is_array($menuData)) {
try {
return NavigationMenu::fromArray($menuData);
} catch (\Exception) {
} catch (\Exception $e) {
error_log("AdminSidebar: Failed to parse navigation menu from array: " . $e->getMessage());
return null;
}
}
// Handle JSON string
if (is_string($menuData)) {
$decoded = json_decode($menuData, true);
if (is_array($decoded)) {
try {
return NavigationMenu::fromArray($decoded);
} catch (\Exception) {
return null;
}
// Decode HTML entities first (template system escapes values in HTML attributes)
$decodedJson = html_entity_decode($menuData, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$decoded = json_decode($decodedJson, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("AdminSidebar: JSON decode error: " . json_last_error_msg() . " - Data: " . substr($decodedJson, 0, 200));
return null;
}
if (!is_array($decoded)) {
error_log("AdminSidebar: Decoded data is not an array: " . gettype($decoded));
return null;
}
try {
return NavigationMenu::fromArray($decoded);
} catch (\Exception $e) {
error_log("AdminSidebar: Failed to parse navigation menu from decoded JSON: " . $e->getMessage() . " - Data: " . json_encode($decoded));
return null;
}
}