[NAE-2412] EnumerationMap, MultichoiceMap with 'caseref' component are editable on unassigned task#330
[NAE-2412] EnumerationMap, MultichoiceMap with 'caseref' component are editable on unassigned task#330SamuelPalaj wants to merge 3 commits into
Conversation
…e editable on unassigned task - added disabled property to task ref component - fixed behavior of task and case list components on unassigned task
…e editable on unassigned task - lint fix
WalkthroughThe PR extends the component hierarchy to expose a ChangesComponent disabled state hierarchy
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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: 3
🤖 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/panel/task-panel-list/default-task-panel-list/abstract-default-task-list.component.ts`:
- Around line 106-122: Guard access to this.route and avoid the nested
subscription: only subscribe if this.route is present (e.g. check this.route !=
null), then replace the inner .subscribe on this._tasks$ with a pipe operator
(use switchMap or map + take(1)) so the tasks stream is consumed once (and add
takeUntil(this._unsubscribe$) on the outer chain to prevent leaks). When
resolving the panel ref, store const panelRef =
this._taskPanelRefs.get(this._redirectTaskId) and null-check it before calling
panelRef.open() or setting panelRef.expanded to avoid crashes if the ref isn't
registered yet; keep using this._unsubscribe$ for teardown.
In
`@projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.html`:
- Around line 2-4: The enumeration control (mat-icon) invokes setValue() even
when the component is disabled; update the click handling to respect the
disabled flag so enumeration approvals aren't editable when disabled. Locate the
mat-icon with (click)="setValue();$event.stopPropagation();" and change its
handler to guard on the disabled property (for example: (click)="disabled ?
$event.stopPropagation() : (setValue(); $event.stopPropagation())") or
alternatively restrict rendering with *ngIf="approval && typeApproval ===
'enumeration' && !disabled" so setValue() is never called when disabled.
In
`@projects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/refs/default-task-view/default-task-view.component.ts`:
- Around line 60-62: The disabled() method currently returns a possibly
undefined value due to optional chaining; update it so it always returns a
boolean by coercing the optional expression to boolean (e.g. using !! or
Boolean(...) or the nullish coalescing operator with false) when reading
this._dataFieldPortalData?.dataField?.formControlRef.disabled; keep the same
method name disabled and the same properties (_dataFieldPortalData, dataField,
formControlRef) but ensure the final returned value is a boolean.
🪄 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: e510ad99-2e9f-49c2-a2ae-98609372171b
📒 Files selected for processing (19)
projects/netgrif-components-core/src/lib/header/abstract-header.component.tsprojects/netgrif-components-core/src/lib/header/header-modes/abstract-header-mode.component.tsprojects/netgrif-components-core/src/lib/panel/case-panel/abstract-case-panel.component.tsprojects/netgrif-components-core/src/lib/panel/task-panel-list/default-task-panel-list/abstract-default-task-list.component.tsprojects/netgrif-components-core/src/lib/panel/task-panel/abstract-task-panel.component.tsprojects/netgrif-components-core/src/lib/view/case-view/components/case-list-paginator/abstract-case-list-paginator.component.tsprojects/netgrif-components-core/src/lib/view/case-view/components/default-case-list/abstract-default-case-list.component.tsprojects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.htmlprojects/netgrif-components/src/lib/header/header-modes/search-mode/search-mode.component.htmlprojects/netgrif-components/src/lib/header/header-modes/sort-mode/sort-mode.component.htmlprojects/netgrif-components/src/lib/header/header.component.htmlprojects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/refs/default-case-ref-list-view/default-case-ref-list-view.component.htmlprojects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/refs/default-task-view/default-task-view.component.htmlprojects/netgrif-components/src/lib/navigation/group-navigation-component-resolver/default-components/refs/default-task-view/default-task-view.component.tsprojects/netgrif-components/src/lib/panel/case-panel/case-panel.component.htmlprojects/netgrif-components/src/lib/panel/task-panel-list-pagination/task-list-pagination.component.htmlprojects/netgrif-components/src/lib/panel/task-panel/task-panel.component.htmlprojects/netgrif-components/src/lib/view/case-view/components/case-list-paginator/case-list-paginator.component.htmlprojects/netgrif-components/src/lib/view/case-view/components/case-list/case-list.component.html
💤 Files with no reviewable changes (1)
- projects/netgrif-components-core/src/lib/view/case-view/components/case-list-paginator/abstract-case-list-paginator.component.ts
| this.route.queryParams | ||
| .pipe(filter(pm => !!pm["taskId"])) | ||
| .subscribe(pm => { | ||
| this._redirectTaskId = pm["taskId"]; | ||
| this._tasks$.pipe().subscribe(tasks => { | ||
| const task = tasks.find( | ||
| t => t.task.stringId === this._redirectTaskId | ||
| ); | ||
| if (!!task && !task.initiallyExpanded) { | ||
| this._taskPanelRefs.get(this._redirectTaskId).open(); | ||
| this._taskPanelRefs.get( | ||
| this._redirectTaskId | ||
| ).expanded = true; | ||
| this._unsubscribe$.next(); | ||
| } | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find projects -name "abstract-default-task-list.component.ts" -type fRepository: netgrif/components
Length of output: 189
🏁 Script executed:
wc -l "projects/netgrif-components-core/src/lib/panel/task-panel-list/default-task-panel-list/abstract-default-task-list.component.ts"Repository: netgrif/components
Length of output: 193
🏁 Script executed:
cat -n "projects/netgrif-components-core/src/lib/panel/task-panel-list/default-task-panel-list/abstract-default-task-list.component.ts"Repository: netgrif/components
Length of output: 5474
Harden onRedirect() against crashes and leaking subscriptions.
Line 106 directly accesses an optional route without a guard. Line 110 creates a nested _tasks$ subscription without teardown, causing subscription leaks on route changes. Line 115 dereferences _taskPanelRefs.get() without null-checking, which crashes if the panel ref hasn't been registered yet.
Suggested fix
-import {filter} from 'rxjs/operators';
+import {filter, take, takeUntil} from 'rxjs/operators';
...
public onRedirect() {
+ if (!this.route) {
+ return;
+ }
this.route.queryParams
- .pipe(filter(pm => !!pm["taskId"]))
+ .pipe(
+ filter(pm => !!pm['taskId']),
+ takeUntil(this._unsubscribe$)
+ )
.subscribe(pm => {
- this._redirectTaskId = pm["taskId"];
- this._tasks$.pipe().subscribe(tasks => {
+ this._redirectTaskId = pm['taskId'];
+ this._tasks$.pipe(take(1), takeUntil(this._unsubscribe$)).subscribe(tasks => {
const task = tasks.find(
t => t.task.stringId === this._redirectTaskId
);
- if (!!task && !task.initiallyExpanded) {
- this._taskPanelRefs.get(this._redirectTaskId).open();
- this._taskPanelRefs.get(
- this._redirectTaskId
- ).expanded = true;
+ const panelRef = this._taskPanelRefs.get(this._redirectTaskId);
+ if (!!task && !task.initiallyExpanded && !!panelRef) {
+ panelRef.open();
+ panelRef.expanded = true;
this._unsubscribe$.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/panel/task-panel-list/default-task-panel-list/abstract-default-task-list.component.ts`
around lines 106 - 122, Guard access to this.route and avoid the nested
subscription: only subscribe if this.route is present (e.g. check this.route !=
null), then replace the inner .subscribe on this._tasks$ with a pipe operator
(use switchMap or map + take(1)) so the tasks stream is consumed once (and add
takeUntil(this._unsubscribe$) on the outer chain to prevent leaks). When
resolving the panel ref, store const panelRef =
this._taskPanelRefs.get(this._redirectTaskId) and null-check it before calling
panelRef.open() or setting panelRef.expanded to avoid crashes if the ref isn't
registered yet; keep using this._unsubscribe$ for teardown.
| <mat-checkbox *ngIf="approval && typeApproval === 'multichoice'" [formControl]="approvalFormControl" [indeterminate]="indeterminate" | ||
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding"></mat-checkbox> | ||
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding" [disabled]="disabled"></mat-checkbox> | ||
| <mat-icon *ngIf="approval && typeApproval === 'enumeration'" color="warn" (click)="setValue();$event.stopPropagation();" class="checkbox-padding cursor-fix">close</mat-icon> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd "edit-mode.component.html" projects/netgrif-componentsRepository: netgrif/components
Length of output: 153
🏁 Script executed:
cat -n projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.htmlRepository: netgrif/components
Length of output: 2369
🏁 Script executed:
fd "edit-mode.component.ts" projects/netgrif-componentsRepository: netgrif/components
Length of output: 151
🏁 Script executed:
cat -n projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.tsRepository: netgrif/components
Length of output: 824
🏁 Script executed:
fd "AbstractEditModeComponent" projects/netgrif-components --type fRepository: netgrif/components
Length of output: 44
🏁 Script executed:
rg "class AbstractEditModeComponent" --type ts -A 30Repository: netgrif/components
Length of output: 4545
🏁 Script executed:
rg "class AbstractHeaderModeComponent" --type ts -A 50 | head -80Repository: netgrif/components
Length of output: 1995
🏁 Script executed:
rg "typeApproval.*enumeration" projects/netgrif-components --type tsRepository: netgrif/components
Length of output: 44
🏁 Script executed:
rg "enumeration" projects/netgrif-components/src/lib/header --type ts -B 2 -A 2Repository: netgrif/components
Length of output: 44
🏁 Script executed:
git log --oneline projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.html | head -5Repository: netgrif/components
Length of output: 171
🏁 Script executed:
git show 4d1a638d9 --stat | head -20Repository: netgrif/components
Length of output: 1059
🏁 Script executed:
git show 4d1a638d9 -- projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.html | head -50Repository: netgrif/components
Length of output: 2838
Apply disabled behavior to the enumeration approval control.
Line 4 allows setValue() to execute while disabled, making enumeration approvals editable on unassigned tasks. The multichoice checkbox correctly implements [disabled]="disabled", but the enumeration control lacks equivalent protection.
Suggested fix
- <mat-icon *ngIf="approval && typeApproval === 'enumeration'" color="warn" (click)="setValue();$event.stopPropagation();" class="checkbox-padding cursor-fix">close</mat-icon>
+ <button *ngIf="approval && typeApproval === 'enumeration'"
+ mat-icon-button
+ type="button"
+ class="checkbox-padding cursor-fix"
+ [disabled]="disabled"
+ (click)="!disabled && setValue(); $event.stopPropagation();">
+ <mat-icon color="warn">close</mat-icon>
+ </button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <mat-checkbox *ngIf="approval && typeApproval === 'multichoice'" [formControl]="approvalFormControl" [indeterminate]="indeterminate" | |
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding"></mat-checkbox> | |
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding" [disabled]="disabled"></mat-checkbox> | |
| <mat-icon *ngIf="approval && typeApproval === 'enumeration'" color="warn" (click)="setValue();$event.stopPropagation();" class="checkbox-padding cursor-fix">close</mat-icon> | |
| <mat-checkbox *ngIf="approval && typeApproval === 'multichoice'" [formControl]="approvalFormControl" [indeterminate]="indeterminate" | |
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding" [disabled]="disabled"></mat-checkbox> | |
| <button *ngIf="approval && typeApproval === 'enumeration'" | |
| mat-icon-button | |
| type="button" | |
| class="checkbox-padding cursor-fix" | |
| [disabled]="disabled" | |
| (click)="!disabled && setValue(); $event.stopPropagation();"> | |
| <mat-icon color="warn">close</mat-icon> | |
| </button> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@projects/netgrif-components/src/lib/header/header-modes/edit-mode/edit-mode.component.html`
around lines 2 - 4, The enumeration control (mat-icon) invokes setValue() even
when the component is disabled; update the click handling to respect the
disabled flag so enumeration approvals aren't editable when disabled. Locate the
mat-icon with (click)="setValue();$event.stopPropagation();" and change its
handler to guard on the disabled property (for example: (click)="disabled ?
$event.stopPropagation() : (setValue(); $event.stopPropagation())") or
alternatively restrict rendering with *ngIf="approval && typeApproval ===
'enumeration' && !disabled" so setValue() is never called when disabled.
| public disabled(): boolean { | ||
| return this._dataFieldPortalData?.dataField?.formControlRef.disabled; | ||
| } |
There was a problem hiding this comment.
Type mismatch in disabled() return value.
The method declares return type boolean but the optional chaining can return undefined when any part of the chain (_dataFieldPortalData, dataField, formControlRef) is nullish. While Angular templates treat undefined as falsy, this violates the type contract.
🔧 Proposed fix to ensure boolean return type
public disabled(): boolean {
- return this._dataFieldPortalData?.dataField?.formControlRef.disabled;
+ return this._dataFieldPortalData?.dataField?.formControlRef.disabled ?? false;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public disabled(): boolean { | |
| return this._dataFieldPortalData?.dataField?.formControlRef.disabled; | |
| } | |
| public disabled(): boolean { | |
| return this._dataFieldPortalData?.dataField?.formControlRef.disabled ?? 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/src/lib/navigation/group-navigation-component-resolver/default-components/refs/default-task-view/default-task-view.component.ts`
around lines 60 - 62, The disabled() method currently returns a possibly
undefined value due to optional chaining; update it so it always returns a
boolean by coercing the optional expression to boolean (e.g. using !! or
Boolean(...) or the nullish coalescing operator with false) when reading
this._dataFieldPortalData?.dataField?.formControlRef.disabled; keep the same
method name disabled and the same properties (_dataFieldPortalData, dataField,
formControlRef) but ensure the final returned value is a boolean.
|
|
|
||
|
|
||
| @Input() public case_: Case; | ||
| @Input() public approval: boolean; |
There was a problem hiding this comment.
can we rename all "approval" properties to "showSelection"? it is more intuitive (my bad naming from previous implementation)
change type boolean to ENUM with 3 values - Editable, Visible, Hidden, default value hidden
| @Input() showCasePanelIcon = true; | ||
| @Input() showDeleteMenu = false; | ||
| @Input() textEllipsis = false; | ||
| @Input() public disabled: boolean = false; |
There was a problem hiding this comment.
this is replaced with enu, in previous comment
| @Input() public indeterminate: boolean; | ||
| @Input() public approvalFormControl: FormControl; | ||
| @Input() public typeApproval: string; | ||
| @Input() public disabled: boolean = false; |
There was a problem hiding this comment.
rename approval and rework to enum, and remove this disabled property
| @Input() showSearchButton = true; | ||
| @Input() showTableSection = true; | ||
| @Input() public approval: boolean; | ||
| @Input() public disabled: boolean = false; |
There was a problem hiding this comment.
rename approval and rework to enum, and remove this disabled property
| <div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" class="netgrif-input netgrif-header-input netgrif-input-fix netgrif-zero-field-wrapper"> | ||
| <mat-checkbox *ngIf="approval && typeApproval === 'multichoice'" [formControl]="approvalFormControl" [indeterminate]="indeterminate" | ||
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding"></mat-checkbox> | ||
| (click)="$event.stopPropagation();" color='primary' class="checkbox-padding" [disabled]="disabled"></mat-checkbox> |
There was a problem hiding this comment.
turn of the ripple if you change this to button



Description
Fixes NAE-2412
How Has Been This Tested?
manualy
Test Configuration
Checklist:
Summary by CodeRabbit
New Features
Bug Fixes