Releases: Wintersta7e/FlowForge
Releases · Wintersta7e/FlowForge
FlowForge v2.0.0
Added
- Molten Works redesign — cast-iron stations with chrome pipes, forge-amber / cyan / magenta / lime / purple palette, and embedded Instrument Serif / Oswald / JetBrains Mono typography. 11 hand-drawn forge-themed SVG icons (pit, mold, die, chisel, brand, sieve, rack, mill, crucible, press, loupe). Rebuilt top bar (FLOW·FORGE logo, pipeline path, STN/PIPE stats, IGNITE / QUENCH / DRY RUN buttons), operations library, inspector, and bottom console to match the concept.
- Traveling mercury beads —
MwMercuryDropletcustom control renders four staggered beads riding each pipe's cubic bezier while a pipeline is running. Uses the same midpoint formula as the pipe so the bead tracks the rendered curve by construction. - Custom pipe shape —
MwPipeConnectionreplaces Nodify'sConnectionso the pipe and droplets share the exact same geometry. Five layered strokes for the chrome look (shadow / outer / core / inner channel / liquid). - Running-state visuals — category-colored aura behind each station, pulsing heat glow inside the iron body, pulsing LIVE dot, animated gauge strip (opacity + color change), and mercury inner-dot + glow on active ports.
- Canvas backdrop — radial forge glow, cyan HUD wash, magenta corner brackets, 40×40 / 200×200 grid overlay, animated cyan scanline, 14 staggered ember particles rising from the bottom, system HUD with lat/mem/err stats.
- DEMO button — toggles the running-state visuals on every station and pipe without executing a real pipeline. Disabled while an actual run is in flight.
- Shared pipe / bead geometry helper — new
MwGeometry.IsFinitevalidators are wired into theStyledPropertyregistrations on bothMwPipeConnectionandMwMercuryDroplet, so the two ends of the shared cubic reject the same class of non-finite input at the property boundary.
Changed
- Dark-only theme — light theme support removed. Placeholder
LightResourceDictionaryand runtime toggle dropped;App.axamllocksRequestedThemeVariant="Dark". Toolbar theme-toggle button,ToggleThemecommand,IsDarkTheme/ThemeIconproperties, and theActualThemeVariantChangedsubscription removed. Breaking change for anyone who was using the light theme. - Screenshots refreshed — three new shots matching the redesigned UI (empty state hero, populated editor, running stations). Old pre-redesign screenshots deleted.
Fixed
PathGuard.EnsureWithinDirectorytrailing-separator bug — a user-typed trailing backslash on the output folder, or a drive-root / UNC-share selected as the allowed root (C:\,\\server\share\), doubled the separator in the prefix check and rejected every valid child as "resolves outside".Path.TrimEndingDirectorySeparatornormalization plus a newPathGuard.NormalizedRootPrefixhelper that preserves a root-anchored trailing separator rather than doubling it. Same fix routed throughFolderInputNodeenumeration.- Empty-value validation —
FolderInput,FolderOutput,RenamePattern,RenameRegex, andImageConvertnow throw a friendlyNodeConfigurationExceptionnaming the station when a required field is empty or whitespace, instead of letting rawArgumentException/ IO failures fan out per file. - Bool / int config silent corruption —
JsonElement.GetRawText()returned lowercase"true"/"false"butBoolStringConverter.ConvertBackemits"True"/"False". Case mismatch on the first CheckBox round-trip re-firedOnValueChanged, pushed another UndoRedo entry, rebuilt Fields, produced another mismatched VM, and looped until the UI thread starved.ConfigFieldViewModelnow normalizes bool values in its constructor, and an unparseable bool or int string no longer lands in a typed slot whereGetBoolean/GetInt32would throw on next load. - Inspector blanking after CheckBox toggle —
OnUndoRedoStateChangedcalledRefreshPropertiesPanelsynchronously inside a binding setter's event dispatch, detaching the very CheckBox whose event was still on the stack. Refresh now deferred viaDispatcher.UIThread.Post. - PropertiesView empty-state layout — DockPanel default-Left docking made the empty-state prompt a narrow strip while the Fields
ScrollViewertookLastChildFill. Wrapped both in aGridsoIsVisiblealone controls which shows. - Execution progress bar scale —
ProgressBar.Maximumwas1while the VM'sProgressproperty scales to0..100, so the bar clamped to full at roughly 1 % on every real run. Maximum is now100. - Mercury droplet layout side effects — positioning via
Canvas.SetLeft/SetTophappened insideMeasureOverride, which writes layout-affecting attached properties during the measure pass. Moved toArrangeOverridewithAffectsArrangeonly; render output is position-independent. - Mercury droplet progress overshoot — beads briefly flew off the pipe at animation keyframe boundaries.
ComputeBezierPointclampsProgressto[0, 1], and theStyledPropertyvalidators on Source, Target, Progress, and the pipe's offsets reject NaN / ±Infinity so the cubic geometry cannot be silently poisoned. - Running-state thread safety —
ExecutePipelineAsync'sfinallyflippedExecutionLog.IsRunningon whatever threadRunAsyncresumed on (typically a thread-pool thread), then mutated the node / connectionObservableCollectionfrom off-thread.UpdateRunningVisualnow guards withDispatcher.UIThread.CheckAccessand re-posts when off-thread; thefinallyawaitsDispatcher.UIThread.InvokeAsync(...)so the next execute call sees the flipped flag at its guard. - Running-state on graph mutations — stations and pipes added after the canvas was already in the "forge lit" state (template load, undo of a delete, bulk
Clear + Add) stayed visually idle.OnEditorRunningCollectionChangednow seedsIsRunningonNewItemsand re-syncs the whole canvas onReset. - 30+ regression tests — trailing-separator enumeration across drive-root / UNC / user-typed paths, empty-value configs, bool / int unparseable-input rejection, bool round-trip idempotency, running-state + demo propagation, every registered TypeKey has a bespoke MwOpsMap entry whose category bucket matches its
NodeRegistry.GetCategoryForTypeKey.
See CHANGELOG.md for full history.
FlowForge v1.6.0
Fixed
- Node connections broken since v1.4.0 — dragging a connection wire from any connector was offset and unusable; caused by
RotateTransform(45°)applied directly to the Nodify Connector control, which rotated Nodify's internal coordinate calculations; moved rotation into a custom ControlTemplate Border so the diamond shape is preserved without affecting drag math - Atomic writes for image nodes — ImageConvertNode and ImageResizeNode now use temp-file-then-rename pattern, preventing data loss on I/O errors or cancellation (previously wrote directly to target/original path)
- Path traversal hardening — PathGuard now validates backup paths in FolderOutputNode; RenameRegexNode fullpath scope uses PathGuard instead of hand-rolled check; FolderInputNode filters out symlinked files outside source root; CLI validates --input/--output directories exist
- FilterNode thread safety — removed mutable
_dryRuninstance field; parameter is now passed directly to helper methods - Semaphore disposal race — PipelineRunner now fully drains in-flight tasks before disposing the semaphore
- Buffered transform double-counting — SortNode jobs were counted as both Skipped and Failed when flush failed; runner now skips early disposition for IBufferedTransformNode
- ImageResizeNode missing ErrorMessage — file-too-large failure now sets
job.ErrorMessage(was null in UI) - FilterNode inconsistent date defaults — missing-file paths now return
DateTime.MinValueconsistently (wasstring.Emptyfor live runs) - SortNode stale buffer — buffer is cleared in Configure to prevent cancelled-run jobs bleeding into next run
- NodeLibrary theme refresh — brushes now update on theme toggle; search filter reapplied after refresh
- Runner log diagnostics — failure log messages now include
job.ErrorMessage
Changed
- Full codebase audit — 2-round review across 6 dimensions (security, leaks, performance, architecture, bugs, coverage) with 45+ issues resolved
- Performance — MetadataExtractNode reads EXIF once per file (was once per key); FilterNode uses single FileInfo per file; SortByKey uses index-based sorting; HashSet for SupportedFormats and InvalidFileNameChars lookups; static ValidFormats in ImageConvertNode
- RecentPipelines validation — AppSettings.Validate() now filters entries with null bytes, excessive length, relative paths, or whitespace
- 342 tests — 20 new tests for FilterNode operators, date fields, RenamePattern conflict resolution, SortNode date sorting, RenameRegex fullpath I/O, null deserialization, RecentPipelines validation; cross-platform temp paths replacing hardcoded
/tmp/; removed 2 redundant tests; strengthened assertions on FolderOutput content and SortNode ordering - CommunityToolkit.Mvvm 8.4.1 → 8.4.2
See CHANGELOG.md for full history.