mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 10:18:20 +00:00
feat(domains): add structured URL editing and responsive domain controls
Add reusable domain URL parsing and input components, expose per-domain redirect and indexing controls, and improve application and service domain layouts across responsive breakpoints.
This commit is contained in:
1 parent
61a2b183d3
commit
32bf1860d4
30 files changed
+693
-292
No files matched your search
@@ -41,10 +41,6 @@ class Domains extends Component
|
||||
|
||||
public string $editingDomain = '';
|
||||
|
||||
public string $editingIndexing = 'index';
|
||||
|
||||
public string $editingDirection = 'both';
|
||||
|
||||
public ?string $editingService = null;
|
||||
|
||||
/** @var array<int, array{url: string, service: ?string, dns_status: string, dns_message: string, expected_ip: ?string, checked_at?: ?string, is_suggested?: bool, suggested_for?: ?string, suggestion_label?: ?string, needs_force_add?: bool}> */
|
||||
@@ -103,8 +99,6 @@ class Domains extends Component
|
||||
return [
|
||||
'newDomain' => ValidationPatterns::applicationDomainRules(),
|
||||
'editingDomain' => ValidationPatterns::applicationDomainRules(),
|
||||
'editingIndexing' => 'string|in:index,noindex',
|
||||
'editingDirection' => 'string|in:both,www,non-www',
|
||||
'redirect' => 'string|required|in:both,www,non-www',
|
||||
'serviceRedirects' => 'array',
|
||||
'serviceRedirects.*' => 'string|in:both,www,non-www',
|
||||
@@ -151,6 +145,12 @@ class Domains extends Component
|
||||
$this->dispatch('success', 'Search engine indexing updated.');
|
||||
}
|
||||
|
||||
public function updateRedirect(string $redirect): void
|
||||
{
|
||||
$this->redirect = $redirect;
|
||||
$this->setRedirect();
|
||||
}
|
||||
|
||||
public function loadDomainState(): void
|
||||
{
|
||||
$this->application->refresh();
|
||||
@@ -912,8 +912,6 @@ class Domains extends Component
|
||||
$this->editingIndex = $index;
|
||||
$this->editingDomain = $this->domainRows[$index]['url'];
|
||||
$this->editingService = $this->domainRows[$index]['service'];
|
||||
$this->editingDirection = $this->serviceRedirectFor($this->editingService);
|
||||
$this->editingIndexing = $this->application->isDomainNoindexed($this->editingDomain) ? 'noindex' : 'index';
|
||||
$this->resetEditDomainDnsGate();
|
||||
$this->resetErrorBag('editingDomain');
|
||||
$this->showEditDomainModal = true;
|
||||
@@ -996,8 +994,6 @@ class Domains extends Component
|
||||
$this->editingIndex = null;
|
||||
$this->editingDomain = '';
|
||||
$this->editingService = null;
|
||||
$this->editingDirection = 'both';
|
||||
$this->editingIndexing = 'index';
|
||||
$this->resetEditDomainDnsGate();
|
||||
$this->resetErrorBag('editingDomain');
|
||||
if ($this->pendingAction === 'update') {
|
||||
@@ -1040,6 +1036,7 @@ class Domains extends Component
|
||||
$newUrl = $this->splitDomains($normalized)[0];
|
||||
$oldUrl = $this->domainRows[$this->editingIndex]['url'];
|
||||
$service = $this->editingService;
|
||||
$wasNoindexed = $this->application->isDomainNoindexed($oldUrl);
|
||||
|
||||
$current = $this->currentDomainList($service);
|
||||
if ($newUrl !== $oldUrl && $current->contains($newUrl)) {
|
||||
@@ -1066,20 +1063,13 @@ class Domains extends Component
|
||||
}
|
||||
|
||||
$noindexDomains = $this->application->noindexDomains()->reject(fn (string $domain) => $domain === $oldUrl);
|
||||
if ($this->editingIndexing === 'noindex') {
|
||||
if ($wasNoindexed) {
|
||||
$noindexDomains->push($newUrl);
|
||||
}
|
||||
$this->application->setNoindexDomains($noindexDomains);
|
||||
$this->application->save();
|
||||
$this->resetDefaultLabels();
|
||||
|
||||
if ($this->isCompose && filled($service) && $this->editingDirection !== $this->savedRedirectForService($service)) {
|
||||
$this->serviceRedirects[$this->serviceRedirectWireKey($service)] = $this->editingDirection;
|
||||
$this->notifyRedirectUpdate = false;
|
||||
$this->setServiceRedirect($service);
|
||||
$this->notifyRedirectUpdate = true;
|
||||
}
|
||||
|
||||
$this->forceSaveDomains = false;
|
||||
$this->pendingAction = null;
|
||||
$this->cancelEdit();
|
||||
@@ -1237,6 +1227,12 @@ class Domains extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function updateServiceRedirect(string $serviceName, string $redirect): void
|
||||
{
|
||||
$this->serviceRedirects[$this->serviceRedirectWireKey($serviceName)] = $redirect;
|
||||
$this->setServiceRedirect($serviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed ...$modalArgs Extra args from modal-confirmation (password, etc.)
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Livewire\Project\Shared\ConfigurationChecker;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use App\Models\ServiceApplication;
|
||||
use App\Support\DomainUrlParts;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -46,10 +47,6 @@ class Domains extends Component
|
||||
|
||||
public string $editingDomain = '';
|
||||
|
||||
public string $editingDirection = 'both';
|
||||
|
||||
public string $editingIndexing = 'index';
|
||||
|
||||
public ?int $editingServiceApplicationId = null;
|
||||
|
||||
public bool $showEditDomainModal = false;
|
||||
@@ -102,8 +99,6 @@ class Domains extends Component
|
||||
return [
|
||||
'newDomain' => ValidationPatterns::applicationDomainRules(),
|
||||
'editingDomain' => ValidationPatterns::applicationDomainRules(),
|
||||
'editingDirection' => 'string|in:both,www,non-www',
|
||||
'editingIndexing' => 'string|in:index,noindex',
|
||||
'newServiceApplicationId' => 'nullable|integer',
|
||||
'serviceRedirects' => 'array',
|
||||
'serviceRedirects.*' => 'string|in:both,www,non-www',
|
||||
@@ -924,9 +919,6 @@ class Domains extends Component
|
||||
$this->editingIndex = $index;
|
||||
$this->editingDomain = $this->domainRows[$index]['url'];
|
||||
$this->editingServiceApplicationId = (int) $this->domainRows[$index]['service_application_id'];
|
||||
$app = $this->findServiceApp($this->editingServiceApplicationId);
|
||||
$this->editingDirection = $this->normalizeRedirect($app?->redirect);
|
||||
$this->editingIndexing = $app?->isDomainNoindexed($this->editingDomain) ? 'noindex' : 'index';
|
||||
$this->editDomainDnsFailed = false;
|
||||
$this->editDomainDnsMessage = '';
|
||||
$this->forceSaveEditDns = false;
|
||||
@@ -940,8 +932,6 @@ class Domains extends Component
|
||||
$this->editingIndex = null;
|
||||
$this->editingDomain = '';
|
||||
$this->editingServiceApplicationId = null;
|
||||
$this->editingDirection = 'both';
|
||||
$this->editingIndexing = 'index';
|
||||
$this->editDomainDnsFailed = false;
|
||||
$this->editDomainDnsMessage = '';
|
||||
$this->forceSaveEditDns = false;
|
||||
@@ -974,6 +964,7 @@ class Domains extends Component
|
||||
$newUrl = $this->splitDomains($normalized)[0];
|
||||
$oldUrl = $this->domainRows[$this->editingIndex]['url'];
|
||||
$current = collect($this->splitDomains($app->fqdn));
|
||||
$wasNoindexed = $app->isDomainNoindexed($oldUrl);
|
||||
|
||||
if ($newUrl !== $oldUrl && $current->contains($newUrl)) {
|
||||
$this->addError('editingDomain', "Domain {$newUrl} is already configured for this service.");
|
||||
@@ -1000,18 +991,12 @@ class Domains extends Component
|
||||
}
|
||||
|
||||
$noindexDomains = $app->noindexDomains()->reject(fn (string $domain) => $domain === $oldUrl);
|
||||
if ($this->editingIndexing === 'noindex') {
|
||||
if ($wasNoindexed) {
|
||||
$noindexDomains->push($newUrl);
|
||||
}
|
||||
$app->setNoindexDomains($noindexDomains);
|
||||
$app->save();
|
||||
|
||||
if ($this->editingDirection !== $this->normalizeRedirect($app->redirect)) {
|
||||
$this->notifyRedirectUpdate = false;
|
||||
$this->updateServiceRedirect((int) $app->id, $this->editingDirection);
|
||||
$this->notifyRedirectUpdate = true;
|
||||
}
|
||||
|
||||
$this->cancelEdit();
|
||||
$this->dispatch('edit-domain-saved');
|
||||
$this->forceSaveDomains = false;
|
||||
@@ -1140,12 +1125,9 @@ class Domains extends Component
|
||||
$domain = generateUrl(server: $server, random: new_public_id());
|
||||
$requiredPort = $app->getRequiredPort();
|
||||
if ($requiredPort !== null) {
|
||||
$parts = parse_url($domain);
|
||||
if (is_array($parts) && empty($parts['port'])) {
|
||||
$scheme = $parts['scheme'] ?? 'https';
|
||||
$host = $parts['host'] ?? '';
|
||||
$path = $parts['path'] ?? '';
|
||||
$domain = "{$scheme}://{$host}:{$requiredPort}{$path}";
|
||||
$parts = DomainUrlParts::split($domain);
|
||||
if ($parts['port'] === '') {
|
||||
$domain = DomainUrlParts::compose($parts['scheme'], $parts['host'], (string) $requiredPort, $parts['path']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ class ExecuteContainerCommand extends Component
|
||||
$this->type = 'service';
|
||||
$this->resource = Service::ownedByCurrentTeam()->where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||
$this->authorize('view', $this->resource);
|
||||
if (! $this->resource->isRunning()) {
|
||||
$this->containersLoaded = true;
|
||||
}
|
||||
if ($this->resource->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->server);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user