Skip to content

Commit 92326c0

Browse files
andrasbacsaiclaude
andcommitted
Improve upgrade process UX with better progress visibility
- Add step-by-step progress indicator (Preparing → Helper → Image → Restart) - Display elapsed time during upgrade (MM:SS format) - Show version transition in header (v4.0.0-beta.454 → v4.0.0-beta.456) - Add expandable changelog preview before upgrading - Reduce reload delay from 5s to 3s with countdown timer - Add "Reload Now" button to skip countdown - Improve status messages with step-specific descriptions - Add success state with clear indication when upgrade completes - Create new upgrade-progress component for visual step tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent dafd10d commit 92326c0

File tree

3 files changed

+399
-49
lines changed

3 files changed

+399
-49
lines changed

app/Livewire/Upgrade.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Actions\Server\UpdateCoolify;
66
use App\Models\InstanceSettings;
7+
use App\Services\ChangelogService;
78
use Livewire\Component;
89

910
class Upgrade extends Component
@@ -14,21 +15,57 @@ class Upgrade extends Component
1415

1516
public string $latestVersion = '';
1617

18+
public string $currentVersion = '';
19+
20+
public array $changelogEntries = [];
21+
1722
protected $listeners = ['updateAvailable' => 'checkUpdate'];
1823

24+
public function mount()
25+
{
26+
$this->currentVersion = config('constants.coolify.version');
27+
}
28+
1929
public function checkUpdate()
2030
{
2131
try {
2232
$this->latestVersion = get_latest_version_of_coolify();
33+
$this->currentVersion = config('constants.coolify.version');
2334
$this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false);
2435
if (isDev()) {
2536
$this->isUpgradeAvailable = true;
2637
}
38+
$this->loadChangelog();
2739
} catch (\Throwable $e) {
2840
return handleError($e, $this);
2941
}
3042
}
3143

44+
public function loadChangelog()
45+
{
46+
try {
47+
$service = app(ChangelogService::class);
48+
$currentVersion = str_replace('v', '', $this->currentVersion);
49+
50+
$this->changelogEntries = $service->getEntries(1)
51+
->filter(function ($entry) use ($currentVersion) {
52+
$entryVersion = str_replace('v', '', $entry->tag_name);
53+
54+
return version_compare($entryVersion, $currentVersion, '>');
55+
})
56+
->take(3)
57+
->map(fn ($entry) => [
58+
'tag_name' => $entry->tag_name,
59+
'title' => $entry->title,
60+
'content_html' => $entry->content_html,
61+
])
62+
->values()
63+
->toArray();
64+
} catch (\Throwable $e) {
65+
$this->changelogEntries = [];
66+
}
67+
}
68+
3269
public function upgrade()
3370
{
3471
try {
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
@props(['step' => 0])
2+
3+
<div class="w-full max-w-md mx-auto" x-data="{ activeStep: {{ $step }} }" x-effect="activeStep = $el.closest('[x-data]')?.__x?.$data?.currentStep ?? {{ $step }}">
4+
<div class="flex items-center justify-between">
5+
{{-- Step 1: Preparing --}}
6+
<div class="flex items-center flex-1">
7+
<div class="flex flex-col items-center">
8+
<div class="flex items-center justify-center size-8 rounded-full border-2 transition-all duration-300"
9+
:class="{
10+
'bg-success border-success': currentStep > 1,
11+
'bg-warning/20 border-warning': currentStep === 1,
12+
'border-neutral-400 dark:border-coolgray-300': currentStep < 1
13+
}">
14+
<template x-if="currentStep > 1">
15+
<svg class="size-4 text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
16+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
17+
</svg>
18+
</template>
19+
<template x-if="currentStep === 1">
20+
<svg class="size-4 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
21+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
22+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
23+
</svg>
24+
</template>
25+
<template x-if="currentStep < 1">
26+
<span class="text-xs font-medium text-neutral-500 dark:text-neutral-400">1</span>
27+
</template>
28+
</div>
29+
<span class="mt-1.5 text-xs font-medium transition-colors duration-300"
30+
:class="{
31+
'text-success': currentStep > 1,
32+
'text-warning': currentStep === 1,
33+
'text-neutral-500 dark:text-neutral-400': currentStep < 1
34+
}">Preparing</span>
35+
</div>
36+
<div class="flex-1 h-0.5 mx-2 transition-all duration-300"
37+
:class="currentStep > 1 ? 'bg-success' : 'bg-neutral-300 dark:bg-coolgray-300'"></div>
38+
</div>
39+
40+
{{-- Step 2: Helper --}}
41+
<div class="flex items-center flex-1">
42+
<div class="flex flex-col items-center">
43+
<div class="flex items-center justify-center size-8 rounded-full border-2 transition-all duration-300"
44+
:class="{
45+
'bg-success border-success': currentStep > 2,
46+
'bg-warning/20 border-warning': currentStep === 2,
47+
'border-neutral-400 dark:border-coolgray-300': currentStep < 2
48+
}">
49+
<template x-if="currentStep > 2">
50+
<svg class="size-4 text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
51+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
52+
</svg>
53+
</template>
54+
<template x-if="currentStep === 2">
55+
<svg class="size-4 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
56+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
57+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
58+
</svg>
59+
</template>
60+
<template x-if="currentStep < 2">
61+
<span class="text-xs font-medium text-neutral-500 dark:text-neutral-400">2</span>
62+
</template>
63+
</div>
64+
<span class="mt-1.5 text-xs font-medium transition-colors duration-300"
65+
:class="{
66+
'text-success': currentStep > 2,
67+
'text-warning': currentStep === 2,
68+
'text-neutral-500 dark:text-neutral-400': currentStep < 2
69+
}">Helper</span>
70+
</div>
71+
<div class="flex-1 h-0.5 mx-2 transition-all duration-300"
72+
:class="currentStep > 2 ? 'bg-success' : 'bg-neutral-300 dark:bg-coolgray-300'"></div>
73+
</div>
74+
75+
{{-- Step 3: Image --}}
76+
<div class="flex items-center flex-1">
77+
<div class="flex flex-col items-center">
78+
<div class="flex items-center justify-center size-8 rounded-full border-2 transition-all duration-300"
79+
:class="{
80+
'bg-success border-success': currentStep > 3,
81+
'bg-warning/20 border-warning': currentStep === 3,
82+
'border-neutral-400 dark:border-coolgray-300': currentStep < 3
83+
}">
84+
<template x-if="currentStep > 3">
85+
<svg class="size-4 text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
86+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
87+
</svg>
88+
</template>
89+
<template x-if="currentStep === 3">
90+
<svg class="size-4 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
91+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
92+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
93+
</svg>
94+
</template>
95+
<template x-if="currentStep < 3">
96+
<span class="text-xs font-medium text-neutral-500 dark:text-neutral-400">3</span>
97+
</template>
98+
</div>
99+
<span class="mt-1.5 text-xs font-medium transition-colors duration-300"
100+
:class="{
101+
'text-success': currentStep > 3,
102+
'text-warning': currentStep === 3,
103+
'text-neutral-500 dark:text-neutral-400': currentStep < 3
104+
}">Image</span>
105+
</div>
106+
<div class="flex-1 h-0.5 mx-2 transition-all duration-300"
107+
:class="currentStep > 3 ? 'bg-success' : 'bg-neutral-300 dark:bg-coolgray-300'"></div>
108+
</div>
109+
110+
{{-- Step 4: Restart --}}
111+
<div class="flex items-center">
112+
<div class="flex flex-col items-center">
113+
<div class="flex items-center justify-center size-8 rounded-full border-2 transition-all duration-300"
114+
:class="{
115+
'bg-success border-success': currentStep > 4,
116+
'bg-warning/20 border-warning': currentStep === 4,
117+
'border-neutral-400 dark:border-coolgray-300': currentStep < 4
118+
}">
119+
<template x-if="currentStep > 4">
120+
<svg class="size-4 text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
121+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
122+
</svg>
123+
</template>
124+
<template x-if="currentStep === 4">
125+
<svg class="size-4 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
126+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
127+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
128+
</svg>
129+
</template>
130+
<template x-if="currentStep < 4">
131+
<span class="text-xs font-medium text-neutral-500 dark:text-neutral-400">4</span>
132+
</template>
133+
</div>
134+
<span class="mt-1.5 text-xs font-medium transition-colors duration-300"
135+
:class="{
136+
'text-success': currentStep > 4,
137+
'text-warning': currentStep === 4,
138+
'text-neutral-500 dark:text-neutral-400': currentStep < 4
139+
}">Restart</span>
140+
</div>
141+
</div>
142+
</div>
143+
</div>

0 commit comments

Comments
 (0)