fix(ui): set active server at mount only (race-free)
Revert the hydrate-on-every-request sync — writing the single global active-server session on every async request (slow load(), polls, parallel tabs) is inherently last-writer-wins and races. Setting it only at mount (once per deliberate navigation) is race-free and fixes the visible drift. bfcache restore + multi-tab remain inherent edges of the single-session model — documented in the handoff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>feat/v1-foundation
parent
7ea789c078
commit
0b1b5357d2
|
|
@ -61,29 +61,17 @@ class Show extends Component
|
|||
*/
|
||||
public function mount(): void
|
||||
{
|
||||
$this->syncActiveServer();
|
||||
// Viewing a server's details makes it the ACTIVE server, so the sidebar switcher
|
||||
// (and the scoped sections) reflect the server on screen. Set ONLY at mount — i.e.
|
||||
// once per deliberate navigation — so a slow in-flight load() or a parallel tab
|
||||
// can never write a stale value over a newer selection (the single-session active
|
||||
// server is last-writer-wins; we keep writes to deliberate navigations only).
|
||||
session(['active_server_id' => $this->server->id]);
|
||||
|
||||
// identity + gauges render from the persisted row immediately;
|
||||
// the live snapshot loads lazily via wire:init -> load().
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-assert this server as the ACTIVE one on EVERY request to this component (mount,
|
||||
* the wire:poll tick, any action). This is what keeps the sidebar switcher + scoped
|
||||
* sections in sync with the server on screen — and it also covers a wire:navigate
|
||||
* bfcache restore (Back/Forward), which skips mount() but still hits the server on
|
||||
* the next poll/interaction. Server-side + idempotent, so there is no request race.
|
||||
*/
|
||||
public function hydrate(): void
|
||||
{
|
||||
$this->syncActiveServer();
|
||||
}
|
||||
|
||||
private function syncActiveServer(): void
|
||||
{
|
||||
session(['active_server_id' => $this->server->id]);
|
||||
}
|
||||
|
||||
/** Lazy: pull the full SSH snapshot after the shell renders, behind skeletons. */
|
||||
public function load(FleetService $fleet): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,22 +29,6 @@ class ServerContextSyncTest extends TestCase
|
|||
$this->assertSame($b->id, session('active_server_id'));
|
||||
}
|
||||
|
||||
public function test_interacting_with_a_details_page_resyncs_active_server(): void
|
||||
{
|
||||
// Simulates a bfcache restore where mount() did not run and the session points
|
||||
// elsewhere: the next request to the component (poll/action → hydrate) re-syncs.
|
||||
$this->actingAs(User::factory()->create());
|
||||
$a = $this->server('A');
|
||||
$b = $this->server('B');
|
||||
|
||||
$component = Livewire::test(Show::class, ['server' => $a]);
|
||||
session(['active_server_id' => $b->id]); // drift (as after Back/Forward)
|
||||
|
||||
$component->call('pollMetrics');
|
||||
|
||||
$this->assertSame($a->id, session('active_server_id'));
|
||||
}
|
||||
|
||||
public function test_switching_on_a_details_page_targets_the_new_server(): void
|
||||
{
|
||||
$a = $this->server('A');
|
||||
|
|
|
|||
Loading…
Reference in New Issue