Skip to content

feat(datatypes): datatype rename reference propagation with impact modal (DOPE-536) - #994

Merged
JoaoGSP merged 4 commits into
developmentfrom
feature/DOPE-536-datatype-rename-propagation
Aug 7, 2026
Merged

feat(datatypes): datatype rename reference propagation with impact modal (DOPE-536)#994
JoaoGSP merged 4 commits into
developmentfrom
feature/DOPE-536-datatype-rename-propagation

Conversation

@JoaoGSP

@JoaoGSP JoaoGSP commented Aug 6, 2026

Copy link
Copy Markdown
Member

DOPE-536 — Datatype rename reference propagation (impact modal)

Renaming a data type now propagates the new name into everything that references it, behind a confirmation modal — matching what variable renames already do. Previously the rename only changed the type's own name, leaving every referencing variable pointing at a dead name and breaking compilation.

What changed

  • datatypeActions.rename is now async: after the existing guards (case-insensitive uniqueness, unreadable-.dt collision, name validity) it finds all references and, when any exist, parks a pendingDatatypeRename in the shared slice and awaits the impact modal. Confirm → propagate then rename. Cancel → zero state change, result {ok: false, cancelled: true} (callers skip the failure toast). Zero references or same-name rename skips the modal entirely.
  • New src/frontend/utils/data-type-references.ts (+ data-type-references/types.ts): findAllReferencesToDataType covers POU variables, global variables, other structures' fields, and array data types' base types — both direct user-data-type references and array base types. Mirrors variable-references and returns the same ReferenceImpactAnalysis shape so the existing modal renders it unchanged.
  • New projectActions.propagateDatatypeRename: rewrites all four reference shapes in one Immer pass, rebuilding the ARRAY [dims] OF <type> display string — required for correctness since variable serialization emits type.value verbatim into saved declarations.
  • Post-propagation sync in the shared slice: every touched container's file entry is flagged dirty (single-file save and the close-project check read those flags), and code-mode variables buffers of affected POUs are regenerated — sanitizePou persists editor.variable.code as the authoritative variablesText on save, so a stale buffer would resurrect the old type name.
  • RenameImpactModal gains optional copy-override props (title, list labels, button labels, cancel description); defaults keep the variable-rename wording byte-for-byte. New store-driven DataTypeRenameImpactModal host mounted in app-layout.
  • ReferenceImpactAnalysis made generic (<Location = VariableReferenceLocation>) — existing variable flows compile unchanged.
  • Callers updated: data-type editor name field (async + cancelled-aware toast), project-tree rename.
  • The web-only AI tool-executor change (async executeTool) has no counterpart here — the editor ships no AI adapter.

Deliberately not done

  • No isDataTypeFilesEnabled() gating — this is a correctness fix independent of the .dt persistence switch.
  • Datatype editor components untouched beyond the async call in the name-field blur (DOPE-535 is building there in parallel).

Validation

  • New utils at 100% coverage; store/slices + utils gates green in both repos (jest + vitest).
  • Typecheck, eslint, prettier clean in both repos.
  • Shared surface byte-identical (compare-surfaces.py: 987 files, 0 diffs).
  • Manually validated in the running app: rename with references across all four shapes → modal lists impact → confirm updates everything; cancel leaves the store untouched; zero-reference rename skips the modal.

Mirror of https://github.com/Autonomy-Logic/openplc-web/pull/653

🤖 Generated with Claude Code

https://claude.ai/code/session_01Br23N5eg2d4ASekgSmTFzz

Summary by CodeRabbit

  • New Features

    • Added impact analysis for data type renames, showing affected variables and structures before confirmation.
    • Confirmed renames update references across program variables, global variables, and data type definitions.
    • Added configurable rename-impact modal text and confirmation controls.
  • Bug Fixes

    • Rename operations now wait for completion and restore the original name if unsuccessful or cancelled.
    • Affected files are marked for update and code-mode buffers refresh after confirmed changes.
    • Improved validation for conflicts, missing types, and case-insensitive names.

…act modal (DOPE-536)

Renaming a referenced data type previously only renamed the type itself,
leaving every referencing variable and type pointing at a dead name and
breaking compilation. datatypeActions.rename is now async: it finds all
references (POU variables, globals, struct fields, array base types),
awaits a confirmation modal when any exist, and rewrites them before the
rename. Cancel leaves the store untouched.

Code-mode variable buffers are regenerated after propagation because
sanitizePou persists editor.variable.code as the authoritative variables
block on save, and every touched container file is flagged dirty so
single-file save and the close-project check pick up the propagated
content. The array display value is rebuilt too — variable serialization
emits type.value verbatim into the saved declaration.

Mirror of the openplc-web change (shared frontend surface).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Br23N5eg2d4ASekgSmTFzz
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Data-type renames now detect affected references and request confirmation. Confirmed renames update project references and editor state. Rename controls await completion, while the application layout hosts a configurable impact modal.

Changes

Data-type rename workflow

Layer / File(s) Summary
Reference analysis and rename utilities
src/frontend/utils/data-type-references/*, src/frontend/utils/variable-references/types.ts, src/frontend/utils/__tests__/data-type-references.test.ts
Adds reference-impact types, detection, immutable rename helpers, and coverage for variables, globals, structures, and arrays.
Project reference propagation
src/frontend/store/slices/project/*, src/frontend/store/__tests__/project-slice.test.ts
Adds propagateDatatypeRename and tests propagation across POU variables, global variables, and dependent data types.
Asynchronous rename confirmation
src/frontend/store/slices/shared/*, src/frontend/store/__tests__/shared-slice.test.ts
Makes data-type renames asynchronous, stores pending impact analysis, handles confirmation or cancellation, and updates dirty state and editor buffers.
Rename modal and editor integration
src/frontend/components/_molecules/rename-impact-modal/*, src/frontend/components/_templates/app-layout.tsx, src/frontend/components/_features/[workspace]/data-type/index.tsx, src/frontend/components/_molecules/project-tree/index.tsx
Adds the data-type modal host, configurable modal text, application wiring, and awaited rename handling in both editor entry points.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RenameEditor
  participant SharedSlice
  participant ImpactModal
  participant ProjectActions
  RenameEditor->>SharedSlice: request asynchronous rename
  SharedSlice->>ImpactModal: show reference impact
  ImpactModal->>SharedSlice: confirm or cancel
  SharedSlice->>ProjectActions: propagate confirmed name
  ProjectActions-->>SharedSlice: update references
  SharedSlice-->>RenameEditor: resolve rename result
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: thiagoralves, dcoutinho1328

Poem

A rabbit maps each type with care,
Then checks each reference there.
The modal asks for a clear reply.
Confirmed names propagate nearby.
Cancelled changes safely lie.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes datatype rename reference propagation and the impact modal.
Description check ✅ Passed The description clearly covers scope, implementation, exclusions, testing, and validation, although it omits the template checklist and Jira link.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/DOPE-536-datatype-rename-propagation

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/components/_features/`[workspace]/data-type/index.tsx:
- Around line 56-66: The asynchronous datatypeActions.rename calls must
explicitly handle rejected promises. In
src/frontend/components/_features/[workspace]/data-type/index.tsx:56-66, add a
catch that restores editorContent.name to dataTypeName, shows the failure toast,
and calls setIsEditing(false); in
src/frontend/components/_molecules/project-tree/index.tsx:597-600, add a catch
that restores the previous label via setNewLabel(label || '').

In `@src/frontend/store/slices/shared/slice.ts`:
- Around line 372-379: Guard the pendingDatatypeRename assignment in the rename
flow so a second request cannot overwrite the existing resolver. When a rename
is already pending, explicitly reject or resolve the new request with the
existing cancellation/error result, while preserving the first request’s await
and normal propagation behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 96036f3b-cbd4-4c62-a701-1b8eaab553e1

📥 Commits

Reviewing files that changed from the base of the PR and between 05dc8d7 and f5488dd.

📒 Files selected for processing (15)
  • src/frontend/components/_features/[workspace]/data-type/index.tsx
  • src/frontend/components/_molecules/project-tree/index.tsx
  • src/frontend/components/_molecules/rename-impact-modal/data-type-rename-impact-modal.tsx
  • src/frontend/components/_molecules/rename-impact-modal/index.tsx
  • src/frontend/components/_templates/app-layout.tsx
  • src/frontend/store/__tests__/project-slice.test.ts
  • src/frontend/store/__tests__/shared-slice.test.ts
  • src/frontend/store/slices/project/slice.ts
  • src/frontend/store/slices/project/types.ts
  • src/frontend/store/slices/shared/slice.ts
  • src/frontend/store/slices/shared/types.ts
  • src/frontend/utils/__tests__/data-type-references.test.ts
  • src/frontend/utils/data-type-references.ts
  • src/frontend/utils/data-type-references/types.ts
  • src/frontend/utils/variable-references/types.ts

Comment thread src/frontend/components/_features/[workspace]/data-type/index.tsx Outdated
Comment thread src/frontend/store/slices/shared/slice.ts
JoaoGSP and others added 2 commits August 6, 2026 16:15
…ejections

Review findings from CodeRabbit on this PR:

- A second rename arriving while one awaits the impact modal used to
  overwrite pendingDatatypeRename, dropping the first resolver and
  stranding its await forever (Enter + blur can double-fire). The
  second request is now rejected explicitly.
- Both rename callers consumed the promise with .then only; an
  unexpected rejection would skip the recovery path and leave the name
  input stuck in edit mode. Both now catch, restore the previous name,
  and surface the error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Br23N5eg2d4ASekgSmTFzz
@JoaoGSP
JoaoGSP force-pushed the feature/DOPE-536-datatype-rename-propagation branch from c33004f to 29c8159 Compare August 6, 2026 19:31
@Gustavohsdp

Copy link
Copy Markdown
Contributor

Review — implementation is solid; the blocker is process, not code

Reviewed together with the web counterpart Autonomy-Logic/openplc-web#653 — all 15 shared files are byte-identical between the repos, so everything below applies to both; that PR additionally adapts the AI tool executor, which this repo does not have.

The finder covers the four structured places a data type is referenced — POU variables, global variables, other structures' fields, other arrays' base types — in both shapes (direct user-data-type and array of), and it is case-insensitive the whole way through, which is the correct IEC semantics.

I probed the rewriter at the points where this kind of code usually breaks:

"NewName"                        direct exact
"NewName"                        direct case-differing  (mystruct → MyStruct)
null                             direct partial — "MyStructExtra" does NOT match  ✅
null                             base-type INT does not match                     ✅
"ARRAY [0..9] OF NewName"        array in the serializer's format
"ARRAY [0..9, 0..3] OF NewName"  array that came from the XML importer            ← see 🟡 2
null                             array of an unrelated type does not match        ✅

The MyStructExtra row is the classic failure of this feature (substring replace) and it's correctly avoided — the comparison is exact equality on lowercase, not includes.

How I verified: 15/15 shared files byte-identical (git hash-object); data-type-references, project-slice and shared-slice green at 500/500 under both runners (vitest and jest); tsc, prettier, validate:arch clean.

Two findings from the sibling PRs are fixed here

Worth stating explicitly, because it changes the advice on those PRs:

  • The blocker I raised on the .dt persistence PR (Foo and foo colliding on datatypes/Foo.dt) — datatype name uniqueness is now case-insensitive, with a comment carrying exactly that reasoning: "each one becomes a datatypes/<Name>.dt path, and macOS/Windows fold filename case".
  • The rename-loses-history point from the undo/redo PRsnapshotActions.renameHistory(oldName, newName) now follows the stacks, with the reason in the comment: "otherwise the history is orphaned under the old name and undo becomes a silent no-op after rename".

🟡 1 — CI hasn't run on either PR (this is what blocks merge)

web #653:     gh pr checks → "no checks reported on the branch"   (0 checks)
editor #994:  gh pr checks → only "CodeRabbit / Review rate limited"
gh run list --branch feature/DOPE-536-...  → empty in both repos

For contrast, #993 reports 12 jobs — so this isn't repo configuration, it's this branch not triggering any workflow.

Why it matters. ci-sync (the shared-surface gate), format, lint, build and arch are all unverified. I covered part of that locally — blob identity for all 15 files, tsc/prettier/arch, 500 tests on both sides — but a mirrored-surface PR shouldn't merge on one reviewer's local runs. An empty commit or closing/reopening the PR should kick the workflows off.


🟡 2 — The array display-string rebuild normalises formatting

Measured: an array that came through the XML importer holds value = "ARRAY[0..9,0..3] OF MyStruct" (no spaces — xml-parser/type-xml.ts:35), and after the rename it becomes "ARRAY [0..9, 0..3] OF NewName" (the data-type-serializer.ts:42 format).

Why I'm flagging it. The rebuild itself is necessary and the comment explains why correctly — value is what variable serialization emits verbatim, so not rebuilding it would keep the old base-type name in the saved declaration. Semantically nothing changes either: parseArrayType accepts both formats, as its own docstring shows.

Impact. For projects that came through the importer, renaming a data type rewrites the formatting of those declarations as well as the name — byte churn beyond the rename, showing up as a larger Source Control diff than the user's action explains. In a codebase that invests as much as this one in byte-stability (DOPE-477, "persist the raw object", the byte-identical mirror gates), that deserves to be a conscious call rather than a surprise. Preserving the original spacing when the current value parses is optional; deciding not to is fine too, as long as it's written down.


🟡 3 — A fifth copy of the type name lives in the graphical nodes (question, not a claim)

The finder covers the four structured sites. There's one more place a type name is cached: node.data.block.variableType.type.value, read by sync-nodes-with-variables.ts:40-41 as "the pin's declared type" and used to validate that the connected variable's type matches the pin.

The question: is that cache re-derived from the POU on relink — in which case it self-heals after a rename — or persisted in the flow? If it's persisted, the scenario is: a user FB with a MyStruct-typed pin → an LD/FBD program using that FB with a variable node on the pin → rename the struct → the variable now reads NewName while the cached pin still says MyStruct → a spurious type-mismatch warning in the graphical editor.

I'm not claiming it's broken — I didn't go deep enough to conclude. But it's the only reference site left outside the finder, and whoever knows the relink path can answer it in minutes.


🟢 Smaller

  • A case-only rename is blocked with a misleading message. The guard including the type being renamed is the right call, and the comment says why ("a case-only change writes the new file and then deletes the old path — the same file where the filesystem folds case"). But renaming Foofoo returns "Data type name already exists", which describes a different problem. Something like "case-only renames aren't supported yet" saves a support ticket.
  • syncAfterDatatypePropagation maps global-variable references to the 'Resource' file entry with a comment — worth an explicit test, since it's the one magic string in the flow.

What's good

  • Case-insensitive end to end (nameMatches in the finder, the rewriter and the slice guards) — correct IEC semantics, and it closes the blocker from the .dt PR.
  • renameHistory following the undo/redo stacks, with the reason in the comment.
  • The concurrency guard names the real scenario"Enter + blur double-fire" — and identifies the right consequence: overwriting the pending request would drop its resolver and strand the first caller's await forever. That's the kind of bug that only shows up in production.
  • Regenerating the code-mode variables buffer is the easiest thing in this whole PR to miss: sanitizePou persists editor.variable.code as the authoritative variables block, so a stale buffer would resurrect the old type name on save. Found and documented.
  • Cancel means zero state change, and {ok: false, cancelled: true} lets callers skip the failure toast — "it failed" vs "the user backed out" is expressed in the type rather than by convention.
  • ReferenceImpactAnalysis made generic (<Location = VariableReferenceLocation>) so the existing variable flows compile untouched, and the modal's copy overrides default to the current wording byte-for-byte — the new feature doesn't perturb the shipped one.
  • Both CodeRabbit findings are closed: the concurrent-rename guard, and .catch on both callers (data-type/index.tsx:69, project-tree/index.tsx:602) — verified at head.
  • Mirror is 15/15, and the web-only files (AI tool executor + agentic loop) are exactly the platform adaptation you'd expect, with an AI-initiated rename going through the same modal.

Verdict

Hold only for CI. Once the workflows run and pass, I'd approve: 🟡 2 is a decision to record, 🟡 3 is a minutes-long question for whoever knows the relink path, and the 🟢 is a string.

One ordering note: since the case-insensitive guard lives in shared/slice.ts — which this PR, the .dt PR and the undo/redo PR all touch — if the .dt PR merges first without it, that repo goes back to having the file-collision hole until this one lands. Worth sequencing deliberately.

Review assisted by Claude Code.

@JoaoGSP JoaoGSP closed this Aug 7, 2026
@JoaoGSP JoaoGSP reopened this Aug 7, 2026
@JoaoGSP

JoaoGSP commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

Thanks for the deep review, @Gustavohsdp — point-by-point disposition:

🟡 1 — CI

Root cause was the GitHub Actions major outage on Aug 6 (githubstatus.com had Actions at major_outage all afternoon): the pull_request/push events from this branch were swallowed and never replayed, which is why gh run list was empty while #993 — triggered before the outage — showed its 12 jobs. Actions is operational again this morning, so we closed/reopened both PRs to re-fire the events (chose that over an empty commit to keep the history clean). Workflows are queued now.

🟡 2 — Array display-string normalization: accepted, recorded here

Decision: we keep the rebuild (serializer format) and accept the formatting normalization for XML-imported arrays. Rationale for the byte-stability concern: renameDataTypeInVariableType returns null for anything that doesn't reference the renamed type, so sibling array declarations keep their original value byte-for-byte — the normalization only lands on declaration lines that already change in the same edit (they contain the renamed name). The churn is confined to lines the user's action already modifies, so we're not spending code on spacing preservation. This comment is the written record.

🟡 3 — The fifth copy: your suspicion is right, and it does NOT self-heal → DOPE-548

Verified: block signatures are copied into node.data.variant at drop time and frozen in the saved project; the pin's data.block.variableType is copied from that variant at link time; restampFlowLibraryVariants refreshes library blocks only and explicitly skips user-POU-backed blocks — nothing re-derives them from the FB's current interface. So your scenario is real: rename a struct used as a user-FB pin type and the next relink pass compares the refreshed variable type against the stale cached pin type → spurious wrongVariable + dirtied consumer POU.

Important scoping fact: this is a pre-existing, general hole — editing an FB pin's type from INT to REAL today breaks placed blocks the exact same way; the rename is just one more path into it. Filed DOPE-548 for the principled fix (re-derive user-FB variants on relink, the counterpart of what restamp does for libraries), which heals every entry into the hole rather than special-casing rename inside this PR.

🟢 Case-only rename message

Keeping the current message for now — decided it's not worth a change in this PR.

🟢 'Resource' magic-string test

Already covered: shared-slice.test.ts"confirm flags every affected container file dirty" asserts files['Resource'].saved === false alongside the POU and datatype containers.

Ordering note

Moot, happily: the .dt persistence PR (#651/#991) merged before this branch was cut, and the case-insensitive uniqueness guard was already on development at branch time — this PR inherited it rather than introducing it, so there's no sequencing hazard left.

Reply assisted by Claude Code.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/frontend/store/slices/shared/slice.ts (1)

380-405: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Block every data-type rename while confirmation is pending.

Line 396 rejects a second request only when that request also has references. If OldDT → NewDT awaits confirmation and OtherDT → NewDT has zero references, the second request skips this guard and completes. The confirmed request then operates with a target name that is no longer available.

Check pendingDatatypeRename before reconcileDatatypeText and reference analysis. This also prevents a rejected request from reconciling unrelated editor state. Add a test for a zero-reference rename that targets a pending rename’s newName.

Proposed fix
 const nameCheck = validateElementName(newName)
 if (!nameCheck.ok) return nameCheck

+if (getState().pendingDatatypeRename) {
+  return { ok: false, message: 'Another data type rename is awaiting confirmation' }
+}
+
 const reconcile = state.projectActions.reconcileDatatypeText(oldName)
 if (!reconcile.ok) return { ok: false, message: reconcile.message }

 // ...
-          if (getState().pendingDatatypeRename) {
-            return { ok: false, message: 'Another data type rename is awaiting confirmation' }
-          }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/store/slices/shared/slice.ts` around lines 380 - 405, Update the
rename flow around the datatype rename action to check pendingDatatypeRename
before calling reconcileDatatypeText or findAllReferencesToDataType, rejecting
any concurrent rename while confirmation is pending. Remove the later
conditional-only guard, preserve the existing rejection message, and add
coverage for a zero-reference rename targeting the pending rename’s newName.
src/frontend/components/_features/[workspace]/data-type/index.tsx (2)

288-314: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use buttons for the visualization controls.

TableIcon and CodeIcon are SVG click targets. Keyboard users cannot activate them or determine the selected visualization. Wrap each icon in a <button type="button"> and set aria-pressed from display.

Proposed fix
-            <TableIcon
-              aria-label='Data type table visualization'
-              onClick={() => handleVisualizationTypeChange('table')}
-              size='md'
-              currentVisible={display === 'table'}
-              className={cn(
-                display === 'table' ? 'fill-brand' : 'fill-neutral-100 dark:fill-neutral-900',
-                'rounded-l-md transition-colors ease-in-out hover:cursor-pointer',
-              )}
-            />
+            <button
+              type='button'
+              aria-label='Data type table visualization'
+              aria-pressed={display === 'table'}
+              onClick={() => handleVisualizationTypeChange('table')}
+              className='rounded-l-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-brand'
+            >
+              <TableIcon
+                aria-hidden
+                size='md'
+                currentVisible={display === 'table'}
+                className={display === 'table' ? 'fill-brand' : 'fill-neutral-100 dark:fill-neutral-900'}
+              />
+            </button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/components/_features/`[workspace]/data-type/index.tsx around
lines 288 - 314, Update the visualization controls around TableIcon and CodeIcon
to use type="button" elements, moving each icon’s click handler onto its button.
Set aria-pressed based on whether display matches the corresponding
visualization, while preserving the existing styling, labels, and
handleVisualizationTypeChange behavior.

Source: Learnings


175-186: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the Node type assertions.

Lines 177 and 184 use as Node; narrow e.target and e.relatedTarget with instanceof Node before passing them to contains.

Proposed fix
-      if (containerRef.current.contains(e.target as Node)) return
+      const target = e.target
+      if (target instanceof Node && containerRef.current.contains(target)) return
...
-      const newTarget = e.relatedTarget as Node | null
-      if (newTarget && containerRef.current.contains(newTarget)) return
+      const newTarget = e.relatedTarget
+      if (newTarget instanceof Node && containerRef.current.contains(newTarget)) return
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/components/_features/`[workspace]/data-type/index.tsx around
lines 175 - 186, Update onDocMouseDown and onFocusOut to remove the Node type
assertions; first narrow e.target and e.relatedTarget with instanceof Node, then
call containerRef.current.contains only for confirmed Node values while
preserving the existing commit behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/store/slices/shared/slice.ts`:
- Around line 385-392: Update the data-type rename validation around
findAllReferencesToDataType to check state.project.data.pous with nameMatches
before reconciliation or confirmation. Reject targets matching any POU name in
either exact-case or case-insensitive form, preserving the existing data-type
and unparsed-file checks. Add tests covering both exact-case and case-variant
POU name collisions.

---

Outside diff comments:
In `@src/frontend/components/_features/`[workspace]/data-type/index.tsx:
- Around line 288-314: Update the visualization controls around TableIcon and
CodeIcon to use type="button" elements, moving each icon’s click handler onto
its button. Set aria-pressed based on whether display matches the corresponding
visualization, while preserving the existing styling, labels, and
handleVisualizationTypeChange behavior.
- Around line 175-186: Update onDocMouseDown and onFocusOut to remove the Node
type assertions; first narrow e.target and e.relatedTarget with instanceof Node,
then call containerRef.current.contains only for confirmed Node values while
preserving the existing commit behavior.

In `@src/frontend/store/slices/shared/slice.ts`:
- Around line 380-405: Update the rename flow around the datatype rename action
to check pendingDatatypeRename before calling reconcileDatatypeText or
findAllReferencesToDataType, rejecting any concurrent rename while confirmation
is pending. Remove the later conditional-only guard, preserve the existing
rejection message, and add coverage for a zero-reference rename targeting the
pending rename’s newName.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ddcfee5-3b8a-4f09-9352-5e08708c8c05

📥 Commits

Reviewing files that changed from the base of the PR and between 10e70ff and 9096d24.

📒 Files selected for processing (7)
  • src/frontend/components/_features/[workspace]/data-type/index.tsx
  • src/frontend/components/_molecules/project-tree/index.tsx
  • src/frontend/store/__tests__/project-slice.test.ts
  • src/frontend/store/__tests__/shared-slice.test.ts
  • src/frontend/store/slices/project/slice.ts
  • src/frontend/store/slices/project/types.ts
  • src/frontend/store/slices/shared/slice.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/frontend/components/_molecules/project-tree/index.tsx
  • src/frontend/store/slices/project/types.ts
  • src/frontend/store/tests/project-slice.test.ts
  • src/frontend/store/tests/shared-slice.test.ts
  • src/frontend/store/slices/project/slice.ts

Comment thread src/frontend/store/slices/shared/slice.ts
@JoaoGSP
JoaoGSP merged commit f4238f0 into development Aug 7, 2026
19 checks passed
@JoaoGSP
JoaoGSP deleted the feature/DOPE-536-datatype-rename-propagation branch August 7, 2026 13:17
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