mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 22:17:19 +00:00
feat(ui): show internal hostname and densify config UI
Add an application Internal access section that loads the running container hostname (skipped for Compose apps), densify configuration diff and popup-small defaults, dock the server-timing HUD into the mobile top bar, restyle the 2FA challenge with the auth shell, and enforce 16px mobile form fonts to prevent iOS zoom.
This commit is contained in:
1 parent
8046e5a28d
commit
4d35c63d89
22 files changed
+369
-213
No files matched your search
@@ -109,23 +109,26 @@ test('removes stale Content-Length after injecting the HUD', function () {
|
||||
expect($response->headers->has('Content-Length'))->toBeFalse();
|
||||
});
|
||||
|
||||
test('app shell exposes Server-Timing HUD dock slot in the desktop top bar only', function () {
|
||||
test('app shell exposes Server-Timing HUD dock slots in desktop and mobile top bars', function () {
|
||||
$layout = file_get_contents(resource_path('views/layouts/app.blade.php'));
|
||||
|
||||
expect($layout)
|
||||
->toContain('id="server-timing-hud-slot"')
|
||||
->toContain('data-server-timing-hud-slot')
|
||||
->not->toContain('id="server-timing-hud-slot-mobile"');
|
||||
->toContain('id="server-timing-hud-slot-mobile"')
|
||||
->toContain('data-server-timing-hud-slot');
|
||||
});
|
||||
|
||||
test('Server-Timing HUD docks on desktop only and floats on smaller viewports', function () {
|
||||
test('Server-Timing HUD docks into navbar slots and floats only as fallback', function () {
|
||||
$hud = file_get_contents(resource_path('views/components/server-timing-hud.blade.php'));
|
||||
|
||||
expect($hud)
|
||||
->toContain('server-timing-hud-slot')
|
||||
->toContain('server-timing-hud-slot-mobile')
|
||||
->toContain("matchMedia('(min-width: 1024px)')")
|
||||
->toContain('float bottom-left instead of docking')
|
||||
->not->toContain('server-timing-hud-slot-mobile');
|
||||
->toContain('floats bottom-left only if no navbar slot is available')
|
||||
// Mobile pill is compact (app ms only); full "ST · db · q" breakdown stays desktop/float.
|
||||
->toContain("parentElement.id === 'server-timing-hud-slot-mobile'")
|
||||
->toContain('compactSummary');
|
||||
});
|
||||
|
||||
test('does not inject HUD into non-HTML or fragment responses', function () {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
it('shows internal Docker access details in application general settings', function () {
|
||||
$generalSettings = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));
|
||||
$generalComponent = file_get_contents(app_path('Livewire/Project/Application/General.php'));
|
||||
$configurationSidebar = file_get_contents(resource_path('views/components/application/configuration-sidebar.blade.php'));
|
||||
|
||||
expect($generalSettings)
|
||||
->toContain('id="internal-access-section"')
|
||||
->toContain('title="Internal access"')
|
||||
->toContain('Internal hostname')
|
||||
->toContain('Docker network')
|
||||
->toContain('Exposed ports')
|
||||
->toContain('Network aliases')
|
||||
->toContain('wire:init="loadCurrentInternalHostname"')
|
||||
->toContain('$currentInternalHostname')
|
||||
->not->toContain('Changes with each deployment')
|
||||
->toContain("window.scrollToSettingsSection?.('networking-section')")
|
||||
->and($generalComponent)
|
||||
->toContain('public ?string $currentInternalHostname = null;')
|
||||
->toContain('public function loadCurrentInternalHostname(): void')
|
||||
->toContain('getCurrentApplicationContainerStatus(')
|
||||
->toContain("data_get(\$currentContainer, 'Names')")
|
||||
->and($configurationSidebar)
|
||||
->toContain("['id' => 'internal-access-section', 'label' => 'Internal access']");
|
||||
});
|
||||
|
||||
it('does not show the internal access section for Docker Compose applications', function () {
|
||||
$generalSettings = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));
|
||||
$configurationSidebar = file_get_contents(resource_path('views/components/application/configuration-sidebar.blade.php'));
|
||||
|
||||
expect($generalSettings)
|
||||
->toContain("@if (\$buildPack !== 'dockercompose')")
|
||||
->and($configurationSidebar)
|
||||
->toContain("\$isComposeApp ? null : ['id' => 'internal-access-section', 'label' => 'Internal access']");
|
||||
});
|
||||
@@ -67,7 +67,7 @@ it('renders the changed configuration labels without a second backend request',
|
||||
|
||||
Livewire::test(ConfigurationChecker::class, ['resource' => $application->refresh()])
|
||||
->assertSee('The latest configuration has not been applied')
|
||||
->assertSee('A rebuild is required.')
|
||||
->assertSee('Rebuild required.')
|
||||
->assertSee('Build command');
|
||||
|
||||
$view = file_get_contents(resource_path('views/livewire/project/shared/configuration-checker.blade.php'));
|
||||
@@ -114,7 +114,7 @@ it('shows an unapplied configuration warning after a directory mount is added',
|
||||
->dispatch('configurationChanged')
|
||||
->assertSet('isConfigurationChanged', true)
|
||||
->assertSee('The latest configuration has not been applied')
|
||||
->assertSee('Please redeploy to apply the new configuration.')
|
||||
->assertSee('Redeploy to apply.')
|
||||
->assertSee('Directory mount');
|
||||
});
|
||||
|
||||
|
||||
@@ -32,3 +32,16 @@ test('confirm password page uses the shared auth shell', function () {
|
||||
->not->toContain('bg-gray-50 dark:bg-base')
|
||||
->not->toContain('!text-5xl font-extrabold');
|
||||
});
|
||||
|
||||
test('two factor challenge page uses the shared auth shell', function () {
|
||||
$challenge = file_get_contents(resource_path('views/auth/two-factor-challenge.blade.php'));
|
||||
|
||||
expect($challenge)
|
||||
->toContain('x-auth.shell')
|
||||
->toContain('title="Coolify"')
|
||||
->toContain('x-auth.alert')
|
||||
->toContain('auth-guidance')
|
||||
->toContain('Verify and continue')
|
||||
->not->toContain('bg-gray-50 dark:bg-base')
|
||||
->not->toContain('!text-5xl font-extrabold');
|
||||
});
|
||||
@@ -21,7 +21,8 @@ it('collapses server subsystem badges into one status summary', function () {
|
||||
->toContain('wire:loading.flex wire:target="checkProxyStatus"')
|
||||
->toContain('Refreshing status')
|
||||
->toContain('<x-loading compact />')
|
||||
->toContain('name="refresh" class="size-3 opacity-70"')
|
||||
->toContain('name="refresh" class="size-2.5 opacity-70"')
|
||||
->toContain('min-h-0! h-7! gap-1.5! px-2! py-1! text-[11px]')
|
||||
->not->toContain('@click="open = false" role="menuitem"');
|
||||
|
||||
expect($badgeView)
|
||||
|
||||
@@ -34,6 +34,12 @@ it('draws a single border between the desktop sidebar and main content', functio
|
||||
->and($layout)->not->toContain('lg:border-l border-neutral-200');
|
||||
});
|
||||
|
||||
it('separates the mobile sidebar from the page with a visible border', function () {
|
||||
$layout = file_get_contents(resource_path('views/layouts/app.blade.php'));
|
||||
|
||||
expect($layout)->toContain('max-w-56 min-w-0 flex-col border-l border-neutral-200 bg-white shadow-xl dark:border-white/[0.12] dark:bg-panel');
|
||||
});
|
||||
|
||||
it('shows section titles and descriptions above settings navigation on smaller screens', function (string $view, string $title, string $description) {
|
||||
$layout = file_get_contents(resource_path("views/components/{$view}"));
|
||||
$css = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
@@ -36,6 +36,14 @@ it('renders service container statuses as shared status badges', function () {
|
||||
->not->toContain('badge-success');
|
||||
});
|
||||
|
||||
it('uses bordered status badges in the top breadcrumb', function () {
|
||||
$breadcrumb = file_get_contents(resource_path('views/components/top-breadcrumb.blade.php'));
|
||||
$borderedBadgeClasses = 'rounded-full border border-neutral-200 bg-neutral-100';
|
||||
|
||||
expect(substr_count($breadcrumb, $borderedBadgeClasses))->toBe(4)
|
||||
->and(substr_count($breadcrumb, 'rounded-full bg-neutral-100'))->toBe(0);
|
||||
});
|
||||
|
||||
it('uses a shared refresh badge for resource status refresh actions', function () {
|
||||
$statusIndex = file_get_contents(resource_path('views/components/status/index.blade.php'));
|
||||
$serviceStatus = file_get_contents(resource_path('views/components/status/services.blade.php'));
|
||||
|
||||
Reference in new issue
Block a user