feat(v5): authorize creates, deep-link selection, list apps in v4

Restrict V5 application and resource-connection creation to team admins.
Resolve project, environment, and application from query params and keep
session selection in sync. Surface V5 apps on the v4 resource index and
count them for project/environment emptiness. Create the flux data dir
on install and upgrade.
This commit is contained in:
Andras Bacsai
2026-07-18 15:55:47 +02:00
parent 772093928f
commit a4ab69df56
23 changed files with 299 additions and 38 deletions
@@ -51,6 +51,7 @@ class ApplicationController extends Controller
public function store(Request $request): JsonResponse
{
$currentTeam = $this->currentTeamOrFail($request);
$this->authorize('create', [V5Application::class, $currentTeam]);
$projects = $this->projects($currentTeam);
[$selectedProject, $selectedEnvironment] = $this->selectedProjectAndEnvironment($request, $projects);
@@ -34,8 +34,8 @@ trait ResolvesProjectSelection
*/
protected 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);
$selectedProjectUuid = $request->query('project', $request->session()->get(self::SELECTED_PROJECT_SESSION_KEY));
$selectedEnvironmentUuid = $request->query('environment', $request->session()->get(self::SELECTED_ENVIRONMENT_SESSION_KEY));
$selectedProject = null;
foreach ($projects as $project) {
@@ -59,6 +59,13 @@ trait ResolvesProjectSelection
$selectedEnvironment ??= $selectedProject['environments'][0] ?? null;
if ($request->query->has('project') || $request->query->has('environment')) {
$request->session()->put([
self::SELECTED_PROJECT_SESSION_KEY => $selectedProject['uuid'] ?? null,
self::SELECTED_ENVIRONMENT_SESSION_KEY => $selectedEnvironment['uuid'] ?? null,
]);
}
return [$selectedProject, $selectedEnvironment];
}
@@ -33,17 +33,23 @@ class DashboardController extends Controller
$currentTeam = $request->attributes->get('v5.currentTeam');
$projects = $this->projects($currentTeam);
[$selectedProject, $selectedEnvironment] = $this->selectedProjectAndEnvironment($request, $projects);
$applications = $this->applications($currentTeam, $selectedProject, $selectedEnvironment);
$requestedApplicationUuid = $request->query('application');
$selectedApplicationUuid = collect($applications)->contains(
fn (array $application): bool => $application['id'] === $requestedApplicationUuid
) ? $requestedApplicationUuid : null;
return Inertia::render('Dashboard', [
'currentTeam' => $this->serializeCurrentTeam($currentTeam),
'flux' => $fluxHealth->check(),
'applications' => $this->applications($currentTeam, $selectedProject, $selectedEnvironment),
'applications' => $applications,
'caddyIngresses' => $this->caddyIngresses($currentTeam),
'resourceConnections' => $this->resourceConnections($currentTeam, $selectedProject, $selectedEnvironment),
'nginxServers' => $this->nginxServers($currentTeam),
'projects' => $projects,
'selectedProjectUuid' => $selectedProject['uuid'] ?? null,
'selectedEnvironmentUuid' => $selectedEnvironment['uuid'] ?? null,
'selectedApplicationUuid' => $selectedApplicationUuid,
]);
}
@@ -35,6 +35,7 @@ class ResourceConnectionController extends Controller
public function store(Request $request): JsonResponse
{
$currentTeam = $this->currentTeamOrFail($request);
$this->authorize('create', [ResourceConnection::class, $currentTeam]);
$projects = $this->projects($currentTeam);
[$selectedProject, $selectedEnvironment] = $this->selectedProjectAndEnvironment($request, $projects);