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
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue