fix(editor): per-field output dots + dynamic card width
Two issues Stefan spotted in the screenshot:
1. Output port labels rendered on the right side of each
step card, but the canvas-side port DOTS were missing —
only the inputs side carried interactive dots. The
_portOverlays generator looped once per step and stamped
a single anchor; with per-field outputs we now loop
per declared (or YAML-implied) output field and yield
one dot per field, each with its own drag-start
handler that stamps fromField into the ConnectionDraft.
New edges out of those dots persist the precise output
name (e.g. $summarize.response) instead of the
placeholder $summarize.result.
2. Long labels (model_endpoint, source_language) were
ellipsis-clipped because every card rendered at the
220 px fixed minimum. NodeGeometry now exposes
widthFor(maxInputChars, maxOutputChars) that grows the
card to fit the longest label on each side, plus
gutters and slack. _stepWidth(step) on the canvas
computes it per step from the merged label lists;
_outputPortPosition, fit-to-content, and _stepPositioned
all route through it so dots, edges, and bounding boxes
stay aligned when cards stretch.
Connected-ports set keys per-field on the source side too
(${stepId}:${fieldName}) so the dot fills the way the
input-side dots do once any edge actually leaves it.
Legacy ${stepId}:__out__ stays seeded for the
no-declared-outputs fallback.
Bumps fai_studio_flow_editor to 0.10.2.
Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
7797654572
commit
3a6e92fe09
3 changed files with 143 additions and 28 deletions
|
|
@ -34,7 +34,38 @@ import '../tokens.dart';
|
|||
/// its content)
|
||||
/// - bodyBottomPad
|
||||
class NodeGeometry {
|
||||
/// Minimum card width — used when labels are short. Cards
|
||||
/// grow beyond this via [widthFor] when their longest port
|
||||
/// label wouldn't fit.
|
||||
static const double width = 220;
|
||||
|
||||
/// Approximate render width per character at the
|
||||
/// `labelSmall` text style used in port labels. Not exact
|
||||
/// — we don't lay out text per build — but close enough
|
||||
/// to ensure long labels like `model_endpoint` or
|
||||
/// `source_language` aren't ellipsis-clipped on the
|
||||
/// stock width.
|
||||
static const double _charWidth = 7.5;
|
||||
|
||||
/// Compute a card width that fits the longest input AND
|
||||
/// output label without truncation. The two-column body
|
||||
/// layout reserves a left gutter (input port dot), a
|
||||
/// middle gap, and a right gutter (output port dot). We
|
||||
/// add a small slack so labels don't kiss the column
|
||||
/// boundary.
|
||||
static double widthFor({
|
||||
required int maxInputChars,
|
||||
required int maxOutputChars,
|
||||
}) {
|
||||
const minMiddleGap = 12.0;
|
||||
const slack = 6.0;
|
||||
final inputW = maxInputChars * _charWidth;
|
||||
final outputW = maxOutputChars * _charWidth;
|
||||
final needed =
|
||||
portGutter + inputW + minMiddleGap + outputW + portGutter + slack;
|
||||
return needed > width ? needed : width;
|
||||
}
|
||||
|
||||
// Header band is constant whether the node has a subtitle
|
||||
// or not. Endpoint nodes (inputs / outputs) render an empty
|
||||
// subtitle slot — that keeps port-row Y-offsets identical
|
||||
|
|
@ -167,6 +198,12 @@ class FlowNode extends StatelessWidget {
|
|||
/// the active editor style.
|
||||
final bool elevated;
|
||||
|
||||
/// Explicit card width. Defaults to [NodeGeometry.width].
|
||||
/// Callers pass a larger value computed from the longest
|
||||
/// port label so labels like `model_endpoint` or
|
||||
/// `source_language` don't ellipsis-clip.
|
||||
final double width;
|
||||
|
||||
/// Live status from the most recent run, when this node is
|
||||
/// a step. Coloured dot in the header so the operator can
|
||||
/// glance at the canvas and see what's running.
|
||||
|
|
@ -200,6 +237,7 @@ class FlowNode extends StatelessWidget {
|
|||
this.onContextMenu,
|
||||
this.elevated = true,
|
||||
this.pulse,
|
||||
this.width = NodeGeometry.width,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -218,7 +256,7 @@ class FlowNode extends StatelessWidget {
|
|||
// animation source is wired or the step isn't running.
|
||||
if (pulse != null && status == FlowNodeStatus.running) {
|
||||
return SizedBox(
|
||||
width: NodeGeometry.width,
|
||||
width: width,
|
||||
height: height,
|
||||
child: AnimatedBuilder(
|
||||
animation: pulse!,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue