Two visible UX fixes:
1. Properties-panel toggle. Tap a step → opens. Tap the
same step again → closes (deselect via toggle). Tap the
canvas background → also closes. selectStep now returns
to null when called with the already-selected id; the
editor-controller test updated for the new semantics.
2. LabVIEW-style type colours on every port + wire.
_typeAccent now picks vibrant brightness-aware hues per
datatype:
text → magenta/pink (LabVIEW string)
json → amber/orange (cluster feel)
bytes → cyan/teal (raw binary)
file → green (file reference)
number → yellow/amber
Step-input dots, step-output dots, and outputs-endpoint
dots all switch from the generic theme.primary to the
field's declared type accent. Operators read the
payload from the dot alone.
Editor tests still pass (20).
Signed-off-by: flemming-it <sf@flemming.it>
99 lines
2.9 KiB
Dart
99 lines
2.9 KiB
Dart
// Behaviour tests for FlowEditorController — the bridge
|
|
// between the YAML buffer + the graph + the layout sidecar.
|
|
// The model tests cover parsing correctness; these cover
|
|
// that the controller wires text -> graph reparsing,
|
|
// graph -> YAML emission, selection bookkeeping, and
|
|
// dirty/saved transitions correctly.
|
|
|
|
import 'package:fai_studio_flow_editor/src/editor_controller.dart';
|
|
import 'package:fai_studio_flow_editor/src/model/flow_graph.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('FlowEditorController', () {
|
|
test('openFlow seeds the graph + clears the dirty flag', () {
|
|
final c = FlowEditorController();
|
|
addTearDown(c.dispose);
|
|
c.openFlow('hello', '''
|
|
name: hello
|
|
inputs:
|
|
name: text
|
|
steps:
|
|
- id: greet
|
|
use: debug.echo@^0
|
|
with:
|
|
message: \$inputs.name
|
|
outputs:
|
|
greeting: \$greet.echoed
|
|
''');
|
|
expect(c.activeName, 'hello');
|
|
expect(c.graph.steps, hasLength(1));
|
|
expect(c.graph.steps.single.id, 'greet');
|
|
expect(c.isDirty, isFalse);
|
|
});
|
|
|
|
test('graph edit re-emits YAML into the text buffer', () {
|
|
final c = FlowEditorController();
|
|
addTearDown(c.dispose);
|
|
c.openFlow('demo', '''
|
|
name: demo
|
|
steps:
|
|
- id: a
|
|
use: debug.echo@^0
|
|
outputs: {}
|
|
''');
|
|
final initialText = c.codeController.fullText;
|
|
c.applyGraphEdit(
|
|
c.graph.withStepAdded(const FlowStep(id: 'b', use: 'debug.echo@^0')),
|
|
);
|
|
expect(c.codeController.fullText, isNot(initialText));
|
|
expect(c.codeController.fullText, contains('id: b'));
|
|
expect(c.graph.steps, hasLength(2));
|
|
});
|
|
|
|
test('graph edit marks the buffer dirty against the baseline', () {
|
|
final c = FlowEditorController();
|
|
addTearDown(c.dispose);
|
|
c.openFlow('demo', '''
|
|
steps:
|
|
- id: a
|
|
use: debug.echo@^0
|
|
outputs: {}
|
|
''');
|
|
expect(c.isDirty, isFalse);
|
|
c.applyGraphEdit(
|
|
c.graph.withStepAdded(const FlowStep(id: 'b', use: 'debug.echo@^0')),
|
|
);
|
|
expect(c.isDirty, isTrue);
|
|
c.markSaved();
|
|
expect(c.isDirty, isFalse);
|
|
});
|
|
|
|
test('selectStep notifies on change + toggles off on same-id click', () {
|
|
final c = FlowEditorController();
|
|
addTearDown(c.dispose);
|
|
c.openFlow('demo', '''
|
|
steps:
|
|
- id: only
|
|
use: debug.echo@^0
|
|
outputs: {}
|
|
''');
|
|
var calls = 0;
|
|
c.addListener(() => calls++);
|
|
// First select — selectedStepId goes null → 'only',
|
|
// listeners fire once.
|
|
c.selectStep('only');
|
|
expect(c.selectedStepId, 'only');
|
|
expect(calls, 1);
|
|
// Clicking the same step again deselects (toggle
|
|
// semantics): selectedStepId goes 'only' → null,
|
|
// listeners fire again. That IS a state change.
|
|
c.selectStep('only');
|
|
expect(c.selectedStepId, null);
|
|
expect(calls, 2);
|
|
// Explicit null while already null is a no-op.
|
|
c.selectStep(null);
|
|
expect(calls, 2);
|
|
});
|
|
});
|
|
}
|