feat(doctor): update banner via HubAdmin.CheckUpdate (v0.9.0)
Doctor page now opens with a slim banner above the summary strip
in two cases: an actually newer version on the channel ("Update
available — v0.x.y", success-tone "new" pill, release-notes URL
when present) or the release host being unreachable
("Release host unreachable", neutral "offline" pill, with the
network reason). When local matches latest the banner stays
hidden — quiet UI is the right default.
Hooks into the existing parallel-fetch in `HubService.doctor` so
the new RPC adds zero latency to the page load.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
753db4fc60
commit
18db6ff164
5 changed files with 113 additions and 3 deletions
|
|
@ -59,9 +59,14 @@ class _DoctorPageState extends State<DoctorPage> {
|
|||
);
|
||||
}
|
||||
final s = snapshot.data!;
|
||||
final showUpdate = s.update.updateAvailable ||
|
||||
(!s.update.manifestReachable &&
|
||||
s.update.localVersion.isNotEmpty);
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
children: [
|
||||
if (showUpdate) _UpdateBanner(status: s.update),
|
||||
if (showUpdate) const SizedBox(height: FaiSpace.lg),
|
||||
_SummaryStrip(snapshot: s),
|
||||
const SizedBox(height: FaiSpace.xl),
|
||||
_Section(
|
||||
|
|
@ -431,3 +436,72 @@ class _ServicesPanel extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _UpdateBanner extends StatelessWidget {
|
||||
final UpdateStatus status;
|
||||
|
||||
const _UpdateBanner({required this.status});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final available = status.updateAvailable;
|
||||
final iconData = available
|
||||
? Icons.system_update_alt_outlined
|
||||
: Icons.cloud_off_outlined;
|
||||
final iconColor = available
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurfaceVariant;
|
||||
final title = available
|
||||
? 'Update available — ${status.latestVersion}'
|
||||
: 'Release host unreachable';
|
||||
final body = available
|
||||
? 'Channel ${status.channel} now offers ${status.latestVersion}. '
|
||||
'Apply with: fai update apply --channel ${status.channel}'
|
||||
: (status.reason ?? 'Could not contact the release feed for ${status.channel}.');
|
||||
return FaiCard(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(iconData, size: 20, color: iconColor),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
body,
|
||||
style: FaiTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
if (available && status.releaseNotesUrl != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'notes: ${status.releaseNotesUrl}',
|
||||
style: FaiTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
FaiPill(
|
||||
label: available ? 'new' : 'offline',
|
||||
tone: available ? FaiPillTone.success : FaiPillTone.neutral,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue