feat(editor): persistent diagnostic strip + run-block + copyable run errors
Three connected fixes that close the loop the analyzer started:
- **Strip lives at page level, not text-tab**. Moved
_DiagnosticStrip out of _textTab and into _tabbedBody
below the TabBarView, so the same error list + quick-fix
buttons are visible on Graph + Text + Run. The Graph-tab
operator now sees both the pulsing node AND the message
explaining what's broken, without flipping tabs. One strip,
one source of truth.
- **Run button disabled when there are analyzer errors**.
FlowEditorController.analyzerErrorCount counts `IssueType.error`
issues; the action strip's Run button + the RunTab's Start
button both check it. When > 0:
· button greys out + icon flips to Icons.block
· tooltip names the count ('2 errors prevent the run')
· the Run tab grows an inline red explanation next to
the disabled Start so the operator isn't left guessing
Warnings (orange) do NOT block — they're nudges. Operators
who want to run a half-broken flow during dev can still
silence the analyzer via the strip.
- **Run failures are copyable everywhere**. New
_CopyableErrorBox replaces both the per-run failure detail
and the per-step failure suffix in the RunTab. Selectable
monospace + explicit Copy button with 'Copied' feedback.
Scrollbar-capped at 220 px so the box doesn't push outputs
off-screen. Mirrors the operator-visible contract:
'every error is copyable, always.'
Closes the operator-reported regression where a failed run
showed 'Lauf fehlgeschlagen' as plain Text, leaving the
operator unable to paste it into a bug report.
Bumped to 0.19.0.
Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
efdfa7dd79
commit
b6bb8741a9
4 changed files with 230 additions and 82 deletions
|
|
@ -546,9 +546,11 @@ outputs:
|
|||
tabs: _tabs,
|
||||
saving: _controller.isSaving,
|
||||
running: _controller.isRunning,
|
||||
errorCount: _controller.analyzerErrorCount,
|
||||
onAddStep: _controller.activeName != null ? _addStep : null,
|
||||
onSave: _controller.activeName != null ? _save : null,
|
||||
onRun: _controller.activeName != null
|
||||
onRun: _controller.activeName != null &&
|
||||
_controller.analyzerErrorCount == 0
|
||||
? () => _tabs.animateTo(2)
|
||||
: null,
|
||||
),
|
||||
|
|
@ -569,6 +571,15 @@ outputs:
|
|||
],
|
||||
),
|
||||
),
|
||||
// Persistent diagnostic strip — lives below the tab bar
|
||||
// so the same issue list is visible on Graph + Text +
|
||||
// Run. The Graph tab no longer needs a separate
|
||||
// per-node tooltip because the strip is right there with
|
||||
// the message + quick-fix buttons.
|
||||
_DiagnosticStrip(
|
||||
controller: _controller.codeController,
|
||||
onApplyFix: _applyQuickFix,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
@ -714,41 +725,31 @@ outputs:
|
|||
height: 1.45,
|
||||
color: theme.colorScheme.onSurface,
|
||||
);
|
||||
// The bottom diagnostic strip now lives at the page level
|
||||
// (one persistent strip across all three tabs) instead of
|
||||
// being duplicated per-tab — see _tabbedBody. That keeps the
|
||||
// graph + run tabs informed too, not just text.
|
||||
return CodeTheme(
|
||||
data: CodeThemeData(styles: _yamlStyle(theme)),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CodeField(
|
||||
controller: _controller.codeController,
|
||||
textStyle: mono,
|
||||
expands: true,
|
||||
minLines: null,
|
||||
maxLines: null,
|
||||
gutterStyle: GutterStyle(
|
||||
textStyle: mono.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
background: theme.colorScheme.surfaceContainer,
|
||||
showLineNumbers: true,
|
||||
// Disable the built-in error column entirely.
|
||||
// The Icons.cancel pin is hard-positioned inside
|
||||
// a 16-px slot, and its mouse-hover popup paints
|
||||
// OVER the code area instead of beside it — the
|
||||
// overlap was the operator-visible glitch in
|
||||
// editor 0.15.1. Issues remain surfaced via the
|
||||
// wavy underline (FlowYamlCodeController) plus
|
||||
// the bottom diagnostic strip below.
|
||||
showErrors: false,
|
||||
),
|
||||
background: theme.colorScheme.surface,
|
||||
),
|
||||
child: CodeField(
|
||||
controller: _controller.codeController,
|
||||
textStyle: mono,
|
||||
expands: true,
|
||||
minLines: null,
|
||||
maxLines: null,
|
||||
gutterStyle: GutterStyle(
|
||||
textStyle: mono.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
_DiagnosticStrip(
|
||||
controller: _controller.codeController,
|
||||
onApplyFix: _applyQuickFix,
|
||||
),
|
||||
],
|
||||
background: theme.colorScheme.surfaceContainer,
|
||||
showLineNumbers: true,
|
||||
// Disable the built-in error column entirely — its
|
||||
// hard-positioned popup overlaps the code area.
|
||||
// Issues are surfaced via the wavy underline + the
|
||||
// page-level diagnostic strip.
|
||||
showErrors: false,
|
||||
),
|
||||
background: theme.colorScheme.surface,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -939,6 +940,7 @@ class _TabActionStrip extends StatelessWidget {
|
|||
final TabController tabs;
|
||||
final bool saving;
|
||||
final bool running;
|
||||
final int errorCount;
|
||||
final VoidCallback? onAddStep;
|
||||
final VoidCallback? onSave;
|
||||
final VoidCallback? onRun;
|
||||
|
|
@ -947,6 +949,7 @@ class _TabActionStrip extends StatelessWidget {
|
|||
required this.tabs,
|
||||
required this.saving,
|
||||
required this.running,
|
||||
required this.errorCount,
|
||||
required this.onAddStep,
|
||||
required this.onSave,
|
||||
required this.onRun,
|
||||
|
|
@ -997,16 +1000,27 @@ class _TabActionStrip extends StatelessWidget {
|
|||
label: Text(strings.save),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
FilledButton.icon(
|
||||
onPressed: onRun,
|
||||
icon: running
|
||||
? const SizedBox(
|
||||
width: 14,
|
||||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.play_arrow, size: 18),
|
||||
label: Text(strings.run),
|
||||
Tooltip(
|
||||
message: errorCount > 0
|
||||
? '$errorCount error${errorCount == 1 ? '' : 's'} '
|
||||
'prevent the run — fix them first'
|
||||
: '',
|
||||
child: FilledButton.icon(
|
||||
onPressed: onRun,
|
||||
icon: running
|
||||
? const SizedBox(
|
||||
width: 14,
|
||||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: Icon(
|
||||
errorCount > 0
|
||||
? Icons.block
|
||||
: Icons.play_arrow,
|
||||
size: 18,
|
||||
),
|
||||
label: Text(strings.run),
|
||||
),
|
||||
),
|
||||
],
|
||||
const Spacer(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue