feat(studio): central error helpers + inline log viewer + Today CTAs
Some checks failed
Security / Security check (push) Failing after 1s

Bundles the error-UX overhaul and the inline log viewer:

  - New `FaiLog` (`~/.fai/logs/studio-errors.log`, 256 KiB rotation,
    JSON-per-line). Every operator-visible failure is appended so
    `fai admin doctor` and the new viewer can show the trail
    without the operator having to reproduce the failure.
  - New `showFaiErrorSnack` / `showFaiErrorDialog` helpers wrap
    `FaiErrorBox` in copyable surfaces; 27 ad-hoc
    `SnackBar(content: Text(e.toString()))` sites swept to use
    them (settings, doctor, audit, store, module sheet, system-AI
    editor, flow output).
  - New `FaiLogViewer` modal (`showFaiLogViewer`) renders log
    files inline with line numbers, JSON-key + `[level]` token
    colouring, Copy-all, Refresh, Open-externally. Doctor's
    daemon-paths panel grows a "View" button next to "Open" for
    every `.log` row and now also lists the Studio errors log.
  - Today carousel: CTAs now actually re-run search after a
    `filterCategory` / `runQuery` story is tapped (was only
    flipping the chip state). Fallback story list bumped to 8.
  - Editor bumped to git ref carrying 0.15.0 (type-token
    colouring + analyzer diagnostics).

Studio bumped to 0.62.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-04 02:08:15 +02:00
parent 2731062a13
commit 8f5cd2528b
22 changed files with 1087 additions and 134 deletions

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import '../data/error_presentation.dart';
import '../data/hub.dart';
import '../l10n/app_localizations.dart';
import '../theme/theme.dart';
@ -53,21 +54,16 @@ class _AuditPageState extends State<AuditPage> {
_refresh();
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l.auditClearFailed(_friendly(e)))));
showFaiErrorSnack(context, 'audit.clear', e);
}
}
String _friendly(Object e) {
final s = e.toString();
// The hub returns FailedPrecondition for compliance-locked
// channels; tonic stringifies that as "failed_precondition:
// ". Strip the noise so the operator sees the real reason.
final marker = 'failed_precondition: ';
final idx = s.toLowerCase().indexOf(marker);
return idx >= 0 ? s.substring(idx + marker.length) : s;
}
// _friendly was an inline shadow of friendlyError() in
// data/friendly_error.dart kept only because the original
// call site predated the central mapper. Removed in favour
// of showFaiErrorSnack, which uses friendlyError under the
// hood (with proper gRPC-code mapping + selectable
// copy-affordance).
Future<void> _refresh() async {
try {