Skip to content

A profile switch that does not reload is invisible: the list denies it, and it cannot be cancelled #582

Description

@mairas

SettingsService.setActiveProfile persists the chosen profile and then asks ReloadService to reload. When that reload is declined — the server probe fails or returns 5xx, e.g. a Traefik 502 while Signal K restarts — the switch is deferred: the device will boot onto the new profile at the next reload, whenever that is.

Nothing durable records that state, and three affordances actively contradict it.

What the user sees

  • The list says the switch did not happen. getActiveProfileName() returns the loaded slot, so the profile row still reads "Active on this device" for the old profile. That is honest about what is on screen and silent about what the device will boot into.
  • The only signal is a snackbar that the app itself destroys. ReloadService.showUnreachableToast() opens one MatSnackBar with a Retry action. The decline scenario is a Signal K restart, so the WebSocket is retrying and app.component.ts shows a 3s toast on each WebSocketRetrying transition — Material shows one snackbar at a time, so the Retry toast is displaced roughly one backoff interval (5s) after it appears.
  • There is no cancel. The profile list renders a Switch button only when !profile.isActive, so the old profile — the one the user now wants to stay on — has no button. Undoing the pending switch means switching to a third profile and back, which presupposes understanding a state the UI denies exists.
  • deleteProfile's guard keys off getActiveProfileName(), so the profile the device is pointed at is deletable. The next boot then 404s on the persisted slot and lands in the missing-shared-config recovery.

A marine display is power-cycled routinely, so "the next reload" can be hours later, with no reminder that the choice was pending.

Also worth deciding

setRemoteContextDemand keys by the persisted name while computing the value from the loaded profile's dashboards, so a dashboard edit during a pending switch writes the old profile's AIS demand under the new profile's key. app-initNetwork reads that key pre-auth and fails open only on a missing key — a present, wrong one defeats it, and the new profile's AIS widgets come up empty for that boot.

Scope

  • R1. Decide whether a pending switch should exist at all, or whether a declined reload should abandon it and require the user to ask again.
  • R2. If it stays: surface it (a pending marker on the profile row with a Cancel), refuse to delete the pending target, and key the remote-context demand off the loaded slot.
  • R3. Route the toast's Retry back through ProfileService.switchProfile rather than a raw reload(), so the slot-still-exists check and the write-queue drain run before the navigation. Today a Retry can navigate with edits still queued against the old profile.

Found by the review on #578, which fixed the data-loss half (saves no longer follow the pending name). This is the part that change deliberately left alone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions