fix(shell): auth-rejected hub no longer reported as unreachable
Some checks are pending
Security / Security check (push) Waiting to run
Some checks are pending
Security / Security check (push) Waiting to run
The sustained-failure banner treated every failed health poll as 'can't reach the hub'. With token auth active, a wrong or rotated token gets UNAUTHENTICATED from a perfectly reachable hub — the old wording sent the operator to fix the endpoint. The shell now uses the SDK's probe() and, on auth rejection, switches the banner to 'rejected the sign-in — check the access token' (key-off icon, DE+EN). Two widget tests pin the wording per failure kind and the banner clearing once the probe turns serving. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
33e5d35ac9
commit
f0f151fa7a
8 changed files with 127 additions and 5 deletions
|
|
@ -275,6 +275,18 @@ class StudioShellState extends State<StudioShell> {
|
|||
/// flash the banner — only sustained failure does.
|
||||
bool get _hubUnreachable => _failedPolls >= _unreachableThreshold;
|
||||
|
||||
/// True when the last failed poll was an auth rejection
|
||||
/// (UNAUTHENTICATED / PERMISSION_DENIED): the hub is up, the
|
||||
/// token is wrong. The banner must say so — "can't reach the
|
||||
/// hub" would send the operator to fix the wrong thing.
|
||||
bool _authRejected = false;
|
||||
|
||||
/// Test-only: replaces the hub health probe so widget tests can
|
||||
/// simulate sustained unreachable / auth-rejected states
|
||||
/// without a live hub.
|
||||
@visibleForTesting
|
||||
static Future<HubProbeResult> Function()? debugProbeOverride;
|
||||
|
||||
/// Current connection state, for descendants (e.g. WelcomePage)
|
||||
/// that adapt their content to hub availability.
|
||||
bool? get connected => _connected;
|
||||
|
|
@ -411,17 +423,25 @@ class StudioShellState extends State<StudioShell> {
|
|||
}
|
||||
|
||||
Future<void> _checkHealth() async {
|
||||
final ok = await HubService.instance.healthy();
|
||||
final probe = debugProbeOverride != null
|
||||
? await debugProbeOverride!()
|
||||
: await HubService.instance.probeHealth();
|
||||
if (!mounted) return;
|
||||
final ok = probe == HubProbeResult.serving;
|
||||
final authRejected = probe == HubProbeResult.authRejected;
|
||||
final wasUnreachable = _hubUnreachable;
|
||||
final nextFailed = ok ? 0 : _failedPolls + 1;
|
||||
final connectionChanged = _connected != ok;
|
||||
final bannerChanged =
|
||||
wasUnreachable != (nextFailed >= _unreachableThreshold);
|
||||
if (connectionChanged || _failedPolls != nextFailed || bannerChanged) {
|
||||
if (connectionChanged ||
|
||||
_failedPolls != nextFailed ||
|
||||
bannerChanged ||
|
||||
_authRejected != authRejected) {
|
||||
setState(() {
|
||||
_connected = ok;
|
||||
_failedPolls = nextFailed;
|
||||
_authRejected = authRejected;
|
||||
});
|
||||
}
|
||||
if (ok) {
|
||||
|
|
@ -557,6 +577,7 @@ class StudioShellState extends State<StudioShell> {
|
|||
if (_hubUnreachable)
|
||||
_HubUnreachableBanner(
|
||||
endpoint: HubService.instance.endpointLabel,
|
||||
authRejected: _authRejected,
|
||||
onOpenSettings: () => ChainSettingsDialog.show(context),
|
||||
),
|
||||
Expanded(
|
||||
|
|
@ -595,13 +616,17 @@ class StudioShellState extends State<StudioShell> {
|
|||
/// One-line banner shown when the hub has been unreachable for
|
||||
/// several consecutive health polls. Replaces the indefinite
|
||||
/// silent "connecting…" with an explicit message + a jump to
|
||||
/// Settings, where the operator can fix the endpoint.
|
||||
/// Settings, where the operator can fix the endpoint. When the
|
||||
/// failure is an auth rejection the wording flips to "check the
|
||||
/// access token" — the endpoint is fine in that case.
|
||||
class _HubUnreachableBanner extends StatelessWidget {
|
||||
final String endpoint;
|
||||
final bool authRejected;
|
||||
final VoidCallback onOpenSettings;
|
||||
|
||||
const _HubUnreachableBanner({
|
||||
required this.endpoint,
|
||||
required this.authRejected,
|
||||
required this.onOpenSettings,
|
||||
});
|
||||
|
||||
|
|
@ -619,14 +644,16 @@ class _HubUnreachableBanner extends StatelessWidget {
|
|||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_off_outlined,
|
||||
authRejected ? Icons.key_off_outlined : Icons.cloud_off_outlined,
|
||||
size: 18,
|
||||
color: theme.colorScheme.onErrorContainer,
|
||||
),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l.hubUnreachableBanner(endpoint),
|
||||
authRejected
|
||||
? l.hubAuthRejectedBanner(endpoint)
|
||||
: l.hubUnreachableBanner(endpoint),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onErrorContainer,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue