mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 08:15:24 +00:00
feat(ui): toggle Server Timing HUD and link missing env badge
Add a local-only command palette action to show/hide the Server Timing HUD via localStorage and a visibility event. Make the service heading "Required variables missing" badge link to environment variables, with tests covering both behaviors.
This commit is contained in:
1 parent
fd6dbd5863
commit
d68b198d53
6 files changed
+93
-2
No files matched your search
@@ -101,6 +101,7 @@
|
||||
window.__coolifyServerTimingHud = true;
|
||||
|
||||
const STORAGE_KEY = 'coolify.serverTimingHud.open';
|
||||
const ENABLED_STORAGE_KEY = 'coolify.serverTimingHud.enabled';
|
||||
const MAX_ENTRIES = 50;
|
||||
const MS_KEYS = new Set(['app', 'db', 'php', 'dbslow']);
|
||||
|
||||
@@ -117,6 +118,25 @@
|
||||
return document.getElementById('server-timing-hud');
|
||||
}
|
||||
|
||||
function isHudEnabled() {
|
||||
return localStorage.getItem(ENABLED_STORAGE_KEY) !== '0';
|
||||
}
|
||||
|
||||
function applyVisibilityPreference() {
|
||||
const root = rootEl();
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabled = isHudEnabled();
|
||||
root.style.display = enabled ? 'block' : 'none';
|
||||
|
||||
const slot = root.parentElement?.matches('[data-server-timing-hud-slot]') ? root.parentElement : null;
|
||||
if (slot) {
|
||||
slot.style.display = enabled ? 'flex' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function pickSlot() {
|
||||
const desktop = document.getElementById('server-timing-hud-slot');
|
||||
const mobile = document.getElementById('server-timing-hud-slot-mobile');
|
||||
@@ -306,6 +326,7 @@
|
||||
applyFloatStyles(keep);
|
||||
}
|
||||
applyOpenState();
|
||||
applyVisibilityPreference();
|
||||
return keep;
|
||||
}
|
||||
|
||||
@@ -960,6 +981,7 @@
|
||||
}
|
||||
});
|
||||
window.addEventListener('resize', redock);
|
||||
window.addEventListener('server-timing-hud-visibility-changed', redock);
|
||||
// App shell uses x-cloak; re-dock once Alpine reveals the top bar.
|
||||
document.addEventListener('alpine:initialized', redock);
|
||||
// Safety: retry a few times after load in case cloak clears late.
|
||||
|
||||
@@ -14,6 +14,21 @@
|
||||
const ua = navigator.userAgent || '';
|
||||
return /Mac|iPhone|iPad|iPod/i.test(platform) || /Mac OS X|Macintosh/i.test(ua) ? '⌘' : 'Ctrl+';
|
||||
})(),
|
||||
serverTimingHudEnabled: localStorage.getItem('coolify.serverTimingHud.enabled') !== '0',
|
||||
developerCommandsEnabled: @js(app()->environment('local')),
|
||||
|
||||
get showServerTimingCommand() {
|
||||
if (!this.developerCommandsEnabled) return false;
|
||||
const query = this.searchQuery.toLowerCase().trim();
|
||||
return query.length > 0 && ['server timing', 'timing hud', 'debug hud'].some(term => term.includes(query) || query.includes(term));
|
||||
},
|
||||
|
||||
toggleServerTimingHud() {
|
||||
this.serverTimingHudEnabled = !this.serverTimingHudEnabled;
|
||||
localStorage.setItem('coolify.serverTimingHud.enabled', this.serverTimingHudEnabled ? '1' : '0');
|
||||
window.dispatchEvent(new CustomEvent('server-timing-hud-visibility-changed'));
|
||||
this.closeModal();
|
||||
},
|
||||
|
||||
// Client-side search function
|
||||
get searchResults() {
|
||||
@@ -327,6 +342,24 @@
|
||||
|
||||
<!-- Search results -->
|
||||
<div x-show="searchQuery.length >= 1" x-cloak class="command-palette-body relative">
|
||||
@if (app()->environment('local'))
|
||||
<div x-show="showServerTimingCommand && !$wire.isSelectingResource"
|
||||
class="command-palette-section">
|
||||
<div class="command-palette-group-label">Developer tools</div>
|
||||
<button type="button" @click="toggleServerTimingHud()"
|
||||
class="search-result-item command-palette-item">
|
||||
<div class="command-palette-item-main">
|
||||
<div class="command-palette-item-title">
|
||||
<span class="command-palette-item-name">Toggle Server Timing HUD</span>
|
||||
<span class="command-palette-type-badge" x-text="serverTimingHudEnabled ? 'Enabled' : 'Disabled'"></span>
|
||||
</div>
|
||||
<div class="command-palette-item-meta"
|
||||
x-text="serverTimingHudEnabled ? 'Hide the local request timing overlay' : 'Show the local request timing overlay'"></div>
|
||||
</div>
|
||||
<x-reicon name="time-back" class="command-palette-item-chevron" />
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
<div x-show="isPaletteTransitioning" x-cloak
|
||||
class="absolute inset-0 z-30 flex items-center justify-center bg-white/50 backdrop-blur-[2px] dark:bg-black/40">
|
||||
<x-loading text="Loading…" />
|
||||
@@ -639,7 +672,7 @@
|
||||
</template>
|
||||
|
||||
<template
|
||||
x-if="searchQuery.length >= 2 && searchResults.length === 0 && filteredCreatableItems.length === 0 && !$wire.isSelectingResource && !$wire.autoOpenResource && !isLoadingInitialData">
|
||||
x-if="searchQuery.length >= 2 && searchResults.length === 0 && filteredCreatableItems.length === 0 && !showServerTimingCommand && !$wire.isSelectingResource && !$wire.autoOpenResource && !isLoadingInitialData">
|
||||
<div class="command-palette-empty">
|
||||
<p class="command-palette-empty-title">No results found</p>
|
||||
<p class="command-palette-empty-desc">
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
));
|
||||
|
||||
$serviceStatus = str($service->status ?? 'exited');
|
||||
$environmentVariablesUrl = route('project.service.environment-variables', [
|
||||
'project_uuid' => $service->environment->project->uuid,
|
||||
'environment_uuid' => $service->environment->uuid,
|
||||
'service_uuid' => $service->uuid,
|
||||
]);
|
||||
@endphp
|
||||
|
||||
<livewire:project.shared.configuration-checker :resource="$service" />
|
||||
@@ -158,6 +163,11 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<a href="{{ $environmentVariablesUrl }}" {{ wireNavigate() }}
|
||||
class="mb-3 inline-flex" aria-label="Open required environment variables">
|
||||
<x-status-badge status="Required variables missing" type="error" />
|
||||
</a>
|
||||
@endif
|
||||
|
||||
<div class="resource-heading-menus w-full">
|
||||
@@ -209,7 +219,10 @@
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@else
|
||||
<x-status-badge status="Required variables missing" type="error" />
|
||||
<a href="{{ $environmentVariablesUrl }}" {{ wireNavigate() }}
|
||||
aria-label="Open required environment variables">
|
||||
<x-status-badge status="Required variables missing" type="error" />
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -214,3 +214,16 @@ test('SERVER_TIMING_ENABLED can force server_timing on or off regardless of APP_
|
||||
expect($resolve('0', 'local'))->toBeFalse();
|
||||
expect($resolve('off', 'local'))->toBeFalse();
|
||||
});
|
||||
test('server timing HUD can be toggled from the development command center', function () {
|
||||
$hud = file_get_contents(resource_path('views/components/server-timing-hud.blade.php'));
|
||||
$commandCenter = file_get_contents(resource_path('views/livewire/global-search.blade.php'));
|
||||
|
||||
expect($hud)
|
||||
->toContain('coolify.serverTimingHud.enabled')
|
||||
->toContain('server-timing-hud-visibility-changed')
|
||||
->and($commandCenter)
|
||||
->toContain("app()->environment('local')")
|
||||
->toContain('Toggle Server Timing HUD')
|
||||
->toContain("localStorage.setItem('coolify.serverTimingHud.enabled'")
|
||||
->toContain("window.dispatchEvent(new CustomEvent('server-timing-hud-visibility-changed'))");
|
||||
});
|
||||
@@ -111,6 +111,7 @@ it('warns when a service has missing required environment variables', function (
|
||||
->assertSee('Required environment variable missing')
|
||||
->assertSee('PLUNK_API_KEY')
|
||||
->assertSee('Open environment variables');
|
||||
|
||||
});
|
||||
|
||||
it('marks the service environment variables menu when required values are missing', function () {
|
||||
|
||||
@@ -82,6 +82,15 @@ it('docks desktop resource actions in the top bar instead of floating over conte
|
||||
}
|
||||
});
|
||||
|
||||
it('links the service header missing variables warning to environment variables', function () {
|
||||
$heading = file_get_contents(resource_path('views/livewire/project/service/heading.blade.php'));
|
||||
|
||||
expect($heading)
|
||||
->toContain("route('project.service.environment-variables'")
|
||||
->toContain('Required variables missing')
|
||||
->toContain('href="{{ $environmentVariablesUrl }}"');
|
||||
});
|
||||
|
||||
it('places the account menu beside the desktop sidebar toggle while retaining it on mobile', function () {
|
||||
$layout = file_get_contents(resource_path('views/layouts/app.blade.php'));
|
||||
$navbar = file_get_contents(resource_path('views/components/navbar.blade.php'));
|
||||
|
||||
Reference in new issue
Block a user