mirror of
https://github.com/tiennm99/coolify.git
synced 2026-08-20 02:27:57 +00:00
fix(ui): polish create flows for compose and GitHub repos
Use shared listbox for private-repo selection, align listbox trigger heights with form inputs, restore compose editor spacing and full width, and wire loading states on create/continue actions.
This commit is contained in:
@@ -1430,8 +1430,10 @@ html[data-theme="custom"] textarea:disabled {
|
||||
/* Inputs & selects: recessed fill + line border (surface hierarchy) */
|
||||
.application-settings-workspace .input,
|
||||
.application-settings-workspace .select,
|
||||
.application-settings-workspace .listbox-trigger,
|
||||
.application-settings-form .input,
|
||||
.application-settings-form .select {
|
||||
.application-settings-form .select,
|
||||
.application-settings-form .listbox-trigger {
|
||||
height: 2rem;
|
||||
border-radius: 8px;
|
||||
border-color: var(--coollabs-line);
|
||||
@@ -1741,7 +1743,7 @@ html[data-theme="custom"] textarea:disabled {
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 2rem;
|
||||
height: 2.25rem;
|
||||
padding: 0 0.625rem 0 0.75rem;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="mt-8 w-full max-w-[1180px] lg:mt-3">
|
||||
<div class="mt-8 w-full lg:mt-3">
|
||||
<form wire:submit="submit">
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
@@ -6,9 +6,9 @@
|
||||
<h2>Docker Compose</h2>
|
||||
<p>Create a multi-container service directly from a Compose file.</p>
|
||||
</div>
|
||||
<x-forms.button type="submit" isHighlighted>Create service</x-forms.button>
|
||||
<x-forms.button type="submit" wire:target="submit" isHighlighted>Create service</x-forms.button>
|
||||
</div>
|
||||
<div class="application-settings-section-body p-0!">
|
||||
<div class="application-settings-section-body">
|
||||
<x-forms.textarea useMonacoEditor monacoEditorLanguage="yaml" label="Docker Compose file"
|
||||
rows="20" id="dockerComposeRaw" autofocus placeholder='services:
|
||||
app:
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
<div class="application-settings-section-body p-0!">
|
||||
@foreach ($github_apps as $ghapp)
|
||||
<button type="button"
|
||||
class="group flex w-full items-center gap-3 border-b border-neutral-200 px-4 py-3 text-left transition-colors last:border-b-0 hover:bg-neutral-50 dark:border-white/[0.06] dark:hover:bg-white/[0.025]"
|
||||
class="group relative flex w-full items-center gap-3 border-b border-neutral-200 px-4 py-3 text-left transition-colors last:border-b-0 hover:bg-neutral-50 dark:border-white/[0.06] dark:hover:bg-white/[0.025]"
|
||||
wire:click.prevent="loadRepositories({{ $ghapp->id }})"
|
||||
wire:loading.class="coolbox-loading"
|
||||
wire:loading.attr="disabled" wire:target="loadRepositories({{ $ghapp->id }})"
|
||||
wire:key="{{ $ghapp->id }}">
|
||||
<div
|
||||
@@ -71,13 +72,13 @@
|
||||
<div class="application-settings-section-body">
|
||||
@if ($repositories->isNotEmpty())
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.datalist class="w-full" label="Repository"
|
||||
placeholder="Search repositories…" wire:model.live="selected_repository_id">
|
||||
@foreach ($repositories as $repo)
|
||||
<option value="{{ data_get($repo, 'id') }}">{{ data_get($repo, 'name') }}</option>
|
||||
@endforeach
|
||||
</x-forms.datalist>
|
||||
<x-forms.listbox id="selected_repository_id" label="Repository" required live
|
||||
:options="$repositories->map(fn ($repository) => [
|
||||
'value' => data_get($repository, 'id'),
|
||||
'label' => data_get($repository, 'name'),
|
||||
])->values()->all()" />
|
||||
<x-forms.button :showLoadingIndicator="false" wire:click.prevent="loadBranches"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="loadBranches,selected_repository_id">
|
||||
<x-loading-on-button wire:loading.delay
|
||||
wire:target="loadBranches,selected_repository_id" />
|
||||
@@ -99,7 +100,7 @@
|
||||
<h2>Build configuration</h2>
|
||||
<p>Choose the branch and build strategy for this application.</p>
|
||||
</div>
|
||||
<x-forms.button type="submit" isHighlighted>Continue</x-forms.button>
|
||||
<x-forms.button type="submit" wire:target="submit" isHighlighted>Continue</x-forms.button>
|
||||
</div>
|
||||
<div class="application-settings-section-body space-y-5">
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
it('keeps spacing around the Docker Compose editor', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/new/docker-compose.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('class="application-settings-section-body"')
|
||||
->not->toContain('class="application-settings-section-body p-0!"');
|
||||
});
|
||||
|
||||
it('lets the Docker Compose editor use the available width', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/new/docker-compose.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('class="mt-8 w-full lg:mt-3"')
|
||||
->not->toContain('max-w-[1180px]');
|
||||
});
|
||||
|
||||
it('shows a loading indicator while creating the service', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/new/docker-compose.blade.php'));
|
||||
|
||||
expect($view)->toContain('<x-forms.button type="submit" wire:target="submit" isHighlighted>');
|
||||
});
|
||||
@@ -105,6 +105,32 @@ describe('GitHub Private Repository Component', function () {
|
||||
->assertSet('selected_repository_id', 1);
|
||||
});
|
||||
|
||||
test('repository selection uses the shared listbox and disables loading action', function () {
|
||||
fakeGithubHttp([
|
||||
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
|
||||
]);
|
||||
|
||||
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
|
||||
->call('loadRepositories', $this->githubApp->id)
|
||||
->assertSee('id="selected_repository_id-trigger"', false)
|
||||
->assertSee('wire:loading.attr="disabled"', false)
|
||||
->assertSee('wire:target="loadBranches,selected_repository_id"', false)
|
||||
->assertDontSee('<datalist', false);
|
||||
});
|
||||
|
||||
test('continue button uses the shared submit loading indicator', function () {
|
||||
fakeGithubHttp([
|
||||
['id' => 1, 'name' => 'alpha-repo', 'owner' => ['login' => 'testuser']],
|
||||
]);
|
||||
|
||||
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
|
||||
->call('loadRepositories', $this->githubApp->id)
|
||||
->set('branches', collect([['name' => 'main']]))
|
||||
->assertSee('type="submit"', false)
|
||||
->assertSee('wire:target="submit"', false)
|
||||
->assertSee('wire:loading.class="is-loading"', false);
|
||||
});
|
||||
|
||||
test('loadRepositories rejects a github app owned by another team', function () {
|
||||
$victimTeam = Team::factory()->create();
|
||||
$victimPrivateKey = githubPrivateRepositoryTestPrivateKeyForTeam($victimTeam);
|
||||
|
||||
@@ -14,6 +14,14 @@ test('listbox trigger styles constrain width and ellipsize long labels', functio
|
||||
->toContain('white-space: nowrap;');
|
||||
});
|
||||
|
||||
test('listbox trigger height matches shared inputs', function () {
|
||||
$css = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($css)
|
||||
->toMatch('/\.listbox-trigger \{[^}]*height: 2\.25rem;/s')
|
||||
->toMatch('/\.application-settings-workspace \.listbox-trigger[^}]*height: 2rem;/s');
|
||||
});
|
||||
|
||||
test('listbox component uses shared trigger label truncation', function () {
|
||||
$html = Blade::render(<<<'BLADE'
|
||||
<x-forms.listbox id="longOption" label="Example"
|
||||
|
||||
Reference in New Issue
Block a user