feat(store): advisory-version badge for federated entries
Some checks failed
Security / Security check (push) Failing after 1s

Store cards + detail-sheet now prefix the version pill with
`~` and attach a tooltip for federated entries (MCP / n8n /
Temporal). Upstream services don't honour semver, so the
version pill is a label, not a contract — the tilde says
"this number may change without a version bump."

Three render sites updated to stay visually consistent:
- compact card pill in grid view
- expanded card pill row
- detail-sheet header pill cluster

EN + DE l10n entries added (`storeAdvisoryVersionTooltip`)
and `app_localizations.dart` regenerated.

dart analyze clean; flutter test green (11 tests).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-28 23:26:49 +02:00
parent c5a96bc8d4
commit 327bc0fea2
7 changed files with 55 additions and 13 deletions

View file

@ -776,6 +776,7 @@
} }
} }
}, },
"storeAdvisoryVersionTooltip": "Föderierter Upstream-Dienst — Version ist Richtwert; der Upstream kann ohne Versionsanhebung Kompatibilität brechen.",
"maintenanceHeader": "HUB-WARTUNG", "maintenanceHeader": "HUB-WARTUNG",
"maintenanceResetBlurb": "Operator-Zustand zurücksetzen und mit einem sauberen Hub neu starten. Stoppt jeden laufenden Daemon, sichert ~/.fai/ atomar in ein Backup, legt es dann neu an — Binary, Channel-Pointer, MCP-/n8n-/System-AI-Konfiguration und Registry-Token bleiben erhalten. Wiederherstellen durch Zurückverschieben des Backup-Ordners.", "maintenanceResetBlurb": "Operator-Zustand zurücksetzen und mit einem sauberen Hub neu starten. Stoppt jeden laufenden Daemon, sichert ~/.fai/ atomar in ein Backup, legt es dann neu an — Binary, Channel-Pointer, MCP-/n8n-/System-AI-Konfiguration und Registry-Token bleiben erhalten. Wiederherstellen durch Zurückverschieben des Backup-Ordners.",
"maintenanceKeepModulesTitle": "Installierte Module behalten", "maintenanceKeepModulesTitle": "Installierte Module behalten",

View file

@ -779,6 +779,7 @@
} }
} }
}, },
"storeAdvisoryVersionTooltip": "Federated upstream service — version is advisory; the upstream may break compatibility without bumping it.",
"maintenanceHeader": "HUB MAINTENANCE", "maintenanceHeader": "HUB MAINTENANCE",
"maintenanceResetBlurb": "Wipe operator state and start over with a clean hub. Stops every running daemon, atomically backs ~/.fai/ up, then recreates it with the binary, channel state, MCP / n8n / system-AI config, and registry token preserved. Restore by moving the backup directory back.", "maintenanceResetBlurb": "Wipe operator state and start over with a clean hub. Stops every running daemon, atomically backs ~/.fai/ up, then recreates it with the binary, channel state, MCP / n8n / system-AI config, and registry token preserved. Restore by moving the backup directory back.",
"maintenanceKeepModulesTitle": "Keep installed modules", "maintenanceKeepModulesTitle": "Keep installed modules",

View file

@ -2246,6 +2246,12 @@ abstract class AppLocalizations {
/// **'Could not save: {error}'** /// **'Could not save: {error}'**
String hubAuthTokenSaveFailedToast(String error); String hubAuthTokenSaveFailedToast(String error);
/// No description provided for @storeAdvisoryVersionTooltip.
///
/// In en, this message translates to:
/// **'Federated upstream service — version is advisory; the upstream may break compatibility without bumping it.'**
String get storeAdvisoryVersionTooltip;
/// No description provided for @maintenanceHeader. /// No description provided for @maintenanceHeader.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View file

@ -1284,6 +1284,10 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Speichern fehlgeschlagen: $error'; return 'Speichern fehlgeschlagen: $error';
} }
@override
String get storeAdvisoryVersionTooltip =>
'Föderierter Upstream-Dienst — Version ist Richtwert; der Upstream kann ohne Versionsanhebung Kompatibilität brechen.';
@override @override
String get maintenanceHeader => 'HUB-WARTUNG'; String get maintenanceHeader => 'HUB-WARTUNG';

View file

@ -1299,6 +1299,10 @@ class AppLocalizationsEn extends AppLocalizations {
return 'Could not save: $error'; return 'Could not save: $error';
} }
@override
String get storeAdvisoryVersionTooltip =>
'Federated upstream service — version is advisory; the upstream may break compatibility without bumping it.';
@override @override
String get maintenanceHeader => 'HUB MAINTENANCE'; String get maintenanceHeader => 'HUB MAINTENANCE';

View file

@ -1661,10 +1661,22 @@ class _FeaturedTile extends StatelessWidget {
Row( Row(
children: [ children: [
if (item.bestVersion.isNotEmpty) if (item.bestVersion.isNotEmpty)
FaiPill( Tooltip(
label: 'v${item.bestVersion}', // Federated upstream services (MCP, n8n,
tone: FaiPillTone.neutral, // Temporal workflows) don't honour semver,
monospace: true, // so their version pill carries a "~"
// prefix + tooltip noting that the value
// is advisory only.
message: item.isFederated
? l.storeAdvisoryVersionTooltip
: '',
child: FaiPill(
label: item.isFederated
? '~v${item.bestVersion}'
: 'v${item.bestVersion}',
tone: FaiPillTone.neutral,
monospace: true,
),
), ),
const SizedBox(width: FaiSpace.xs), const SizedBox(width: FaiSpace.xs),
if (item.status.isNotEmpty) if (item.status.isNotEmpty)
@ -1835,10 +1847,17 @@ class _StoreCard extends StatelessWidget {
Row( Row(
children: [ children: [
if (item.bestVersion.isNotEmpty) ...[ if (item.bestVersion.isNotEmpty) ...[
FaiPill( Tooltip(
label: 'v${item.bestVersion}', message: item.isFederated
tone: FaiPillTone.neutral, ? l.storeAdvisoryVersionTooltip
monospace: true, : '',
child: FaiPill(
label: item.isFederated
? '~v${item.bestVersion}'
: 'v${item.bestVersion}',
tone: FaiPillTone.neutral,
monospace: true,
),
), ),
const SizedBox(width: FaiSpace.xs), const SizedBox(width: FaiSpace.xs),
], ],
@ -2134,10 +2153,17 @@ class _StoreDetailSheetState extends State<_StoreDetailSheet> {
runSpacing: 4, runSpacing: 4,
children: [ children: [
if (item.bestVersion.isNotEmpty) if (item.bestVersion.isNotEmpty)
FaiPill( Tooltip(
label: 'v${item.bestVersion}', message: item.isFederated
tone: FaiPillTone.neutral, ? l.storeAdvisoryVersionTooltip
monospace: true, : '',
child: FaiPill(
label: item.isFederated
? '~v${item.bestVersion}'
: 'v${item.bestVersion}',
tone: FaiPillTone.neutral,
monospace: true,
),
), ),
if (item.status.isNotEmpty) if (item.status.isNotEmpty)
FaiPill( FaiPill(

View file

@ -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.47.0 version: 0.47.1
environment: environment:
sdk: ^3.11.0-200.1.beta sdk: ^3.11.0-200.1.beta