feat(ui): Shadow UI redesign, domain management, and DNS autoconfigure (#11119)

Co-authored-by: ShadowArcanist <162910371+ShadowArcanist@users.noreply.github.com>
This commit is contained in:
Andras BacsaiandShadowArcanist authored and GitHub committed 2026-08-03 23:11:54 +02:00
1 parent 0b843bb07c
commit 8ae56587d5
497 files changed
+44045 -22630

No files matched your search

@@ -2,7 +2,9 @@
namespace App\Livewire\Project\Application\Deployment;
use App\Enums\ApplicationDeploymentStatus;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Support\Collection;
use Livewire\Component;
@@ -28,6 +30,18 @@ class Index extends Component
public ?string $pull_request_id = null;
public array $pullRequestOptions = [];
public string $search = '';
public string $deploymentFilter = 'all';
public string $deploymentSort = 'newest';
public array $statusFilterOptions = [];
public array $sourceFilterOptions = [];
protected $queryString = ['pull_request_id'];
public function getListeners()
@@ -64,8 +78,16 @@ class Index extends Component
}
}
['deployments' => $deployments, 'count' => $count] = $application->deployments(0, $this->defaultTake, $this->pull_request_id);
$this->application = $application;
$this->loadPullRequestOptions();
$this->loadDeploymentFilterOptions();
['deployments' => $deployments, 'count' => $count] = $application->deployments(
search: $this->search,
filter: $this->deploymentFilter,
sort: $this->deploymentSort,
take: $this->defaultTake,
pullRequestId: $this->pull_request_id,
);
$this->deployments = $deployments;
$this->deployments_count = $count;
$this->current_url = url()->current();
@@ -114,14 +136,75 @@ class Index extends Component
$this->loadDeployments();
}
public function goToPage(int $page): void
{
$lastPage = max(1, (int) ceil($this->deployments_count / $this->defaultTake));
$page = max(1, min($page, $lastPage));
$this->skip = ($page - 1) * $this->defaultTake;
$this->showPrev = $page > 1;
$this->updateCurrentPage();
$this->loadDeployments();
}
public function loadDeployments()
{
['deployments' => $deployments, 'count' => $count] = $this->application->deployments($this->skip, $this->defaultTake, $this->pull_request_id);
['deployments' => $deployments, 'count' => $count] = $this->application->deployments(
skip: $this->skip,
take: $this->defaultTake,
pullRequestId: $this->pull_request_id,
search: $this->search,
filter: $this->deploymentFilter,
sort: $this->deploymentSort,
);
$this->deployments = $deployments;
$this->deployments_count = $count;
$this->showMore();
}
public function updatedSearch(): void
{
$this->resetPaginationAndLoad();
}
public function setDeploymentFilter(string $filter): void
{
$validFilters = collect($this->statusFilterOptions)
->concat($this->sourceFilterOptions)
->pluck('value')
->push('all');
if (! $validFilters->contains($filter)) {
return;
}
$this->deploymentFilter = $filter;
$this->pull_request_id = null;
$this->resetPaginationAndLoad();
}
public function setPullRequestFilter(string $pullRequestId): void
{
$validPullRequestIds = collect($this->pullRequestOptions)->pluck('value');
if (! $validPullRequestIds->contains($pullRequestId)) {
return;
}
$this->pull_request_id = $pullRequestId === '' ? null : $pullRequestId;
$this->deploymentFilter = 'all';
$this->resetPaginationAndLoad();
}
public function setDeploymentSort(string $sort): void
{
if (! in_array($sort, ['newest', 'oldest'], true)) {
return;
}
$this->deploymentSort = $sort;
$this->resetPaginationAndLoad();
}
public function updatedPullRequestId($value)
{
// Sanitize and validate the pull request ID
@@ -139,20 +222,15 @@ class Index extends Component
$this->pull_request_id = null;
}
// Reset pagination when filter changes
$this->skip = 0;
$this->showPrev = false;
$this->updateCurrentPage();
$this->loadDeployments();
$this->deploymentFilter = 'all';
$this->resetPaginationAndLoad();
}
public function clearFilter()
{
$this->pull_request_id = null;
$this->skip = 0;
$this->showPrev = false;
$this->updateCurrentPage();
$this->loadDeployments();
$this->deploymentFilter = 'all';
$this->resetPaginationAndLoad();
}
private function updateCurrentPage()
@@ -160,6 +238,95 @@ class Index extends Component
$this->currentPage = intval($this->skip / $this->defaultTake) + 1;
}
private function loadPullRequestOptions(): void
{
$pullRequestIds = ApplicationDeploymentQueue::query()
->where('application_id', $this->application->id)
->where('pull_request_id', '>', 0)
->distinct()
->orderByDesc('pull_request_id')
->pluck('pull_request_id')
->map(fn ($pullRequestId) => (string) $pullRequestId)
->values();
if ($this->pull_request_id && ! $pullRequestIds->contains($this->pull_request_id)) {
$this->pull_request_id = null;
}
$this->pullRequestOptions = collect([
['value' => '', 'label' => 'All deployments'],
])
->concat($pullRequestIds->map(fn ($pullRequestId) => [
'value' => $pullRequestId,
'label' => "Pull request #{$pullRequestId}",
]))
->all();
}
private function loadDeploymentFilterOptions(): void
{
$statuses = ApplicationDeploymentQueue::query()
->where('application_id', $this->application->id)
->distinct()
->pluck('status');
$statusLabels = [
ApplicationDeploymentStatus::FINISHED->value => 'Success',
ApplicationDeploymentStatus::FAILED->value => 'Failed',
ApplicationDeploymentStatus::IN_PROGRESS->value => 'In progress',
ApplicationDeploymentStatus::QUEUED->value => 'Queued',
ApplicationDeploymentStatus::CANCELLED_BY_USER->value => 'Cancelled',
];
$this->statusFilterOptions = collect($statusLabels)
->filter(fn (string $label, string $status) => $statuses->contains($status))
->map(fn (string $label, string $status) => [
'value' => "status:{$status}",
'label' => $label,
])
->values()
->all();
$sourceKeys = ApplicationDeploymentQueue::query()
->where('application_id', $this->application->id)
->selectRaw("
CASE
WHEN pull_request_id > 0 THEN 'pull-request'
WHEN is_webhook THEN 'webhook'
WHEN rollback THEN 'rollback'
WHEN is_api THEN 'api'
ELSE 'manual'
END AS source_key
")
->distinct()
->pluck('source_key');
$sourceLabels = [
'manual' => 'Manual',
'pull-request' => 'Pull requests',
'webhook' => 'Webhooks',
'api' => 'API',
'rollback' => 'Rollbacks',
];
$this->sourceFilterOptions = collect($sourceLabels)
->filter(fn (string $label, string $source) => $sourceKeys->contains($source))
->map(fn (string $label, string $source) => [
'value' => "source:{$source}",
'label' => $label,
])
->values()
->all();
}
private function resetPaginationAndLoad(): void
{
$this->skip = 0;
$this->showPrev = false;
$this->updateCurrentPage();
$this->loadDeployments();
}
public function render()
{
return view('livewire.project.application.deployment.index');