mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-09 20:15:07 +00:00
feat(ui): polish email modal, search loading, and volume tables
Move profile email change into a modal with Alpine focus/close handling, show a loading overlay during command-palette navigation, and adjust volumes/config-diff grids plus related service/storage UI. Cover with feature tests for search, profile, storage, and domains.
This commit is contained in:
1 parent
a7a06aa6c8
commit
0312cc8ffb
18 files changed
+236
-109
No files matched your search
@@ -60,6 +60,7 @@ it('renders frontend-only application backup search data for volume names and fr
|
||||
->assertSee('Target A–Z')
|
||||
->assertSee('filterOpen')
|
||||
->assertSee('sortOpen')
|
||||
->assertDontSee('class="font-mono text-xs">daily', false)
|
||||
->assertDontSee('backup-type-filter-trigger', false)
|
||||
->assertDontSee('backup-sort-trigger', false);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
it('shows a loading overlay while resource selection steps load', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/global-search.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('wire:loading.class="pointer-events-none opacity-40 blur-[2px]"')
|
||||
->toContain('wire:loading.flex')
|
||||
->toContain('selectServer,selectDestination,selectProject,selectEnvironment')
|
||||
->toContain('Loading selection…')
|
||||
->toContain('isPaletteTransitioning')
|
||||
->toContain('runPaletteTransition')
|
||||
->toContain('Loading…');
|
||||
});
|
||||
@@ -131,6 +131,12 @@ it('uses the same eye-off2 icon in configuration changes expand toggle', functio
|
||||
->not->toContain('M22.2954 6.31083');
|
||||
});
|
||||
|
||||
it('uses a wide configuration changes dialog', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/shared/configuration-checker.blade.php'));
|
||||
|
||||
expect($view)->toContain('max-w-6xl');
|
||||
});
|
||||
|
||||
it('renders env var password input before visibility toggle in tab order', function () {
|
||||
$html = Blade::render('<x-forms.env-var-input type="password" id="secret" />');
|
||||
|
||||
|
||||
@@ -118,7 +118,9 @@ it('batches volume backup meta and exposes forms for every volume', function ()
|
||||
$component = Livewire::test(All::class, ['resource' => $application]);
|
||||
|
||||
expect($component->get('volumeBackupMeta'))->toHaveCount(5)
|
||||
->and($component->get('forms'))->toHaveCount(5);
|
||||
->and($component->get('forms'))->toHaveCount(5)
|
||||
->and($component->html())->toContain('volumes-col-backup')
|
||||
->not->toContain('table-badge table-badge-success');
|
||||
|
||||
foreach ($component->get('volumeBackupMeta') as $meta) {
|
||||
expect($meta['enabled'])->toBeTrue()
|
||||
|
||||
@@ -101,13 +101,15 @@ it('renders volumes as a data table with shared column headers', function () {
|
||||
->toContain('Volume Name')
|
||||
->toContain('Source Path')
|
||||
->toContain('Destination Path')
|
||||
->toContain('volumes-col-backup')
|
||||
->toContain('supportsPreviewSuffix')
|
||||
->toContain('openBackupModal')
|
||||
->toContain('data-table-row')
|
||||
->toContain('volumes-mobile-label')
|
||||
->toContain('table-badge-success')
|
||||
->not->toContain('table-badge table-badge-success')
|
||||
->not->toContain('livewire:project.shared.storages.show')
|
||||
->not->toContain('x-status-badge');
|
||||
->not->toContain('x-status-badge')
|
||||
->not->toContain('Service volume mounts are read-only here.');
|
||||
|
||||
// Show remains available for isolated embeds/tests but is no longer nested from All.
|
||||
expect($showView)
|
||||
@@ -118,7 +120,16 @@ it('renders volumes as a data table with shared column headers', function () {
|
||||
expect($storageView)
|
||||
->toContain('Str::headline($resource->name)')
|
||||
->toContain(':flush="true"')
|
||||
->toContain('storage-service-');
|
||||
->toContain("'storage-service-'.\$resource->uuid");
|
||||
|
||||
$serviceConfigurationView = file_get_contents(resource_path('views/livewire/project/service/configuration.blade.php'));
|
||||
|
||||
expect($serviceConfigurationView)
|
||||
->toContain('storageSections')
|
||||
->toContain('menu-subitem')
|
||||
->toContain('scrollToSettingsSection')
|
||||
->toContain('Service volume mounts are read-only here.')
|
||||
->toContain("'storage-service-'.\$resource->uuid");
|
||||
|
||||
$css = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
@@ -131,6 +142,8 @@ it('renders volumes as a data table with shared column headers', function () {
|
||||
->toContain('@media (max-width: 768px)')
|
||||
->toContain('.table-badge-success');
|
||||
|
||||
expect($css)->toContain('17.5rem');
|
||||
|
||||
// Settings form labels are 13px (not Tailwind text-sm 14px).
|
||||
expect($css)
|
||||
->toMatch('/\.application-settings-form label\s*\{[^}]*font-size:\s*13px/s');
|
||||
|
||||
@@ -17,6 +17,22 @@ it('adds profile navigation with an appearance tab and route', function () {
|
||||
->not->toContain('<h1>Profile</h1>\n <div class="subtitle -mt-2">');
|
||||
});
|
||||
|
||||
it('opens the email change form without a Livewire request', function () {
|
||||
$profileView = file_get_contents(resource_path('views/livewire/profile/index.blade.php'));
|
||||
|
||||
expect($profileView)
|
||||
->toContain('@click="openEmailModal()"')
|
||||
->toContain('this.$refs.newEmailInput?.focus()')
|
||||
->toContain('x-ref="newEmailInput"')
|
||||
->toContain('x-show="emailModalOpen"')
|
||||
->toContain('x-teleport="body"')
|
||||
->toContain('Change email')
|
||||
->toContain('Send code')
|
||||
->toContain('Verify email')
|
||||
->not->toContain('>Cancel</x-forms.button>')
|
||||
->not->toContain('wire:click="showEmailChangeForm"');
|
||||
});
|
||||
|
||||
it('keeps color theme preferences on the profile appearance view without page width or density controls', function () {
|
||||
$appearanceView = file_get_contents(resource_path('views/livewire/profile/appearance.blade.php'));
|
||||
|
||||
|
||||
@@ -185,7 +185,8 @@ it('auto-adds the suggested www pair when adding a service domain with both dire
|
||||
->set('newDomain', 'https://web.example.com')
|
||||
->call('addDomain')
|
||||
->assertHasNoErrors()
|
||||
->assertDispatched('success');
|
||||
->assertDispatched('success')
|
||||
->assertSee('DNS skipped');
|
||||
|
||||
expect(explode(',', (string) $this->webApp->fresh()->fqdn))
|
||||
->toContain('https://web.example.com')
|
||||
@@ -203,6 +204,22 @@ it('adds a domain to a selected service application', function () {
|
||||
$this->webApp->refresh();
|
||||
expect(explode(',', (string) $this->webApp->fqdn))
|
||||
->toBe(['https://web.example.com', 'https://www.web.example.com']);
|
||||
|
||||
$dnsStatuses = $this->webApp->domain_dns_statuses;
|
||||
|
||||
expect($dnsStatuses)
|
||||
->toHaveKey('https://web.example.com')
|
||||
->toHaveKey('https://www.web.example.com')
|
||||
->and($dnsStatuses['https://web.example.com']['status'])
|
||||
->toBe('skipped')
|
||||
->and($dnsStatuses['https://web.example.com']['checked_at'])
|
||||
->not->toBeNull();
|
||||
});
|
||||
|
||||
it('does not duplicate the service name as a badge in the domain cell', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/service/partials/domain-table.blade.php'));
|
||||
|
||||
expect($view)->not->toContain('domains-service-mobile table-badge');
|
||||
});
|
||||
|
||||
it('rolls back a domain change when compose regeneration fails', function () {
|
||||
@@ -273,7 +290,9 @@ it('prunes the previous dns status when a service domain is renamed', function (
|
||||
$this->apiApp->refresh();
|
||||
|
||||
expect($this->apiApp->fqdn)->toBe('https://renamed.example.com')
|
||||
->and($this->apiApp->domain_dns_statuses)->toBeNull();
|
||||
->and($this->apiApp->domain_dns_statuses)->not->toHaveKey('https://api.example.com')
|
||||
->and($this->apiApp->domain_dns_statuses)->toHaveKey('https://renamed.example.com')
|
||||
->and($this->apiApp->domain_dns_statuses['https://renamed.example.com']['status'])->toBe('skipped');
|
||||
});
|
||||
|
||||
it('does not restore stale dns status when a removed service domain is re-added', function () {
|
||||
@@ -392,8 +411,7 @@ it('hides dns message text when service domain dns status is ok', function () {
|
||||
|
||||
Livewire::test(Domains::class, ['service' => $this->service->fresh(['applications', 'server'])])
|
||||
->assertSee('DNS OK')
|
||||
->assertDontSee('DNS points to 203.0.113.10')
|
||||
->assertDontSee('Last checked');
|
||||
->assertDontSee('DNS points to 203.0.113.10');
|
||||
});
|
||||
|
||||
it('forbids read-only users from checking service domain dns', function (string $action, array $parameters) {
|
||||
|
||||
Reference in new issue
Block a user