feat(studio): localise Settings sidebar + add inline help docs + Approvals doc
Some checks failed
Security / Security check (push) Failing after 1s
Some checks failed
Security / Security check (push) Failing after 1s
Three operator-UX gaps closed:
- Settings dialog's six-category sidebar (General / Appearance /
System AI / Integrations / Security / Maintenance) was
hardcoded English; now flows through AppLocalizations
("Allgemein" / "Darstellung" / "System-KI" / "Integrationen" /
"Sicherheit" / "Wartung"). Same for the per-panel title +
description.
- Per-channel daemon-action labels ('enable autostart' /
'disable autostart' / 'daemon restart' etc.) and the
OK / Failed result line in the toast also moved to l10n,
so the system-action feedback reads as one language.
- New 'Approvals' doc bundle (en + de) under assets/docs/,
registered as a fifth doc card on Welcome plus exposed via
the new public helper. The
Approvals, Audit and Doctor app-bars grow a Help icon button
next to Refresh that opens the matching doc in the existing
bottom-sheet reader — no extra screen, no learning curve.
Studio bumped to 0.67.0; editor path-override pulls in 0.20.1
(flow-list row polish).
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
2be7d241bf
commit
28fafce7dc
15 changed files with 681 additions and 36 deletions
|
|
@ -27,6 +27,9 @@
|
|||
"welcomeDocAuditBlurb": "Wie die Hash-Kette funktioniert und warum WORM-1 für KRITIS reicht.",
|
||||
"welcomeDocFlowsTitle": "Flow-Komposition",
|
||||
"welcomeDocFlowsBlurb": "YAML-Grundlagen, Templating-Referenz, das Extract→Summarize-Beispiel.",
|
||||
"welcomeDocApprovalsTitle": "Freigaben",
|
||||
"welcomeDocApprovalsBlurb": "Human-in-the-Loop-Checkpoints — wann nutzen, wie das Audit-Log sie protokolliert.",
|
||||
"helpTooltip": "Hilfe",
|
||||
"welcomeDocClose": "Schließen",
|
||||
"welcomeDocFailedToLoad": "Doku konnte nicht geladen werden: {error}",
|
||||
"@welcomeDocFailedToLoad": {
|
||||
|
|
@ -1449,6 +1452,41 @@
|
|||
}
|
||||
},
|
||||
"doctorPathStudioErrors": "Studio-Fehler",
|
||||
"settingsCategoryGeneral": "Allgemein",
|
||||
"settingsCategoryAppearance": "Darstellung",
|
||||
"settingsCategoryAi": "System-KI",
|
||||
"settingsCategoryIntegrations": "Integrationen",
|
||||
"settingsCategorySecurity": "Sicherheit",
|
||||
"settingsCategoryMaintenance": "Wartung",
|
||||
"settingsAiPanelTitle": "System-KI",
|
||||
"settingsAiPanelBody": "Operator-verwalteter LLM-Endpunkt, den Studio für die KI-Helfer nutzt (System-KI-Edit, Install-Vorschläge, Doctor-Zusammenfassung). Kein Flow ruft das jemals auf; Module sprechen mit ihrem eigenen LLM.",
|
||||
"settingsIntegrationsPanelTitle": "Integrationen",
|
||||
"settingsIntegrationsPanelBody": "Externe Tool-Server, deren Capabilities der Hub föderiert. MCP-Server bieten Tool-Endpunkte; n8n-Endpunkte stellen gehostete Workflows bereit.",
|
||||
"settingsSecurityPanelTitle": "Sicherheit & Zugangsdaten",
|
||||
"settingsSecurityPanelBody": "Tokens, die der Hub für dich verwahrt. Liegen in ~/.fai/ mit Modus 0600; werden nie als Telemetrie versendet.",
|
||||
"settingsMaintenancePanelTitle": "Wartung",
|
||||
"settingsMaintenancePanelBody": "Destruktive Aktionen, abgesichert durch explizite Bestätigungs-Dialoge. Nutzen z.B. beim Re-Pilot-Testen oder Debuggen.",
|
||||
"tooltipMoveUp": "Nach oben",
|
||||
"tooltipMoveDown": "Nach unten",
|
||||
"tooltipRemove": "Entfernen",
|
||||
"daemonActionEnableAutostart": "Autostart aktivieren",
|
||||
"daemonActionDisableAutostart": "Autostart deaktivieren",
|
||||
"daemonActionRestart": "Daemon neu starten",
|
||||
"daemonActionStart": "Daemon starten",
|
||||
"daemonActionStop": "Daemon stoppen",
|
||||
"daemonActionStatus": "Daemon-Status",
|
||||
"daemonActionResultOk": "OK · {label}",
|
||||
"@daemonActionResultOk": {
|
||||
"placeholders": {
|
||||
"label": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"daemonActionResultFailed": "Fehlgeschlagen · {label}",
|
||||
"@daemonActionResultFailed": {
|
||||
"placeholders": {
|
||||
"label": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"addSourceTitle": "Modul-Quelle hinzufügen",
|
||||
"addSourceIntro": "`{capability}` ist nicht im öffentlichen Store. Zeig dem Hub eine `.fai`-Bundle-URL oder einen lokalen Bundle-Pfad — der Hub lädt es herunter, prüft (sha256 + Signatur) und installiert.",
|
||||
"@addSourceIntro": {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
"welcomeDocAuditBlurb": "How the hash chain works and why WORM-1 is enough for KRITIS.",
|
||||
"welcomeDocFlowsTitle": "Flow composition",
|
||||
"welcomeDocFlowsBlurb": "YAML basics, templating reference, the extract→summarize example.",
|
||||
"welcomeDocApprovalsTitle": "Approvals",
|
||||
"welcomeDocApprovalsBlurb": "Human-in-the-loop checkpoints — when to use them, how the audit log records them.",
|
||||
"helpTooltip": "Help",
|
||||
"welcomeDocClose": "Close",
|
||||
"welcomeDocFailedToLoad": "Could not load documentation: {error}",
|
||||
"@welcomeDocFailedToLoad": {
|
||||
|
|
@ -1452,6 +1455,41 @@
|
|||
}
|
||||
},
|
||||
"doctorPathStudioErrors": "Studio errors",
|
||||
"settingsCategoryGeneral": "General",
|
||||
"settingsCategoryAppearance": "Appearance",
|
||||
"settingsCategoryAi": "System AI",
|
||||
"settingsCategoryIntegrations": "Integrations",
|
||||
"settingsCategorySecurity": "Security",
|
||||
"settingsCategoryMaintenance": "Maintenance",
|
||||
"settingsAiPanelTitle": "System AI",
|
||||
"settingsAiPanelBody": "Operator-managed LLM endpoint used by Studio for the AI helpers (system-ai-edit, install-suggest, doctor-summary). No flow ever calls this; modules speak to their own LLM.",
|
||||
"settingsIntegrationsPanelTitle": "Integrations",
|
||||
"settingsIntegrationsPanelBody": "External tool servers the hub federates capabilities from. MCP servers expose tool-shaped endpoints; n8n endpoints expose hosted workflows.",
|
||||
"settingsSecurityPanelTitle": "Security & credentials",
|
||||
"settingsSecurityPanelBody": "Tokens the hub holds on the operator's behalf. Stored in ~/.fai/ with mode 0600; never sent in telemetry.",
|
||||
"settingsMaintenancePanelTitle": "Maintenance",
|
||||
"settingsMaintenancePanelBody": "Destructive operations gated behind explicit confirm dialogs. Use when re-pilot-testing or debugging.",
|
||||
"tooltipMoveUp": "Move up",
|
||||
"tooltipMoveDown": "Move down",
|
||||
"tooltipRemove": "Remove",
|
||||
"daemonActionEnableAutostart": "enable autostart",
|
||||
"daemonActionDisableAutostart": "disable autostart",
|
||||
"daemonActionRestart": "daemon restart",
|
||||
"daemonActionStart": "daemon start",
|
||||
"daemonActionStop": "daemon stop",
|
||||
"daemonActionStatus": "daemon status",
|
||||
"daemonActionResultOk": "OK · {label}",
|
||||
"@daemonActionResultOk": {
|
||||
"placeholders": {
|
||||
"label": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"daemonActionResultFailed": "Failed · {label}",
|
||||
"@daemonActionResultFailed": {
|
||||
"placeholders": {
|
||||
"label": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"addSourceTitle": "Add module source",
|
||||
"addSourceIntro": "`{capability}` is not in the public store. Point the hub at a `.fai` bundle URL or a local bundle path; the hub downloads, verifies (sha256 + signature) and installs it.",
|
||||
"@addSourceIntro": {
|
||||
|
|
|
|||
|
|
@ -260,6 +260,24 @@ abstract class AppLocalizations {
|
|||
/// **'YAML basics, templating reference, the extract→summarize example.'**
|
||||
String get welcomeDocFlowsBlurb;
|
||||
|
||||
/// No description provided for @welcomeDocApprovalsTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Approvals'**
|
||||
String get welcomeDocApprovalsTitle;
|
||||
|
||||
/// No description provided for @welcomeDocApprovalsBlurb.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Human-in-the-loop checkpoints — when to use them, how the audit log records them.'**
|
||||
String get welcomeDocApprovalsBlurb;
|
||||
|
||||
/// No description provided for @helpTooltip.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Help'**
|
||||
String get helpTooltip;
|
||||
|
||||
/// No description provided for @welcomeDocClose.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
@ -3968,6 +3986,156 @@ abstract class AppLocalizations {
|
|||
/// **'Studio errors'**
|
||||
String get doctorPathStudioErrors;
|
||||
|
||||
/// No description provided for @settingsCategoryGeneral.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'General'**
|
||||
String get settingsCategoryGeneral;
|
||||
|
||||
/// No description provided for @settingsCategoryAppearance.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Appearance'**
|
||||
String get settingsCategoryAppearance;
|
||||
|
||||
/// No description provided for @settingsCategoryAi.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'System AI'**
|
||||
String get settingsCategoryAi;
|
||||
|
||||
/// No description provided for @settingsCategoryIntegrations.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Integrations'**
|
||||
String get settingsCategoryIntegrations;
|
||||
|
||||
/// No description provided for @settingsCategorySecurity.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Security'**
|
||||
String get settingsCategorySecurity;
|
||||
|
||||
/// No description provided for @settingsCategoryMaintenance.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Maintenance'**
|
||||
String get settingsCategoryMaintenance;
|
||||
|
||||
/// No description provided for @settingsAiPanelTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'System AI'**
|
||||
String get settingsAiPanelTitle;
|
||||
|
||||
/// No description provided for @settingsAiPanelBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Operator-managed LLM endpoint used by Studio for the AI helpers (system-ai-edit, install-suggest, doctor-summary). No flow ever calls this; modules speak to their own LLM.'**
|
||||
String get settingsAiPanelBody;
|
||||
|
||||
/// No description provided for @settingsIntegrationsPanelTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Integrations'**
|
||||
String get settingsIntegrationsPanelTitle;
|
||||
|
||||
/// No description provided for @settingsIntegrationsPanelBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'External tool servers the hub federates capabilities from. MCP servers expose tool-shaped endpoints; n8n endpoints expose hosted workflows.'**
|
||||
String get settingsIntegrationsPanelBody;
|
||||
|
||||
/// No description provided for @settingsSecurityPanelTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Security & credentials'**
|
||||
String get settingsSecurityPanelTitle;
|
||||
|
||||
/// No description provided for @settingsSecurityPanelBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Tokens the hub holds on the operator\'s behalf. Stored in ~/.fai/ with mode 0600; never sent in telemetry.'**
|
||||
String get settingsSecurityPanelBody;
|
||||
|
||||
/// No description provided for @settingsMaintenancePanelTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Maintenance'**
|
||||
String get settingsMaintenancePanelTitle;
|
||||
|
||||
/// No description provided for @settingsMaintenancePanelBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Destructive operations gated behind explicit confirm dialogs. Use when re-pilot-testing or debugging.'**
|
||||
String get settingsMaintenancePanelBody;
|
||||
|
||||
/// No description provided for @tooltipMoveUp.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Move up'**
|
||||
String get tooltipMoveUp;
|
||||
|
||||
/// No description provided for @tooltipMoveDown.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Move down'**
|
||||
String get tooltipMoveDown;
|
||||
|
||||
/// No description provided for @tooltipRemove.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove'**
|
||||
String get tooltipRemove;
|
||||
|
||||
/// No description provided for @daemonActionEnableAutostart.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'enable autostart'**
|
||||
String get daemonActionEnableAutostart;
|
||||
|
||||
/// No description provided for @daemonActionDisableAutostart.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'disable autostart'**
|
||||
String get daemonActionDisableAutostart;
|
||||
|
||||
/// No description provided for @daemonActionRestart.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'daemon restart'**
|
||||
String get daemonActionRestart;
|
||||
|
||||
/// No description provided for @daemonActionStart.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'daemon start'**
|
||||
String get daemonActionStart;
|
||||
|
||||
/// No description provided for @daemonActionStop.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'daemon stop'**
|
||||
String get daemonActionStop;
|
||||
|
||||
/// No description provided for @daemonActionStatus.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'daemon status'**
|
||||
String get daemonActionStatus;
|
||||
|
||||
/// No description provided for @daemonActionResultOk.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'OK · {label}'**
|
||||
String daemonActionResultOk(String label);
|
||||
|
||||
/// No description provided for @daemonActionResultFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Failed · {label}'**
|
||||
String daemonActionResultFailed(String label);
|
||||
|
||||
/// No description provided for @addSourceTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
String get welcomeDocFlowsBlurb =>
|
||||
'YAML-Grundlagen, Templating-Referenz, das Extract→Summarize-Beispiel.';
|
||||
|
||||
@override
|
||||
String get welcomeDocApprovalsTitle => 'Freigaben';
|
||||
|
||||
@override
|
||||
String get welcomeDocApprovalsBlurb =>
|
||||
'Human-in-the-Loop-Checkpoints — wann nutzen, wie das Audit-Log sie protokolliert.';
|
||||
|
||||
@override
|
||||
String get helpTooltip => 'Hilfe';
|
||||
|
||||
@override
|
||||
String get welcomeDocClose => 'Schließen';
|
||||
|
||||
|
|
@ -2323,6 +2333,89 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get doctorPathStudioErrors => 'Studio-Fehler';
|
||||
|
||||
@override
|
||||
String get settingsCategoryGeneral => 'Allgemein';
|
||||
|
||||
@override
|
||||
String get settingsCategoryAppearance => 'Darstellung';
|
||||
|
||||
@override
|
||||
String get settingsCategoryAi => 'System-KI';
|
||||
|
||||
@override
|
||||
String get settingsCategoryIntegrations => 'Integrationen';
|
||||
|
||||
@override
|
||||
String get settingsCategorySecurity => 'Sicherheit';
|
||||
|
||||
@override
|
||||
String get settingsCategoryMaintenance => 'Wartung';
|
||||
|
||||
@override
|
||||
String get settingsAiPanelTitle => 'System-KI';
|
||||
|
||||
@override
|
||||
String get settingsAiPanelBody =>
|
||||
'Operator-verwalteter LLM-Endpunkt, den Studio für die KI-Helfer nutzt (System-KI-Edit, Install-Vorschläge, Doctor-Zusammenfassung). Kein Flow ruft das jemals auf; Module sprechen mit ihrem eigenen LLM.';
|
||||
|
||||
@override
|
||||
String get settingsIntegrationsPanelTitle => 'Integrationen';
|
||||
|
||||
@override
|
||||
String get settingsIntegrationsPanelBody =>
|
||||
'Externe Tool-Server, deren Capabilities der Hub föderiert. MCP-Server bieten Tool-Endpunkte; n8n-Endpunkte stellen gehostete Workflows bereit.';
|
||||
|
||||
@override
|
||||
String get settingsSecurityPanelTitle => 'Sicherheit & Zugangsdaten';
|
||||
|
||||
@override
|
||||
String get settingsSecurityPanelBody =>
|
||||
'Tokens, die der Hub für dich verwahrt. Liegen in ~/.fai/ mit Modus 0600; werden nie als Telemetrie versendet.';
|
||||
|
||||
@override
|
||||
String get settingsMaintenancePanelTitle => 'Wartung';
|
||||
|
||||
@override
|
||||
String get settingsMaintenancePanelBody =>
|
||||
'Destruktive Aktionen, abgesichert durch explizite Bestätigungs-Dialoge. Nutzen z.B. beim Re-Pilot-Testen oder Debuggen.';
|
||||
|
||||
@override
|
||||
String get tooltipMoveUp => 'Nach oben';
|
||||
|
||||
@override
|
||||
String get tooltipMoveDown => 'Nach unten';
|
||||
|
||||
@override
|
||||
String get tooltipRemove => 'Entfernen';
|
||||
|
||||
@override
|
||||
String get daemonActionEnableAutostart => 'Autostart aktivieren';
|
||||
|
||||
@override
|
||||
String get daemonActionDisableAutostart => 'Autostart deaktivieren';
|
||||
|
||||
@override
|
||||
String get daemonActionRestart => 'Daemon neu starten';
|
||||
|
||||
@override
|
||||
String get daemonActionStart => 'Daemon starten';
|
||||
|
||||
@override
|
||||
String get daemonActionStop => 'Daemon stoppen';
|
||||
|
||||
@override
|
||||
String get daemonActionStatus => 'Daemon-Status';
|
||||
|
||||
@override
|
||||
String daemonActionResultOk(String label) {
|
||||
return 'OK · $label';
|
||||
}
|
||||
|
||||
@override
|
||||
String daemonActionResultFailed(String label) {
|
||||
return 'Fehlgeschlagen · $label';
|
||||
}
|
||||
|
||||
@override
|
||||
String get addSourceTitle => 'Modul-Quelle hinzufügen';
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
String get welcomeDocFlowsBlurb =>
|
||||
'YAML basics, templating reference, the extract→summarize example.';
|
||||
|
||||
@override
|
||||
String get welcomeDocApprovalsTitle => 'Approvals';
|
||||
|
||||
@override
|
||||
String get welcomeDocApprovalsBlurb =>
|
||||
'Human-in-the-loop checkpoints — when to use them, how the audit log records them.';
|
||||
|
||||
@override
|
||||
String get helpTooltip => 'Help';
|
||||
|
||||
@override
|
||||
String get welcomeDocClose => 'Close';
|
||||
|
||||
|
|
@ -2328,6 +2338,89 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get doctorPathStudioErrors => 'Studio errors';
|
||||
|
||||
@override
|
||||
String get settingsCategoryGeneral => 'General';
|
||||
|
||||
@override
|
||||
String get settingsCategoryAppearance => 'Appearance';
|
||||
|
||||
@override
|
||||
String get settingsCategoryAi => 'System AI';
|
||||
|
||||
@override
|
||||
String get settingsCategoryIntegrations => 'Integrations';
|
||||
|
||||
@override
|
||||
String get settingsCategorySecurity => 'Security';
|
||||
|
||||
@override
|
||||
String get settingsCategoryMaintenance => 'Maintenance';
|
||||
|
||||
@override
|
||||
String get settingsAiPanelTitle => 'System AI';
|
||||
|
||||
@override
|
||||
String get settingsAiPanelBody =>
|
||||
'Operator-managed LLM endpoint used by Studio for the AI helpers (system-ai-edit, install-suggest, doctor-summary). No flow ever calls this; modules speak to their own LLM.';
|
||||
|
||||
@override
|
||||
String get settingsIntegrationsPanelTitle => 'Integrations';
|
||||
|
||||
@override
|
||||
String get settingsIntegrationsPanelBody =>
|
||||
'External tool servers the hub federates capabilities from. MCP servers expose tool-shaped endpoints; n8n endpoints expose hosted workflows.';
|
||||
|
||||
@override
|
||||
String get settingsSecurityPanelTitle => 'Security & credentials';
|
||||
|
||||
@override
|
||||
String get settingsSecurityPanelBody =>
|
||||
'Tokens the hub holds on the operator\'s behalf. Stored in ~/.fai/ with mode 0600; never sent in telemetry.';
|
||||
|
||||
@override
|
||||
String get settingsMaintenancePanelTitle => 'Maintenance';
|
||||
|
||||
@override
|
||||
String get settingsMaintenancePanelBody =>
|
||||
'Destructive operations gated behind explicit confirm dialogs. Use when re-pilot-testing or debugging.';
|
||||
|
||||
@override
|
||||
String get tooltipMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get tooltipMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get tooltipRemove => 'Remove';
|
||||
|
||||
@override
|
||||
String get daemonActionEnableAutostart => 'enable autostart';
|
||||
|
||||
@override
|
||||
String get daemonActionDisableAutostart => 'disable autostart';
|
||||
|
||||
@override
|
||||
String get daemonActionRestart => 'daemon restart';
|
||||
|
||||
@override
|
||||
String get daemonActionStart => 'daemon start';
|
||||
|
||||
@override
|
||||
String get daemonActionStop => 'daemon stop';
|
||||
|
||||
@override
|
||||
String get daemonActionStatus => 'daemon status';
|
||||
|
||||
@override
|
||||
String daemonActionResultOk(String label) {
|
||||
return 'OK · $label';
|
||||
}
|
||||
|
||||
@override
|
||||
String daemonActionResultFailed(String label) {
|
||||
return 'Failed · $label';
|
||||
}
|
||||
|
||||
@override
|
||||
String get addSourceTitle => 'Add module source';
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import 'widgets/widgets.dart';
|
|||
/// Studio's own build version. Bump on every UI commit so the
|
||||
/// running app self-identifies — visible in the sidebar header
|
||||
/// and quick-glance proof that you're seeing the current build.
|
||||
const String kStudioVersion = '0.66.0';
|
||||
const String kStudioVersion = '0.67.0';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import '../l10n/app_localizations.dart';
|
|||
import '../theme/theme.dart';
|
||||
import '../theme/tokens.dart';
|
||||
import '../widgets/widgets.dart';
|
||||
import 'welcome.dart' show showFaiDoc;
|
||||
|
||||
class ApprovalsPage extends StatefulWidget {
|
||||
const ApprovalsPage({super.key});
|
||||
|
|
@ -213,6 +214,11 @@ class _ApprovalsPageState extends State<ApprovalsPage>
|
|||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.help_outline, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.helpTooltip,
|
||||
onPressed: () => showFaiDoc(context, 'approvals'),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.approvalsReloadTooltip,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import '../l10n/app_localizations.dart';
|
|||
import '../theme/theme.dart';
|
||||
import '../theme/tokens.dart';
|
||||
import '../widgets/widgets.dart';
|
||||
import 'welcome.dart' show showFaiDoc;
|
||||
|
||||
class AuditPage extends StatefulWidget {
|
||||
const AuditPage({super.key});
|
||||
|
|
@ -102,6 +103,11 @@ class _AuditPageState extends State<AuditPage> {
|
|||
onChanged: (v) => setState(() => _typeFilter = v),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.help_outline, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.helpTooltip,
|
||||
onPressed: () => showFaiDoc(context, 'audit'),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete_sweep_outlined, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.auditClearLogTooltip,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import '../l10n/app_localizations.dart';
|
|||
import '../theme/theme.dart';
|
||||
import '../theme/tokens.dart';
|
||||
import '../widgets/widgets.dart';
|
||||
import 'welcome.dart' show showFaiDoc;
|
||||
|
||||
class DoctorPage extends StatefulWidget {
|
||||
const DoctorPage({super.key});
|
||||
|
|
@ -36,6 +37,11 @@ class _DoctorPageState extends State<DoctorPage> {
|
|||
appBar: AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.doctorTitle),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.help_outline, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.helpTooltip,
|
||||
onPressed: () => showFaiDoc(context, 'architecture'),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 18),
|
||||
tooltip: AppLocalizations.of(context)!.doctorRecheckTooltip,
|
||||
|
|
@ -504,12 +510,13 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
});
|
||||
final r = await action();
|
||||
if (!mounted) return;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_output =
|
||||
(r.ok
|
||||
? 'OK · $label\n${r.stdout}'
|
||||
: 'Failed · $label\n${r.stderr.isEmpty ? r.stdout : r.stderr}')
|
||||
? '${l.daemonActionResultOk(label)}\n${r.stdout}'
|
||||
: '${l.daemonActionResultFailed(label)}\n${r.stderr.isEmpty ? r.stdout : r.stderr}')
|
||||
.trim();
|
||||
});
|
||||
// Refresh the status pill — restart / stop / start all
|
||||
|
|
@ -594,7 +601,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
onPressed: _busy
|
||||
? null
|
||||
: () => _run(
|
||||
'daemon restart',
|
||||
l.daemonActionRestart,
|
||||
() => SystemActions.faiDaemon(['restart']),
|
||||
),
|
||||
icon: const Icon(Icons.restart_alt, size: 16),
|
||||
|
|
@ -605,7 +612,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
onPressed: _busy
|
||||
? null
|
||||
: () => _run(
|
||||
'daemon start',
|
||||
l.daemonActionStart,
|
||||
() => SystemActions.faiDaemon(['start']),
|
||||
),
|
||||
icon: const Icon(Icons.play_arrow, size: 16),
|
||||
|
|
@ -615,7 +622,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
onPressed: _busy
|
||||
? null
|
||||
: () => _run(
|
||||
'daemon stop',
|
||||
l.daemonActionStop,
|
||||
() => SystemActions.faiDaemon(['stop']),
|
||||
),
|
||||
icon: const Icon(Icons.stop_circle_outlined, size: 16),
|
||||
|
|
@ -625,7 +632,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
onPressed: _busy
|
||||
? null
|
||||
: () => _run(
|
||||
'daemon status',
|
||||
l.daemonActionStatus,
|
||||
() => SystemActions.faiDaemon(['status']),
|
||||
),
|
||||
icon: const Icon(Icons.health_and_safety_outlined, size: 16),
|
||||
|
|
|
|||
|
|
@ -829,8 +829,27 @@ final List<_DocEntry> _kDocs = <_DocEntry>[
|
|||
title: (l) => l.welcomeDocFlowsTitle,
|
||||
blurb: (l) => l.welcomeDocFlowsBlurb,
|
||||
),
|
||||
_DocEntry(
|
||||
slug: 'approvals',
|
||||
icon: Icons.gavel_outlined,
|
||||
title: (l) => l.welcomeDocApprovalsTitle,
|
||||
blurb: (l) => l.welcomeDocApprovalsBlurb,
|
||||
),
|
||||
];
|
||||
|
||||
/// Public entry-point for the doc-reader sheet. Pass a slug
|
||||
/// ("approvals", "audit", "security", "architecture", "flows")
|
||||
/// and the bottom sheet opens with the localized markdown.
|
||||
/// Returns null when the slug isn't registered — caller can
|
||||
/// log + show a SnackBar.
|
||||
Future<void>? showFaiDoc(BuildContext context, String slug) {
|
||||
final entry = _kDocs.firstWhere(
|
||||
(d) => d.slug == slug,
|
||||
orElse: () => _kDocs.first,
|
||||
);
|
||||
return _DocReaderSheet.show(context, entry);
|
||||
}
|
||||
|
||||
/// Two-by-two doc grid on wide windows, single column on
|
||||
/// narrow. Each card opens `_DocReaderSheet` for its slug.
|
||||
class _DocsRow extends StatelessWidget {
|
||||
|
|
|
|||
|
|
@ -311,11 +311,12 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
});
|
||||
final r = await action();
|
||||
if (!mounted) return;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
setState(() {
|
||||
_saving = false;
|
||||
_channelToast = r.ok
|
||||
? 'OK · $label\n${r.stdout.trim()}'
|
||||
: 'Failed · $label\n${(r.stderr.isEmpty ? r.stdout : r.stderr).trim()}';
|
||||
? '${l.daemonActionResultOk(label)}\n${r.stdout.trim()}'
|
||||
: '${l.daemonActionResultFailed(label)}\n${(r.stderr.isEmpty ? r.stdout : r.stderr).trim()}';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -528,13 +529,13 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
onEnableAutostart: _saving
|
||||
? null
|
||||
: () => _runDaemon(
|
||||
'enable autostart',
|
||||
l.daemonActionEnableAutostart,
|
||||
() => SystemActions.faiDaemonEnable(ch.name),
|
||||
),
|
||||
onDisableAutostart: _saving
|
||||
? null
|
||||
: () => _runDaemon(
|
||||
'disable autostart',
|
||||
l.daemonActionDisableAutostart,
|
||||
() => SystemActions.faiDaemonDisable(ch.name),
|
||||
),
|
||||
),
|
||||
|
|
@ -562,10 +563,8 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
List<Widget> _aiPanel(AppLocalizations l, ThemeData theme) {
|
||||
return [
|
||||
_panelTitle(
|
||||
'System AI',
|
||||
'Operator-managed LLM endpoint used by Studio for the AI '
|
||||
'helpers (system-ai-edit, install-suggest, doctor-summary). '
|
||||
'No flow ever calls this; modules speak to their own LLM.',
|
||||
l.settingsAiPanelTitle,
|
||||
l.settingsAiPanelBody,
|
||||
theme,
|
||||
),
|
||||
if (_aiStatus == null)
|
||||
|
|
@ -586,10 +585,8 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
List<Widget> _integrationsPanel(AppLocalizations l, ThemeData theme) {
|
||||
return [
|
||||
_panelTitle(
|
||||
'Integrations',
|
||||
'External tool servers the hub federates capabilities from. '
|
||||
'MCP servers expose tool-shaped endpoints; n8n endpoints '
|
||||
'expose hosted workflows.',
|
||||
l.settingsIntegrationsPanelTitle,
|
||||
l.settingsIntegrationsPanelBody,
|
||||
theme,
|
||||
),
|
||||
if (_mcpClients == null)
|
||||
|
|
@ -618,9 +615,8 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
List<Widget> _securityPanel(AppLocalizations l, ThemeData theme) {
|
||||
return [
|
||||
_panelTitle(
|
||||
'Security & credentials',
|
||||
'Tokens the hub holds on the operator\'s behalf. Stored in '
|
||||
'~/.fai/ with mode 0600; never sent in telemetry.',
|
||||
l.settingsSecurityPanelTitle,
|
||||
l.settingsSecurityPanelBody,
|
||||
theme,
|
||||
),
|
||||
_RegistryCredentialsPanel(
|
||||
|
|
@ -640,9 +636,8 @@ class _FaiSettingsDialogState extends State<FaiSettingsDialog> {
|
|||
List<Widget> _maintenancePanel(AppLocalizations l, ThemeData theme) {
|
||||
return [
|
||||
_panelTitle(
|
||||
'Maintenance',
|
||||
'Destructive operations gated behind explicit confirm '
|
||||
'dialogs. Use when re-pilot-testing or debugging.',
|
||||
l.settingsMaintenancePanelTitle,
|
||||
l.settingsMaintenancePanelBody,
|
||||
theme,
|
||||
),
|
||||
_MaintenancePanel(
|
||||
|
|
@ -2525,19 +2520,19 @@ class _ScopeRow extends StatelessWidget {
|
|||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_upward, size: 16),
|
||||
tooltip: 'Move up',
|
||||
tooltip: AppLocalizations.of(context)!.tooltipMoveUp,
|
||||
onPressed: busy || index == 0 ? null : onUp,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_downward, size: 16),
|
||||
tooltip: 'Move down',
|
||||
tooltip: AppLocalizations.of(context)!.tooltipMoveDown,
|
||||
onPressed: busy || index == total - 1 ? null : onDown,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete_outline, size: 16),
|
||||
tooltip: 'Remove',
|
||||
tooltip: AppLocalizations.of(context)!.tooltipRemove,
|
||||
onPressed: busy ? null : onRemove,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
|
|
@ -2559,13 +2554,26 @@ class _Sidebar extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
final items = <(_Category, IconData, String)>[
|
||||
(_Category.general, Icons.tune, 'General'),
|
||||
(_Category.appearance, Icons.palette_outlined, 'Appearance'),
|
||||
(_Category.ai, Icons.psychology_outlined, 'System AI'),
|
||||
(_Category.integrations, Icons.hub_outlined, 'Integrations'),
|
||||
(_Category.security, Icons.shield_outlined, 'Security'),
|
||||
(_Category.maintenance, Icons.build_outlined, 'Maintenance'),
|
||||
(_Category.general, Icons.tune, l.settingsCategoryGeneral),
|
||||
(
|
||||
_Category.appearance,
|
||||
Icons.palette_outlined,
|
||||
l.settingsCategoryAppearance,
|
||||
),
|
||||
(_Category.ai, Icons.psychology_outlined, l.settingsCategoryAi),
|
||||
(
|
||||
_Category.integrations,
|
||||
Icons.hub_outlined,
|
||||
l.settingsCategoryIntegrations,
|
||||
),
|
||||
(_Category.security, Icons.shield_outlined, l.settingsCategorySecurity),
|
||||
(
|
||||
_Category.maintenance,
|
||||
Icons.build_outlined,
|
||||
l.settingsCategoryMaintenance,
|
||||
),
|
||||
];
|
||||
return SizedBox(
|
||||
width: 220,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue