Skip to content

Fix/step 31 final adjustments#697

Merged
thiagoralves merged 40 commits into
refactor/shared-ui-migrationfrom
fix/step-31-final-adjustments
Mar 31, 2026
Merged

Fix/step 31 final adjustments#697
thiagoralves merged 40 commits into
refactor/shared-ui-migrationfrom
fix/step-31-final-adjustments

Conversation

@dcoutinho1328
Copy link
Copy Markdown
Collaborator

@dcoutinho1328 dcoutinho1328 commented Mar 16, 2026

Summary

Comprehensive bug fixes for the frontend/backend migration branch. All changes follow the refactored port architecture (docs/ports/WIRING.md) with identical frontend code for both Electron and web platforms.

Monaco editor theme

  • Use Zustand store (shouldUseDarkMode) instead of DOM class check for Monaco theme switching — works in both Electron and web
  • Import missing ReactFlow dark theme CSS and add prefers-color-scheme media query fallback for Electron
  • Persist theme preference to electron-store on IPC toggle (keyboard shortcut path)

Tab close behavior

  • Wire useHandleRemoveTab hook with closeFile (unsaved-changes guard) matching the web migration branch
  • Add closeFile action to shared slice

Debug system (PR #646 + #684 port)

Save/discard modals

  • Save-changes-file modal: "Save" actually saves via projectPort.saveProject(); "Don't Save" reloads POU from disk using parseGraphicalPouFromString/parseTextualPouFromString
  • Save-changes-project modal: both paths now call clearStatesOnCloseProject() to return to start screen

False unsaved marks (asterisk)

  • FBD: root cause was syncNodesWithVariablesFBD during project open calling updateNodeflow.updated=true. Reset all flow flags at end of handleOpenProjectResponse
  • FBD comment component: skip initial mount updateNode via didMountRef
  • LD: root cause was variable.tsx reference comparison (refStale) always true on mount. Removed stale ref check — name comparisons are sufficient
  • LD/FBD/ST: guard handleFileAndWorkspaceSavedState with isDebuggerVisible to prevent debug-mode false dirties
  • addFBDFlow/addLadderFlow: reset updated to false on load; legacy connectedVariables migration only sets updated when needed

Undo/redo for LD/FBD

  • usePouSnapshot now deep-copies ladderFlow/fbdFlow into snapshots
  • undo/redo restores flow state via applyLadderFlowSnapshot/applyFBDFlowSnapshot with updated: false
  • FBD onNodeDragStart captures snapshot for position undo
  • savedAtDepth tracking: undo/redo clears dirty flag when returning to save point
  • markAllSaved() called at all save sites

Legacy project compatibility

  • Normalize connectedVariables from object to array format in addLadderFlow (fast-path skip for modern projects)
  • Array.isArray guards at all direct access sites

Test plan

  • Open project with FBD/LD/ST/IL POUs — no false asterisks
  • Edit FBD/LD POU, Ctrl+Z — change undone, dirty flag cleared
  • Edit FBD/LD POU, save, edit again, Ctrl+Z past save point — dirty flag cleared at save point
  • Close modified tab → "Don't Save" → reopen — original content restored
  • Close project with unsaved changes → "Close without saving" → returns to start screen
  • Toggle theme via keyboard shortcut → persists across restart
  • Debug mode: badges appear correctly, switch between ST/IL tabs — correct positions
  • Debug mode: no false asterisks on any POU type
  • Open legacy project with object-format connectedVariables — no crash

🤖 Generated with Claude Code

dcoutinho1328 and others added 7 commits March 13, 2026 18:15
…names

Replace direct window.bridge casts and sharedWorkspaceActions with
ProjectPort methods for create/save/watch operations. Update snapshot
actions (addSnapshot -> pushToHistory) and tab close (closeFile ->
forceCloseFile) to match unified store API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Components copied from src/ used the old DTO shape (pou.data.name,
pou.type) but src2/ stores POUs as flat PLCPou (pou.name, pou.pouType,
pou.interface?.variables). Updated 33 files across frontend surface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Button

ActivityBarButton now uses forwardRef for tooltip compatibility. Explorer
panels split 50/50 instead of 40/40, and workspace/editor panels adjusted
to 84/69 for better proportions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…veHandle

These const declarations were referenced in useImperativeHandle before
their initialization, causing a ReferenceError (temporal dead zone).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ming

createVariable silently failed when POU.interface was undefined (set by
project adapter for POUs with no variables). Now the adapter always
initializes interface and createVariable returns the created data.

Also fix configuration -> configurations (plural) mismatch across
6 frontend files, and add error toast to ladder autocomplete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…al support

Add DebugValueBadge and BlockOutputDebugBadges components for showing
live debug values on block outputs and variable nodes during debug
sessions. Fix case-sensitive variable matching in block instance
linking, add type validation in wrongVariable detection, wire literal
type support in ladder variable nodes, and fix autocomplete Enter key
handling to use triggerSubmit consistently. Also includes variable
table validation improvements and editor config updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nagement

Cmd+S/Cmd+Shift+S now update editingState and mark files as saved.
Added missing handlers: findInProject, switchPerspective, quitApp,
theme update, auto-close handshake, and darwin quit.
Split window close vs darwin quit into separate port methods.
Added system library data files for block definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • development

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0b1a0b1c-51c3-4730-a064-1f6c7dc60c18

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/step-31-final-adjustments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

dcoutinho1328 and others added 22 commits March 16, 2026 20:11
…ed surfaces

Type definition fixes: extend ModbusRemoteTcpConfig with RTU fields, add
CompileProgressEvent.level/firmwarePath, add S7CommBufferMapping.type,
rename PLCInstance.taskName/pouName to task/program, make ModbusIOGroup.ioPoints
optional, add PLCProject alias, add workspace loading state.

Consumer fixes: configuration->configurations, SharedResponse.success->.ok,
RTU casing, import.meta.env->getEnv helper, missing type re-exports from
graphical-editor atoms, remove orphaned react-flow custom-nodes, null guards,
type assertions, stub modules for web-only imports, and import sorting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d type errors

Remove duplicate bare ts-loader rule from src2 webpack config that caused
"exports is not defined" ReferenceError via double-compilation with CommonJS.
Add src2 lint/format scripts and lint-staged config. Fix various type errors,
import ordering, and Tab component prop naming across shared surfaces.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ity gaps

Add pre-save POU sanitization (variablesText sync) and debug variable
collection via prepareSavePayload utility. Wire servers/remoteDevices
through adapter save payload. Add toast feedback and post-save state
cleanup to accelerator handler and save-changes-modal. Fix open-recent
callback flow by passing project data through onAfterAction. Add DHCP
IP input modal trigger and PLC auto-start check to debugger click flow.
Add removeDebugVariable call to global variables editor on delete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make the new three-layer architecture app the primary codebase.
Update all config files (webpack, jest, eslint, tsconfig, tailwind),
scripts, and architecture validators to use the new directory names.

- src2/ -> src/ (new main application)
- src/ -> src_old/ (legacy app preserved)
- Config files renamed: *.src2.* -> primary names, old -> *.old.*
- Package.json scripts: :src2 variants become primary, old get :old suffix
- Architecture validator: SRC2_ROOT -> SRC_ROOT

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add getErrorMessage utility, replace ~62 String(error) patterns
- Replace console.log/error with winston logger in main process
- Consolidate checkVariableNameUnit into checkVariableName
- Extract deleteElement/renameElement helpers in shared slice
- Centralize PLC address prefix constants and regex patterns
- Replace 65+ deep relative imports (7+ ../) with @root aliases
- Extract httpRequest helper in IPC main, simplify 4 HTTP handlers
- Remove i18n and ProjectState imports from backend (decouple layers)
- Type IPC bridge callbacks, remove eslint-disable for no-explicit-any

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ladder editor, FBD editor, activity bar, store slices, and adapter
cleanups from step-31 final adjustments. Fix lint errors (unused
imports, missing import sort, nonexistent eslint rule references).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DebuggerPort.connect() and verifyMd5() now accept DebugConnectionConfig
directly instead of relying on a closure-based setter that was never
called. The activity bar's handleDebuggerClick matches src_old/'s full
flow: connection type resolution (TCP/RTU/WebSocket/simulator), debug
compilation, MD5 verification with re-verify after recompile, and
variable map building (index, tree, FB instances).

New debugger-session.ts provides shared map-building utilities
(buildVariableIndexMap, buildDebugVariableTreeMap, buildFbInstanceMap)
adapted for port-format types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
useDebugSession and useDebugPolling no longer import debugBridge or
simulatorService singletons. Both hooks now use useDebugger() and
useSimulator() port interfaces from PlatformProvider, making them
fully platform-agnostic.

useDebugSession provides connectAndStart() which reads the debug file,
builds variable index/tree/FB maps, connects via DebuggerPort, and
stores all artifacts in the workspace store.

useDebugPolling polls via DebuggerPort.getVariablesList() with
board-aware intervals (50ms simulator, 200ms others).

Activity bar slimmed from 948 to 535 lines — session lifecycle
delegated to useDebugSession hook, polling to useDebugPolling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ments

Gate platform-specific UI features (about dialog, orchestrators, serial ports)
behind useCapabilities(), make DebuggerPort.connect() accept explicit
DebugConnectionConfig, normalize PLC schema types to lowercase, and update
compiler adapter and backend services for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove orphaned eslint-disable comments for unconfigured react-hooks and
react-refresh plugins, fix unused imports/variables, add type annotations
to resolve unsafe-argument/return/assignment errors from Zod type inference,
and fix misc issues (constant conditions, unbound methods, explicit any in tests).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make DebugManager a pure session orchestrator that delegates all
transport concerns to the platform adapter via DebugConnectionConfig.

- Add 'webrtc' to DebugConnectionType and extend connectionParams
- Update DebugManager to build DebugConnectionConfig and call
  connectAndStart() instead of legacy startDebug/stopDebug casts
- Remove web-only files from shared frontend/ surface: ai-chat
  components, useAI, useWebRTCConnection (deleted from editor,
  moved to web adapter layer in openplc-web)
- Add ExtensionPanelProvider for optional UI component injection
  (useChatPanel hook), making workspace-screen.tsx platform-agnostic
- Move debug/simulator services to backend/shared/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The pou-text-serializer was refactored to use the flat port PLCPou type
but the editor backend still passed the nested IPC format, causing save
to crash. Added ipcPouToFlat() converter at all backend call sites.

Also fixed IpcSaveResponse field name mismatch (reason -> error) so save
errors are properly reported instead of showing generic "Save failed".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Syncs shared surfaces from web: RuntimePort.isReadyForDebug() for
platform-specific connection readiness, debugger pre-connect before
MD5 verification, CompileResult.programSt field, and fixed @root
import paths in cpp codegen utils.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All save call sites omitted projectName from SaveProjectParams, causing
the web adapter to fall back to projectId as the name in project.json.

Also includes orchestrator-list runtime port wiring and lint fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was gated behind hasNativeMenu which is false on web, preventing all
keyboard shortcuts (Ctrl+S, Ctrl+Z, etc.) from working. Editor-only
features inside the handler are already guarded by their own capability
checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
applyThemeNow() was reading document.documentElement.classList for the
dark class, which is never set in Electron. Pass shouldUseDarkMode from
the store directly so the theme works in both Electron and web.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tabs component was calling removeTab + removeFile directly, which only
removed the tab from the bar without updating the editor state. Aligned
with openplc-web migration branch: use useHandleRemoveTab hook which
calls closeFile (with unsaved-changes guard) then forceCloseFile to
properly select the next tab or clear the editor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e debug

Cherry-pick of PR #684 (eea9b84) applied to both src_old/ and the
migrated src/frontend/ copy. When an ST tab is opened after the debugger
is already running, editorRef is null during the initial debugVarPositions
memo computation. Adds an editorMounted state flag set in
handleEditorDidMount so the position-scanning memo re-runs when the
editor becomes available.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reimplements the optimization from PR #646 using the refactored port
architecture. The debug polling hook now filters variables to only poll
what is actively needed: watched (debug=true), forced, graph-listed,
diagram-visible (LD/FBD node scan), source-visible (ST/IL regex), and
expansion-aware nested children.

Diagram/source scan results are cached per {pouName, language, fbContext}
since the editor is read-only during debug. This reduces polling traffic
by 100-500x on large projects, restoring interactive update speed on
Modbus RTU serial targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
thiagoralves and others added 11 commits March 30, 2026 11:23
The style.css with dark theme variables for ReactFlow controls existed
but was not imported in the migrated code (old code had the import).
Also added a prefers-color-scheme media query fallback so the dark
theme works in Electron (which uses OS preference) in addition to the
web (which sets the .dark class on html).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The handleUpdateTheme IPC handler toggled nativeTheme but did not save
the new theme to electron-store. When the user toggled theme via
keyboard shortcut (which goes through the ThemePort adapter → IPC),
the preference was lost on restart. The menu-based toggle already
persisted correctly via updateAppTheme() in menu.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When loading older projects, block nodes may have connectedVariables
stored as an object ({handleId: {variable, type}}) instead of an array.
The connectedOutputNames memo crashed with "not iterable" when this
happened. Added Array.isArray guard and a migration effect that converts
the legacy object format to the expected array format on first render.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ccess

Old projects stored block connectedVariables as an object
({ handleId: { variable, type } }) instead of the current array format.
This caused "not iterable" crashes in multiple ladder components.

- addLadderFlow now detects legacy format via a quick .some() scan and
  only runs the migration pass when needed (modern projects skip it)
- Marks flow as updated after migration so the next save writes the
  new format, eliminating the need for future migrations
- Added Array.isArray guards at all 4 remaining direct access sites
  as safety nets
- Added normalizeConnectedVariables helper in ladder utils for
  duplicateRung

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When two textual POUs (ST/IL) are open in tabs, debug badges showed in
wrong positions or disappeared because the debugVarPositions memo scanned
a stale model during tab switches. Ports the remaining fixes from PR #646
(commits 039d382 and 681f519):

- Add modelVersion state bumped by onDidChangeModel listener to detect
  when Monaco swaps models on tab change with keepCurrentModel
- Add URI guard in debugVarPositions memo to prevent scanning a model
  that doesn't match the current POU during the React/Monaco race
- Add modelVersion to the memo dependency array so it re-scans after
  the model swap completes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sync byte-identical surfaces: menu bar implementation, graphical editor
fixes, AI port extraction, and middleware shared updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three independent causes of false asterisks on POU tabs:

1. syncNodesWithVariablesFBD calls updateNode during project open,
   which sets flow.updated=true as a side effect. Reset all LD/FBD
   flow updated flags after sync completes in the shared slice.
   Also reset updated on addFBDFlow/addLadderFlow since these load
   from saved project data.

2. FBD comment component called updateNode on initial mount (the
   commentFocused effect fires with false on mount). Added a
   didMountRef guard to skip the initial render.

3. During debug, read-only editors fired onChange/flowUpdated events
   from internal state management. Added isDebuggerVisible guards
   in the FBD, LD, and Monaco editor flowUpdated/onChange handlers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Save-changes-file modal (tab close):
- Save: now actually saves the project via projectPort then closes tab
- Don't Save: reloads the POU from disk (using parseGraphicalPouFromString
  for LD/FBD, parseTextualPouFromString for ST/IL), restores the flow
  state, marks saved, then closes the tab. Changes are fully discarded.

Save-changes-project modal (project close):
- Both "Save and close" and "Close without saving" now call
  clearStatesOnCloseProject() to actually clear all state and return
  to the start screen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…king

Undo/redo:
- usePouSnapshot now deep-copies ladderFlow/fbdFlow into snapshots
- undo/redo restores flow state via applyLadderFlowSnapshot/applyFBDFlowSnapshot
  with updated:false to prevent re-dirtying
- FBD onNodeDragStart captures snapshot for position undo

Dirty flag on undo:
- Added savedAtDepth to PouHistoryBucket, initialized to 0 (loaded = saved)
- pushToHistory invalidates savedAtDepth when future is discarded
- undo/redo checks if pastLength matches savedAtDepth and clears dirty flag
- markAllSaved called at all 5 save sites alongside setAllToSaved

LD false unsaved on open:
- variable.tsx had a reference comparison (nodeVarRef !== variable) that was
  always true on mount since store objects are different references even when
  content matches. Removed the refStale check — name comparisons are sufficient.

FBD false unsaved on open (prior commit complement):
- applyFBDFlowSnapshot/applyLadderFlowSnapshot now set updated:false since
  snapshot restore is not a user edit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move runtime-https-config.ts from src/frontend/utils/ to
  src/backend/editor/utils/ — it uses process.env (Node.js-only) and
  is consumed exclusively by backend code
- Remove unnecessary `as any` cast in shared/slice.ts — both sides of
  the call use PLCVariable[] from the same source type
- Remove debug console.log leftovers in fbd-xml.ts
- Remove redundant console.error calls in validation functions that
  already return structured { ok, title, message } error responses
- Add TODO to get-env.ts documenting relocation plan to web middleware

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…aths

- Use npm ci --ignore-scripts to skip the heavy postinstall hook
  (download-binaries, electron-builder, DLL build) that was OOMing
  on CI runners and timing out after 60 minutes
- Update src2/__architecture__/validate.ts → src/__architecture__/validate.ts
  (src2/ was renamed to src/ in the directory migration)
- Update jest.config.src2.json → jest.config.json (old config was deleted)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@thiagoralves thiagoralves merged commit 9f4bfc4 into refactor/shared-ui-migration Mar 31, 2026
3 of 4 checks passed
@thiagoralves thiagoralves deleted the fix/step-31-final-adjustments branch March 31, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants