Skip to content

[NAE-2454] View Configuration 2.0#340

Open
Retoocs wants to merge 18 commits into
release/6.5.0from
NAE-2454
Open

[NAE-2454] View Configuration 2.0#340
Retoocs wants to merge 18 commits into
release/6.5.0from
NAE-2454

Conversation

@Retoocs

@Retoocs Retoocs commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Description

New features

  • Introduced edit button for item in menu. Button opens settings transition in dialog
  • Introduced create item button in menu. Button opens initialize transition in dialog
  • Implemented default sorting for case view & task view defined in menu item
  • Introduced task-view dialog component (previous task-view component renamed to single-task-view component)
  • Added reloadMenu in FrontActionRegistry

Improvements

  • added params to CreateCaseRequestBody

Fixes

  • Fixed race condition between loading user and loading menu
  • Fixed memory leaks
  • Fixed dialog-task-responsive class' height problem (no scrollbar)

Implements NAE-2454

Dependencies

No new dependencies were introduced

Third party dependencies

No new dependencies were introduced

Blocking Pull requests

There are no dependencies on other PR

How Has Been This Tested?

Manually and by unit tests

Test Configuration

Name Tested on
OS Ubuntu 24.04.1 LTS
Runtime Node 23.6.1
Dependency Manager NPM 11.0.0
Framework version Angular 19.2.2
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @...
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • New Features
    • Added menu edit mode in the navigation drawer with create/edit actions for menu items and menu reload.
    • Added a Single Task View dialog and updated task dialogs to use search-based filters.
    • Enabled dynamic default sorting in case and task views.
  • Bug Fixes
    • Improved navigation and pagination robustness with better subscription cleanup and empty-request handling.
    • Added snackbar error feedback when menu-item creation fails; refined responsive dialog scrolling and layout.
  • Documentation
    • Updated German, English, and Slovak translations for the new edit-mode controls and error message.

Retoocs added 11 commits June 22, 2026 14:26
- add params to create-case-request-body.ts
- introduce reload menu frontend action
- introduce edit mode in double drawer menu
- leave some todos
- fix some memory leaks
- introduce task view dialog
- rename existing task dialog to single task dialog
- rework task dialog content filtering
- fix edit btn position
- rework loading of folders
- fix dialog overflow
- improve memory usage
- fix user and double drawer race condition
- implement handling of dynamic default sorting in menu item views
- fix memory leak in case-view-service.ts
- add docs
@Retoocs Retoocs self-assigned this Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds navigation menu edit mode, shared meta-header factories, dynamic default sort wiring for case and task views, and a searchBody-based task dialog flow with a new single-task dialog component.

Changes

Navigation Menu Edit Mode and Folder Detection

Layer / File(s) Summary
Navigation constants and folder/sort fields
projects/netgrif-components-core/src/lib/navigation/model/group-navigation-constants.ts, projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/util/double-drawer-utils.ts, projects/netgrif-components-core/src/assets/i18n/*.json
Replaces ITEM_FIELD_ID_HAS_CHILDREN with ITEM_FIELD_ID_IS_FOLDER; adds case/task header sort mode enum members; adds edit-mode and menu-item translation keys.
Double-drawer navigation service flow
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts
Gates node tracking by user, converts several flows to one-shot subscriptions, switches folder detection to isFolder, and short-circuits empty case-id queries.
Edit mode methods and dialog wiring
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts, projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts, projects/netgrif-components-core/src/lib/resources/interface/create-case-request-body.ts
Adds edit-mode state, menu edit/create actions, role checks, cleanup for tracked subscriptions, and a params field for case creation.
Navigation component wiring, template, and reload action
projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts, projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html, projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.scss, projects/netgrif-components/src/lib/navigation/navigation.module.ts, projects/netgrif-components/src/lib/navigation/model/reload-menu.ts
Wires new services through the component, updates the edit-mode UI, adds supporting styles, and registers the reloadMenu front action.

Header Meta-Field Factory and Dynamic Default Sort

Layer / File(s) Summary
Header meta-fields factory extraction
projects/netgrif-components-core/src/lib/header/models/meta-fields-factory.ts, projects/netgrif-components-core/src/lib/header/case-header/case-header.service.ts, projects/netgrif-components-core/src/lib/header/task-header/task-header.service.ts, projects/netgrif-components-core/src/lib/header/workflow-header/workflow-header.service.ts, projects/netgrif-components-core/src/lib/header/models/public-api.ts, projects/netgrif-components-core/src/lib/header/public-api.ts, projects/netgrif-components-core/src/lib/header/header-modes/sort-mode/abstract-sort-mode.component.ts, projects/netgrif-components-core/src/lib/header/case-header/case-header.service.spec.ts, projects/netgrif-components-core/src/lib/header/header-modes/edit-mode/abstract-edit-mode.component.spec.ts, projects/netgrif-components-core/src/lib/panel/case-panel/abstract-case-panel.component.ts, projects/netgrif-components-core/src/lib/panel/case-panel/abstract-case-panel.component.spec.ts, projects/netgrif-components-core/src/lib/search/header-search-service/header-search.service.ts
Creates shared meta-header factory functions, refactors header services to use them, updates the header public API, and corrects CaseMetaField import paths.
Dynamic default sort token and builders
projects/netgrif-components-core/src/lib/view/case-view/models/dynamic-default-sort-token.ts, projects/netgrif-components-core/src/lib/view/public-api.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/model/factory-methods.ts
Adds the dynamic default sort injection token and builders that derive sort descriptions from navigation item data.
Case view dynamic sort integration
projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts
CaseViewService now tracks its active-filter subscription, injects optional dynamic sort metadata, and defers page requests through a conditional helper.
Task view dynamic sort integration
projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts
TaskViewService applies the same conditional dynamic-sort page-request pattern to task view loading.
View provider wiring and test fixtures
projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-case-view/default-simple-case-view.component.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-case-view/default-simple-case-view.component.spec.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-task-view/default-simple-task-view.component.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-task-view/default-simple-task-view.component.spec.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tab-view/default-tab-view.component.spec.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-case-view/default-tabbed-case-view.component.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-case-view/default-tabbed-case-view.component.spec.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-task-view/default-tabbed-task-view.component.ts, projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-task-view/default-tabbed-task-view.component.spec.ts
Registers dynamic sort providers in simple and tabbed case/task views and updates fixtures with the new sort-mode fields.

Task and Single-Task Dialog Rework

Layer / File(s) Summary
Dialog data contracts
projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts, projects/netgrif-components-core/src/lib/side-menu/content-components/task-view/model/task-view-injection-data.ts, projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts, projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts, projects/netgrif-components-core/src/lib/dialog/public-api.ts, projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts, projects/netgrif-components-core/src/lib/resources/interface/create-case-request-body.ts
Introduces task-view dialog injection data, removes the old task-view injection model field, adds the single-task view injection token, and extends create-case request bodies with params.
Dialog action wiring
projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts
openTaskDialog now passes searchBody into the task dialog payload and uses the updated dialog injection type.
Single task dialog component
projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts, projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.html, projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.scss, projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.spec.ts, projects/netgrif-components/src/lib/dialog/dialog.module.ts, projects/netgrif-components/src/lib/dialog/public-api.ts, projects/netgrif-components/src/lib/dialog/dialog.theme.scss
Adds the single-task dialog component, filter factory, template, stylesheet, tests, and module/public API wiring.
Task view dialog pagination flow
projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts, projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.html, projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.spec.ts, projects/netgrif-components/src/lib/header/header.component.ts
TaskViewDialogComponent now uses searchBody, requires autoCloseOnEvent for success handling, and renders task-list pagination.

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

Possibly related PRs

  • netgrif/components#289: Both PRs modify AbstractNavigationDoubleDrawerComponent and related navigation lifecycle logic.
  • netgrif/components#294: Both PRs touch subscription teardown and lifecycle cleanup in the navigation double-drawer component.
  • netgrif/components#333: Both PRs touch the case meta-header construction by extending CaseHeaderService/case META fields with shared header columns.

Suggested labels: improvement, new feature, breaking change, Large

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is too generic and does not clearly describe the main changes in the PR. Use a concise title that names the primary change, such as menu item edit/create actions and dynamic default sorting support.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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.

@Retoocs Retoocs marked this pull request as ready for review July 6, 2026 10:05
@Retoocs

Retoocs commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review this PR

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

@Retoocs I'll review this PR now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (1)
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts (1)

158-168: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Unguarded rightItemsSub.unsubscribe() will throw if canApplyAutoSelect() is false.

rightItemsSub is only assigned inside the if (this.canApplyAutoSelect()) branch in ngOnInit (Line 143). Whenever that condition is false (the common case for any drawer instance not matching the configured auto-select URL), rightItemsSub stays undefined. ngOnDestroy then unconditionally calls this.rightItemsSub.unsubscribe(), throwing a TypeError on every such component's destruction. _breakpointSubscription already uses optional chaining (Line 159) for the same reason — the new fields should follow suit.

🐛 Proposed fix
     public ngOnDestroy(): void {
         this._breakpointSubscription?.unsubscribe();
         this.loggedOut.complete();
         this.stateChanged.complete();
         this.itemClicked.complete();
         this.resized.complete();
         this.itemLoaded.complete();
-        this.itemClickedSub.unsubscribe();
-        this.itemLoadedSub.unsubscribe();
-        this.rightItemsSub.unsubscribe();
+        this.itemClickedSub?.unsubscribe();
+        this.itemLoadedSub?.unsubscribe();
+        this.rightItemsSub?.unsubscribe();
     }

Also applies to: 142-149, 95-97

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
around lines 158 - 168, The ngOnDestroy cleanup in
abstract-navigation-double-drawer currently unconditionally calls
rightItemsSub.unsubscribe(), but rightItemsSub is only initialized in the
canApplyAutoSelect() branch of ngOnInit and may be undefined. Update the
teardown logic in ngOnDestroy to guard rightItemsSub the same way
_breakpointSubscription is guarded, and keep the cleanup consistent with the
other subscriptions like itemClickedSub and itemLoadedSub so destruction is safe
when auto-select is disabled.
🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`:
- Around line 373-375: The case title in the navigation double drawer flow is
still hardcoded in English, bypassing the new translation support. Update the
menu-item creation logic in abstract-navigation-double-drawer.ts where the
object is built with netId, title, and params so that the title comes from the
same i18n/localization source used for the surrounding feature instead of the
literal “New menu item”. Keep the change consistent with the translated keys
already introduced for createMenuItemBtn and editMenuItem, and use the existing
menu-item creation path to ensure non-English users see a localized case title.
- Around line 369-401: The createMenuItem() method in
AbstractNavigationDoubleDrawer is using the deprecated multi-argument
subscribe(next, error) form. Update the observable subscription on the
getNet('menu_item') pipeline to use a single observer object with next and error
handlers instead of separate callback arguments, while preserving the existing
success path, _log.error reporting, and snack bar behavior.

In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`:
- Line 150: The newly touched RxJS subscriptions in
double-drawer-navigation.service.ts still use the deprecated multi-argument
subscribe(next, error) overload; update each affected subscription in the
double-drawer navigation flow to use the partial-observer form instead. Focus on
the subscribe calls in the service methods around
getNodeByPath/resolveParentPath and the other three matching sites in this file,
and keep the existing pipe(take(1)) behavior unchanged while moving next and
error handlers into a single observer object.

In
`@projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts`:
- Around line 124-131: The dynamic-sort subscribe/update/emit logic is
duplicated in this case-view paging path and also in nextPagePagination and
TaskViewService, so extract it into a shared helper on the service (for example,
applyDynamicSortThen(cb)) and call that from the existing branch. Keep the
behavior the same: when _dynamicDefaultSort$ exists and
_lastHeaderSearchState.fieldIdentifier is empty, subscribe to the sort change,
update _lastHeaderSearchState, and then dispatch the PageLoadRequestContext;
otherwise dispatch immediately.

In `@projects/netgrif-components/src/lib/dialog/dialog.theme.scss`:
- Around line 24-30: The dialog theme rule is using mat-mdc-dialog-container as
a type selector, so it never matches the Angular Material container class.
Update the selector in dialog.theme.scss to target the actual class with a
leading dot, matching the existing .mat-mdc-dialog-container usage elsewhere in
the file, so the overflow-y:auto styling applies to the dialog container as
intended.

In
`@projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.scss`:
- Around line 1-77: Remove the unused copy-pasted styles from
single-task-view-dialog.component.scss and keep only the selectors actually
referenced by SingleTaskViewDialogComponent’s template, namely
task-view-container, virtual-scroll-padding, and task-panel-padding-mini. Delete
the leftover dialog-specific classes such as task-tab-background, search-panel,
content-margin, search-width, full-height, public-button, public-button-padding,
single-page-task, logoimg, upper-card, upper-card-title, upper-divider, and
footer-custom so the stylesheet only contains relevant rules.

In
`@projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html`:
- Around line 182-191: Both clickable row <div>s in
navigation-double-drawer.component.html are mouse-only interactive elements and
need keyboard support. Update the item row using onItemClick(item) and the
createMenuItem() row to behave like accessible controls by adding appropriate
keyboard activation handling and focus semantics, and keep the existing click
behavior in sync with those handlers. Use the existing templates around
onItemClick, createMenuItem, and the menu-item rows to apply the same accessible
pattern to both segments.

---

Outside diff comments:
In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`:
- Around line 158-168: The ngOnDestroy cleanup in
abstract-navigation-double-drawer currently unconditionally calls
rightItemsSub.unsubscribe(), but rightItemsSub is only initialized in the
canApplyAutoSelect() branch of ngOnInit and may be undefined. Update the
teardown logic in ngOnDestroy to guard rightItemsSub the same way
_breakpointSubscription is guarded, and keep the cleanup consistent with the
other subscriptions like itemClickedSub and itemLoadedSub so destruction is safe
when auto-select is disabled.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9304774-99b3-4ef8-96de-92eb652ec0bf

📥 Commits

Reviewing files that changed from the base of the PR and between 6a78c83 and 6498061.

📒 Files selected for processing (48)
  • projects/netgrif-components-core/src/assets/i18n/de.json
  • projects/netgrif-components-core/src/assets/i18n/en.json
  • projects/netgrif-components-core/src/assets/i18n/sk.json
  • projects/netgrif-components-core/src/lib/header/case-header/case-header.service.ts
  • projects/netgrif-components-core/src/lib/header/header-modes/sort-mode/abstract-sort-mode.component.ts
  • projects/netgrif-components-core/src/lib/header/models/meta-fields-factory.ts
  • projects/netgrif-components-core/src/lib/header/models/public-api.ts
  • projects/netgrif-components-core/src/lib/header/task-header/task-header.service.ts
  • projects/netgrif-components-core/src/lib/header/workflow-header/workflow-header.service.ts
  • projects/netgrif-components-core/src/lib/navigation/model/group-navigation-constants.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/util/double-drawer-utils.ts
  • projects/netgrif-components-core/src/lib/resources/interface/create-case-request-body.ts
  • projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
  • projects/netgrif-components-core/src/lib/side-menu/content-components/task-view/model/task-view-injection-data.ts
  • projects/netgrif-components-core/src/lib/view/case-view/models/dynamic-default-sort-token.ts
  • projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts
  • projects/netgrif-components-core/src/lib/view/public-api.ts
  • projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts
  • projects/netgrif-components/src/lib/dialog/dialog.module.ts
  • projects/netgrif-components/src/lib/dialog/dialog.theme.scss
  • projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts
  • projects/netgrif-components/src/lib/dialog/public-api.ts
  • projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.html
  • projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.scss
  • projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.spec.ts
  • projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts
  • projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.html
  • projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.spec.ts
  • projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts
  • projects/netgrif-components/src/lib/header/header.component.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/model/factory-methods.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-case-view/default-simple-case-view.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-case-view/default-simple-case-view.component.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-task-view/default-simple-task-view.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/simple-views/default-simple-task-view/default-simple-task-view.component.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tab-view/default-tab-view.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-case-view/default-tabbed-case-view.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-case-view/default-tabbed-case-view.component.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-task-view/default-tabbed-task-view.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/tabbed/default-tabbed-task-view/default-tabbed-task-view.component.ts
  • projects/netgrif-components/src/lib/navigation/model/reload-menu.ts
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.scss
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts
  • projects/netgrif-components/src/lib/navigation/navigation.module.ts

Comment thread projects/netgrif-components/src/lib/dialog/dialog.theme.scss
Comment on lines +1 to +77
.task-tab-background{
height: 100%;
width: 100%;
overflow: auto;
background-color: transparent;
}
.search-panel{
margin-top: 8px;
}
.content-margin{
margin: 0 8px;
}
.task-panel-padding-mini{
padding-bottom: 8px;
padding-top: 8px;
}

.search-width {
width: 100%;
}

.full-height {
height: 100%;
}
.public-button {
height: 36px;
width: 200px;
}

.public-button-padding {
padding: 16px;
flex-direction: column;
display: flex;
align-items: center;
}

.single-page-task {
width: 85% !important;
padding-bottom: 25px;
}

.logoimg {
height: 120px;
outline: none !important;
cursor: pointer;
}

.upper-card {
margin-bottom: 10px;
}

.upper-card-title {
display: flex;
align-items: center;
flex-direction: column;
}

.upper-divider {
border-top-width: 20px;
border-top-color: #023b7e;
border-radius: 4px;
margin-bottom: 10px;
}

.footer-custom {
border-radius: 4px;
margin-bottom: 10px;
}
.task-view-container {
height: calc(100% - 64px) !important;
padding-left: 8px !important;
padding-right: 8px !important;
margin: 0;
}
.virtual-scroll-padding {
padding-right: 4px;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused/copy-pasted CSS classes.

Only .task-view-container, .virtual-scroll-padding, and .task-panel-padding-mini are referenced in this component's template. The remaining classes (.task-tab-background, .search-panel, .content-margin, .search-width, .full-height, .public-button, .public-button-padding, .single-page-task, .logoimg, .upper-card, .upper-card-title, .upper-divider, .footer-custom) look like leftovers copied from another dialog and are dead weight here.

🤖 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
`@projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.scss`
around lines 1 - 77, Remove the unused copy-pasted styles from
single-task-view-dialog.component.scss and keep only the selectors actually
referenced by SingleTaskViewDialogComponent’s template, namely
task-view-container, virtual-scroll-padding, and task-panel-padding-mini. Delete
the leftover dialog-specific classes such as task-tab-background, search-panel,
content-margin, search-width, full-height, public-button, public-button-padding,
single-page-task, logoimg, upper-card, upper-card-title, upper-divider, and
footer-custom so the stylesheet only contains relevant rules.

@@ -0,0 +1,42 @@
import {HeaderColumn, HeaderColumnType} from "./header-column";
import {CaseMetaField} from "../case-header/case-menta-enum";

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.

rename file to meta please

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done


this._currentNodeSubscription = this._uriService.activeNode$.subscribe(node => {
this._currentNodeSubscription = this._userService.user$.pipe(
filter(user => !!user && user.id !== ''),

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.

We should create a method in userService for this, if isn't exists now, because it is used on more places and in some projects the property id is not used

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done, used existing isUserEmpty method

this.resolveUriForChildViews(childViewConfigPath, childView);
this.resolveHiddenMenuItemFromChildViews(childViewConfigPath, childView);
});
this._userSubscription = this._userService.user$.pipe(filter(user => !!user && user.id !== '')).subscribe(user => {

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.

shouldn't be here also take(1) instead of userSubscription ? if this method is called more times, only last subscription will be unsubscribed, and can create memory leaks on userChange. If the intension is to change entries on some userChange, then the subscription should be in constructor and some refresh mechanism should be applied

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done, used take(1)

return;
}
const _case = (outcome.outcome as CreateCaseEventOutcome).aCase;
const taskView = this._injector.get(NAE_TASK_VIEW_COMPONENT);

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.

we should directly inject this injectionToken into constructor and not use an injector like this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

data: {
autoCloseOnEvent: true,
searchBody: {
transitionId: "initialize",

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.

do we want show only initialize transition in dialog? or maybe also item_settings, which is next after initialize

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think showing only initialize trans is enough. Once you finish the task, the dialog closes. Then you can do something else on the page or by one click open settings dialog

import {SideMenuInjectionData} from "../../../models/side-menu-injection-data";
import {TaskSearchRequestBody} from "../../../../filter/models/task-search-request-body";

export interface TaskViewInjectionData extends SideMenuInjectionData {

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.

do we still support side menu ? or is this interface used also in dialogs? we should create interface only for dialogs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Currently I use the map from the interface to save attribute autoCloseOnEvent

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done, I introduced TaskViewDialogInjectionData, where the autoCloseOnEvent atrribute exists

if (!!this._dynamicDefaultSort$ && this._lastHeaderSearchState.fieldIdentifier === '') {
this._dynamicDefaultSort$.subscribe(sortChangeDesc => {
this._lastHeaderSearchState = sortChangeDesc;
this._nextPage$.next(new PageLoadRequestContext(this.activeFilter, Object.assign({}, this._pagination, {number: 0})));

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.

i think we want to push defalut value to nextPage before the nextPage pipe in column 94, or we? because now the pipe is executed twice, also with initial null value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

this._closeTaskTabOnNoTasks = bool;
});

if (!!this._dynamicDefaultSort$ && this._lastHeaderSearchState.fieldIdentifier === '') {

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.

same as in caseViewService, do we want to push this after the requestedPage pipe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done


public processTaskEvents(notification: TaskEventNotification): void {
if (!notification.success) {
if (!notification.success || !this._injectedData['autoCloseOnEvent']) {

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.

shouldnt be this added to interface?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

HotkeyModule.forRoot(),
UtilityModule
UtilityModule,
TranslateModule

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.

translateLibModule is already imported, and it exports TranslateModule, so we should prevent double importing ( as I see also TranslateLibModule is here twice)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

_redirectService: RedirectService,
_snackBarService: SnackBarService,
_dialog: MatDialog,
_injector: Injector,

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.

new properties in constructor should be at the most possible end of it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

return;
}
this._nextPage$.next(requestContext);
if (!!this._dynamicDefaultSort$ && this._lastHeaderSearchState.fieldIdentifier === '') {

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.

duplicate code as in constructor, create function for it and pipe(take(1))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

- resolve PR comments
@coderabbitai coderabbitai Bot added breaking change Fix or feature that would cause existing functionality doesn't work as expected improvement New feature or request labels Jul 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (7)
projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts (2)

23-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated filter-factory logic with taskViewFilterFactory.

singleTaskViewFilterFactory is nearly identical to taskViewFilterFactory in projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts (Lines 22-30) — same validation, same error message, same SimpleFilter.fromTaskQuery call. Consider extracting a shared factory helper to avoid drift between the two dialogs.

🤖 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
`@projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts`
around lines 23 - 32, The singleTaskViewFilterFactory logic is duplicated with
taskViewFilterFactory, including the same null check, error message, and
SimpleFilter.fromTaskQuery call. Extract the shared validation and filter
निर्माण into a common helper used by both singleTaskViewFilterFactory and
taskViewFilterFactory, so both dialogs reuse the same implementation and stay in
sync.

73-85: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

processTaskEvents ignores autoCloseOnEvent, unlike the sibling TaskViewDialogComponent.

this._injectedData is typed as TaskViewDialogInjectionData (which declares autoCloseOnEvent), but this method unconditionally closes on any successful FINISH/CANCEL event, never consulting that flag — whereas TaskViewDialogComponent.processTaskEvents requires _injectedData.autoCloseOnEvent to be truthy (task-view-dialog.component.ts, Line 73). If intentional (single-task dialogs should always auto-close), consider dropping the unused field from this component's contract or adding a short comment explaining the divergence to avoid future confusion.

🤖 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
`@projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts`
around lines 73 - 85, `processTaskEvents` currently closes the dialog on every
successful `FINISH`/`CANCEL` event without checking
`this._injectedData.autoCloseOnEvent`, unlike
`TaskViewDialogComponent.processTaskEvents`. Update
`SingleTaskViewDialogComponent.processTaskEvents` to either honor the
`autoCloseOnEvent` flag before calling `_dialogRef.close`, or if single-task
dialogs should always close, remove `autoCloseOnEvent` from the injected data
contract and document the intentional difference. Use `processTaskEvents`,
`_injectedData`, and `_dialogRef.close` to locate the behavior.
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts (3)

346-358: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

customItemsInitialized/hiddenCustomItemsInitialized are only set after the async user emission resolves.

The guard at the top of the method (if (!view || this.customItemsInitialized || ...) return;) is checked synchronously, but the flags themselves are only flipped inside the user$ subscribe callback. If initializeCustomViewsOfView is invoked more than once before the first non-empty user emits (e.g. two view-init calls in quick succession), both calls will pass the guard and each will push duplicate entries into _childCustomViews/_hiddenCustomItems$ once the user resolves.

🔧 Proposed fix
     public initializeCustomViewsOfView(view: View, viewConfigPath: string): void {
         if (!view || this.customItemsInitialized || this.hiddenCustomItemsInitialized) return;
+        this.customItemsInitialized = true;
+        this.hiddenCustomItemsInitialized = true;

         this._userService.user$.pipe(filter(user => !this._userService.isUserEmpty(user)), take(1)).subscribe(user => {
             Object.entries(view.children).forEach(([key, childView]) => {
                 const childViewConfigPath: string = viewConfigPath + '/' + key;
                 this.resolveUriForChildViews(childViewConfigPath, childView);
                 this.resolveHiddenMenuItemFromChildViews(childViewConfigPath, childView);
             });

             this.resolveCustomViewsInRightSide();
             this.resolveCustomViewsInLeftSide();
-
-            this.customItemsInitialized = true;
-            this.hiddenCustomItemsInitialized = true;
         });
     }
🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`
around lines 346 - 358, The initialization guard in initializeCustomViewsOfView
is vulnerable to duplicate work because customItemsInitialized and
hiddenCustomItemsInitialized are only set inside the async user$.subscribe
callback. Mark these flags before subscribing, or add a separate “initialization
started” guard in the same method, so repeated calls cannot enqueue duplicate
child/custom view resolution while waiting for the first non-empty user
emission.

379-422: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

loadLeftSide and loadRightSide are near-duplicates.

Both methods now share almost identical fetch → derive-child-ids → fetch-cases → sort/emit → error-handling structure, differing mainly in pagination splitting and item mapping. The just-found missed observer-object fix in loadRightSide is direct evidence that duplicated logic drifts out of sync. Consider extracting the common getItemCaseByNodePath(...) -> childCases$ resolution into a shared helper parameterized by the divergent mapping/splitting behavior.

Also applies to: 424-470

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`
around lines 379 - 422, The `loadLeftSide` and `loadRightSide` flows are
duplicated and already drifting apart, so extract the shared
fetch/derive-child-ids/fetch-cases/error-handling logic into a common helper
used by both methods. Keep the method-specific differences in pagination
splitting and item mapping in small callbacks or parameters, and update
`loadLeftSide`/`loadRightSide` to delegate to that helper so future observer or
error-handling fixes only need to be made once.

136-169: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Serialize deferred navigation loading; don’t queue multiple waiters on _nodeLoading$

currentNode can be assigned again while a prior parent lookup is still in flight. Each assignment then registers another filter(!isActive).take(1) callback on the same LoadingEmitter, so one off() can trigger multiple loadNavigationItems(node) calls with different captured nodes. Replace this with a single-flight flow or cancel the previous deferred subscription before registering a new one.

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`
around lines 136 - 169, `set currentNode` in
`double-drawer-navigation.service.ts` can register multiple deferred callbacks
on `_nodeLoading$`, causing repeated `loadNavigationItems(node)` calls for stale
nodes when parent lookup is still pending. Update the `currentNode` flow to use
a single-flight/cancellable deferred load: before adding the
`filter(!isActive).take(1)` subscription, cancel any previous waiter or reuse
one pending subscription, and ensure only the latest `node` is loaded after
`_nodeLoading$.off()` in the `set currentNode` logic.
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts (2)

100-133: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

_injector: Injector appears unused after switching _taskView to constructor injection.

The past review comment asking to inject NAE_TASK_VIEW_COMPONENT directly rather than via Injector.get(...) was addressed (line 120 now uses @Inject), but the _injector: Injector parameter (line 119) and its Injector import (line 2) don't appear to be referenced anywhere else in this file. If nothing else needs it, it can be dropped.

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
around lines 100 - 133, The abstractNavigationDoubleDrawer constructor still
keeps an unused Injector dependency after switching to direct
NAE_TASK_VIEW_COMPONENT injection. Remove the _injector: Injector parameter from
AbstractNavigationDoubleDrawer and drop the Injector import if nothing else in
this file uses it; keep the existing `@Inject`(NAE_TASK_VIEW_COMPONENT) _taskView
injection as the source of the component.

96-98: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

rightItemsSub may be undefined when ngOnDestroy unsubscribes it unconditionally.

rightItemsSub is only assigned inside if (this.canApplyAutoSelect()) (lines 144-151). If that condition is false for a given component instance, rightItemsSub stays undefined, and ngOnDestroy (line 169) calling this.rightItemsSub.unsubscribe() without optional chaining will throw, potentially interrupting Angular's destroy lifecycle.

🔧 Proposed fix
-        this.itemClickedSub.unsubscribe();
-        this.itemLoadedSub.unsubscribe();
-        this.rightItemsSub.unsubscribe();
+        this.itemClickedSub?.unsubscribe();
+        this.itemLoadedSub?.unsubscribe();
+        this.rightItemsSub?.unsubscribe();

Also applies to: 144-151, 167-170

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
around lines 96 - 98, rightItemsSub can remain undefined when
canApplyAutoSelect() is false, but ngOnDestroy in AbstractNavigationDoubleDrawer
unsubscribes it unconditionally. Update the destruction logic to guard
rightItemsSub the same way as the other subscriptions (for example, using the
same optional cleanup pattern already used for itemClickedSub and
itemLoadedSub), and make sure the assignment in the auto-select block stays the
only place it is created.
♻️ Duplicate comments (4)
projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts (1)

3-6: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Consider making autoCloseOnEvent optional with a documented default.

autoCloseOnEvent is declared as a required boolean, but at least one caller (openTaskDialog in projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts) constructs this data via an as cast without ever setting it. Since as bypasses missing-property checks, this compiles but leaves autoCloseOnEvent undefined at runtime, silently changing dialog-close behavior (see comment on dialog-actions.ts). Making the field optional (autoCloseOnEvent?: boolean) and having consumers explicitly ?? false/?? true would surface the intent and prevent this class of bug.

🤖 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
`@projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts`
around lines 3 - 6, `TaskViewDialogInjectionData` currently պահանջs
`autoCloseOnEvent`, but `openTaskDialog` is already constructing it via an `as`
cast without setting that field, so make the property optional in the interface
and document the default behavior. Update the consumers that read
`TaskViewDialogInjectionData` to explicitly apply a fallback with `??` so the
intended close behavior is set in one place rather than relying on an undefined
value.
projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts (1)

72-75: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Auto-close guard is correct here, but depends on a caller that omits the flag.

The autoCloseOnEvent check is correctly implemented per the TaskViewDialogInjectionData contract, but projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts (openTaskDialog) never sets autoCloseOnEvent when opening this dialog, so it will always early-return and never auto-close for that call site. See the comment on dialog-actions.ts for the root-cause fix.

🤖 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
`@projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts`
around lines 72 - 75, The auto-close logic in processTaskEvents is fine, but
openTaskDialog in dialog-actions is not populating the autoCloseOnEvent field,
so this dialog always exits early. Update openTaskDialog to pass the
autoCloseOnEvent value into the TaskViewDialogInjectionData when creating the
dialog, matching the contract used by TaskViewDialogComponent and its
processTaskEvents guard.
projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts (1)

17-19: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Missing autoCloseOnEvent breaks task-dialog auto-close.

The injected data only sets searchBody; autoCloseOnEvent is omitted and the as TaskViewDialogInjectionData cast masks this at compile time. At runtime, TaskViewDialogComponent.processTaskEvents guards on !this._injectedData.autoCloseOnEvent (task-view-dialog.component.ts, Line 73), so with autoCloseOnEvent undefined this dialog will never auto-close on FINISH/CANCEL when opened through this openDialog action.

🐛 Proposed fix
             data: {
-                searchBody: { stringId: frontAction.args[0] }
+                searchBody: { stringId: frontAction.args[0] },
+                autoCloseOnEvent: true
             } as TaskViewDialogInjectionData,
🤖 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 `@projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts` around
lines 17 - 19, The `openDialog` action in `dialog-actions.ts` is constructing
`TaskViewDialogInjectionData` with only `searchBody`, so
`TaskViewDialogComponent.processTaskEvents` never sees `autoCloseOnEvent` and
the dialog cannot auto-close on task completion/cancel. Update the injected
`data` object to include `autoCloseOnEvent` with the appropriate value for this
action, and avoid relying on the `as TaskViewDialogInjectionData` cast to hide
the missing field. Use the `openDialog` flow and `TaskViewDialogInjectionData`
shape as the guide so the dialog behavior matches
`TaskViewDialogComponent.processTaskEvents`.
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts (1)

424-470: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Deprecated two-argument subscribe(next, error) reintroduced in loadRightSide's inner subscription.

Every other subscription in this diff (including the sibling loadLeftSide inner subscribe at line 401 and the outer subscribes at 385/427) was migrated to the { next, error } observer form, matching the fix from the earlier SonarCloud-flagged review. This one (line 443) was missed, reintroducing the same deprecated pattern in the same file.

♻️ Proposed fix
-                childCases$.pipe(take(1)).subscribe(result => {
-                    result = (result as Case[]).sort((a, b) => orderedChildCaseIds.indexOf(a.stringId) - orderedChildCaseIds.indexOf(b.stringId));
-                    if (result.length > RIGHT_SIDE_INIT_PAGE_SIZE) {
-                        const rawRightItems: Case[] = result.splice(0, RIGHT_SIDE_INIT_PAGE_SIZE);
-                        this._rightItems$.next(rawRightItems.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
-                        this._moreItems$.next(result.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
-                    } else {
-                        this._rightItems$.next(result.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
-                    }
-                    this.resolveCustomViewsInRightSide();
-                    this._rightLoading$.off();
-                    this.itemLoaded.emit({menu: 'right', items: this.rightItems});
-                }, error => {
-                    this._log.error(error);
-                    this._rightItems$.next([]);
-                    this._moreItems$.next([]);
-                    this.resolveCustomViewsInRightSide();
-                    this._rightLoading$.off();
-                });
+                childCases$.pipe(take(1)).subscribe({
+                    next: result => {
+                        result = (result as Case[]).sort((a, b) => orderedChildCaseIds.indexOf(a.stringId) - orderedChildCaseIds.indexOf(b.stringId));
+                        if (result.length > RIGHT_SIDE_INIT_PAGE_SIZE) {
+                            const rawRightItems: Case[] = result.splice(0, RIGHT_SIDE_INIT_PAGE_SIZE);
+                            this._rightItems$.next(rawRightItems.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
+                            this._moreItems$.next(result.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
+                        } else {
+                            this._rightItems$.next(result.map(folder => this.resolveItemCaseToNavigationItem(folder)).filter(i => !!i));
+                        }
+                        this.resolveCustomViewsInRightSide();
+                        this._rightLoading$.off();
+                        this.itemLoaded.emit({menu: 'right', items: this.rightItems});
+                    },
+                    error: error => {
+                        this._log.error(error);
+                        this._rightItems$.next([]);
+                        this._moreItems$.next([]);
+                        this.resolveCustomViewsInRightSide();
+                        this._rightLoading$.off();
+                    }
+                });
🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`
around lines 424 - 470, The inner subscription in loadRightSide still uses the
deprecated two-argument subscribe form. Update that
childCases$.pipe(take(1)).subscribe call in DoubleDrawerNavigationService to the
observer object style with next and error handlers, matching the surrounding
subscriptions and the loadLeftSide pattern already used in this class.
🤖 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
`@projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts`:
- Around line 373-382: The subscription in requestPageWithDynamicSort can leak
because _dynamicDefaultSort$ is subscribed without teardown when
_lastHeaderSearchState.fieldIdentifier is empty. Update this path in
CaseViewService to use a one-time subscription (for example by applying take(1))
or otherwise capture and dispose the Subscription in ngOnDestroy, and keep the
existing behavior of updating _lastHeaderSearchState before calling
_nextPage$.next(requestContext).
- Around line 92-95: Initialize the _nextPage$ stream before it is used in
CaseViewService, since the constructor currently calls this._nextPage$.pipe(...)
while the field is still undefined. Update the CaseViewService setup so
_nextPage$ is assigned to a valid observable before requestPageWithDynamicSort
or any pipe usage, and verify the constructor path cannot run until the stream
is created.

In
`@projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts`:
- Around line 90-92: Initialize _requestedPage$ before calling
requestPageWithDynamicSort() in TaskViewService, because
requestPageWithDynamicSort() immediately uses this._requestedPage$.next(...) and
the observable is currently still unset when the first request is triggered
during construction. Move or add the _requestedPage$ assignment so it exists
before the initial requestPageWithDynamicSort(new PageLoadRequestContext(...))
call, and verify the constructor sets it up before any subscriptions to
_requestedPage$ are created.

---

Outside diff comments:
In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`:
- Around line 100-133: The abstractNavigationDoubleDrawer constructor still
keeps an unused Injector dependency after switching to direct
NAE_TASK_VIEW_COMPONENT injection. Remove the _injector: Injector parameter from
AbstractNavigationDoubleDrawer and drop the Injector import if nothing else in
this file uses it; keep the existing `@Inject`(NAE_TASK_VIEW_COMPONENT) _taskView
injection as the source of the component.
- Around line 96-98: rightItemsSub can remain undefined when
canApplyAutoSelect() is false, but ngOnDestroy in AbstractNavigationDoubleDrawer
unsubscribes it unconditionally. Update the destruction logic to guard
rightItemsSub the same way as the other subscriptions (for example, using the
same optional cleanup pattern already used for itemClickedSub and
itemLoadedSub), and make sure the assignment in the auto-select block stays the
only place it is created.

In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`:
- Around line 346-358: The initialization guard in initializeCustomViewsOfView
is vulnerable to duplicate work because customItemsInitialized and
hiddenCustomItemsInitialized are only set inside the async user$.subscribe
callback. Mark these flags before subscribing, or add a separate “initialization
started” guard in the same method, so repeated calls cannot enqueue duplicate
child/custom view resolution while waiting for the first non-empty user
emission.
- Around line 379-422: The `loadLeftSide` and `loadRightSide` flows are
duplicated and already drifting apart, so extract the shared
fetch/derive-child-ids/fetch-cases/error-handling logic into a common helper
used by both methods. Keep the method-specific differences in pagination
splitting and item mapping in small callbacks or parameters, and update
`loadLeftSide`/`loadRightSide` to delegate to that helper so future observer or
error-handling fixes only need to be made once.
- Around line 136-169: `set currentNode` in
`double-drawer-navigation.service.ts` can register multiple deferred callbacks
on `_nodeLoading$`, causing repeated `loadNavigationItems(node)` calls for stale
nodes when parent lookup is still pending. Update the `currentNode` flow to use
a single-flight/cancellable deferred load: before adding the
`filter(!isActive).take(1)` subscription, cancel any previous waiter or reuse
one pending subscription, and ensure only the latest `node` is loaded after
`_nodeLoading$.off()` in the `set currentNode` logic.

In
`@projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts`:
- Around line 23-32: The singleTaskViewFilterFactory logic is duplicated with
taskViewFilterFactory, including the same null check, error message, and
SimpleFilter.fromTaskQuery call. Extract the shared validation and filter
निर्माण into a common helper used by both singleTaskViewFilterFactory and
taskViewFilterFactory, so both dialogs reuse the same implementation and stay in
sync.
- Around line 73-85: `processTaskEvents` currently closes the dialog on every
successful `FINISH`/`CANCEL` event without checking
`this._injectedData.autoCloseOnEvent`, unlike
`TaskViewDialogComponent.processTaskEvents`. Update
`SingleTaskViewDialogComponent.processTaskEvents` to either honor the
`autoCloseOnEvent` flag before calling `_dialogRef.close`, or if single-task
dialogs should always close, remove `autoCloseOnEvent` from the injected data
contract and document the intentional difference. Use `processTaskEvents`,
`_injectedData`, and `_dialogRef.close` to locate the behavior.

---

Duplicate comments:
In
`@projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts`:
- Around line 3-6: `TaskViewDialogInjectionData` currently պահանջs
`autoCloseOnEvent`, but `openTaskDialog` is already constructing it via an `as`
cast without setting that field, so make the property optional in the interface
and document the default behavior. Update the consumers that read
`TaskViewDialogInjectionData` to explicitly apply a fallback with `??` so the
intended close behavior is set in one place rather than relying on an undefined
value.

In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts`:
- Around line 424-470: The inner subscription in loadRightSide still uses the
deprecated two-argument subscribe form. Update that
childCases$.pipe(take(1)).subscribe call in DoubleDrawerNavigationService to the
observer object style with next and error handlers, matching the surrounding
subscriptions and the loadLeftSide pattern already used in this class.

In `@projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts`:
- Around line 17-19: The `openDialog` action in `dialog-actions.ts` is
constructing `TaskViewDialogInjectionData` with only `searchBody`, so
`TaskViewDialogComponent.processTaskEvents` never sees `autoCloseOnEvent` and
the dialog cannot auto-close on task completion/cancel. Update the injected
`data` object to include `autoCloseOnEvent` with the appropriate value for this
action, and avoid relying on the `as TaskViewDialogInjectionData` cast to hide
the missing field. Use the `openDialog` flow and `TaskViewDialogInjectionData`
shape as the guide so the dialog behavior matches
`TaskViewDialogComponent.processTaskEvents`.

In
`@projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts`:
- Around line 72-75: The auto-close logic in processTaskEvents is fine, but
openTaskDialog in dialog-actions is not populating the autoCloseOnEvent field,
so this dialog always exits early. Update openTaskDialog to pass the
autoCloseOnEvent value into the TaskViewDialogInjectionData when creating the
dialog, matching the contract used by TaskViewDialogComponent and its
processTaskEvents guard.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5fd62461-b08d-44b3-ab75-fe6efc10a135

📥 Commits

Reviewing files that changed from the base of the PR and between 6498061 and 616d027.

📒 Files selected for processing (23)
  • projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts
  • projects/netgrif-components-core/src/lib/dialog/public-api.ts
  • projects/netgrif-components-core/src/lib/header/case-header/case-header.service.spec.ts
  • projects/netgrif-components-core/src/lib/header/case-header/case-meta-enum.ts
  • projects/netgrif-components-core/src/lib/header/header-modes/edit-mode/abstract-edit-mode.component.spec.ts
  • projects/netgrif-components-core/src/lib/header/models/meta-fields-factory.ts
  • projects/netgrif-components-core/src/lib/header/public-api.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/service/double-drawer-navigation.service.ts
  • projects/netgrif-components-core/src/lib/panel/case-panel/abstract-case-panel.component.spec.ts
  • projects/netgrif-components-core/src/lib/panel/case-panel/abstract-case-panel.component.ts
  • projects/netgrif-components-core/src/lib/search/header-search-service/header-search.service.ts
  • projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts
  • projects/netgrif-components-core/src/lib/side-menu/content-components/task-view/model/task-view-injection-data.ts
  • projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts
  • projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts
  • projects/netgrif-components/src/lib/dialog/dialog.module.ts
  • projects/netgrif-components/src/lib/dialog/dialog.theme.scss
  • projects/netgrif-components/src/lib/dialog/model/dialog-actions.ts
  • projects/netgrif-components/src/lib/dialog/single-task-view-dialog/single-task-view-dialog.component.ts
  • projects/netgrif-components/src/lib/dialog/task-view-dialog/task-view-dialog.component.ts
  • projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/model/factory-methods.ts
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts
💤 Files with no reviewable changes (2)
  • projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts
  • projects/netgrif-components-core/src/lib/side-menu/content-components/task-view/model/task-view-injection-data.ts

Retoocs added 2 commits July 7, 2026 11:26
- resolve PR comments
- fix observable initialization
- fix import

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts (1)

373-390: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Initialize _nextPage$ before the dynamic-sort request. On the process-backed dynamic-sort path, requestPageWithDynamicSort() can defer requestNextPage() until after the constructor already reaches this._nextPage$.pipe(...), so _nextPage$ is still undefined and the service crashes on first load. Create _nextPage$ eagerly, then let requestNextPage() only push into it.

🤖 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
`@projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts`
around lines 373 - 390, Initialize `_nextPage$` before any dynamic-sort handling
in `requestPageWithDynamicSort`/`requestNextPage`, because the first
process-backed load can reach the `_nextPage$.pipe(...)` subscription before
`requestNextPage()` runs and `_nextPage$` is still undefined. Make `_nextPage$`
eagerly available when the service starts, then change `requestNextPage(page:
PageLoadRequestContext)` to only emit into the existing subject instead of
conditionally creating it, and keep `requestPageWithDynamicSort` focused on
choosing between the dynamic-sort path and the normal `requestNextPage` call.
projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts (1)

369-386: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Initialize _requestedPage$ before subscribing to dynamic sort

When the injected default sort comes from processService.getNet(...), it can emit after the constructor reaches this._requestedPage$.pipe(...), leaving _requestedPage$ undefined and crashing initialization. Create _requestedPage$ eagerly, then let requestNextPage() only .next().

🤖 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
`@projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts`
around lines 369 - 386, Initialize _requestedPage$ eagerly in
task-view.service.ts before requestPageWithDynamicSort can subscribe to
_dynamicDefaultSort$, because the current lazy creation in requestNextPage can
leave the stream undefined when processService.getNet(...) emits late and the
constructor already wires _requestedPage$.pipe(...). Update requestNextPage() to
only emit with .next(), and ensure the constructor or initialization path
creates the BehaviorSubject up front so requestPageWithDynamicSort and
requestNextPage always operate on an existing subject.
🤖 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
`@projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts`:
- Line 371: The subscription created in task-view.service’s
nextPage/nextPagePagination flow on _dynamicDefaultSort$ is never torn down, so
repeated calls can leak subscriptions. Update the _dynamicDefaultSort$.subscribe
usage to complete after the first emission with pipe(take(1)), or store the
Subscription returned by subscribe and clean it up in ngOnDestroy alongside the
existing service teardown logic.

---

Outside diff comments:
In
`@projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts`:
- Around line 373-390: Initialize `_nextPage$` before any dynamic-sort handling
in `requestPageWithDynamicSort`/`requestNextPage`, because the first
process-backed load can reach the `_nextPage$.pipe(...)` subscription before
`requestNextPage()` runs and `_nextPage$` is still undefined. Make `_nextPage$`
eagerly available when the service starts, then change `requestNextPage(page:
PageLoadRequestContext)` to only emit into the existing subject instead of
conditionally creating it, and keep `requestPageWithDynamicSort` focused on
choosing between the dynamic-sort path and the normal `requestNextPage` call.

In
`@projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts`:
- Around line 369-386: Initialize _requestedPage$ eagerly in
task-view.service.ts before requestPageWithDynamicSort can subscribe to
_dynamicDefaultSort$, because the current lazy creation in requestNextPage can
leave the stream undefined when processService.getNet(...) emits late and the
constructor already wires _requestedPage$.pipe(...). Update requestNextPage() to
only emit with .next(), and ensure the constructor or initialization path
creates the BehaviorSubject up front so requestPageWithDynamicSort and
requestNextPage always operate on an existing subject.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8277a00a-8d67-4c6c-8fc7-ad794b9680a6

📥 Commits

Reviewing files that changed from the base of the PR and between 616d027 and 9e7f44b.

📒 Files selected for processing (4)
  • projects/netgrif-components-core/src/lib/dialog/models/task-view-dialog-injection-data.ts
  • projects/netgrif-components-core/src/lib/view/case-view/service/case-view-service.ts
  • projects/netgrif-components-core/src/lib/view/task-view/service/task-view.service.ts
  • projects/netgrif-components/src/lib/dialog/dialog.module.ts
💤 Files with no reviewable changes (1)
  • projects/netgrif-components/src/lib/dialog/dialog.module.ts

@Retoocs

Retoocs commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai is there anything why you request changes?

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr view 340 --repo netgrif/components --json reviews,reviewDecision,comments -q '.reviewDecision'
echo "---REVIEWS---"
gh pr view 340 --repo netgrif/components --json reviews -q '.reviews[] | {author: .author.login, state: .state, body: .body}'
echo "---REVIEW COMMENTS---"
gh api repos/netgrif/components/pulls/340/comments --jq '.[] | {user: .user.login, path: .path, line: .line, body: .body}'

Length of output: 104321


@Retoocs Looking at the review history, most of the earlier CodeRabbit findings have already been resolved or withdrawn (e.g., the _nextPage$/_requestedPage$ initialization fix, isUserEmpty usage, take(1) fix, meta-fields-factory rename, the hardcoded title and keyboard-accessibility items I withdrew after your clarifications).

However, a few items still look outstanding without a confirmed fix or reply:

From Kovy95's review (likely the main driver of the "Changes requested" state, since it hasn't been dismissed):

  1. Inject NAE_TASK_VIEW_COMPONENT directly in the constructor instead of resolving it via Injector (abstract-navigation-double-drawer.ts).
  2. Whether the create/edit-menu-item dialog should only show the initialize transition, or also the following item_settings transition.
  3. TranslateLibModule appears imported twice in dialog.module.ts — should be deduplicated.
  4. Whether autoCloseOnEvent should be explicitly declared on the interface used in task-view-dialog.component.ts (you mentioned using the map from the interface — worth confirming this is settled).
  5. New constructor parameters in navigation-double-drawer.component.ts (Line 84) should be placed at the end of the parameter list.
  6. Duplicate dynamic-sort dispatch logic in case-view-service.ts — extract into a shared helper with pipe(take(1)).

From my own review, still open (lower priority):

  • singleTaskViewFilterFactory duplicates taskViewFilterFactory almost exactly — consider extracting a shared helper.
  • SingleTaskViewDialogComponent.processTaskEvents closes the dialog unconditionally on success, unlike TaskViewDialogComponent, which checks autoCloseOnEvent — worth confirming this divergence is intentional.
  • initializeCustomViewsOfView in double-drawer-navigation.service.ts sets its init flags only after the async user$ emission resolves, so concurrent calls before the first emission could duplicate work (Major).
  • currentNode setter in the same service can register multiple deferred _nodeLoading$ waiters if reassigned while a lookup is in flight, causing stale-node loads (Major).
  • loadLeftSide/loadRightSide are near-duplicate flows that could be consolidated.
  • Unused _injector: Injector in abstract-navigation-double-drawer.ts (ties into Kovy95's point #1 above).
  • Leftover/unused SCSS classes in single-task-view-dialog.component.scss.

None of these are unrecoverable blockers, and several are trivial/nitpick-level, but they explain why the review status still shows "changes requested." Let me know if you'd like me to help draft fixes for any of these, or if some should be deferred to a follow-up PR.

[resolve]

- remove unused injector
@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
36.5% Coverage on New Code (required ≥ 50%)
B Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (3)
projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts (3)

356-402: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated dialog-open boilerplate between editMenuItem and createMenuItem.

Both methods build a near-identical this._dialog.open(this._taskView, {panelClass: "dialog-task-responsive", data: {...} as TaskViewDialogInjectionData}) call, differing only in autoCloseOnEvent and searchBody. Extracting a small private helper would keep the panel class/typing in one place and reduce drift risk as this dialog flow evolves (e.g. adding afterClosed() handling later).

♻️ Proposed helper extraction
+    private _openMenuItemTaskDialog(searchBody: TaskViewDialogInjectionData['searchBody'], autoCloseOnEvent: boolean) {
+        this._dialog.open(this._taskView, {
+            panelClass: "dialog-task-responsive",
+            data: {autoCloseOnEvent, searchBody} as TaskViewDialogInjectionData,
+        });
+    }
+
     public editMenuItem(menuItemCase: Case) {
-        this._dialog.open(this._taskView, {
-            panelClass: "dialog-task-responsive",
-            data: {
-                autoCloseOnEvent: false,
-                searchBody: {
-                    transitionId: ["item_settings", "move_item", "duplicate_item", "children_order"],
-                    case: { id: menuItemCase.stringId }
-                }
-            } as TaskViewDialogInjectionData,
-        });
+        this._openMenuItemTaskDialog({
+            transitionId: ["item_settings", "move_item", "duplicate_item", "children_order"],
+            case: { id: menuItemCase.stringId }
+        }, 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
around lines 356 - 402, Both `editMenuItem` and the success path in
`createMenuItem` duplicate the same `_dialog.open(this._taskView, ...)`
boilerplate, which should be extracted into a private helper to keep the
`panelClass` and `TaskViewDialogInjectionData` wiring in one place. Add a small
helper on `AbstractNavigationDoubleDrawer` that accepts the differing
`autoCloseOnEvent` and `searchBody` inputs, then have `editMenuItem` and
`createMenuItem` call it instead of constructing the dialog config inline.

369-402: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard createMenuItem() until currentNode is available. UriService.activeNode starts as undefined until the root request resolves, but the edit-mode action is exposed without a root/current-node guard, so clicking it early can throw on this.currentNode.uriPath before the existing error handling runs.

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
around lines 369 - 402, Guard createMenuItem() in AbstractNavigationDoubleDrawer
until currentNode is set, since currentNode.uriPath is used before the root node
resolves and can throw early. Add a defensive check or disable the action until
currentNode is available, then only call _caseResourceService.createCase after
confirming currentNode exists and use its uriPath safely; keep the existing
error handling in createMenuItem() for service failures.

144-144: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard rightItemsSub in ngOnDestroy().
rightItemsSub is only assigned when canApplyAutoSelect() passes, so this unsubscribe() can still throw when that path never runs. Use ?.unsubscribe() or initialize it up front.

🤖 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
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`
at line 144, The cleanup in ngOnDestroy for AbstractNavigationDoubleDrawer
should safely handle rightItemsSub being unset when canApplyAutoSelect() never
ran. Update the ngOnDestroy logic to guard the rightItemsSub unsubscribe call
with optional chaining or initialize rightItemsSub upfront so the teardown path
cannot throw when the subscription was never created.
🤖 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.

Outside diff comments:
In
`@projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts`:
- Around line 356-402: Both `editMenuItem` and the success path in
`createMenuItem` duplicate the same `_dialog.open(this._taskView, ...)`
boilerplate, which should be extracted into a private helper to keep the
`panelClass` and `TaskViewDialogInjectionData` wiring in one place. Add a small
helper on `AbstractNavigationDoubleDrawer` that accepts the differing
`autoCloseOnEvent` and `searchBody` inputs, then have `editMenuItem` and
`createMenuItem` call it instead of constructing the dialog config inline.
- Around line 369-402: Guard createMenuItem() in AbstractNavigationDoubleDrawer
until currentNode is set, since currentNode.uriPath is used before the root node
resolves and can throw early. Add a defensive check or disable the action until
currentNode is available, then only call _caseResourceService.createCase after
confirming currentNode exists and use its uriPath safely; keep the existing
error handling in createMenuItem() for service failures.
- Line 144: The cleanup in ngOnDestroy for AbstractNavigationDoubleDrawer should
safely handle rightItemsSub being unset when canApplyAutoSelect() never ran.
Update the ngOnDestroy logic to guard the rightItemsSub unsubscribe call with
optional chaining or initialize rightItemsSub upfront so the teardown path
cannot throw when the subscription was never created.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b3ef5451-383a-4cd1-90ef-2d186ca31d0b

📥 Commits

Reviewing files that changed from the base of the PR and between 9e7f44b and 524bfd2.

📒 Files selected for processing (4)
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts
  • projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.spec.ts
  • projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Fix or feature that would cause existing functionality doesn't work as expected improvement New feature or request Large new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants