fix(versions): keep the changelog series stable on reload (0.10 -> 0.1 bug)
The series rail synced ?series=<key> via Livewire #[Url] with a bare numeric key like "0.10". Livewire type-juggles that to 0.1 (the trailing zero is lost), so reloading while viewing the 0.10 series silently switched to 0.1 and rewrote the URL. Prefix the series key with a non-numeric "v" (?series=v0.10) so it round-trips as a string; the rail label still shows the dotted "0.10". Surfaced now that a 0.10 series exists. Browser-verified: selecting 0.10 -> ?series=v0.10, and it survives a reload. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/v1-foundation
parent
d8da46151e
commit
8dfc11fd5d
|
|
@ -382,7 +382,10 @@ class Index extends Component
|
|||
if ($rel['unreleased']) {
|
||||
$key = 'unreleased';
|
||||
} elseif (preg_match('/^v?(\d+)\.(\d+)\./', $rel['version'], $m)) {
|
||||
$key = $m[1].'.'.$m[2];
|
||||
// Prefix the series key with a non-numeric 'v' so the ?series= URL value is never a
|
||||
// bare decimal — Livewire's #[Url] otherwise type-juggles "0.10" → 0.1 (the trailing
|
||||
// zero is lost), silently switching the selected series on reload. The label strips it.
|
||||
$key = 'v'.$m[1].'.'.$m[2];
|
||||
} else {
|
||||
$key = 'other';
|
||||
}
|
||||
|
|
@ -397,7 +400,7 @@ class Index extends Component
|
|||
'label' => match ($key) {
|
||||
'unreleased' => __('versions.unreleased'),
|
||||
'other' => __('versions.series_other'),
|
||||
default => $key,
|
||||
default => ltrim($key, 'v'), // display the dotted series (the 'v' is only for the URL)
|
||||
},
|
||||
'unreleased' => $key === 'unreleased',
|
||||
'count' => count($rels),
|
||||
|
|
@ -415,7 +418,7 @@ class Index extends Component
|
|||
return $ra <=> $rb;
|
||||
}
|
||||
|
||||
return $ra === 1 ? version_compare($b['key'].'.0', $a['key'].'.0') : 0;
|
||||
return $ra === 1 ? version_compare(ltrim($b['key'], 'v').'.0', ltrim($a['key'], 'v').'.0') : 0;
|
||||
});
|
||||
|
||||
return $series;
|
||||
|
|
@ -628,7 +631,7 @@ class Index extends Component
|
|||
|
||||
// Mark the series that holds the running version (a small "installed" cue in the rail).
|
||||
$installed = ltrim((string) config('clusev.version'), 'vV');
|
||||
$currentSeries = preg_match('/^(\d+)\.(\d+)\./', $installed, $m) ? $m[1].'.'.$m[2] : null;
|
||||
$currentSeries = preg_match('/^(\d+)\.(\d+)\./', $installed, $m) ? 'v'.$m[1].'.'.$m[2] : null;
|
||||
|
||||
// Passive (no network): cached remote result if a check has run, else local .git.
|
||||
$latestTag = $this->resolveLatestTag($this->channel());
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ class VersionsChangelogTest extends TestCase
|
|||
// …selecting the 0.1 series brings it into view and jumps back to page 1.
|
||||
Livewire::test(Index::class)
|
||||
->set('changelogPage', 3)
|
||||
->call('selectSeries', '0.1')
|
||||
->assertSet('series', '0.1')
|
||||
->call('selectSeries', 'v0.1')
|
||||
->assertSet('series', 'v0.1')
|
||||
->assertSet('changelogPage', 1)
|
||||
->assertSee('v0.1.0');
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ class VersionsChangelogTest extends TestCase
|
|||
public function test_a_long_series_is_paginated_to_the_per_page_limit(): void
|
||||
{
|
||||
Livewire::test(Index::class)
|
||||
->call('selectSeries', '0.9')
|
||||
->call('selectSeries', 'v0.9')
|
||||
->assertViewHas('totalPages', fn ($total): bool => $total > 1)
|
||||
->assertViewHas('pagedReleases', fn ($releases): bool => is_array($releases) && count($releases) <= 8);
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ class VersionsChangelogTest extends TestCase
|
|||
$pageOne = null;
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->call('selectSeries', '0.9')
|
||||
->call('selectSeries', 'v0.9')
|
||||
->assertViewHas('pagedReleases', function ($releases) use (&$pageOne): bool {
|
||||
$pageOne = array_column($releases, 'version');
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ class VersionsChangelogTest extends TestCase
|
|||
});
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->call('selectSeries', '0.9')
|
||||
->call('selectSeries', 'v0.9')
|
||||
->call('gotoChangelogPage', 2)
|
||||
->assertViewHas('pagedReleases', function ($releases) use (&$pageOne): bool {
|
||||
$pageTwo = array_column($releases, 'version');
|
||||
|
|
@ -121,7 +121,7 @@ class VersionsChangelogTest extends TestCase
|
|||
public function test_an_out_of_range_page_is_clamped(): void
|
||||
{
|
||||
Livewire::test(Index::class)
|
||||
->call('selectSeries', '0.9')
|
||||
->call('selectSeries', 'v0.9')
|
||||
->call('gotoChangelogPage', 9999)
|
||||
->assertViewHas('changelogPage', fn ($page): bool => $page >= 1)
|
||||
->assertViewHas('pagedReleases', fn ($releases): bool => is_array($releases) && count($releases) >= 1)
|
||||
|
|
@ -132,7 +132,7 @@ class VersionsChangelogTest extends TestCase
|
|||
{
|
||||
config()->set('clusev.version', '0.7.3');
|
||||
|
||||
Livewire::test(Index::class)->assertViewHas('currentSeries', '0.7');
|
||||
Livewire::test(Index::class)->assertViewHas('currentSeries', 'v0.7');
|
||||
}
|
||||
|
||||
public function test_total_release_count_is_passed_for_the_panel_subtitle(): void
|
||||
|
|
@ -143,12 +143,22 @@ class VersionsChangelogTest extends TestCase
|
|||
public function test_series_and_page_are_deep_linkable_via_the_query_string(): void
|
||||
{
|
||||
// ?series= + ?page= drive the view so a series/page is shareable and survives reload.
|
||||
Livewire::withQueryParams(['series' => '0.9', 'page' => 2])
|
||||
Livewire::withQueryParams(['series' => 'v0.9', 'page' => 2])
|
||||
->test(Index::class)
|
||||
->assertSet('series', '0.9')
|
||||
->assertSet('series', 'v0.9')
|
||||
->assertSet('changelogPage', 2);
|
||||
}
|
||||
|
||||
public function test_a_trailing_zero_series_like_0_10_survives_a_deep_link(): void
|
||||
{
|
||||
// The 'v' prefix keeps the ?series= value non-numeric, so "0.10" is NOT type-juggled to
|
||||
// "0.1" on reload (which used to silently switch the selected series).
|
||||
Livewire::withQueryParams(['series' => 'v0.10'])
|
||||
->test(Index::class)
|
||||
->assertSet('series', 'v0.10')
|
||||
->assertViewHas('activeKey', 'v0.10');
|
||||
}
|
||||
|
||||
public function test_chevron_right_icon_renders_a_real_path(): void
|
||||
{
|
||||
// The accordion disclosure caret and the pagination "Next" button both use x-icon
|
||||
|
|
|
|||
Loading…
Reference in New Issue