feat(ui): add collapsible advanced settings and enlarge compose modal

Extract a shared forms collapsible for advanced SSH/build settings
across boarding, server creation, and application general. Support
larger modals with header actions, close the compose editor after
save via compose-save-finished, and cover the layout in tests.
This commit is contained in:
Andras Bacsai committed 2026-08-07 16:22:11 +02:00
1 parent 4926cdba0e
commit ada3ea354a
12 files changed
+207 -144

No files matched your search

+15 -1
View File
@@ -16,5 +16,19 @@ test('compose actions are grouped with the application details header', function
test('docker compose heading separates its title and action', function () {
$view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));
expect($view)->toContain('<div class="flex items-center gap-4">');
expect($view)
->toContain('<div x-data="{ showRaw: true }" class="mt-5">')
->toContain('<div class="flex items-center justify-between gap-4">');
});
test('onboarding uses the reusable advanced settings component', function () {
$view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php'));
$onboarding = file_get_contents(resource_path('views/livewire/boarding/index.blade.php'));
expect($view)
->toContain('id="dockerComposeCustomBuildCommand"')
->not->toContain('<x-forms.collapsible class="pt-4" content-class="grid gap-4">')
->not->toContain('The following commands are for advanced use cases.')
->and($onboarding)
->toContain('<x-forms.collapsible title="Advanced Connection Settings"');
});
+64
View File
@@ -0,0 +1,64 @@
<?php
use Illuminate\Support\Facades\Blade;
it('uses the large modal treatment for the compose editor', function () {
$view = file_get_contents(resource_path('views/livewire/project/service/stack-form.blade.php'));
$modal = file_get_contents(resource_path('views/components/modal-input.blade.php'));
expect($view)
->toContain('title="Docker Compose"')
->toContain(':isLarge="true"')
->toContain('<x-slot:headerActions>')
->toContain("\$dispatch('compose-preview-toggle')")
->toContain("\$dispatch('compose-save')")
->toContain('@compose-save-finished.window="saving = false"')
->toContain('<x-loading-on-button x-show="saving" x-cloak />')
->toContain('x-bind:disabled="saving"')
->not->toContain('name="refresh"')
->not->toContain("saving ? 'Saving...' : 'Save changes'")
->not->toContain(' :disabled="saving"')
->toContain('Preview generated Compose')
->toContain('Back to source Compose')
->toContain('Save changes')
->toContain('isHighlighted');
expect($modal)->toContain('lg:w-[95vw]! lg:max-w-7xl!');
});
it('renders the compose editor with clear guidance settings and actions', function () {
$view = file_get_contents(resource_path('views/livewire/project/service/edit-compose.blade.php'));
expect($view)
->toContain('<x-callout type="info" title="Volume names">')
->not->toContain('View the final names')
->toContain('Use plain-text editor')
->toContain('min-h-[24rem]')
->toContain('@compose-preview-toggle.window')
->toContain('@compose-save.window')
->not->toContain("finally(() => \$dispatch('compose-save-finished'))")
->not->toContain('sticky bottom-0')
->not->toContain('Cancel')
->not->toContain('Show Normal Textarea')
->not->toContain('Show Deployable Compose');
});
it('keeps the save button loading until the parent compose save finishes', function () {
$component = file_get_contents(app_path('Livewire/Project/Service/StackForm.php'));
expect($component)
->toContain('public function saveCompose($raw)')
->toContain("\$this->dispatch('compose-save-finished')");
});
it('does not show a saving notification for compose changes', function () {
$component = file_get_contents(app_path('Livewire/Project/Service/EditCompose.php'));
expect($component)->not->toContain("\$this->dispatch('info', 'Saving new docker compose...')");
});
it('keeps the saving state as an Alpine button binding', function () {
$html = Blade::render('<x-forms.button x-bind:disabled="saving">Save changes</x-forms.button>');
expect($html)->toContain('x-bind:disabled="saving"');
});
@@ -5,10 +5,7 @@ test('server creation keeps private key actions together and advanced options co
expect($view)
->toContain('class="flex items-end gap-3"')
->toContain('x-data="{ advancedOpen: false }"')
->toContain('x-show="advancedOpen" x-cloak')
->toContain('Advanced settings')
->toContain('class="flex w-full cursor-pointer items-center justify-between gap-3')
->toContain('<x-forms.collapsible class="mt-5 border-t border-neutral-200 pt-4 dark:border-white/[0.08]"')
->toContain('label="Use as a dedicated build server"')
->toContain('helper="Build servers compile applications but do not host deployments. Enabling this makes the server build-only."');
});