feat(visualization): redesign node context menu - #4492
Conversation
Migrate the node context menu from ui/nodeContextMenu (Material, CDK overlay, SCSS) to features/nodeContextMenu following the new feature architecture: standalone OnPush components with signals, DaisyUI templates, ngrx confined to stores/ and selectors/. - Header row shows the node name and copies its path without the leading root segment on click - New "Show in Explorer" action (map right-clicks only) expands the File Explorer, scrolls to the node, and briefly highlights it via the new ExplorerRevealService - rightClickedNodeData state gains an origin field to distinguish map and explorer right-clicks - Folder color row keeps the five marking colors, adds a clear button for custom colors, and reuses the inline color picker, which moved to features/shared with a new brush-trigger variant - Unflatten entry shows the flatten icon rotated 180 degrees Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThis PR redesigns the node context menu by migrating from Angular Material/CDK/SCSS in ChangesNode Context Menu Redesign
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
`@visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/markFolderRow.component.ts`:
- Around line 54-60: onCustomColorChange currently calls
this.markFolderStore.markFolder(nodePath, color) but does not emit the
folderMarked event like the other handlers; update onCustomColorChange (in
markFolderRow.component.ts) to emit the same folderMarked event after
successfully marking the folder (e.g., call the component's folderMarked emitter
or emitFolderMarked helper with the nodePath and/or color) so consumers receive
a consistent folderMarked notification.
In
`@visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.ts`:
- Around line 104-115: Wrap the navigator.clipboard.writeText call in copyPath
in a try/catch so clipboard write rejections are handled; only call
this.wasPathCopied.set(true) and start/clear this.pathCopiedTimeout on
successful write, and in the catch block avoid changing the copied state and log
or surface the error (e.g., via console.error or existing logger). Ensure you
still guard for a missing node via menuNode() and keep using
pathWithoutRootSegment(node) and PATH_COPIED_FEEDBACK_DURATION_MS as before.
🪄 Autofix (Beta)
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: defaults
Review profile: CHILL
Plan: Pro
Run ID: fa056f0f-411f-48eb-a9d6-32b2179fc59f
⛔ Files ignored due to path filters (4)
plans/context-menu/redesign-context-menu.pngis excluded by!**/*.pngplans/context-menu/verify-clear-custom-color.pngis excluded by!**/*.pngplans/context-menu/verify-menu-from-explorer.pngis excluded by!**/*.pngplans/context-menu/verify-show-in-explorer-reveal.pngis excluded by!**/*.png
📒 Files selected for processing (71)
plans/context-menu/redesign-context-menu.mdvisualization/CHANGELOG.mdvisualization/app/app.config.tsvisualization/app/codeCharta/codeCharta.component.htmlvisualization/app/codeCharta/codeCharta.component.tsvisualization/app/codeCharta/codeCharta.model.tsvisualization/app/codeCharta/features/metricsBar/components/colorSettingsPopover/colorBandRow.component.tsvisualization/app/codeCharta/features/metricsBar/components/colorSettingsPopover/folderOverrideRow.component.tsvisualization/app/codeCharta/features/metricsBar/components/colorSettingsPopover/inlineColorPicker.component.htmlvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/contextMenuItem.component.htmlvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/contextMenuItem.component.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/markFolderRow.component.htmlvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/markFolderRow.component.spec.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/markFolderRow.component.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.htmlvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.spec.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.e2e.tsvisualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.po.tsvisualization/app/codeCharta/features/nodeContextMenu/facade.tsvisualization/app/codeCharta/features/nodeContextMenu/selectors/markFolderItems.selector.spec.tsvisualization/app/codeCharta/features/nodeContextMenu/selectors/markFolderItems.selector.tsvisualization/app/codeCharta/features/nodeContextMenu/stores/contextMenuBlacklist.store.tsvisualization/app/codeCharta/features/nodeContextMenu/stores/focusedNode.store.tsvisualization/app/codeCharta/features/nodeContextMenu/stores/markFolder.store.tsvisualization/app/codeCharta/features/nodeContextMenu/stores/rightClickedNode.store.tsvisualization/app/codeCharta/features/shared/components/inlineColorPicker/inlineColorPicker.component.htmlvisualization/app/codeCharta/features/shared/components/inlineColorPicker/inlineColorPicker.component.spec.tsvisualization/app/codeCharta/features/shared/components/inlineColorPicker/inlineColorPicker.component.tsvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.htmlvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.spec.tsvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.tsvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.e2e.tsvisualization/app/codeCharta/features/sidebarExplorer/facade.tsvisualization/app/codeCharta/features/sidebarExplorer/services/explorerCollapse.service.tsvisualization/app/codeCharta/features/sidebarExplorer/services/explorerReveal.service.spec.tsvisualization/app/codeCharta/features/sidebarExplorer/services/explorerReveal.service.tsvisualization/app/codeCharta/features/sidebarExplorer/stores/appStatus.store.spec.tsvisualization/app/codeCharta/state/effects/openNodeContextMenu/openNodeContextMenu.effect.spec.tsvisualization/app/codeCharta/state/effects/openNodeContextMenu/openNodeContextMenu.effect.tsvisualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.spec.tsvisualization/app/codeCharta/ui/codeMap/codeMap.mouseEvent.service.tsvisualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.tsvisualization/app/codeCharta/ui/nodeContextMenu/excludeButton/excludeButton.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/excludeButton/excludeButton.component.tsvisualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.tsvisualization/app/codeCharta/ui/nodeContextMenu/focusButtons/focusButtons.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/focusButtons/focusButtons.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/focusButtons/isNodeFocused.pipe.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/focusButtons/isNodeFocused.pipe.tsvisualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.tsvisualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.scssvisualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.tsvisualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.service.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.service.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuButton.component.scssvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.htmlvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.scssvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.tsvisualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts
💤 Files with no reviewable changes (33)
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.scss
- visualization/app/codeCharta/ui/nodeContextMenu/excludeButton/excludeButton.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.ts
- visualization/app/codeCharta/ui/nodeContextMenu/focusButtons/isNodeFocused.pipe.ts
- visualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/excludeButton/excludeButton.component.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.service.spec.ts
- visualization/app/codeCharta/features/metricsBar/components/colorSettingsPopover/inlineColorPicker.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/focusButtons/isNodeFocused.pipe.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenu.service.ts
- visualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/flattenButtons/flattenButtons.component.ts
- visualization/app/codeCharta/ui/nodeContextMenu/focusButtons/focusButtons.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.ts
- visualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/selectors/markFolderItems.selector.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.scss
- visualization/app/codeCharta/ui/nodeContextMenu/focusButtons/focusButtons.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuButton.component.scss
- visualization/app/codeCharta/state/effects/openNodeContextMenu/openNodeContextMenu.effect.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/copyButton/copyPathButton.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.ts
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/nodeContextMenuCard.component.ts
- visualization/app/app.config.ts
- visualization/app/codeCharta/state/effects/openNodeContextMenu/openNodeContextMenu.effect.ts
- visualization/app/codeCharta/ui/nodeContextMenu/markFolderRow/markFolderRow.component.html
- visualization/app/codeCharta/ui/nodeContextMenu/nodeContextMenuCard/lastPartOfNodePath.pipe.spec.ts
- visualization/app/codeCharta/ui/nodeContextMenu/highlightButtons/highlightButtons.component.html
| onCustomColorChange(color: string) { | ||
| const nodePath = this.nodePath() | ||
| if (!nodePath) { | ||
| return | ||
| } | ||
| this.markFolderStore.markFolder(nodePath, color) | ||
| } |
There was a problem hiding this comment.
Emit folderMarked after custom color selection for consistent action flow.
onCustomColorChange marks the folder but does not emit folderMarked, unlike clear/preset handlers. This creates inconsistent behavior for consumers relying on that event.
Suggested fix
onCustomColorChange(color: string) {
const nodePath = this.nodePath()
if (!nodePath) {
return
}
this.markFolderStore.markFolder(nodePath, color)
+ this.folderMarked.emit()
}🤖 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
`@visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/markFolderRow.component.ts`
around lines 54 - 60, onCustomColorChange currently calls
this.markFolderStore.markFolder(nodePath, color) but does not emit the
folderMarked event like the other handlers; update onCustomColorChange (in
markFolderRow.component.ts) to emit the same folderMarked event after
successfully marking the folder (e.g., call the component's folderMarked emitter
or emitFolderMarked helper with the nodePath and/or color) so consumers receive
a consistent folderMarked notification.
| async copyPath() { | ||
| const node = this.menuNode() | ||
| if (!node) { | ||
| return | ||
| } | ||
| await navigator.clipboard.writeText(this.pathWithoutRootSegment(node)) | ||
| this.wasPathCopied.set(true) | ||
| if (this.pathCopiedTimeout) { | ||
| clearTimeout(this.pathCopiedTimeout) | ||
| } | ||
| this.pathCopiedTimeout = setTimeout(() => this.wasPathCopied.set(false), PATH_COPIED_FEEDBACK_DURATION_MS) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.ts"
echo "== file = $FILE"
ls -la "$FILE" || true
echo
echo "== lines 70-160"
nl -ba "$FILE" | sed -n '70,160p'
echo
echo "== search for copyPath and clipboard usage"
rg -n "copyPath|clipboard\.writeText|pathCopiedTimeout|PATH_COPIED_FEEDBACK_DURATION_MS|wasPathCopied" "$FILE"
echo
echo "== search project for wasPathCopied / pathCopiedTimeout handling"
rg -n "wasPathCopied|pathCopiedTimeout" visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu -SRepository: MaibornWolff/codecharta
Length of output: 425
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.ts"
echo "== lines 70-160 (with line numbers)"
cat -n "$FILE" | sed -n '70,160p'
echo
echo "== copyPath + clipboard usage"
rg -n "async copyPath|navigator\.clipboard\.writeText|pathWithoutRootSegment|wasPathCopied|pathCopiedTimeout|PATH_COPIED_FEEDBACK_DURATION_MS" "$FILE"
echo
echo "== project-wide handling of wasPathCopied/pathCopiedTimeout"
rg -n "wasPathCopied|pathCopiedTimeout" visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu -SRepository: MaibornWolff/codecharta
Length of output: 5585
🏁 Script executed:
#!/bin/bash
set -euo pipefail
BASE="visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu"
echo "== search for copyPath call sites in component folder"
rg -n "copyPath\(" "$BASE" -S
echo
echo "== search for navigator.clipboard usage in repo (quick scope)"
rg -n "navigator\.clipboard\.writeText|navigator\.clipboard" visualization/app -SRepository: MaibornWolff/codecharta
Length of output: 1222
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== clipboardWriter.ts"
cat -n visualization/app/codeCharta/util/clipboard/clipboardWriter.ts
echo
echo "== clipboardWriter.spec.ts"
cat -n visualization/app/codeCharta/util/clipboard/clipBoardWriter.spec.ts | sed -n '1,120p'
echo
echo "== inspectorHeader.component.ts (clipboard usage)"
cat -n visualization/app/codeCharta/features/sidebarInspector/components/inspectorHeader/inspectorHeader.component.ts | sed -n '1,120p'
echo
echo "== nodeContextMenu.component.html (click handler)"
cat -n visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.html | sed -n '1,80p'Repository: MaibornWolff/codecharta
Length of output: 9558
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "checkWriteToClipboardAllowed|clipboardWriter|setToClipboard|try\s*\{[^}]*clipboard|catch\s*\([^)]*\)[^{]*clipboard|navigator\.clipboard" visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu -S
echo "----"
rg -n "checkWriteToClipboardAllowed|setToClipboard" visualization/app/codeCharta -SRepository: MaibornWolff/codecharta
Length of output: 3046
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="visualization/app/codeCharta/features/viewCubeToolbox/services/screenshot.service.ts"
echo "== screenshot.service.ts"
cat -n "$FILE" | sed -n '1,220p'
echo
echo "== search for try/catch around clipboard in repo"
rg -n "clipboard\.writeText|clipboardWriter|setToClipboard|write\(" visualization/app/codeCharta -S | head -n 50Repository: MaibornWolff/codecharta
Length of output: 11408
🌐 Web query:
Angular template event binding (click)="asyncMethod()" unhandled promise rejection handling behavior
💡 Result:
In Angular, if you bind an event to an async method in a template—such as (click)="asyncMethod"—the behavior regarding unhandled promise rejections depends heavily on your application's use of Zone.js and your global error configuration [1][2][3]. Angular's built-in ErrorHandler is primarily designed to catch errors that occur synchronously during the framework's execution (e.g., component lifecycle hooks, template expression evaluation) [1][2][3]. Because asynchronous operations (like those inside an async method) often resolve or reject outside the framework's direct control, they are not automatically intercepted by the standard ErrorHandler [1][2]. Key behaviors and handling strategies: 1. Zone.js Environment: When using Zone.js, it monkey-patches asynchronous browser APIs [4][3]. Historically, this provided a "catch-all" that could intercept unhandled promise rejections and forward them to the global ErrorHandler [3]. However, this mechanism is not foolproof and can be brittle; relying on it for critical error handling is discouraged [1][2]. 2. Zoneless Environment / Modern Angular: In modern Angular applications, particularly those running in a "zoneless" configuration, the framework does not implicitly intercept asynchronous errors [3]. The responsibility for handling these errors lies with the developer [2]. 3. Recommended Solution: To ensure unhandled promise rejections are consistently captured and forwarded to your ErrorHandler, you should use the provideBrowserGlobalErrorListeners() provider [2][5][3]. This provider attaches listeners to the browser's global unhandledrejection and error events, ensuring that any unhandled asynchronous errors are forwarded to your application's central ErrorHandler [2][5]. 4. Implementation Best Practices: - Use try/catch blocks locally within your async methods to handle expected failures gracefully, rather than relying on global catchers [2]. - If a promise fails and you want to prevent global error handling (e.g., to display a custom UI state instead), ensure you handle the error locally and avoid re-throwing it [6][7]. - For applications using the AsyncPipe, errors are handled at the stream level [7]. You can use the catchError operator in your observable streams to catch and transform errors into a safe state (e.g., a default value or an error message) for display in the template [6][7]. In summary, Angular does not automatically bridge all promise rejections in event bindings to the ErrorHandler [1][2]. To maintain robust error reporting, explicitly configure global error listeners and manage errors locally within your asynchronous code [2][3].
Citations:
- 1: ErrorHandler don't works with async function angular/angular#57106
- 2: https://github.com/angular/angular/blob/0aaadafc/adev/src/content/best-practices/error-handling.md
- 3: https://medium.com/@monsieur_ricky/going-zoneless-why-your-angular-errorhandler-went-silent-and-how-to-fix-it-eb8edd038a2e
- 4: zone.js promises returning Unhandled Promise Rejection error even with catch blocks angular/angular#51328
- 5: https://github.com/angular/angular/blob/main/packages/core/src/error_handler.ts
- 6: https://stackoverflow.com/questions/69424533/is-there-a-way-to-deal-with-error-handling-in-a-async-pipe-in-such-a-way-that-my
- 7: https://modernangular.com/articles/handling-errors-reactively-with-async-pipe
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "provideBrowserGlobalErrorListeners|unhandledrejection|unhandledRejection|window\.onunhandledrejection|addEventListener\(\"unhandledrejection\"|zoneless|provideZoneChangeDetection|withZone|bootstrapApplication" visualization/app -SRepository: MaibornWolff/codecharta
Length of output: 402
🏁 Script executed:
#!/bin/bash
set -euo pipefail
MAIN="visualization/app/main.ts"
echo "== main.ts"
cat -n "$MAIN" | sed -n '1,200p'
echo
echo "== find appConfig definition"
rg -n "appConfig" visualization/app -S
echo
echo "== print the file where appConfig is defined (search result first hit)"
APP_CONFIG_FILE=$(rg -n "const appConfig|export const appConfig|appConfig\s*=" visualization/app -S --files-with-matches | head -n 1 || true)
echo "appConfig file: $APP_CONFIG_FILE"
if [ -n "${APP_CONFIG_FILE:-}" ]; then
cat -n "$APP_CONFIG_FILE" | sed -n '1,240p'
fiRepository: MaibornWolff/codecharta
Length of output: 5394
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== search for ErrorHandler providers / custom implementations"
rg -n "ErrorHandler|error-handler|provide: ErrorHandler|provideErrorHandler|Uncaught|unhandledrejection|onunhandledrejection" visualization/app -S
echo
echo "== search for global error handling in app/codeCharta"
rg -n "unhandledrejection|unhandledRejection|ErrorHandler" visualization/app/codeCharta -SRepository: MaibornWolff/codecharta
Length of output: 129
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "ErrorHandler|provideErrorHandler|error-handler|unhandledrejection|unhandledRejection|onunhandledrejection" . -S || true
echo "----"
rg -n "zone\.js|zone\.js" . -S || true
echo "----"
rg -n "window\.addEventListener\(\s*['\"]unhandledrejection['\"]|addEventListener\(\s*['\"]unhandledrejection['\"]" . -S || trueRepository: MaibornWolff/codecharta
Length of output: 50382
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.ts"
cat -n "$FILE" | sed -n '1,120p'Repository: MaibornWolff/codecharta
Length of output: 6477
Handle clipboard write failures in copyPath
copyPath awaits navigator.clipboard.writeText(...) without catching rejections; clipboard permission/security-context failures can reject and leave the UI state inconsistent / surface an unhandled async error.
Suggested fix
async copyPath() {
const node = this.menuNode()
if (!node) {
return
}
- await navigator.clipboard.writeText(this.pathWithoutRootSegment(node))
- this.wasPathCopied.set(true)
- if (this.pathCopiedTimeout) {
- clearTimeout(this.pathCopiedTimeout)
- }
- this.pathCopiedTimeout = setTimeout(() => this.wasPathCopied.set(false), PATH_COPIED_FEEDBACK_DURATION_MS)
+ try {
+ await navigator.clipboard.writeText(this.pathWithoutRootSegment(node))
+ this.wasPathCopied.set(true)
+ if (this.pathCopiedTimeout) {
+ clearTimeout(this.pathCopiedTimeout)
+ }
+ this.pathCopiedTimeout = setTimeout(() => this.wasPathCopied.set(false), PATH_COPIED_FEEDBACK_DURATION_MS)
+ } catch {
+ this.wasPathCopied.set(false)
+ }
}🤖 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
`@visualization/app/codeCharta/features/nodeContextMenu/components/nodeContextMenu/nodeContextMenu.component.ts`
around lines 104 - 115, Wrap the navigator.clipboard.writeText call in copyPath
in a try/catch so clipboard write rejections are handled; only call
this.wasPathCopied.set(true) and start/clear this.pathCopiedTimeout on
successful write, and in the catch block avoid changing the copied state and log
or surface the error (e.g., via console.error or existing logger). Ensure you
still guard for a missing node via menuNode() and keep using
pathWithoutRootSegment(node) and PATH_COPIED_FEEDBACK_DURATION_MS as before.
|



Migrate the node context menu from ui/nodeContextMenu (Material, CDK overlay, SCSS) to features/nodeContextMenu following the new feature architecture: standalone OnPush components with signals, DaisyUI templates, ngrx confined to stores/ and selectors/.
{Meaningful title}
Please read the CONTRIBUTING.md before opening a PR.
Closes: #
Description
Descriptive pull request text, answering:
Definition of Done
A PR is only ready for merge once all the following acceptance criteria are fulfilled:
Screenshots or gifs
Summary by CodeRabbit
New Features
Changed