[NAE-2418] Verify @Transient handling across persistence layers in na…#436
[NAE-2418] Verify @Transient handling across persistence layers in na…#436renczesstefan wants to merge 6 commits intorelease/7.0.0-rev10from
Conversation
…e-spring-core-adapter Replaced the incorrect `java.beans.Transient` import with `org.springframework.data.annotation.Transient`. This ensures proper handling of transiency in the context of Spring Data.
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
WalkthroughCore auth/actor types gained denormalized ID sets and MongoDB post-load resolution; many User/Group usages were switched to Spring adapter subclasses. Core Petri net arc types were made abstract and Spring adapter arc subclasses were added with persistence-transient getters. Minor Spring Data import and an empty PetriNet after-load hook were added. ChangesAuth / Actor model, persistence wiring, and tests
Petri net arc abstractions and Spring adapter arcs
Small Spring Data / persistence hooks
Sequence Diagram(s)sequenceDiagram
participant MongoDB as MongoDB
participant Spring as Spring Data Mapping
participant Listener as UserMongoEventListener
participant PRS as ProcessRoleService
participant AS as AuthorityService
MongoDB->>Spring: read document (AbstractActor)
Spring->>Listener: onAfterLoad / onAfterConvert(actor)
Listener->>PRS: findById(processRoleId) [for each id]
PRS-->>Listener: ProcessRole
Listener->>AS: findById(authorityId) [for each id]
AS-->>Listener: Authority
Listener-->>Spring: actor populated (processRoles & authorities)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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. Review rate limit: 0/1 reviews remaining, refill in 25 minutes and 49 seconds.Comment |
…e-spring-core-adapter - created new arc classes in spring core adapter - refactored existing arc class to be abstract - added transient to arcs
3f362f9
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetEventHandler.java`:
- Around line 21-24: Remove the no-op Spring Data lifecycle hook by deleting the
onAfterLoad(AfterLoadEvent<PetriNet> event) method from the PetriNetEventHandler
class and also remove the unused AfterLoadEvent import; ensure no other code
references onAfterLoad so compilation remains clean.
In
`@nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/arcs/Arc.java`:
- Around line 12-14: The copy constructor public Arc(Arc arc) is too narrowly
typed; change its parameter to the core/base arc type (the base Arc
interface/class used by the superclass) so it can accept core arcs, e.g. public
Arc(BaseArcType arc) { super(arc); }, and update the import for that core/base
Arc type; keep the body calling super(arc) unchanged to delegate copying to the
superclass.
🪄 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: d5fe2af9-b04f-42a0-b2dd-3da8dca5d1d3
📒 Files selected for processing (10)
application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ArcFactory.javaapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetEventHandler.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/arcs/Arc.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/arcs/InhibitorArc.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/arcs/ReadArc.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/arcs/ResetArc.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/arcs/Arc.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/arcs/InhibitorArc.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/arcs/ReadArc.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/domain/arcs/ResetArc.java
…e-spring-core-adapter - added annotation to user objects, so process list is transient
…e-spring-core-adapter Refactored `AbstractActor` to manage roles and authorities with additional `processRoleIds` and `authorityIds` fields for better flexibility. Updated related services, repositories, and XML test resources to align with the modified structure. Introduced `UserMongoEventListener` to resolve roles and authorities from IDs after data loading.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java (1)
187-191:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMigrate this query to
processRoleIdsas well to avoid inconsistent results.This method still filters by
processRoles._id, while the new persistence path uses denormalizedprocessRoleIds. With transient role objects, this query path can miss valid users.Suggested fix
default Page<User> findDistinctByStateAndProcessRoles__idIn(UserState state, Collection<ProcessResourceId> roleId, Pageable pageable, MongoTemplate mongoTemplate, String collection) { Query query = Query.query( Criteria.where("state").is(state) - .and("processRoles._id").in(roleId)); + .and("processRoleIds").in(roleId.stream().map(ProcessResourceId::toString).toList())); return resolveUserPage(pageable, mongoTemplate, collection, query); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java` around lines 187 - 191, The query in findDistinctByStateAndProcessRoles__idIn still filters on "processRoles._id" which misses users when roles are denormalized to "processRoleIds"; update the Criteria in that method to query "processRoleIds" instead (or use an OR Criteria that checks both "processRoleIds" and "processRoles._id" for backward compatibility) so resolveUserPage receives a query that finds users by the denormalized role IDs; ensure the change uses the existing roleId parameter and preserves return via resolveUserPage.nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java (1)
223-233:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFix authority ID/object desynchronization in fallback removal path.
If object removal falls back to name-based matching, the removed authority object may not match the originally removed ID, leaving stale entries in
authorityIds.Suggested fix
public void removeAuthority(Authority authority) { + if (authority == null) { + return; + } if (this.authorityIds == null) { this.authorityIds = new HashSet<>(); - } else { - this.authorityIds.remove(authority.getStringId()); } if (this.authoritySet == null) { this.authoritySet = new HashSet<>(); } else if (!this.authoritySet.remove(authority)) { - this.authoritySet.removeIf(it -> it.getName().equals(authority.getName())); + Authority matched = this.authoritySet.stream() + .filter(it -> it.getName().equals(authority.getName())) + .findFirst() + .orElse(null); + if (matched != null) { + this.authoritySet.remove(matched); + this.authorityIds.remove(matched.getStringId()); + } + return; } + this.authorityIds.remove(authority.getStringId()); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java` around lines 223 - 233, The removeAuthority(Authority authority) method can leave stale IDs in authorityIds when it falls back to name-based removal from authoritySet; update the fallback path so that when you remove by name (in the removeIf on authoritySet) you also remove the corresponding authority IDs from authorityIds (e.g., find entries in authorityIds whose Authority.getStringId() corresponds to the removed objects or remove IDs whose names match authority.getName()), ensuring null-safe handling of authorityIds and authoritySet; modify removeAuthority to synchronize both collections in both the direct remove(authority) branch and the removeIf(name) fallback so IDs and objects stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java`:
- Around line 281-289: In addAllProcessRoles, guard against a null roles
argument: check if the incoming Set<ProcessRole> roles is null (or empty) at the
top of the method and return early to avoid calling roles.stream() or
this.processRoles.addAll(roles); ensure existing initialization of
this.processRoleIds and this.processRoles (as already present) remains, then
only perform
this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList())
and this.processRoles.addAll(roles) when roles is non-null; reference the method
addAllProcessRoles and the fields processRoleIds/processRoles and class
ProcessRole to locate the code.
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Group.java`:
- Line 19: The Group class was made abstract but GroupController still
instantiates it with new Group(...), causing a compile error; either revert
Group to a concrete class until the constructor call is migrated, or update the
controller to use the concrete Spring adapter class (the adapter that implements
Group) instead of new Group(...). Locate the Group class declaration (public
abstract class Group extends AbstractActor) and either remove the abstract
modifier or change the instantiation in GroupController (the code that does new
Group(...)) to call the concrete adapter/implementation class that wraps Spring
functionality; ensure constructors/signatures match so compilation succeeds.
In
`@nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserMongoEventListener.java`:
- Around line 23-24: The trace logs in UserMongoEventListener currently print
the entire loaded user document via event.getSource(), which can expose
sensitive fields; change both log.trace calls to avoid logging the full payload
and instead log a minimal identifier (e.g., user id or username) and/or omit the
payload entirely — locate the two calls in UserMongoEventListener where
log.trace("User loaded: {}", event.getSource()) and log.trace("Resolving process
roles of user with id: {}", event.getSource()) are used and replace
event.getSource() with a safe accessor like event.getSource().getId() or
event.getSource().getUsername(), or remove the payload argument so only
non-sensitive context is logged.
- Around line 29-31: In UserMongoEventListener, avoid adding null role/authority
objects into actor collections: when iterating actor.getProcessRoleIds() call
processRoleService.findById(processRoleId) and only add the result to
actor.getProcessRoles() if it is non-null (skip otherwise), and similarly when
iterating actor.getAuthorityIds() call authorityService.getOne(authorityId) and
only add to actor.getAuthoritySet() if non-null; update the loops in the block
that uses AbstractActor actor to perform null checks (or filter nulls) before
calling add to prevent polluted collections and NPEs.
---
Outside diff comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java`:
- Around line 223-233: The removeAuthority(Authority authority) method can leave
stale IDs in authorityIds when it falls back to name-based removal from
authoritySet; update the fallback path so that when you remove by name (in the
removeIf on authoritySet) you also remove the corresponding authority IDs from
authorityIds (e.g., find entries in authorityIds whose Authority.getStringId()
corresponds to the removed objects or remove IDs whose names match
authority.getName()), ensuring null-safe handling of authorityIds and
authoritySet; modify removeAuthority to synchronize both collections in both the
direct remove(authority) branch and the removeIf(name) fallback so IDs and
objects stay consistent.
In
`@nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java`:
- Around line 187-191: The query in findDistinctByStateAndProcessRoles__idIn
still filters on "processRoles._id" which misses users when roles are
denormalized to "processRoleIds"; update the Criteria in that method to query
"processRoleIds" instead (or use an OR Criteria that checks both
"processRoleIds" and "processRoles._id" for backward compatibility) so
resolveUserPage receives a query that finds users by the denormalized role IDs;
ensure the change uses the existing roleId parameter and preserves return via
resolveUserPage.
🪄 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: 7bdab57e-4c74-48c2-86db-e1e6bfd916b9
📒 Files selected for processing (44)
application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.javaapplication-engine/src/main/java/com/netgrif/application/engine/configuration/security/PublicAuthenticationFilter.javaapplication-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.javaapplication-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.javaapplication-engine/src/test/groovy/com/netgrif/application/engine/action/AssignActionTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/action/RemoveActionTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/auth/LoginAttemptsTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/auth/SecurityContextTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/auth/TaskAuthorizationServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/auth/UserServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/auth/WorkflowAuthorizationServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/elastic/ElasticSearchTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/filters/FilterImportExportTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/impersonation/ImpersonationServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/insurance/mvc/InsuranceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/menu/MenuImportExportTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/orgstructure/groups/GroupServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/permissions/ElasticSearchViewPermissionTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/permissions/QueryDSLViewPermissionTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FileFieldTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FileListFieldTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/roles/ProcessRoleTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/CachePetriNetServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/service/PetriNetServiceTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/petrinet/web/PetriNetControllerTest.groovyapplication-engine/src/test/groovy/com/netgrif/application/engine/workflow/TaskControllerTest.groovyapplication-engine/src/test/java/com/netgrif/application/engine/MailSenderServiceTest.javaapplication-engine/src/test/java/com/netgrif/application/engine/auth/service/TokenServiceTest.javaapplication-engine/src/test/java/com/netgrif/application/engine/workflow/WorkflowMvcPerformanceTest.javaapplication-engine/src/test/java/com/netgrif/application/engine/workflow/service/AbstractAuthorizationServiceTest.javaapplication-engine/src/test/java/com/netgrif/application/engine/workflow/service/TaskServiceTest.javaapplication-engine/src/test/java/com/netgrif/application/engine/workflow/web/VariableArcsTest.javaapplication-engine/src/test/resources/petriNets/function_test.xmlapplication-engine/src/test/resources/petriNets/function_test_v2.xmlnae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Group.javanae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/User.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/AnonymousUser.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/Group.javanae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/User.javanae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.javanae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserMongoEventListener.javanae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.javanae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java
| public void addAllProcessRoles(Set<ProcessRole> roles) { | ||
| if (this.processRoleIds == null) { | ||
| this.processRoleIds = new HashSet<>(); | ||
| } | ||
| if (this.processRoles == null) { | ||
| this.processRoles = new HashSet<>(); | ||
| } | ||
| this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList()); | ||
| this.processRoles.addAll(roles); |
There was a problem hiding this comment.
Guard addAllProcessRoles against null input.
roles.stream() and addAll(roles) will throw if roles is null.
Suggested fix
public void addAllProcessRoles(Set<ProcessRole> roles) {
+ if (roles == null || roles.isEmpty()) {
+ return;
+ }
if (this.processRoleIds == null) {
this.processRoleIds = new HashSet<>();
}
if (this.processRoles == null) {
this.processRoles = new HashSet<>();
}
this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList());
this.processRoles.addAll(roles);
}📝 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 void addAllProcessRoles(Set<ProcessRole> roles) { | |
| if (this.processRoleIds == null) { | |
| this.processRoleIds = new HashSet<>(); | |
| } | |
| if (this.processRoles == null) { | |
| this.processRoles = new HashSet<>(); | |
| } | |
| this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList()); | |
| this.processRoles.addAll(roles); | |
| public void addAllProcessRoles(Set<ProcessRole> roles) { | |
| if (roles == null || roles.isEmpty()) { | |
| return; | |
| } | |
| if (this.processRoleIds == null) { | |
| this.processRoleIds = new HashSet<>(); | |
| } | |
| if (this.processRoles == null) { | |
| this.processRoles = new HashSet<>(); | |
| } | |
| this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList()); | |
| this.processRoles.addAll(roles); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java`
around lines 281 - 289, In addAllProcessRoles, guard against a null roles
argument: check if the incoming Set<ProcessRole> roles is null (or empty) at the
top of the method and return early to avoid calling roles.stream() or
this.processRoles.addAll(roles); ensure existing initialization of
this.processRoleIds and this.processRoles (as already present) remains, then
only perform
this.processRoleIds.addAll(roles.stream().map(ProcessRole::getStringId).toList())
and this.processRoles.addAll(roles) when roles is non-null; reference the method
addAllProcessRoles and the fields processRoleIds/processRoles and class
ProcessRole to locate the code.
…e-spring-core-adapter Replaced explicit imports with wildcard in `AbstractActor` for conciseness. Also adjusted the `addAllProcessRoles` method to use a more general `Collection` type for improved flexibility in handling process roles.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java`:
- Around line 188-190: When replacing denormalized ID sets in setAuthorityIds
and setProcessRoleIds, also clear or reset the corresponding hydrated object
collections so in-memory state doesn't stay stale: in setAuthorityIds(String)
assign this.authorityIds as before and also clear/reset authoritySet (e.g.,
this.authoritySet = new HashSet<>() or this.authoritySet.clear()) and in
setProcessRoleIds(String) do the same for processRoles; preserve the
null-to-empty behavior for IDs and ensure you reference setAuthorityIds,
authorityIds, authoritySet, setProcessRoleIds, processRoleIds and processRoles
when making the changes so isAdmin and other in-memory checks reflect the new
IDs.
🪄 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: 24f773a3-fb6e-42af-b287-66d2ab1d09d3
📒 Files selected for processing (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java
| } else { | ||
| this.authoritySet.removeIf(it -> it.getName().equals(name)); | ||
| } else { | ||
| Authority authority = authoritySet.stream().filter(it -> it.getName().equals(name)).findFirst().orElse(null); |
There was a problem hiding this comment.
Are you afraid of using Optional?
There was a problem hiding this comment.
It's okay for me to change it :D I changed it.
| * @param authoritySet set of authorities to set, null creates empty set | ||
| */ | ||
| public void setAuthoritySet(Set<Authority> authoritySet) { | ||
| this.authorityIds = authoritySet == null ? new HashSet<>() : new HashSet<>(authoritySet.stream().map(Authority::getStringId).toList()); |
There was a problem hiding this comment.
if you use .collect(Collectors.toSet()) it should already create hash set
| } | ||
|
|
||
| public void setProcessRoleIds(Set<String> processRoleIds) { | ||
| this.processRoleIds = processRoleIds == null ? new HashSet<>() : new HashSet<>(processRoleIds);; |
| */ | ||
| public void setProcessRoles(Set<ProcessRole> processRoleSet) { | ||
| this.processRoles = processRoleSet == null ? new HashSet<>() : new HashSet<>(processRoleSet); | ||
| this.processRoleIds = processRoleSet == null ? new HashSet<>() : new HashSet<>(processRoleSet.stream().map(ProcessRole::getStringId).toList()); |
There was a problem hiding this comment.
if you use .collect(Collectors.toSet()) it should already create hash set
|
|
||
| /** | ||
| * Adds a process role to the actor. | ||
| * t |
| import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole; | ||
| import lombok.Data; | ||
| import org.bson.types.ObjectId; | ||
| import org.springframework.data.annotation.Transient; |
There was a problem hiding this comment.
Imports added but no changes in code. Are the imports used?
- updated according to PR
Description
Implements NAE-2418
Dependencies
No new dependencies were introduced.
Third party dependencies
There are no dependencies on other PR.
Blocking Pull requests
There are no dependencies on other PR.
How Has Been This Tested?
This was tested manually and with unit tests.
Test Configuration
Checklist:
Summary by CodeRabbit
Chores
New Features
Refactor