feat(v5): add shadcn/ui with button, select, separator, and navbar

This commit is contained in:
Andras Bacsai
2026-06-16 19:38:21 +02:00
parent bc6a12d614
commit c178dfdb39
32 changed files with 8788 additions and 74 deletions
+128
View File
@@ -3,7 +3,9 @@
namespace App\Http\Controllers\V5;
use App\Http\Controllers\Controller;
use App\Models\Environment;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Team;
use App\Models\User;
use App\Models\V5\Cluster as V5Cluster;
@@ -11,6 +13,7 @@ use App\Models\V5\Server as V5Server;
use App\Services\Coold\CoolifyCliBootstrap;
use App\Services\Coold\CoolifyCliVersion;
use App\Services\Flux\FluxHealth;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
@@ -18,13 +21,22 @@ use Inertia\Response;
class HomeController extends Controller
{
private const SELECTED_PROJECT_SESSION_KEY = 'v5.selectedProjectUuid';
private const SELECTED_ENVIRONMENT_SESSION_KEY = 'v5.selectedEnvironmentUuid';
public function __invoke(Request $request, FluxHealth $fluxHealth): Response
{
$currentTeam = $request->attributes->get('v5.currentTeam');
$projects = $this->projects($currentTeam);
[$selectedProject, $selectedEnvironment] = $this->selectedProjectAndEnvironment($request, $projects);
return Inertia::render('Home', [
'flux' => $fluxHealth->check(),
'clusters' => $this->clusters($currentTeam),
'projects' => $projects,
'selectedProjectUuid' => $selectedProject['uuid'] ?? null,
'selectedEnvironmentUuid' => $selectedEnvironment['uuid'] ?? null,
]);
}
@@ -33,6 +45,37 @@ class HomeController extends Controller
return response()->json($coolifyCliVersion->check());
}
public function updateSelection(Request $request): \Illuminate\Http\Response
{
$currentTeam = $request->attributes->get('v5.currentTeam');
if (! $currentTeam instanceof Team) {
abort(403);
}
$validated = $request->validate([
'project_uuid' => ['required', 'string'],
'environment_uuid' => ['nullable', 'string'],
]);
$project = $this->projectQuery($currentTeam)
->where('uuid', $validated['project_uuid'])
->first();
if (! $project instanceof Project) {
abort(403);
}
$environment = $this->selectedEnvironment($project, $validated['environment_uuid'] ?? null);
$request->session()->put([
self::SELECTED_PROJECT_SESSION_KEY => $project->uuid,
self::SELECTED_ENVIRONMENT_SESSION_KEY => $environment?->uuid,
]);
return response()->noContent();
}
public function bootstrapCoolify(Request $request, CoolifyCliBootstrap $coolifyCliBootstrap): JsonResponse
{
$currentTeam = $request->attributes->get('v5.currentTeam');
@@ -132,4 +175,89 @@ class HomeController extends Controller
])
->all();
}
/**
* @param array<int, array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}> $projects
* @return array{0: array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}|null, 1: array{uuid: string, name: string}|null}
*/
private function selectedProjectAndEnvironment(Request $request, array $projects): array
{
$selectedProjectUuid = $request->session()->get(self::SELECTED_PROJECT_SESSION_KEY);
$selectedEnvironmentUuid = $request->session()->get(self::SELECTED_ENVIRONMENT_SESSION_KEY);
$selectedProject = null;
foreach ($projects as $project) {
if ($project['uuid'] === $selectedProjectUuid) {
$selectedProject = $project;
break;
}
}
$selectedProject ??= $projects[0] ?? null;
$selectedEnvironment = null;
foreach ($selectedProject['environments'] ?? [] as $environment) {
if ($environment['uuid'] === $selectedEnvironmentUuid) {
$selectedEnvironment = $environment;
break;
}
}
$selectedEnvironment ??= $selectedProject['environments'][0] ?? null;
return [$selectedProject, $selectedEnvironment];
}
private function selectedEnvironment(Project $project, ?string $environmentUuid): ?Environment
{
if ($environmentUuid === null) {
return $project->environments->first();
}
$environment = $project->environments->firstWhere('uuid', $environmentUuid);
if (! $environment instanceof Environment) {
abort(422, 'The selected environment is not available for the selected project.');
}
return $environment;
}
/**
* @return array<int, array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}>
*/
private function projects(mixed $currentTeam): array
{
if (! $currentTeam instanceof Team) {
return [];
}
return $this->projectQuery($currentTeam)
->get()
->map(fn (Project $project) => [
'uuid' => $project->uuid,
'name' => $project->name,
'environments' => $project->environments
->map(fn ($environment) => [
'uuid' => $environment->uuid,
'name' => $environment->name,
])
->all(),
])
->all();
}
private function projectQuery(Team $currentTeam): Builder
{
return Project::query()
->select(['id', 'uuid', 'name', 'team_id'])
->where('team_id', $currentTeam->id)
->with(['environments' => fn ($query) => $query
->select(['id', 'uuid', 'name', 'project_id'])
->orderByRaw("CASE WHEN LOWER(name) = 'production' THEN 0 ELSE 1 END")
->orderByRaw('LOWER(name)')])
->orderByRaw('LOWER(name)');
}
}