feat(studio): contextual "Add registry token" CTA on install auth wall (v0.46.0)
Some checks are pending
Security / Security check (push) Waiting to run
Some checks are pending
Security / Security check (push) Waiting to run
The hub's v0.10.91 install error message already tells the operator exactly what to do — set FAI_REGISTRY_TOKEN or save to ~/.fai/registry-token via Settings. But that text lives in a FaiErrorBox inside the install dialog. Reading the buried recovery instruction, finding Settings, scrolling to the Registry credentials panel, pasting, then re-clicking the install pill is five hops for what should be one. When at least one item in the install dialog fails with the "registry returned an HTML page" / "no registry token configured" signature, the dialog now surfaces a prominent filled "Add registry token" button next to Close. Click closes the install dialog and opens the Settings dialog directly so the operator pastes + saves without losing context. After Settings dismisses, the operator is back at the flow card and re-clicks the same pill to retry. Detection is signature-based (substring match on the hub's error text) so it activates whether the install was a single- pill click or an "Install all" sequence. Other failure modes (network down, signature invalid, sha mismatch) still show just the Close button — the CTA is specific to the auth-wall case it can actually unblock. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
3db7db7330
commit
7416c34d7c
7 changed files with 43 additions and 1 deletions
|
|
@ -428,6 +428,7 @@
|
||||||
"failed": { "type": "int" }
|
"failed": { "type": "int" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flowsInstallAuthWallButton": "Registry-Token einfügen",
|
||||||
"flowsOpenInEditorTooltip": "YAML-Datei im Standard-Editor öffnen",
|
"flowsOpenInEditorTooltip": "YAML-Datei im Standard-Editor öffnen",
|
||||||
"flowsOpenInEditorFailed": "Konnte Datei nicht öffnen: {error}",
|
"flowsOpenInEditorFailed": "Konnte Datei nicht öffnen: {error}",
|
||||||
"@flowsOpenInEditorFailed": {
|
"@flowsOpenInEditorFailed": {
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,7 @@
|
||||||
"failed": { "type": "int" }
|
"failed": { "type": "int" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flowsInstallAuthWallButton": "Add registry token",
|
||||||
"flowsOpenInEditorTooltip": "Open the YAML file in your default editor",
|
"flowsOpenInEditorTooltip": "Open the YAML file in your default editor",
|
||||||
"flowsOpenInEditorFailed": "Could not open file: {error}",
|
"flowsOpenInEditorFailed": "Could not open file: {error}",
|
||||||
"@flowsOpenInEditorFailed": {
|
"@flowsOpenInEditorFailed": {
|
||||||
|
|
|
||||||
|
|
@ -1958,6 +1958,12 @@ abstract class AppLocalizations {
|
||||||
/// **'{ok} installed, {failed} failed.'**
|
/// **'{ok} installed, {failed} failed.'**
|
||||||
String flowsInstallDepsAnyFailed(int ok, int failed);
|
String flowsInstallDepsAnyFailed(int ok, int failed);
|
||||||
|
|
||||||
|
/// No description provided for @flowsInstallAuthWallButton.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Add registry token'**
|
||||||
|
String get flowsInstallAuthWallButton;
|
||||||
|
|
||||||
/// No description provided for @flowsOpenInEditorTooltip.
|
/// No description provided for @flowsOpenInEditorTooltip.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
|
||||||
|
|
@ -1109,6 +1109,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
return '$ok installiert, $failed fehlgeschlagen.';
|
return '$ok installiert, $failed fehlgeschlagen.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flowsInstallAuthWallButton => 'Registry-Token einfügen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get flowsOpenInEditorTooltip => 'YAML-Datei im Standard-Editor öffnen';
|
String get flowsOpenInEditorTooltip => 'YAML-Datei im Standard-Editor öffnen';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1122,6 +1122,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
return '$ok installed, $failed failed.';
|
return '$ok installed, $failed failed.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get flowsInstallAuthWallButton => 'Add registry token';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get flowsOpenInEditorTooltip =>
|
String get flowsOpenInEditorTooltip =>
|
||||||
'Open the YAML file in your default editor';
|
'Open the YAML file in your default editor';
|
||||||
|
|
|
||||||
|
|
@ -940,6 +940,22 @@ class _InstallDependenciesDialogState
|
||||||
int get _failedCount =>
|
int get _failedCount =>
|
||||||
_items.where((i) => i.status == _InstallStatus.failed).length;
|
_items.where((i) => i.status == _InstallStatus.failed).length;
|
||||||
|
|
||||||
|
/// True iff at least one failure carries the v0.10.91+ HTML-instead-
|
||||||
|
/// of-bundle signature emitted by `download_to_temp` when the
|
||||||
|
/// registry redirects an unauthenticated request to a signin page.
|
||||||
|
/// Used to surface a contextual "Open Settings" button so the
|
||||||
|
/// operator does not have to read the wall of error text first.
|
||||||
|
bool get _anyAuthWallFailure => _items.any(
|
||||||
|
(i) =>
|
||||||
|
i.status == _InstallStatus.failed && _isAuthWallError(i.error),
|
||||||
|
);
|
||||||
|
|
||||||
|
static bool _isAuthWallError(String? msg) {
|
||||||
|
if (msg == null) return false;
|
||||||
|
return msg.contains('registry returned an HTML page') ||
|
||||||
|
msg.contains('no registry token configured');
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
@ -986,6 +1002,18 @@ class _InstallDependenciesDialogState
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
if (!_running && _anyAuthWallFailure)
|
||||||
|
FilledButton.icon(
|
||||||
|
icon: const Icon(Icons.vpn_key_outlined, size: 16),
|
||||||
|
label: Text(l.flowsInstallAuthWallButton),
|
||||||
|
onPressed: () async {
|
||||||
|
// Close install dialog first so the operator returns
|
||||||
|
// to the flow card on Settings dismiss — then they
|
||||||
|
// can re-click the pill to retry the install.
|
||||||
|
Navigator.pop(context, _anySucceeded);
|
||||||
|
await FaiSettingsDialog.show(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: _running
|
onPressed: _running
|
||||||
? null
|
? null
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
name: fai_studio
|
name: fai_studio
|
||||||
description: "F∆I Studio — desktop GUI for the F∆I hub"
|
description: "F∆I Studio — desktop GUI for the F∆I hub"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 0.45.0
|
version: 0.46.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.11.0-200.1.beta
|
sdk: ^3.11.0-200.1.beta
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue