feat(onboarding): add Hetzner integration and fix navigation issues

- Add Hetzner Cloud server creation option to onboarding flow
- Change grid from 2 to 3 columns to accommodate all server options
- Mark both Hetzner and Remote Server as "Recommended"
- Fix Hetzner card height to match other cards
- Remove "select existing server" phase - onboarding always creates new servers
- Fix project loading on page refresh in Project Setup phase
- Fix browser back button navigation - remove aggressive restartBoarding() call
- Fix SSH key dropdown to not auto-select first key - require explicit selection
- Make checkpoint titles more prominent across all phases

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai 2025-10-12 18:52:45 +02:00
parent 1902ef886d
commit 04625591ea
4 changed files with 718 additions and 758 deletions

View file

@ -143,6 +143,11 @@ public function mount()
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
}
}
// Load projects when on create-project state (for page refresh)
if ($this->currentState === 'create-project' && $this->projects->isEmpty()) {
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
}
}
public function explanation()
@ -182,36 +187,12 @@ public function setServerType(string $type)
return $this->validateServer('localhost');
} elseif ($this->selectedServerType === 'remote') {
$this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->privateKeys->count() > 0) {
$this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
}
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->servers->count() > 0) {
$this->selectedExistingServer = $this->servers->first()->id;
$this->updateServerDetails();
$this->currentState = 'select-existing-server';
return;
}
// Don't auto-select - let user explicitly choose from dropdown
// Onboarding always creates new servers, skip existing server selection
$this->currentState = 'private-key';
}
}
public function selectExistingServer()
{
$this->createdServer = Server::find($this->selectedExistingServer);
if (! $this->createdServer) {
$this->dispatch('error', 'Server is not found.');
$this->currentState = 'private-key';
return;
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->getPublicKey();
$this->updateServerDetails();
$this->currentState = 'validate-server';
}
private function updateServerDetails()
{
if ($this->createdServer) {
@ -229,7 +210,7 @@ public function getProxyType()
public function selectExistingPrivateKey()
{
if (is_null($this->selectedExistingPrivateKey)) {
$this->restartBoarding();
$this->dispatch('error', 'Please select a private key.');
return;
}

View file

@ -7,8 +7,8 @@
<div class="flex flex-col items-center">
<div
class="flex items-center justify-center size-10 rounded-full border-2 transition-all duration-300
{{ $i < $currentStep ? 'bg-success border-success' : '' }}
{{ $i === $currentStep ? 'bg-white dark:bg-coolgray-100' : '' }}
{{ $i < $currentStep ? 'bg-success border-success' : 'border-neutral-200 dark:border-coolgray-300' }}
{{ $i === $currentStep ? 'bg-white dark:bg-coolgray-500' : '' }}
">
@if ($i < $currentStep)
<svg class="size-5 text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
@ -38,7 +38,7 @@ class="mt-2 text-xs font-medium text-black dark:text-white">
@if ($i < $totalSteps)
<div
class="flex-1 h-0.5 mx-4 transition-all duration-300
{{ $i < $currentStep ? 'bg-success' : 'bg-coolgray-200 dark:bg-coolgray-600' }}">
{{ $i < $currentStep ? 'bg-success' : 'bg-neutral-200 dark:bg-coolgray-300' }}">
</div>
@endif
</div>

View file

@ -1,5 +1,5 @@
<div class="w-full max-w-4xl">
<div class="bg-white dark:bg-coolgray-100 rounded-lg shadow-sm border border-neutral-200 dark:border-coolgray-300 overflow-hidden">
<div class=" rounded-lg shadow-sm border border-neutral-200 dark:border-coolgray-300 overflow-hidden">
<div class="p-8 lg:p-12">
<h1 class="text-3xl font-bold lg:text-4xl mb-4">{{ $title }}</h1>
@isset($question)
@ -16,7 +16,7 @@
</div>
@isset($explanation)
<div class="dark:bg-coolgray-200 border-t border-neutral-200 dark:border-coolgray-300 p-8 lg:p-12 bg-neutral-50">
<div class=" border-t border-neutral-200 dark:border-coolgray-300 p-8 lg:p-12 ">
<h3 class="text-sm font-bold uppercase tracking-wide mb-4 dark:text-neutral-400">
Technical Details
</h3>

File diff suppressed because it is too large Load diff