fix: drop the duplicate FLOWS panel header, current CLI name in docs (0.24.1)

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-07-18 00:27:24 +02:00
parent 4e7abec24d
commit 7d6a575cae
6 changed files with 69 additions and 89 deletions

View file

@ -1,5 +1,12 @@
# Changelog # Changelog
## 0.24.1
- No ALL-CAPS "FLOWS" panel header: the page toolbar already names
the page — the duplicate label read as a broken title hierarchy.
The refresh action moved next to the list filter.
- Doc comments name the current CLI (`chain install`).
## 0.24.0 ## 0.24.0
Usertest-panel fixes (flow list + language): Usertest-panel fixes (flow list + language):

View file

@ -282,7 +282,8 @@ class _FlowEditorPageState extends State<FlowEditorPage>
final commentIdx = line.indexOf('#', colonIdx + 1); final commentIdx = line.indexOf('#', colonIdx + 1);
final rhsEnd = commentIdx < 0 ? line.length : commentIdx; final rhsEnd = commentIdx < 0 ? line.length : commentIdx;
final tail = commentIdx < 0 ? '' : line.substring(rhsEnd); final tail = commentIdx < 0 ? '' : line.substring(rhsEnd);
final newLine = '${line.substring(0, colonIdx + 1)} ${fix.replacement}' final newLine =
'${line.substring(0, colonIdx + 1)} ${fix.replacement}'
'${tail.isEmpty ? '' : ' $tail'}'; '${tail.isEmpty ? '' : ' $tail'}';
if (newLine == line) return; if (newLine == line) return;
lines[fix.line] = newLine; lines[fix.line] = newLine;
@ -643,7 +644,8 @@ outputs:
errorCount: _controller.analyzerErrorCount, errorCount: _controller.analyzerErrorCount,
onAddStep: _controller.activeName != null ? _addStep : null, onAddStep: _controller.activeName != null ? _addStep : null,
onSave: _controller.activeName != null ? _save : null, onSave: _controller.activeName != null ? _save : null,
onRun: _controller.activeName != null && onRun:
_controller.activeName != null &&
_controller.analyzerErrorCount == 0 _controller.analyzerErrorCount == 0
? () => _tabs.animateTo(2) ? () => _tabs.animateTo(2)
: null, : null,
@ -843,9 +845,7 @@ outputs:
minLines: null, minLines: null,
maxLines: null, maxLines: null,
gutterStyle: GutterStyle( gutterStyle: GutterStyle(
textStyle: mono.copyWith( textStyle: mono.copyWith(color: theme.colorScheme.onSurfaceVariant),
color: theme.colorScheme.onSurfaceVariant,
),
background: theme.colorScheme.surfaceContainer, background: theme.colorScheme.surfaceContainer,
showLineNumbers: true, showLineNumbers: true,
// Disable the built-in error column entirely its // Disable the built-in error column entirely its
@ -1127,9 +1127,7 @@ class _TabActionStrip extends StatelessWidget {
child: CircularProgressIndicator(strokeWidth: 2), child: CircularProgressIndicator(strokeWidth: 2),
) )
: Icon( : Icon(
errorCount > 0 errorCount > 0 ? Icons.block : Icons.play_arrow,
? Icons.block
: Icons.play_arrow,
size: 18, size: 18,
), ),
label: Text(strings.run), label: Text(strings.run),
@ -1392,39 +1390,10 @@ class _FileListState extends State<_FileList> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Container( // No ALL-CAPS panel header: the page toolbar already says
padding: const EdgeInsets.symmetric( // "Flows" the duplicate label read as a broken title
horizontal: FaiSpace.md, // hierarchy (usertest art-director finding). The refresh
vertical: FaiSpace.xs, // action sits next to the filter instead.
),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: theme.dividerColor)),
),
child: Row(
children: [
Expanded(
child: Text(
strings.listHeader,
style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
letterSpacing: 0.6,
),
),
),
IconButton(
onPressed: widget.onRefresh,
tooltip: strings.refresh,
icon: const Icon(Icons.refresh, size: 16),
visualDensity: VisualDensity.compact,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 28,
minHeight: 28,
),
),
],
),
),
Padding( Padding(
padding: const EdgeInsets.fromLTRB( padding: const EdgeInsets.fromLTRB(
FaiSpace.md, FaiSpace.md,
@ -1432,6 +1401,9 @@ class _FileListState extends State<_FileList> {
FaiSpace.md, FaiSpace.md,
FaiSpace.xs, FaiSpace.xs,
), ),
child: Row(
children: [
Expanded(
child: SizedBox( child: SizedBox(
height: 28, height: 28,
child: TextField( child: TextField(
@ -1462,6 +1434,20 @@ class _FileListState extends State<_FileList> {
), ),
), ),
), ),
IconButton(
onPressed: widget.onRefresh,
tooltip: strings.refresh,
icon: const Icon(Icons.refresh, size: 16),
visualDensity: VisualDensity.compact,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 28,
minHeight: 28,
),
),
],
),
),
Expanded(child: _buildBody(context, theme)), Expanded(child: _buildBody(context, theme)),
], ],
), ),
@ -1496,9 +1482,7 @@ class _FileListState extends State<_FileList> {
final needle = _filter.toLowerCase(); final needle = _filter.toLowerCase();
final files = needle.isEmpty final files = needle.isEmpty
? all ? all
: all : all.where((f) => f.name.toLowerCase().contains(needle)).toList();
.where((f) => f.name.toLowerCase().contains(needle))
.toList();
if (files.isEmpty) { if (files.isEmpty) {
// Flows exist, the filter just matches none say that // Flows exist, the filter just matches none say that
// instead of pretending the directory is empty. // instead of pretending the directory is empty.
@ -2027,8 +2011,10 @@ class _DiagnosticStripState extends State<_DiagnosticStrip> {
InkWell( InkWell(
onTap: () => setState(() => _expanded = !_expanded), onTap: () => setState(() => _expanded = !_expanded),
child: Padding( child: Padding(
padding: padding: const EdgeInsets.symmetric(
const EdgeInsets.symmetric(horizontal: 12, vertical: 6), horizontal: 12,
vertical: 6,
),
child: Row( child: Row(
children: [ children: [
Container( Container(
@ -2222,16 +2208,10 @@ class _IssueRow extends StatelessWidget {
child: CircularProgressIndicator(strokeWidth: 2), child: CircularProgressIndicator(strokeWidth: 2),
) )
: const Icon(Icons.auto_fix_high, size: 13), : const Icon(Icons.auto_fix_high, size: 13),
label: Text( label: Text(fix.label, style: _monoTextStyle(size: 11)),
fix.label,
style: _monoTextStyle(size: 11),
),
style: FilledButton.styleFrom( style: FilledButton.styleFrom(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
horizontal: 8,
vertical: 4,
),
minimumSize: const Size(0, 24), minimumSize: const Size(0, 24),
), ),
), ),
@ -2280,7 +2260,10 @@ class _IssueHoverCard extends StatelessWidget {
// to viewport so the card never spills off-screen on a // to viewport so the card never spills off-screen on a
// narrow window. // narrow window.
const cardWidth = 380.0; const cardWidth = 380.0;
final maxLeft = (media.size.width - cardWidth - 12).clamp(8.0, double.infinity); final maxLeft = (media.size.width - cardWidth - 12).clamp(
8.0,
double.infinity,
);
final dx = (request.globalPosition.dx + 12).clamp(8.0, maxLeft); final dx = (request.globalPosition.dx + 12).clamp(8.0, maxLeft);
final dy = (request.globalPosition.dy + 18).clamp( final dy = (request.globalPosition.dy + 18).clamp(
8.0, 8.0,
@ -2300,9 +2283,7 @@ class _IssueHoverCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHigh, color: theme.colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all( border: Border.all(color: theme.colorScheme.outlineVariant),
color: theme.colorScheme.outlineVariant,
),
boxShadow: const [ boxShadow: const [
BoxShadow( BoxShadow(
color: Color(0x33000000), color: Color(0x33000000),
@ -2453,11 +2434,7 @@ class _FixDialogState extends State<_FixDialog> {
return AlertDialog( return AlertDialog(
title: Row( title: Row(
children: [ children: [
Icon( Icon(Icons.auto_fix_high, size: 20, color: theme.colorScheme.primary),
Icons.auto_fix_high,
size: 20,
color: theme.colorScheme.primary,
),
const SizedBox(width: 8), const SizedBox(width: 8),
Text(strings.diagnosticFixDialogTitle), Text(strings.diagnosticFixDialogTitle),
], ],
@ -2579,10 +2556,7 @@ class _FixDialogRow extends StatelessWidget {
FilledButton.tonalIcon( FilledButton.tonalIcon(
onPressed: () => onApplyFix(fix), onPressed: () => onApplyFix(fix),
icon: const Icon(Icons.auto_fix_high, size: 13), icon: const Icon(Icons.auto_fix_high, size: 13),
label: Text( label: Text(fix.label, style: _monoTextStyle(size: 11)),
fix.label,
style: _monoTextStyle(size: 11),
),
), ),
], ],
), ),

View file

@ -108,7 +108,7 @@ class FlowYamlCodeController extends CodeController {
/// Replace the analyzer's capability provider. Called by the /// Replace the analyzer's capability provider. Called by the
/// editor host when the installed-capability list changes /// editor host when the installed-capability list changes
/// e.g. after `fai install` while the editor is open. /// e.g. after `chain install` while the editor is open.
void setAvailableCapabilities(List<String> Function() provider) { void setAvailableCapabilities(List<String> Function() provider) {
analyzer = FlowAnalyzer(availableCapabilities: provider); analyzer = FlowAnalyzer(availableCapabilities: provider);
} }

View file

@ -17,7 +17,6 @@ class FlowEditorStrings {
String get save => _t('Save', 'Speichern'); String get save => _t('Save', 'Speichern');
String get run => _t('Run', 'Ausführen'); String get run => _t('Run', 'Ausführen');
String get refresh => _t('Refresh file list', 'Datei-Liste neu laden'); String get refresh => _t('Refresh file list', 'Datei-Liste neu laden');
String get listHeader => _t('FLOWS', 'FLOWS');
String get listStartTooltip => String get listStartTooltip =>
_t('Open on the Run tab', 'Im Starten-Tab öffnen'); _t('Open on the Run tab', 'Im Starten-Tab öffnen');
String get copy => _t('Copy', 'Kopieren'); String get copy => _t('Copy', 'Kopieren');

View file

@ -69,8 +69,8 @@ class InstallCapabilityFix extends QuickFix {
/// Ask the host to register a new module source for an unknown /// Ask the host to register a new module source for an unknown
/// capability used when the capability isn't in the public /// capability used when the capability isn't in the public
/// store. The host's handler typically prompts the operator /// store. The host's handler typically prompts the operator
/// for a local path (`fai install --link`) or a URL /// for a local path (`chain install --link`) or a URL
/// (`fai install <url>`), then installs and reanalyzes. /// (`chain install <url>`), then installs and reanalyzes.
/// ///
/// This is the recovery path for private modules: the public /// This is the recovery path for private modules: the public
/// store doesn't know about `htw.digiscout/onet-lookup`, but /// store doesn't know about `htw.digiscout/onet-lookup`, but

View file

@ -1,6 +1,6 @@
name: chain_studio_flow_editor name: chain_studio_flow_editor
description: Swappable inline YAML editor for F∆I Studio flows. description: Swappable inline YAML editor for F∆I Studio flows.
version: 0.24.0 version: 0.24.1
publish_to: 'none' publish_to: 'none'
repository: https://git.flemming.ai/fai/studio-flow-editor repository: https://git.flemming.ai/fai/studio-flow-editor