mirror of
https://github.com/tiennm99/coolify.git
synced 2026-09-05 12:16:52 +00:00
fix(ui): simplify GitLab source setup view
Use the red incomplete-setup alert like GitHub, keep name + OAuth credentials front-and-center, and tuck GitLab URL / API / SSH / system wide options into an Advanced accordion for self-hosted users.
This commit is contained in:
@@ -59,6 +59,8 @@ class Change extends Component
|
||||
|
||||
public ?string $oauthState = null;
|
||||
|
||||
private bool $shouldDeriveApiUrlAfterHtmlUrlUpdate = false;
|
||||
|
||||
protected function rules(): array
|
||||
{
|
||||
return [
|
||||
@@ -76,6 +78,19 @@ class Change extends Component
|
||||
];
|
||||
}
|
||||
|
||||
public function updatingHtmlUrl(): void
|
||||
{
|
||||
$this->shouldDeriveApiUrlAfterHtmlUrlUpdate = blank($this->apiUrl)
|
||||
|| $this->apiUrl === rtrim($this->htmlUrl, '/').'/api/v4';
|
||||
}
|
||||
|
||||
public function updatedHtmlUrl(): void
|
||||
{
|
||||
if ($this->shouldDeriveApiUrlAfterHtmlUrlUpdate) {
|
||||
$this->apiUrl = rtrim($this->htmlUrl, '/').'/api/v4';
|
||||
}
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -29,28 +29,67 @@
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="name" label="Name" />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="htmlUrl" label="GitLab URL" />
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="apiUrl" label="API URL" />
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="groupName" label="Group Name"
|
||||
helper="Comma-separated group names to filter visible repositories." />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="customUser" label="SSH User" />
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" type="number" id="customPort" label="SSH Port" />
|
||||
</div>
|
||||
@if (!isCloud())
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox canGate="update" :canResource="$gitlab_app" label="System Wide?"
|
||||
<x-forms.checkbox canGate="update" :canResource="$gitlab_app" label="System Wide"
|
||||
helper="If checked, this GitLab App will be available for everyone in this Coolify instance."
|
||||
instantSave id="isSystemWide" />
|
||||
</div>
|
||||
@if ($isSystemWide)
|
||||
<x-callout type="warning" title="Not Recommended">
|
||||
System-wide GitLab Apps are shared across all teams on this Coolify instance. This means any team
|
||||
can use this GitLab App to deploy applications from your repositories. For better security and
|
||||
isolation, it's recommended to create team-specific GitLab Apps instead.
|
||||
</x-callout>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<h3 class="pt-4">OAuth Credentials</h3>
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="clientId" label="Application ID" />
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="clientSecretInput" label="Application Secret" type="password" />
|
||||
|
||||
<div x-data="{
|
||||
activeAccordion: '',
|
||||
setActiveAccordion(id) {
|
||||
this.activeAccordion = (this.activeAccordion == id) ? '' : id
|
||||
}
|
||||
}" class="relative w-full py-2 mx-auto overflow-hidden text-sm font-normal rounded-md">
|
||||
<div x-data="{ id: $id('accordion') }" class="cursor-pointer">
|
||||
<button @click="setActiveAccordion(id)"
|
||||
class="flex items-center justify-between w-full px-1 py-2 text-left select-none dark:hover:text-white hover:bg-white/5"
|
||||
type="button">
|
||||
<h4>Advanced / Self-hosted</h4>
|
||||
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion == id }"
|
||||
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div x-show="activeAccordion==id" x-collapse x-cloak class="px-2">
|
||||
<div class="flex flex-col gap-2 pt-0 opacity-70">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="htmlUrl" label="GitLab URL" />
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="apiUrl" label="API URL" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" id="customUser" label="SSH User" />
|
||||
<x-forms.input canGate="update" :canResource="$gitlab_app" type="number" id="customPort" label="SSH Port" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.select canGate="update" :canResource="$gitlab_app" id="privateKeyId" label="SSH Private Key (optional)">
|
||||
<option value="">None</option>
|
||||
@foreach ($privateKeys as $key)
|
||||
<option value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="pt-4">Webhook</h3>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="text-sm">
|
||||
@@ -63,19 +102,6 @@
|
||||
helper="Set this same token in your GitLab webhook's 'Secret token' field." />
|
||||
</div>
|
||||
|
||||
<h3 class="pt-4">SSH Key (Optional)</h3>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
Only needed if you prefer SSH-based git clone over HTTPS OAuth token.
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.select canGate="update" :canResource="$gitlab_app" id="privateKeyId" label="Private Key">
|
||||
<option value="">None</option>
|
||||
@foreach ($privateKeys as $key)
|
||||
<option value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
|
||||
@if ($applications->count() > 0)
|
||||
<h3 class="pt-4">Applications Using This Source</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
@@ -112,13 +138,13 @@
|
||||
</div>
|
||||
<div class="subtitle">Connect your GitLab instance to deploy private repositories.</div>
|
||||
|
||||
<div class="mb-6 rounded-sm alert-warning">
|
||||
<div class="mb-6 rounded-sm alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>Complete the setup below to connect this GitLab source.</span>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
@@ -140,24 +166,53 @@
|
||||
<h3 class="pt-2">Step 2: Enter the credentials</h3>
|
||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||
<x-forms.input id="name" label="Name" />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="htmlUrl" label="GitLab URL" />
|
||||
<x-forms.input id="apiUrl" label="API URL" />
|
||||
</div>
|
||||
<x-forms.input id="clientId" label="Application ID" required
|
||||
helper="The Application ID from your GitLab OAuth Application." />
|
||||
<x-forms.input id="clientSecretInput" label="Application Secret" type="password" required
|
||||
helper="The Secret from your GitLab OAuth Application." />
|
||||
<x-forms.input id="groupName" label="Group Name"
|
||||
helper="Optional. Comma-separated group names to filter repositories." />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="customUser" label="SSH User" />
|
||||
<x-forms.input type="number" id="customPort" label="SSH Port" />
|
||||
|
||||
<div x-data="{
|
||||
activeAccordion: '',
|
||||
setActiveAccordion(id) {
|
||||
this.activeAccordion = (this.activeAccordion == id) ? '' : id
|
||||
}
|
||||
}" class="relative w-full py-2 mx-auto overflow-hidden text-sm font-normal rounded-md">
|
||||
<div x-data="{ id: $id('accordion') }" class="cursor-pointer">
|
||||
<button @click="setActiveAccordion(id)"
|
||||
class="flex items-center justify-between w-full px-1 py-2 text-left select-none dark:hover:text-white hover:bg-white/5"
|
||||
type="button">
|
||||
<h4>Advanced / Self-hosted</h4>
|
||||
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion == id }"
|
||||
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div x-show="activeAccordion==id" x-collapse x-cloak class="px-2">
|
||||
<div class="flex flex-col gap-2 pt-0 opacity-70">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="htmlUrl" label="GitLab URL"
|
||||
helper="Only change this for self-hosted GitLab (e.g. https://gitlab.example.com)." />
|
||||
<x-forms.input id="apiUrl" label="API URL"
|
||||
helper="Usually your GitLab URL with /api/v4 appended." />
|
||||
</div>
|
||||
<x-forms.input id="groupName" label="Group Name"
|
||||
helper="Optional. Comma-separated group names to filter repositories." />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="customUser" label="SSH User" />
|
||||
<x-forms.input type="number" id="customPort" label="SSH Port" />
|
||||
</div>
|
||||
@if (!isCloud())
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox label="System Wide" id="isSystemWide"
|
||||
helper="If checked, this GitLab App will be available for everyone in this Coolify instance." />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (!isCloud())
|
||||
<x-forms.checkbox label="System Wide?" id="isSystemWide"
|
||||
helper="If checked, this GitLab App will be available for everyone in this Coolify instance." />
|
||||
@endif
|
||||
|
||||
<x-forms.button type="submit" class="mt-2">Save Credentials</x-forms.button>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Source\Gitlab\Change;
|
||||
use App\Models\GitlabApp;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->team = Team::factory()->create();
|
||||
$this->user = User::factory()->create();
|
||||
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
InstanceSettings::forceCreate([
|
||||
'id' => 0,
|
||||
'fqdn' => null,
|
||||
'public_ipv4' => null,
|
||||
'public_ipv6' => null,
|
||||
]);
|
||||
|
||||
$this->gitlabApp = GitlabApp::create([
|
||||
'name' => 'Self-hosted GitLab',
|
||||
'api_url' => 'https://gitlab.com/api/v4',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'custom_user' => 'git',
|
||||
'custom_port' => 22,
|
||||
'team_id' => $this->team->id,
|
||||
'is_system_wide' => false,
|
||||
'is_public' => false,
|
||||
]);
|
||||
});
|
||||
|
||||
describe('GitLab source setup view', function () {
|
||||
test('shows red incomplete-setup alert and keeps advanced fields collapsed', function () {
|
||||
Livewire::withQueryParams(['gitlab_app_uuid' => $this->gitlabApp->uuid])
|
||||
->test(Change::class)
|
||||
->assertSee('You must complete this step before you can use this source!')
|
||||
->assertSeeHtml('alert-error')
|
||||
->assertSee('Advanced / Self-hosted')
|
||||
->assertSee('Application ID')
|
||||
->assertSee('Application Secret')
|
||||
->assertSee('Save Credentials')
|
||||
->assertDontSee('alert-warning');
|
||||
});
|
||||
|
||||
test('derives api url when gitlab url changes', function () {
|
||||
Livewire::withQueryParams(['gitlab_app_uuid' => $this->gitlabApp->uuid])
|
||||
->test(Change::class)
|
||||
->set('htmlUrl', 'https://gitlab.example.com')
|
||||
->assertSet('apiUrl', 'https://gitlab.example.com/api/v4');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user