fix(studio): readable logs + in-app config.yaml viewer
- Strip ANSI / control characters when reading log files so daemon logs that carry colour escape codes render clean instead of as garbled special characters (the source side is fixed in the hub too; this is the defensive belt for existing files). - Generalise the file viewer (read top-down + plain mode) and add an in-Studio "View" affordance for config.yaml / .yml / .toml on the Doctor paths panel, so config is readable without leaving Studio. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
f0a944dce7
commit
b35bbc1b12
2 changed files with 115 additions and 19 deletions
|
|
@ -402,7 +402,15 @@ class _PathRow extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
final isLog = !isDirectory && path.toLowerCase().endsWith('.log');
|
||||
final lower = path.toLowerCase();
|
||||
final isLog = !isDirectory && lower.endsWith('.log');
|
||||
// Text config files get an in-Studio viewer too (read top-down,
|
||||
// no log colouring) so the operator can read config.yaml
|
||||
// without leaving Studio or hunting for an external editor.
|
||||
final isConfig = !isDirectory &&
|
||||
(lower.endsWith('.yaml') ||
|
||||
lower.endsWith('.yml') ||
|
||||
lower.endsWith('.toml'));
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
|
|
@ -428,10 +436,11 @@ class _PathRow extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
if (isLog) ...[
|
||||
if (isLog || isConfig) ...[
|
||||
OutlinedButton.icon(
|
||||
onPressed: () =>
|
||||
showFaiLogViewer(context, path: path, title: label),
|
||||
onPressed: () => isConfig
|
||||
? showFaiConfigViewer(context, path: path, title: label)
|
||||
: showFaiLogViewer(context, path: path, title: label),
|
||||
icon: const Icon(Icons.visibility_outlined, size: 14),
|
||||
label: Text(l.buttonView),
|
||||
style: OutlinedButton.styleFrom(
|
||||
|
|
@ -482,6 +491,11 @@ class _DaemonActionsCard extends StatefulWidget {
|
|||
class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
||||
bool _busy = false;
|
||||
String? _output;
|
||||
|
||||
/// True when the last daemon action failed because no `fai`
|
||||
/// binary could be located. Swaps the raw output line for the
|
||||
/// actionable [FaiBinaryRecovery] block.
|
||||
bool _binaryMissing = false;
|
||||
ChannelStatusSnapshot? _channels;
|
||||
|
||||
@override
|
||||
|
|
@ -511,13 +525,19 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
final r = await action();
|
||||
if (!mounted) return;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
final binaryMissing = !r.ok && r.stderr.trim() == kFaiBinaryNotFound;
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_output =
|
||||
(r.ok
|
||||
? '${l.daemonActionResultOk(label)}\n${r.stdout}'
|
||||
: '${l.daemonActionResultFailed(label)}\n${r.stderr.isEmpty ? r.stdout : r.stderr}')
|
||||
.trim();
|
||||
_binaryMissing = binaryMissing;
|
||||
// When the binary is missing we render the actionable
|
||||
// recovery block instead of a raw output line — the
|
||||
// sentinel is not a user-facing string.
|
||||
_output = binaryMissing
|
||||
? null
|
||||
: (r.ok
|
||||
? '${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
|
||||
// change the running flag.
|
||||
|
|
@ -659,6 +679,15 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
],
|
||||
),
|
||||
],
|
||||
if (_binaryMissing) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
FaiBinaryRecovery(
|
||||
onLocated: () => _run(
|
||||
l.daemonActionStatus,
|
||||
() => SystemActions.faiDaemon(['status']),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_output != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
Container(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue