Skip to content

[NAE-2072] Workspaces #280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: release/7.0.0-rev2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export class PanelsComponent implements OnInit {
stringId: null,
petriNetId: null,
permissions: {},
users: {}
users: {},
workspaceId: ''
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use consistent default workspace ID value.

The empty string value for workspaceId is inconsistent with the "default" example shown in the IUser interface. For demo purposes, using a meaningful value would be better.

-            workspaceId: ''
+            workspaceId: 'default'
📝 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.

Suggested change
workspaceId: ''
workspaceId: 'default'
🤖 Prompt for AI Agents
In projects/nae-example-app/src/app/doc/panels/panels.component.ts at line 72,
the default value for workspaceId is set to an empty string, which is
inconsistent with the "default" example in the IUser interface. Update the
workspaceId default value to match the meaningful default value used in the
IUser interface to maintain consistency and improve demo clarity.

};
this.workflow = {
stringId: 'ID',
Expand All @@ -83,7 +84,8 @@ export class PanelsComponent implements OnInit {
email: '[email protected]',
fullName: 'Test Testovič'
},
immediateData: []
immediateData: [],
workspaceId: ''
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use consistent default workspace ID value.

Similar to the case object above, consider using "default" instead of an empty string for consistency.

-            workspaceId: ''
+            workspaceId: 'default'
📝 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.

Suggested change
workspaceId: ''
workspaceId: 'default'
🤖 Prompt for AI Agents
In projects/nae-example-app/src/app/doc/panels/panels.component.ts at line 88,
the default value for workspaceId is set as an empty string, which is
inconsistent with the "case" object that uses "default". Change the default
value of workspaceId from an empty string to "default" to maintain consistency
across the code.

};
this.featuredFields$ = new BehaviorSubject<Array<HeaderColumn>>([
new HeaderColumn(HeaderColumnType.META, 'visualId', 'Visual ID', 'text'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export class SidemenuExampleComponent implements OnInit {
immediateData: [],
initials: 'EX',
title: 'Example Dummy Process',
version: '1.0.0'
version: '1.0.0',
workspaceId: ''
}),
new Net({
stringId: '999',
Expand All @@ -52,7 +53,8 @@ export class SidemenuExampleComponent implements OnInit {
immediateData: [],
initials: 'EXX',
title: 'Other Example Dummy Process',
version: '1.0.0'
version: '1.0.0',
workspaceId: ''
})])
});
}
Expand Down
3 changes: 3 additions & 0 deletions projects/netgrif-components-core/src/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
"impersonating": "in Vertretung als"
}
},
"navigation":{
"workspace": "Arbeitsbereich auswählen"
},
"search": {
"category": {
"case": {
Expand Down
3 changes: 3 additions & 0 deletions projects/netgrif-components-core/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
"impersonating": "impersonating"
}
},
"navigation":{
"workspace": "Choose workspace"
},
"search": {
"category": {
"case": {
Expand Down
3 changes: 3 additions & 0 deletions projects/netgrif-components-core/src/assets/i18n/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
"impersonating": "v zastúpení"
}
},
"navigation":{
"workspace": "Výber workspacu"
},
"search": {
"category": {
"case": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class UserTransformer implements Transformer<UserResource, User> {
user.realmId,
user.name,
user.surname,
user.workspaceId,
this.transformAuthorities(user.authorities),
user.processRoles,
groups,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {Component, Input, OnDestroy, OnInit, TemplateRef} from '@angular/core';
import {MatDrawerMode} from '@angular/material/sidenav';
import {ActivatedRoute, Router} from '@angular/router';
import {ResizeEvent} from 'angular-resizable-element';
import {Observable, of, Subscription} from 'rxjs';
import {map} from 'rxjs/operators';
import {Observable, of, Subject, Subscription} from 'rxjs';
import {map, tap} from 'rxjs/operators';
import {RoleAccess, View} from '../../../commons/schema';
import {AccessService} from '../../authorization/permission/access.service';
import {ConfigurationService} from '../../configuration/configuration.service';
Expand Down Expand Up @@ -43,6 +43,7 @@ import {
RIGHT_SIDE_NEW_PAGE_SIZE,
SETTINGS_TRANSITION_ID
} from '../model/navigation-configs';
import {Workspace} from "../../user/models/workspace";


@Component({
Expand Down Expand Up @@ -117,6 +118,8 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
};

protected _childCustomViews: { [uri: string]: { [key: string]: NavigationItem } };
public userWorkspaces$: Observable<Array<Workspace>>;
public userWorkspacesLength: number;

protected constructor(protected _router: Router,
protected _activatedRoute: ActivatedRoute,
Expand Down Expand Up @@ -164,6 +167,10 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
this.resolveHiddenMenuItemFromChildViews(viewConfigurationPath + '/' + key, childView);
});
}

this.userWorkspaces$ = this._userService.workspaces$.pipe(
tap(arr => this.userWorkspacesLength = arr.length)
);
}

get currentNode(): UriNodeResource {
Expand Down Expand Up @@ -229,6 +236,14 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
return this._configRightMenu;
}

setWorkspace(workspace: string) {
this._userService.changeWorkspace(workspace);
}

activeWorkspace() {
return this._userService.user.workspaceId;
}

toggleMenu() {
this.toggleRightMenu();
if (this.allClosable) {
Expand Down
14 changes: 14 additions & 0 deletions projects/netgrif-components-core/src/lib/process/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export class Net implements PetriNetReferenceWithPermissions {
* @ignore
*/
private _identifier: string;
/**
* Workspace id
* */
private _workspaceId: string;
/**
* @ignore
* */
Expand Down Expand Up @@ -84,6 +88,7 @@ export class Net implements PetriNetReferenceWithPermissions {
this._transactions = [];
this._roles = [];
this._uriNodeId = net.uriNodeId;
this._workspaceId = net.workspaceId
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix missing semicolon.

The constructor initialization is missing a semicolon at the end of the line.

-        this._workspaceId = net.workspaceId
+        this._workspaceId = net.workspaceId;
📝 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.

Suggested change
this._workspaceId = net.workspaceId
this._workspaceId = net.workspaceId;
🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/process/net.ts at line 91, the
assignment statement setting this._workspaceId is missing a semicolon at the
end. Add a semicolon to properly terminate the statement.

}

get stringId(): string {
Expand Down Expand Up @@ -197,4 +202,13 @@ export class Net implements PetriNetReferenceWithPermissions {
set uriNodeId(uriNodeId: string) {
this._uriNodeId = uriNodeId;
}


get workspaceId(): string {
return this._workspaceId;
}

set workspaceId(value: string) {
this._workspaceId = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export class ProcessService implements OnDestroy {
protected loadNetReference(id: string): Observable<PetriNetReference> {
const returnReference = new ReplaySubject<PetriNetReference>(1);
this._petriNetResource.getOne(id, this.LATEST).subscribe(reference => {
returnReference.next(!reference.stringId ? null : reference);
returnReference.next(!reference?.stringId ? null : reference);
returnReference.complete();
return;
}, error => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Page} from '../interface/page';
import {GroupsInterface} from '../interface/group';
import {AbstractResourceService} from '../abstract-endpoint/abstract-resource.service';
import {UserResource} from '../interface/user-resource';
import {Workspace} from "../../user/models/workspace";

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -69,6 +70,30 @@ export class UserResourceService extends AbstractResourceService {
.pipe(map(r => this.mapToPage<UserResource>(r)));
}

/**
* Get all workspaces
*
* **Request Type:** GET
*
* **Request URL:** {{baseUrl}}/api/user/workspaces
*/
public getAllWorkspaces(params?: Params): Observable<Array<Workspace>> {
return this._resourceProvider.get$('users/workspaces', this.SERVER_URL, params)
.pipe(map(r => this.changeType(r, undefined)));
}

/**
* Get all workspaces
*
* **Request Type:** GET
*
* **Request URL:** {{baseUrl}}/api/user/workspaces
*/
public changeWorkspace(workspaceId: string, params?: Params): Observable<UserResource> {
return this._resourceProvider.post$('users/workspace', this.SERVER_URL, {workspaceId}, params)
.pipe(map(r => this.changeType(r, undefined)));
}

/**
* Get all users with specified roles
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ export interface Case {
* **Example:** 5e4cd5070a975a19858772aa
*/
petriNetId: string;
/**
* Workspace id
* */
workspaceId: string;
Comment on lines +114 to +117
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Improve documentation consistency.

The workspaceId property documentation lacks an example value, unlike other properties in this interface. Consider adding an example for consistency.

     /**
-     * Workspace id
+     * **Example:** default
+     * 
+     * Workspace id
      * */

Verify that existing code creating Case objects won't break with this new required property:


🏁 Script executed:

#!/bin/bash
# Check for Case object creation that might miss the new required property
rg -A 5 -B 2 "new.*Case|Case.*=" --type ts

Length of output: 66678


Add a usage example for workspaceId (no breaking changes detected)

I didn’t find any object literals or new Case constructions missing the new required workspaceId field—most Case instances flow through service calls or are returned from the backend, so TypeScript will receive the field at runtime. However, the documentation on the workspaceId property should still be expanded to match the style of neighboring fields.

• File: projects/netgrif-components-core/src/lib/resources/interface/case.ts
• Lines: 114–117

Suggested diff:

    /**
-    * Workspace id
+    * **Example:** default
+    *
+    * Workspace id
     */
    workspaceId: string;
📝 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.

Suggested change
/**
* Workspace id
* */
workspaceId: string;
/**
* **Example:** default
*
* Workspace id
*/
workspaceId: string;
🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/resources/interface/case.ts around
lines 114 to 117, the workspaceId property lacks an example value in its
documentation, unlike other properties in the interface. Add an example value to
the JSDoc comment for workspaceId to maintain consistency in documentation style
without changing the code functionality.

/**
* **Example:** home
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,9 @@ export interface PetriNetReference {
* [ImmediateData]{@link ImmediateData}
*/
immediateData: Array<ImmediateData>;
/**
* Workspace id
* */
workspaceId: string;
Comment on lines +51 to +54
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify all implementations are updated for the breaking change.

Adding the required workspaceId property to the PetriNetReference interface is a breaking change. Ensure all code that creates or implements this interface has been updated to include the new property.

Run the following script to verify all PetriNetReference implementations include the new property:


🏁 Script executed:

#!/bin/bash
# Description: Find all PetriNetReference object creations and verify workspaceId is included

# Search for PetriNetReference object creations
rg -A 10 -B 2 "PetriNetReference|new.*Net\("

# Search for files that might be missing workspaceId in object literals
ast-grep --pattern $'{ 
  $$$
  title: $_,
  $$$
}'

Length of output: 67189


Add workspaceId to all PetriNetReference instantiations

The new required workspaceId: string field on PetriNetReference is missing in several object literals and tests, causing type errors. Please update each literal to include workspaceId (use an empty string '' or appropriate value in tests). Key locations:

  • projects/netgrif-components/src/lib/panel/workflow-panel/workflow-panel.component.spec.ts
  • projects/netgrif-components/src/lib/panel/public-workflow-panel/public-workflow-panel.component.spec.ts
  • projects/netgrif-components/src/lib/dialog/new-case-dialog/new-case-dialog.component.spec.ts
  • projects/netgrif-components-core/src/lib/view/tree-case-view/tree-component/case-tree.service.spec.ts
  • projects/netgrif-components-core/src/lib/process/net.spec.ts

Example update in a spec file:

public workflow: PetriNetReference = {
  stringId: '',
  title: '',
  identifier: '',
  version: '',
  initials: '',
  defaultCaseName: '',
  createdDate: [],
  author: { email: '', fullName: '' },
  immediateData: undefined,
+ workspaceId: ''
};

Repeat for all other object literals where a PetriNetReference is created.

🤖 Prompt for AI Agents
In
projects/netgrif-components-core/src/lib/resources/interface/petri-net-reference.ts
around lines 51 to 54, the PetriNetReference interface was updated to include a
new required property workspaceId of type string, which is a breaking change. To
fix this, update all object literals and tests that create or implement
PetriNetReference across the codebase to include the workspaceId property with
an appropriate value, such as an empty string '' in tests. Key files to update
include workflow-panel.component.spec.ts,
public-workflow-panel.component.spec.ts, new-case-dialog.component.spec.ts,
case-tree.service.spec.ts, and net.spec.ts. Ensure every PetriNetReference
instantiation has workspaceId added to avoid type errors.

}

Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ export interface Task {
delegateTitle?: string;
immediateData?: Array<ImmediateData>;
assignedUserPolicy?: AssignedUserPolicy;
/**
* Workspace id
* */
workspaceId: string;
Comment on lines +73 to +76
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify all Task implementations include the new required property.

The addition of the required workspaceId property to the Task interface is a breaking change. All code that creates Task objects must be updated to include this property.

Run the following script to identify any Task object creations that might be missing the workspaceId:


🏁 Script executed:

#!/bin/bash
# Description: Find Task object creations and verify workspaceId inclusion

# Search for Task object creations and assignments
rg -A 15 "Task\s*=\s*{|:\s*Task\s*=|new.*Task\(|as\s+Task"

# Look for mock Task objects that might need updating
fd -e ts -x rg -l "Task.*mock|mock.*Task" {}

Length of output: 1368


🏁 Script executed:

#!/bin/bash
# 1. Find object literals explicitly annotated with Task:
echo "=== Object literals typed as Task ==="
rg -n -E ':\s*Task\s*=\s*\{' -n projects/netgrif-components-core || echo "No direct annotations found."

# 2. Find casts to Task:
echo -e "\n=== 'as Task' casts ==="
rg -n 'as\s\+Task' -n projects/netgrif-components-core || echo "No 'as Task' casts found."

# 3. Verify mocks include workspaceId:
echo -e "\n=== Checking mocks for workspaceId ==="
for f in $(fd -e ts -g "create-mock-task*.ts"); do
  if rg -q "workspaceId" "$f"; then
    echo "OK: workspaceId present in $f"
  else
    echo "MISSING: workspaceId not found in $f"
  fi
done

Length of output: 1397


Include workspaceId in all Task mocks

A required workspaceId is missing from one of your test fixtures, which will break Task implementations in tests.

• projects/netgrif-components-core/src/lib/utility/tests/utility/create-mock-task-outcome.ts
– Add a workspaceId: string entry to the exported mock object.

Please also scan for any other untyped Task literals or fixtures to ensure they include the new workspaceId property.

🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/resources/interface/task.ts around
lines 73 to 76, the Task interface now requires a workspaceId string property,
which is a breaking change. You need to update all Task object creations,
especially test mocks like in
projects/netgrif-components-core/src/lib/utility/tests/utility/create-mock-task-outcome.ts,
to include a workspaceId string field. Review all Task literals, casts, and
mocks across the codebase to ensure they define workspaceId to prevent runtime
errors.

}
4 changes: 4 additions & 0 deletions projects/netgrif-components-core/src/lib/user/models/iuser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ export interface IUser {
* **Example:** Netgrif
*/
lastName: string;
/**
* **Example:** default
*/
workspaceId: string;
Comment on lines +37 to +40
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

LGTM! Consistent interface extension.

The workspaceId property follows the established documentation pattern and type conventions. The "default" example value suggests proper fallback handling.

Consider whether validation should be added for workspace ID format and if this should be optional for backward compatibility:


🏁 Script executed:

#!/bin/bash
# Check if there are any existing usages of IUser that might break with this required property
rg -A 3 -B 3 "implements IUser|extends IUser|: IUser"

Length of output: 69072


Add workspaceId to all IUser implementations

The new required workspaceId: string on IUser is a breaking change for existing classes and interfaces that implement or extend IUser. You need to update them accordingly:

• In projects/netgrif-components-core/src/lib/user/models/user.ts
– Add a public workspaceId: string parameter to the User constructor (or make it optional with a default)
– Assign it to the class field so instances implement the new interface member

• In projects/netgrif-components-core/src/lib/resources/interface/user-resource-small.ts
– Add workspaceId: string; (or workspaceId?: string; for backward compatibility) to UserResourceSmall

Also update any mapping or factory methods that create User or UserResourceSmall to populate workspaceId.

🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/user/models/iuser.ts around lines 37
to 40, adding the required workspaceId property to the IUser interface is a
breaking change. To fix this, update all IUser implementations accordingly: in
projects/netgrif-components-core/src/lib/user/models/user.ts, add a public
workspaceId string parameter to the User constructor (optionally with a default
value) and assign it to the class field; in
projects/netgrif-components-core/src/lib/resources/interface/user-resource-small.ts,
add workspaceId as a string property (optionally make it optional for backward
compatibility). Also, update any factory or mapping methods that create User or
UserResourceSmall instances to ensure workspaceId is properly populated.

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class User implements IUser {
public realmId: string,
public firstName: string,
public lastName: string,
public workspaceId: string,
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify constructor parameter placement doesn't break existing code.

Adding workspaceId in the middle of the constructor parameters is a breaking change if any code instantiates User objects using positional arguments rather than named parameters.

Run this script to verify all User constructor calls are compatible:


🏁 Script executed:

#!/bin/bash
# Description: Find all User constructor calls to verify they won't break with the new parameter

# Search for new User() instantiations
echo "=== Direct User constructor calls ==="
rg -A 3 "new User\(" --type ts

# Search for User constructor calls in factories or builders
echo -e "\n=== User creation in factories/transformers ==="
rg -A 5 "User\(" --type ts | grep -v "export class User"

# Check if UserTransformer or similar classes handle the new parameter
echo -e "\n=== UserTransformer implementations ==="
ast-grep --pattern 'class $_ {
  $$$
  transform($$$) {
    $$$
    new User($$$)
    $$$
  }
  $$$
}'

Length of output: 65160


Fix User constructor parameter placement to avoid breaking changes.

The workspaceId parameter was inserted mid‐constructor, but most new User(…) calls across the repo (in transformers, services, mocks and specs) still use the old argument order. You must either:

  • Move workspaceId to the end of the constructor signature in
    projects/netgrif-components-core/src/lib/user/models/user.ts, for example:
     constructor(
       public id: string,
       public username: string,
       public email: string,
       public realmId: string,
  • public workspaceId: string,
    public firstName: string,
    public lastName: string,
    /* … */
  • public workspaceId: string,
    ) { }
- Or update every `new User(…)` invocation to supply the new fifth argument. Critical locations include:  
• `authentication/models/user.transformer.ts`  
• `user/services/user.service.ts` (emptyUser)  
• `utility/tests/mocks/mock-authentication.service.ts`  
• `view/case-view/abstract-case-view.spec.ts`  
• …and dozens of other spec files under `projects/netgrif-components-core` and `projects/netgrif-components`  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion
      constructor(
        public id: string,
        public username: string,
        public email: string,
        public realmId: string,
        public firstName: string,
        public lastName: string,
        public workspaceId: string,
        /* … */
      ) { }
🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/user/models/user.ts at line 16, the
workspaceId parameter was added in the middle of the User constructor
parameters, causing breaking changes for existing positional constructor calls.
To fix this, move the workspaceId parameter to the end of the constructor
parameter list to preserve the original argument order. Alternatively, update
all new User(...) calls across the codebase to include the new fifth argument in
the correct position, especially in critical files like
authentication/models/user.transformer.ts, user/services/user.service.ts,
utility/tests/mocks/mock-authentication.service.ts, and
view/case-view/abstract-case-view.spec.ts.

public authorities: Array<string>,
public roles: Array<ProcessRole>,
public groups?: Array<string>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export interface Workspace {
id: string;
defaultWorkspace: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Injectable, OnDestroy} from '@angular/core';
import {Observable, ReplaySubject, Subscription} from 'rxjs';
import {BehaviorSubject, Observable, ReplaySubject, Subscription} from 'rxjs';
import {ProcessRole} from '../../resources/interface/process-role';
import {User} from '../models/user';
import {Credentials} from '../../authentication/models/credentials';
Expand All @@ -12,6 +12,7 @@ import {HttpErrorResponse} from '@angular/common/http';
import {SessionService} from '../../authentication/session/services/session.service';
import {UserResource} from '../../resources/interface/user-resource';
import {AnonymousService} from '../../authentication/anonymous/anonymous.service';
import {Workspace} from "../models/workspace";

@Injectable({
providedIn: 'root'
Expand All @@ -25,6 +26,7 @@ export class UserService implements OnDestroy {
protected _subAuth: Subscription;
protected _subAnonym: Subscription;
private _publicLoadCalled: boolean;
protected _workspaces: ReplaySubject<Array<Workspace>>;

public readonly GLOBAL_ROLE_PREFIX = 'global_';

Expand All @@ -37,11 +39,14 @@ export class UserService implements OnDestroy {
this._user = this.emptyUser();
this._loginCalled = false;
this._userChange$ = new ReplaySubject<User>(1);
this._workspaces = new ReplaySubject<Array<Workspace>>(1);
this._anonymousUserChange$ = new ReplaySubject<User>(1);
setTimeout(() => {
this._subAuth = this._authService.authenticated$.subscribe(auth => {
if (auth && !this._loginCalled) {
this.loadUser();
} else if (auth && this._loginCalled) {
this.loadWorkspaces();
} else if (!auth) {
this.clearUser();
this.publishUserChange();
Expand All @@ -66,6 +71,10 @@ export class UserService implements OnDestroy {
return this._userChange$.asObservable();
}

get workspaces$(): Observable<Array<Workspace>> {
return this._workspaces.asObservable();
}

get anonymousUser(): User {
return this.anonymousUser;
}
Expand Down Expand Up @@ -177,7 +186,7 @@ export class UserService implements OnDestroy {
}

protected emptyUser() {
return new User('', '', '', '', '', '', [], [], [], []);
return new User('', '', '', '', '', '', '', [], [], [], []);
}

protected loadUser(): void {
Expand All @@ -186,6 +195,7 @@ export class UserService implements OnDestroy {
const backendUser = {...user, id: user.id.toString()};
this._user = this._userTransform.transform(backendUser);
this.publishUserChange();
this.loadWorkspaces();
}
}, error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
Expand All @@ -210,6 +220,24 @@ export class UserService implements OnDestroy {
});
}

public loadWorkspaces() {
this._userResource.getAllWorkspaces().pipe(take(1)).subscribe(workspaces => {
if (workspaces) {
this._workspaces.next(workspaces)
}
}, error => {
this._log.error('Loading workspaces has failed!', error);
});
}

public changeWorkspace(workspaceId: string) {
this._userResource.changeWorkspace(workspaceId).subscribe(user => {
if (user) {
window.location.reload();
}
});
}
Comment on lines +233 to +239
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and input validation.

The method should handle potential failures and validate the input parameter:

 public changeWorkspace(workspaceId: string) {
+    if (!workspaceId) {
+        this._log.error('Workspace ID is required for workspace change');
+        return;
+    }
+    
     this._userResource.changeWorkspace(workspaceId).subscribe(user => {
         if (user) {
             window.location.reload();
         }
+    }, error => {
+        this._log.error('Changing workspace has failed!', error);
     });
 }
📝 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.

Suggested change
public changeWorkspace(workspaceId: string) {
this._userResource.changeWorkspace(workspaceId).subscribe(user => {
if (user) {
window.location.reload();
}
});
}
public changeWorkspace(workspaceId: string) {
if (!workspaceId) {
this._log.error('Workspace ID is required for workspace change');
return;
}
this._userResource.changeWorkspace(workspaceId).subscribe(user => {
if (user) {
window.location.reload();
}
}, error => {
this._log.error('Changing workspace has failed!', error);
});
}
🤖 Prompt for AI Agents
In projects/netgrif-components-core/src/lib/user/services/user.service.ts around
lines 233 to 239, the changeWorkspace method lacks input validation and error
handling. Add a check to ensure workspaceId is valid before proceeding. Also,
add error handling in the subscription to manage potential failures from
changeWorkspace, such as logging the error or notifying the user, instead of
silently failing.


public clearUser() {
this._user = this.emptyUser();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {UserResource} from '../../../resources/interface/user-resource';

export class MockAuthenticationMethodService extends AuthenticationMethodService {
login(credentials: Credentials): Observable<UserResource> {
return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname',
return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname', workspaceId: '',
groups: [], authorities: [], nextGroups: [], processRoles: []});
Comment on lines +8 to 9
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Inconsistent workspace ID value in mock data.

The mock uses an empty string for workspaceId, but the IUser interface example suggests "default" as the expected value. This inconsistency could lead to test scenarios that don't match real-world usage.

Consider updating the mock to use a consistent default value:

-        return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname', workspaceId: '',
+        return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname', workspaceId: 'default',
📝 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.

Suggested change
return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname', workspaceId: '',
groups: [], authorities: [], nextGroups: [], processRoles: []});
return of({
email: 'mail',
id: 'id',
username: 'username',
realmId: 'realmId',
name: 'name',
firstName: 'name',
surname: 'surname',
lastName: 'surname',
fullName: 'name surname',
workspaceId: 'default',
groups: [],
authorities: [],
nextGroups: [],
processRoles: []
});
🤖 Prompt for AI Agents
In
projects/netgrif-components-core/src/lib/utility/tests/mocks/mock-authentication-method-service.ts
at lines 8-9, the mock user object sets workspaceId to an empty string, which is
inconsistent with the IUser interface example that uses "default". Update the
workspaceId value in the mock to "default" to ensure test data aligns with
expected real-world values and avoid potential test discrepancies.

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ export class MockAuthenticationService extends AuthenticationService {
super(_auth, _config, _sessionService, _userTransformer);
}


login(credentials: Credentials): Observable<User> {
return of(new User('id', 'username', 'mail', 'realmId', 'name', 'surname', ['ADMIN'], [{stringId: 'id', name: 'id', importId: 'id'}]));
return of(new User('id', 'username', 'mail', 'realmId', 'name', 'surname', '', ['ADMIN'], [{stringId: 'id', name: 'id', importId: 'id'}]));
}

logout(): Observable<object> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class MockUserResourceService {
}

public getLoggedUser(): Observable<UserResource> {
return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname',
return of({email: 'mail', id: 'id', username: 'username', realmId: 'realmId', name: 'name', firstName: 'name', surname: 'surname', lastName: 'surname', fullName: 'name surname', workspaceId: '',
groups: [], authorities: [], nextGroups: [], processRoles: []});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function createMockCase(stringId = 'stringId',
stringId,
petriNetId,
permissions: {},
users: {}
users: {},
workspaceId: ''
};
}
Loading
Loading