diff --git a/README.md b/README.md index c43ad0ea7..7c1803809 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ multiple organizations. Here are some of the key features: - Single sign-on (SSO) via [OAuth2](https://oauth.net/2/) - No need to install or maintain local Capella clients - clients are made on demand in an underlaying [Kubernetes](https://kubernetes.io/) cluster -- Access to projects and models is self-managed by project leads, model owners +- Access to projects and models is self-managed by project admins, model owners or delegates - Within a project a user could have read or read & write access. Read-only users don't consume licenses in Team for Capella projects. @@ -60,7 +60,7 @@ In addition, we have integrated commercial products: - [pure::variants](https://www.pure-systems.com/purevariants) - Automatic license injection - - Access to licenses is self-managed by project leads + - Access to licenses is self-managed by project admins We've prepared a small video, where we showcase the diagram cache feature and show how you can use Capella and Jupyter in split view in the browser: diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/gitlab/exceptions.py b/backend/capellacollab/projects/toolmodels/modelsources/git/gitlab/exceptions.py index c50cfa818..4b20b9dfc 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/gitlab/exceptions.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/gitlab/exceptions.py @@ -14,7 +14,7 @@ def __init__(self): title="Insufficient Gitlab API access scope", reason=( "The registered token has not enough permissions to access the Gitlab API. " - "Access scope 'read_api' is required. Please contact your project lead." + "Access scope 'read_api' is required. Please contact your project administrator." ), err_code="GITLAB_ACCESS_DENIED", ) diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py b/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py index 26ef52b8a..cb6077ab7 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py @@ -88,7 +88,7 @@ async def get_revisions_of_primary_git_model( ], ) async def get_revisions_with_model_credentials( - url: str = fastapi.Body(), + url: str = fastapi.Body(media_type="text/plain"), git_model: models.DatabaseGitModel = fastapi.Depends( injectables.get_existing_git_model ), diff --git a/backend/capellacollab/projects/toolmodels/restrictions/routes.py b/backend/capellacollab/projects/toolmodels/restrictions/routes.py index fee4aa8b9..402c4252a 100644 --- a/backend/capellacollab/projects/toolmodels/restrictions/routes.py +++ b/backend/capellacollab/projects/toolmodels/restrictions/routes.py @@ -10,15 +10,15 @@ injectables as toolmodels_injectables, ) from capellacollab.projects.toolmodels import models as toolmodels_models -from capellacollab.projects.users import models as projects_users_models +from capellacollab.users import models as users_models from . import crud, exceptions, injectables, models router = fastapi.APIRouter( dependencies=[ fastapi.Depends( - auth_injectables.ProjectRoleVerification( - required_role=projects_users_models.ProjectUserRole.ADMIN + auth_injectables.RoleVerification( + required_role=users_models.Role.ADMIN ) ) ], diff --git a/backend/capellacollab/projects/users/exceptions.py b/backend/capellacollab/projects/users/exceptions.py index 883771c53..7c418ded5 100644 --- a/backend/capellacollab/projects/users/exceptions.py +++ b/backend/capellacollab/projects/users/exceptions.py @@ -44,9 +44,9 @@ def __init__(self): super().__init__( status_code=status.HTTP_403_FORBIDDEN, err_code="PERMISSION_FOR_PROJECT_LEADS_NOT_ALLOWED", - title="Permission for project leads not allowed", + title="Permission for project administrator not allowed", reason=( - "Project leads can't be given permissions. " + "Project administrators can't be given permissions. " "They already have full access to the project." ), ) diff --git a/backend/capellacollab/projects/users/models.py b/backend/capellacollab/projects/users/models.py index 8a76509b3..fd2ccd743 100644 --- a/backend/capellacollab/projects/users/models.py +++ b/backend/capellacollab/projects/users/models.py @@ -5,6 +5,7 @@ import enum import typing as t +import pydantic import sqlalchemy as sa from sqlalchemy import orm @@ -35,7 +36,13 @@ class ProjectUser(core_pydantic.BaseModel): class PostProjectUser(core_pydantic.BaseModel): - role: ProjectUserRole + role: ProjectUserRole = pydantic.Field( + description=( + "The role of the user in the project. " + "Can be 'user' or 'manager'. Manager is also referred " + "to as project administrator in the documentation." + ) + ) permission: ProjectUserPermission username: str reason: str diff --git a/backend/capellacollab/projects/users/routes.py b/backend/capellacollab/projects/users/routes.py index 80a6f2280..771c5dd30 100644 --- a/backend/capellacollab/projects/users/routes.py +++ b/backend/capellacollab/projects/users/routes.py @@ -225,7 +225,7 @@ def update_project_user( ], ) def remove_user_from_project( - reason: str = fastapi.Body(), + reason: str = fastapi.Body(media_type="text/plain"), project: projects_models.DatabaseProject = fastapi.Depends( projects_injectables.get_existing_project ), diff --git a/backend/capellacollab/settings/modelsources/git/exceptions.py b/backend/capellacollab/settings/modelsources/git/exceptions.py index d664cf9c9..dcf656a6a 100644 --- a/backend/capellacollab/settings/modelsources/git/exceptions.py +++ b/backend/capellacollab/settings/modelsources/git/exceptions.py @@ -13,7 +13,7 @@ def __init__(self): title="Error while accessing the Git repository", reason=( "There was an error accessing the model. " - "Please ask your project lead for more information. " + "Please ask your project administrator for more information. " "In most cases, the credentials need to be updated." ), err_code="GIT_REPOSITORY_ACCESS_ERROR", diff --git a/docs/docs/development/docs.md b/docs/docs/development/docs.md index c85cd53ac..0ee5eed23 100644 --- a/docs/docs/development/docs.md +++ b/docs/docs/development/docs.md @@ -101,7 +101,7 @@ subsections: /admin - Administrator documentation + System Administrator documentation For System administrators and businesses, who are interested in administering their own instances. diff --git a/docs/docs/user/projects/access/index.md b/docs/docs/user/projects/access/index.md index ded3996bf..10426026c 100644 --- a/docs/docs/user/projects/access/index.md +++ b/docs/docs/user/projects/access/index.md @@ -5,13 +5,13 @@ # How do I Get Access to a Project? -Please ask a [project lead](../roles.md) of the specific project for access. -The project lead can add you as user to the project. After you've been added, -you should have direct access. If you don't see the project yet, just reload -the page with `F5`. +Please ask a [project administrator](../roles.md) of the specific project for +access. The project administrator can add you as user to the project. After +you've been added, you should have direct access. If you don't see the project +yet, just reload the page with `F5`. -Before a project lead can add you to a project, you have to log in once. The -first login automatically registers your user in the database. +Before a project administrator can add you to a project, you have to log in +once. The first login automatically registers your user in the database. Your project manager can find more information here: [Add a user to a project](../add-user/index.md) diff --git a/docs/docs/user/projects/add-user/index.md b/docs/docs/user/projects/add-user/index.md index 59ee75d57..f8c57448d 100644 --- a/docs/docs/user/projects/add-user/index.md +++ b/docs/docs/user/projects/add-user/index.md @@ -5,7 +5,7 @@ !!! warning - You need to have the Administrator or Project Lead role for a + You need to have the administrator or project administrator role for a project to perform the following steps. ## Add User to Project @@ -37,7 +37,8 @@ You can select from the following options: - Remove a user from the project - - Set role of the user to [project lead](../../projects/roles.md) or + - Set role of the user to + [project administrator](../../projects/roles.md) or [user](../../projects/roles.md) - Set permission of the user to [read/write](../../sessions/types/index.md) or diff --git a/docs/docs/user/projects/create/index.md b/docs/docs/user/projects/create/index.md index 06794312b..416a14f94 100644 --- a/docs/docs/user/projects/create/index.md +++ b/docs/docs/user/projects/create/index.md @@ -7,8 +7,9 @@ In the Collaboration Manager, you can follow a guided process to create projects. Any user can create a project. After creation, you get the role -[project lead](../../projects/roles.md) for the project. To create a project, -go to the _Projects_ tab of the navigation bar, and click on _Add new project_. +[project administrator](../../projects/roles.md) for the project. To create a +project, go to the _Projects_ tab of the navigation bar, and click on _Add new +project_. Please follow the steps: @@ -21,9 +22,9 @@ changed! Additionally, you may want to add a description. ## Step 2: Add Team Members -This page allows to manage the project user. By default, you are project lead -of the project. If you don't want to add an additional user, you can skip this -step. Users can be added later at any time. +This page allows to manage the project user. By default, you are project +administrator of the project. If you don't want to add an additional user, you +can skip this step. Users can be added later at any time. ![Step 2: Team members](./step-2.png) diff --git a/docs/docs/user/projects/models/backups/remove.md b/docs/docs/user/projects/models/backups/remove.md index 2613b6e8f..ae67038df 100644 --- a/docs/docs/user/projects/models/backups/remove.md +++ b/docs/docs/user/projects/models/backups/remove.md @@ -7,7 +7,7 @@ !!! warning - Only administrators and project leads can remove pipelines. + Only global administrators and project administrators can remove pipelines. 1. Select the project in the `Projects` overview. 1. In the model overview, select the `Synchronize`-button diff --git a/docs/docs/user/projects/models/backups/setup.md b/docs/docs/user/projects/models/backups/setup.md index f8b2b7f18..79367b5f2 100644 --- a/docs/docs/user/projects/models/backups/setup.md +++ b/docs/docs/user/projects/models/backups/setup.md @@ -7,7 +7,7 @@ !!! warning - You need to have the Administrator or Project Lead role for a + You need to have the global administrator or project administrator role for a project to perform the following steps. !!! danger diff --git a/docs/docs/user/projects/models/complexity_badge.md b/docs/docs/user/projects/models/complexity_badge.md index 601508950..4f500d88d 100644 --- a/docs/docs/user/projects/models/complexity_badge.md +++ b/docs/docs/user/projects/models/complexity_badge.md @@ -13,7 +13,7 @@ - A file called `model-complexity-badge.svg` has to exist in the repository. We provide a Gitlab CI template and a Github action to generate the file. Find more information below. - - Only project leads can set up the model complexity badge. In addition, one needs access to the Git repository of the model. + - Only project administrators can set up the model complexity badge. In addition, one needs access to the Git repository of the model. 1. To set up the model complexity badge, you need to add the Git API URL to your Git instance. More information diff --git a/docs/docs/user/projects/models/create.md b/docs/docs/user/projects/models/create.md index c34031b62..7ec160d7c 100644 --- a/docs/docs/user/projects/models/create.md +++ b/docs/docs/user/projects/models/create.md @@ -6,9 +6,9 @@ # Create a _Collaboration Manager_ Model We offer a guided process to create models in a project. To create a model, you -have to be at least [project lead](../../projects/roles.md). If you're coming -from project creation, you're ready to go. Otherwise, please navigate to the -_Projects_ tab of the navigation bar, open the project in which you want to +have to be at least [project administrator](../../projects/roles.md). If you're +coming from project creation, you're ready to go. Otherwise, please navigate to +the _Projects_ tab of the navigation bar, open the project in which you want to create a model, and click on the “+” icon. The creation can be interrupted at any step, however an unfinished model will @@ -30,14 +30,15 @@ following options: 1. Create a new **Git** repository. This option is not supported yet. Please create the repository yourself and continue with the first option. 1. Link a **TeamForCapella** repository. Only available for the `Capella` tool. - If you're project lead and not administrator, you are not able to select - this option. You'll need assistance by an administrator. You can abort the - process here and continue with the help of an administrator later on. + If you're project administrator and not global administrator, you are not + able to select this option. You'll need assistance by an administrator. You + can abort the process here and continue with the help of an administrator + later on. 1. Create a **TeamForCapella** repository. Only available for the `Capella` - tool. If you're project lead and not administrator, you are not able to - select this option. You'll need assistance by an administrator. You can - abort the process here and continue with the help of an administrator later - on. + tool. If you're project administrator and not global administrator, you are + not able to select this option. You'll need assistance by an administrator. + You can abort the process here and continue with the help of an + administrator later on. ## Step 3: Add Source @@ -84,7 +85,7 @@ You have to enter the following information: The credentials should be scoped and should only work for the required repository. When changing the repository URL and the credentials are not - changed, other project leads can gain access to different repositories + changed, other project administrators can gain access to different repositories with your token. ### Step 3.2 Link Existing T4C Repository diff --git a/docs/docs/user/projects/roles.md b/docs/docs/user/projects/roles.md index f85778f6d..4f80e6027 100644 --- a/docs/docs/user/projects/roles.md +++ b/docs/docs/user/projects/roles.md @@ -11,7 +11,7 @@ Projects are self-managed. There are different roles for this: Permissions - `Administrator` + `Global Administrator` :material-check-all: All permissions
:material-check: Manage TeamForCapella instances
@@ -19,7 +19,7 @@ Projects are self-managed. There are different roles for this: :material-check: Manage Git repositories - `Project lead` + `Project administrator` :material-check: Manage users of a project
:material-check: Manage model sources
diff --git a/docs/docs/user/sessions/troubleshooting/index.md b/docs/docs/user/sessions/troubleshooting/index.md index 790761509..d905b2a8c 100644 --- a/docs/docs/user/sessions/troubleshooting/index.md +++ b/docs/docs/user/sessions/troubleshooting/index.md @@ -42,12 +42,12 @@ This happens if the loading of one of the models fails. - Please reach out your project lead. If you are project lead, please check + Please reach out your project administrator. If you are project administrator, please check the primary Git models with a matching tool version of your project. These are used for the `read-only` session. Common mistakes are wrong credentials, wrong entrypoints (e.g. with typos) and missing `aird`-files. - If you have no success, please reach out your administrator. Administrators + If you have no success, please reach out your global administrator. They can see the logs of read-only sessions. diff --git a/docs/docs/user/tools/capella/troubleshooting/index.md b/docs/docs/user/tools/capella/troubleshooting/index.md index f48e95abf..4a84c88ce 100644 --- a/docs/docs/user/tools/capella/troubleshooting/index.md +++ b/docs/docs/user/tools/capella/troubleshooting/index.md @@ -15,7 +15,7 @@ reported to the Eclipse Capella team directly in the [Github repository](https://github.com/eclipse/capella/issues). - Administrators can see the logs of all sessions to identify the issues + Global administrators can see the logs of all sessions to identify the issues remotely. In addition, the session owner can also see the events in the UI. In your session, please follow these steps: diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index c626b4ff4..cf7e91495 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -72,7 +72,7 @@ nav: - api/swagger.md - api/redoc.md - api/openapi.md - - Administrator Documentation: + - System Administrator Documentation: - Introduction: admin/index.md - Installation: admin/installation.md - Authentication: diff --git a/frontend/src/app/helpers/input-dialog/input-dialog.component.html b/frontend/src/app/helpers/input-dialog/input-dialog.component.html index ac3f64313..b99b4656e 100644 --- a/frontend/src/app/helpers/input-dialog/input-dialog.component.html +++ b/frontend/src/app/helpers/input-dialog/input-dialog.component.html @@ -5,7 +5,7 @@
-

{{ data.title }}

+

{{ data.title }}

{{ data.text }}

diff --git a/frontend/src/app/openapi/api/projects-models-git.service.ts b/frontend/src/app/openapi/api/projects-models-git.service.ts index 9a74a5beb..0e60953f6 100644 --- a/frontend/src/app/openapi/api/projects-models-git.service.ts +++ b/frontend/src/app/openapi/api/projects-models-git.service.ts @@ -557,7 +557,7 @@ export class ProjectsModelsGitService { // to determine the Content-Type header const consumes: string[] = [ - 'application/json' + 'text/plain' ]; const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); if (httpContentTypeSelected !== undefined) { diff --git a/frontend/src/app/openapi/api/projects.service.ts b/frontend/src/app/openapi/api/projects.service.ts index 73b986089..b370f8a25 100644 --- a/frontend/src/app/openapi/api/projects.service.ts +++ b/frontend/src/app/openapi/api/projects.service.ts @@ -758,7 +758,7 @@ export class ProjectsService { // to determine the Content-Type header const consumes: string[] = [ - 'application/json' + 'text/plain' ]; const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); if (httpContentTypeSelected !== undefined) { diff --git a/frontend/src/app/openapi/model/post-project-user.ts b/frontend/src/app/openapi/model/post-project-user.ts index b1f7f7b6f..4cf9da321 100644 --- a/frontend/src/app/openapi/model/post-project-user.ts +++ b/frontend/src/app/openapi/model/post-project-user.ts @@ -14,6 +14,9 @@ import { ProjectUserPermission } from './project-user-permission'; export interface PostProjectUser { + /** + * The role of the user in the project. Can be \'user\' or \'manager\'. Manager is also referred to as project administrator in the documentation. + */ role: ProjectUserRole; permission: ProjectUserPermission; username: string; diff --git a/frontend/src/app/projects/project-detail/model-overview/model-complexity-badge/model-complexity-badge.component.html b/frontend/src/app/projects/project-detail/model-overview/model-complexity-badge/model-complexity-badge.component.html index da2238230..bba205df9 100644 --- a/frontend/src/app/projects/project-detail/model-overview/model-complexity-badge/model-complexity-badge.component.html +++ b/frontend/src/app/projects/project-detail/model-overview/model-complexity-badge/model-complexity-badge.component.html @@ -50,7 +50,7 @@ Error loading the complexity badge.
{{ errorMessage || - "Please ask your project lead or administrator for help." + "Please ask your project administrator or global administrator for help." }}
diff --git a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.html b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.html index f41ef4bcf..ea3183d4c 100644 --- a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.html +++ b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.html @@ -4,7 +4,7 @@ -->
-
+

Models

@if (projectUserService.verifyRole("manager")) { Models } }
-
-
-
+
+ @if ((modelService.models$ | async) === undefined) { + @for (card of [0, 1, 2]; track $index) { -
-
- -
+ } + } + @for (model of modelService.models$ | async; track model.id) {
-
-
- {{ model.name }} +
+
+
+ {{ model.name }} +
+ + {{ model.tool.name }} + @if (model.version) { + {{ model.version.name }} + } @else { + (Version not specified) + } +
- - {{ model.tool.name }} - {{ model.version.name }} - (Version not specified) - -
-
-
-
-
Nature
-
- {{ model.nature.name }} +
+
+
+
Nature
+ + @if (model.nature) { + {{ model.nature.name }} + } @else { + Not specified + } +
-
Not specified
-
-
-
-
Working mode
-
- {{ getPrimaryWorkingMode(model) }} +
+
+
Working mode
+
+ {{ getPrimaryWorkingMode(model) }} +
-
-
-
- {{ model.description || "This model has no description." }} -
-
- -
-
- - settings - - - key - - - - link - - - sync - - - open_in_new - - +
+ {{ model.description || "This model has no description." }} +
+
+ @if (model.tool.name === "Capella") { + + } +
+
+ @if (userService.user?.role === "administrator") { + + key + + } + @if (projectUserService.verifyRole("manager")) { + + settings + + + + link + + @if (!project?.is_archived && project?.type !== "training") { + + sync + + } + } + + @if (model.git_models) { + + open_in_new + + @if (model.tool.name === "Capella") { + + } + } + + @if ( !project?.is_archived && - project?.type !== 'training' && + project?.type !== "training" && model.t4c_models && - projectUserService.verifyPermission('write') - " - > - screen_share - - - + projectUserService.verifyPermission("write") + ) { + + screen_share + + } +
-
+ }
diff --git a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts index e9c79897c..c9aa24b30 100644 --- a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts +++ b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf, NgFor, AsyncPipe } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { MatAnchor, @@ -44,8 +44,6 @@ import { ModelComplexityBadgeComponent } from './model-complexity-badge/model-co MatTooltip, MatIcon, MatButton, - NgIf, - NgFor, NgxSkeletonLoaderModule, ModelComplexityBadgeComponent, MatMiniFabAnchor, diff --git a/frontend/src/app/projects/project-detail/model-overview/model-overview.stories.ts b/frontend/src/app/projects/project-detail/model-overview/model-overview.stories.ts new file mode 100644 index 000000000..2305b695e --- /dev/null +++ b/frontend/src/app/projects/project-detail/model-overview/model-overview.stories.ts @@ -0,0 +1,105 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { ModelWrapperService } from 'src/app/projects/models/service/model.service'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; +import { UserWrapperService } from 'src/app/services/user/user.service'; +import { mockModel, MockModelWrapperService } from 'src/storybook/model'; +import { MockProjectUserService } from 'src/storybook/project-users'; +import { mockUser, MockUserService } from 'src/storybook/user'; +import { ModelOverviewComponent } from './model-overview.component'; + +const meta: Meta = { + title: 'Model Components / Model Overview', + component: ModelOverviewComponent, +}; + +export default meta; +type Story = StoryObj; + +export const Loading: Story = { + args: {}, +}; + +export const Overview: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ModelWrapperService, + useFactory: () => + new MockModelWrapperService(mockModel, [ + { ...mockModel, name: 'mockModel1' }, + { + ...mockModel, + name: 'mockModel2', + description: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + }, + { + ...mockModel, + name: 'ModelWithMissingInfo', + version: null, + nature: null, + }, + { + ...mockModel, + name: 'Capella model', + tool: { ...mockModel.tool, name: 'Capella' }, + }, + ]), + }, + ], + }), + ], +}; + +export const AsProjectAdmin: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ModelWrapperService, + useFactory: () => + new MockModelWrapperService(mockModel, [ + { ...mockModel, name: 'mockModel1' }, + ]), + }, + { + provide: ProjectUserService, + useFactory: () => new MockProjectUserService('manager', 'write'), + }, + ], + }), + ], +}; + +export const AsGlobalAdmin: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ModelWrapperService, + useFactory: () => + new MockModelWrapperService(mockModel, [ + { ...mockModel, name: 'mockModel1' }, + ]), + }, + { + provide: ProjectUserService, + useFactory: () => new MockProjectUserService('manager', 'write'), + }, + { + provide: UserWrapperService, + useFactory: () => + new MockUserService({ ...mockUser, role: 'administrator' }), + }, + ], + }), + ], +}; diff --git a/frontend/src/app/projects/project-detail/project-details.component.html b/frontend/src/app/projects/project-detail/project-details.component.html index 70fbdedbf..9ff2654a6 100644 --- a/frontend/src/app/projects/project-detail/project-details.component.html +++ b/frontend/src/app/projects/project-detail/project-details.component.html @@ -3,15 +3,15 @@ ~ SPDX-License-Identifier: Apache-2.0 --> -
+
-
+
-
+ @if (projectUserService.verifyRole("manager")) { -
+ }
diff --git a/frontend/src/app/projects/project-detail/project-details.stories.ts b/frontend/src/app/projects/project-detail/project-details.stories.ts new file mode 100644 index 000000000..a2b7fe528 --- /dev/null +++ b/frontend/src/app/projects/project-detail/project-details.stories.ts @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; +import { MockProjectUserService } from 'src/storybook/project-users'; +import { ProjectDetailsComponent } from './project-details.component'; + +const meta: Meta = { + title: 'Project Components / Project Details', + component: ProjectDetailsComponent, + parameters: { + chromatic: { viewports: [1920] }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Loading: Story = { + args: {}, +}; + +export const LoadingAsProjectLead: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ProjectUserService, + useFactory: () => new MockProjectUserService('manager'), + }, + ], + }), + ], +}; diff --git a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.component.html b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.component.html index 2afdc9eda..a05e983c8 100644 --- a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.component.html +++ b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.component.html @@ -4,9 +4,9 @@ -->
-

Project Information

+

Project Information

@if (project !== undefined) {
diff --git a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.docs.mdx b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.docs.mdx index b95fe4c51..30679b3a0 100644 --- a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.docs.mdx +++ b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.docs.mdx @@ -20,7 +20,7 @@ While loading the project, it looks the same for all users: A "normal" project user can see the title and description: -Project leads have the option to modify some settings: +Project Administrators have the option to modify some settings: This is how an archived projects looks like for normal users: diff --git a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.stories.ts b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.stories.ts index 23002d28f..f55b0a932 100644 --- a/frontend/src/app/projects/project-detail/project-metadata/project-metadata.stories.ts +++ b/frontend/src/app/projects/project-detail/project-metadata/project-metadata.stories.ts @@ -3,26 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; -import { - ProjectUserRole, - ProjectUserService, -} from 'src/app/projects/project-detail/project-users/service/project-user.service'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; import { mockProject } from 'src/storybook/project'; +import { MockProjectUserService } from 'src/storybook/project-users'; import { ProjectMetadataComponent } from './project-metadata.component'; -class MockProjectUserService implements Partial { - user: ProjectUserRole; - - constructor(user: ProjectUserRole) { - this.user = user; - } - - verifyRole(requiredRole: ProjectUserRole): boolean { - const roles = ['user', 'manager', 'administrator']; - return roles.indexOf(requiredRole) <= roles.indexOf(this.user); - } -} - const meta: Meta = { title: 'Project Components / Project Metadata', component: ProjectMetadataComponent, diff --git a/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.html b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.html index 6eab0af77..e8862821d 100644 --- a/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.html +++ b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.html @@ -4,58 +4,53 @@ -->
-

Add user

+

Add User to Project

Username - - Please enter a username! - - - Usernames can only contain lowercase letters! - - - The user is already a member of this project! - + @if (username.getError("required")) { + Please enter a username! + } @else if (username.getError("lowerCaseError")) { + Usernames can only contain lowercase letters! + } @else if (username.getError("userAlreadyInProjectError")) { + The user is already a member of this project! + }
- - Role - - {{ role.value }} - - You have to select a role! - -
- - Permission - - {{ permission.value }} - - You have to select a permission! - +
+ Role:
+ + @for (role of roles | keyvalue; track role.key) { + {{ + role.value + }} + } +
+ + @if (addUserToProjectForm.value.role !== "manager") { +
+ Permission:
+ + @for (permission of permissions | keyvalue; track permission.key) { + {{ + permission.value + }} + } + +
+ } Reason - - Please enter a reason! - + @if (addUserToProjectForm.controls.reason.errors?.required) { + Please enter a reason! + }
- +
diff --git a/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.ts b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.ts index 47d02bb59..19ea90e12 100644 --- a/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.ts +++ b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf, NgFor, KeyValuePipe } from '@angular/common'; +import { KeyValuePipe } from '@angular/common'; import { Component, Inject } from '@angular/core'; import { AbstractControl, @@ -21,10 +21,11 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatFormField, MatLabel, MatError } from '@angular/material/form-field'; import { MatIcon } from '@angular/material/icon'; import { MatInput } from '@angular/material/input'; +import { MatRadioModule } from '@angular/material/radio'; import { MatSelect } from '@angular/material/select'; import { Observable, map, take } from 'rxjs'; import { ToastService } from 'src/app/helpers/toast/toast.service'; -import { Project } from 'src/app/openapi'; +import { Project, ProjectUserPermission } from 'src/app/openapi'; import { ProjectUserService, SimpleProjectUserRole, @@ -41,10 +42,9 @@ import { MatFormField, MatLabel, MatInput, - NgIf, + MatRadioModule, MatError, MatSelect, - NgFor, MatOption, MatButton, MatIcon, @@ -58,8 +58,8 @@ export class AddUserToProjectDialogComponent { validators: [Validators.required], asyncValidators: [this.asyncUserAlreadyInProjectValidator()], }), - role: new FormControl('', Validators.required), - permission: new FormControl(''), + role: new FormControl('user', Validators.required), + permission: new FormControl('read'), reason: new FormControl('', Validators.required), }, this.permissionRequiredValidator(), @@ -72,6 +72,14 @@ export class AddUserToProjectDialogComponent { @Inject(MAT_DIALOG_DATA) public data: { project: Project }, ) {} + get permissions() { + return ProjectUserService.PERMISSIONS; + } + + get roles() { + return ProjectUserService.ROLES; + } + asyncUserAlreadyInProjectValidator(): AsyncValidatorFn { return (control: AbstractControl): Observable => { return this.projectUserService.projectUsers$.pipe( @@ -97,7 +105,7 @@ export class AddUserToProjectDialogComponent { const permission = control.get('permission')!; const role = control.get('role'); if ( - permission?.value in this.projectUserService.PERMISSIONS || + permission?.value in ProjectUserService.PERMISSIONS || role?.value == 'manager' ) { permission?.setErrors(null); @@ -119,7 +127,7 @@ export class AddUserToProjectDialogComponent { this.data.project.slug, formValue.username as string, formValue.role as SimpleProjectUserRole, - permission as string, + permission as ProjectUserPermission, formValue.reason as string, ) .subscribe(() => { @@ -128,8 +136,12 @@ export class AddUserToProjectDialogComponent { `User added`, `User '${formValue.username}' has been added to project '${this.data.project.name}'`, ); - this.matDialogRef.close(); + this.close(); }); } } + + close(): void { + this.matDialogRef.close(); + } } diff --git a/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.stories.ts b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.stories.ts new file mode 100644 index 000000000..d8ddbbd35 --- /dev/null +++ b/frontend/src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.stories.ts @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { dialogWrapper } from 'src/storybook/decorators'; +import { mockProject } from 'src/storybook/project'; +import { AddUserToProjectDialogComponent } from './add-user-to-project.component'; + +const meta: Meta = { + title: 'Project Components / Add User', + component: AddUserToProjectDialogComponent, + decorators: [dialogWrapper], +}; + +export default meta; +type Story = StoryObj; + +export const Dialog: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MAT_DIALOG_DATA, + useValue: { + project: mockProject, + }, + }, + ], + }), + ], +}; diff --git a/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.html b/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.html index d4f7ab4cd..ee5d77e77 100644 --- a/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.html +++ b/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.html @@ -3,24 +3,12 @@ ~ SPDX-License-Identifier: Apache-2.0 --> -
-

Project Members

-
-
-
- -
+@if (!isInProjectCreation()) { +

Project Members

+} -

New members

- -
+
+
+ @if (!isInProjectCreation()) { + + }
-

Current members

Current members search
-
+ @for (role of ["manager", "user", "administrator"]; track role) {
- {{ capitalizeFirstLetter(role) }} + @switch (role) { + @case ("manager") { + Project Administrator + } + @case ("administrator") { + Global Administrator + } + @case ("user") { + Project User + } + }
-
- -
- account_circle -
-
-
{{ user.user.name }}
-
- {{ projectUserService.ADVANCED_ROLES[user.role] }}, - {{ projectUserService.PERMISSIONS[user.permission] }} + @for ( + user of getProjectUsersByRole( + projectUserService.projectUsers$ | async, + role + ); + track user.user.id + ) { + - -
- - - - -
- - +
+
{{ user.user.name }}
+
+ {{ advanced_roles[user.role] }}, + {{ permissions[user.permission] }} +
+
+ +
+ @if (user.role === "user") { + @if (user.permission === "read") { + + } @else { + + } + } + @if (user.role === "user") { + + } @else if (user.role === "manager") { + + } + @if (user.role !== "administrator") { + + }
-
-
+ } + @if ((projectUserService.projectUsers$ | async) === undefined) { Current members border: '1px solid white', }" > -
-
+ } + }
diff --git a/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.ts b/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.ts index 8eaf04fa5..ce86a799d 100644 --- a/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.ts +++ b/frontend/src/app/projects/project-detail/project-users/project-user-settings.component.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf, NgFor, AsyncPipe } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatButton, MatIconButton } from '@angular/material/button'; @@ -25,14 +25,15 @@ import { InputDialogResult, } from 'src/app/helpers/input-dialog/input-dialog.component'; import { ToastService } from 'src/app/helpers/toast/toast.service'; -import { Project, User } from 'src/app/openapi'; -import { AddUserToProjectDialogComponent } from 'src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component'; -import { ProjectAuditLogComponent } from 'src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component'; import { + Project, ProjectUser, ProjectUserPermission, - ProjectUserService, -} from 'src/app/projects/project-detail/project-users/service/project-user.service'; + User, +} from 'src/app/openapi'; +import { AddUserToProjectDialogComponent } from 'src/app/projects/project-detail/project-users/add-user-to-project/add-user-to-project.component'; +import { ProjectAuditLogComponent } from 'src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; import { UserWrapperService } from 'src/app/services/user/user.service'; import { ProjectWrapperService } from '../../service/project.service'; @@ -42,7 +43,6 @@ import { ProjectWrapperService } from '../../service/project.service'; templateUrl: './project-user-settings.component.html', standalone: true, imports: [ - NgIf, MatButton, MatIcon, MatDivider, @@ -51,7 +51,6 @@ import { ProjectWrapperService } from '../../service/project.service'; MatInput, FormsModule, MatSuffix, - NgFor, RouterLink, MatIconButton, MatTooltip, @@ -81,6 +80,14 @@ export class ProjectUserSettingsComponent implements OnInit { }); } + get permissions() { + return ProjectUserService.PERMISSIONS; + } + + get advanced_roles() { + return ProjectUserService.ADVANCED_ROLES; + } + removeUserFromProject(user: User): void { if (!this.project) { return; @@ -166,7 +173,7 @@ export class ProjectUserSettingsComponent implements OnInit { next: () => this.toastService.showSuccess( `User modified`, - `User '${user.name}' is no longer project lead in the project '${projectName}'`, + `User '${user.name}' is no longer project administrator in the project '${projectName}'`, ), }); } @@ -217,6 +224,7 @@ export class ProjectUserSettingsComponent implements OnInit { if (projectUsers === undefined || projectUsers === null) { return undefined; } + return projectUsers?.filter( (pUser) => pUser.role == role && @@ -224,10 +232,6 @@ export class ProjectUserSettingsComponent implements OnInit { ); } - capitalizeFirstLetter(role: string) { - return role.charAt(0).toUpperCase() + role.slice(1); - } - openAddUserDialog() { this.dialog.open(AddUserToProjectDialogComponent, { data: { project: this.project }, @@ -244,7 +248,11 @@ export class ProjectUserSettingsComponent implements OnInit { }); } - hasRoute(route: string) { + hasRoute(route: string): boolean { return this.router.url.includes(route); } + + isInProjectCreation(): boolean { + return this.hasRoute('projects/create'); + } } diff --git a/frontend/src/app/projects/project-detail/project-users/project-user-settings.stories.ts b/frontend/src/app/projects/project-detail/project-users/project-user-settings.stories.ts new file mode 100644 index 000000000..1fcc2964b --- /dev/null +++ b/frontend/src/app/projects/project-detail/project-users/project-user-settings.stories.ts @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; +import { MockProjectUserService } from 'src/storybook/project-users'; +import { mockUser } from 'src/storybook/user'; +import { ProjectUserSettingsComponent } from './project-user-settings.component'; + +const meta: Meta = { + title: 'Project Components / Project Users', + component: ProjectUserSettingsComponent, +}; + +export default meta; +type Story = StoryObj; + +export const Loading: Story = { + args: {}, +}; + +export const Overview: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ProjectUserService, + useFactory: () => + new MockProjectUserService('user', undefined, [ + { + role: 'administrator', + permission: 'write', + user: { ...mockUser, name: 'administrator1' }, + }, + { + role: 'administrator', + permission: 'write', + user: { ...mockUser, name: 'administrator2' }, + }, + { + role: 'user', + permission: 'write', + user: { ...mockUser, name: 'projectuser1' }, + }, + { + role: 'user', + permission: 'read', + user: { ...mockUser, name: 'projectuser2' }, + }, + { + role: 'manager', + permission: 'write', + user: { ...mockUser, name: 'projectadmin1' }, + }, + ]), + }, + ], + }), + ], +}; diff --git a/frontend/src/app/projects/project-detail/project-users/service/project-user.service.ts b/frontend/src/app/projects/project-detail/project-users/service/project-user.service.ts index a2db1a9f8..8e9522004 100644 --- a/frontend/src/app/projects/project-detail/project-users/service/project-user.service.ts +++ b/frontend/src/app/projects/project-detail/project-users/service/project-user.service.ts @@ -2,7 +2,6 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { BehaviorSubject, @@ -13,28 +12,33 @@ import { switchMap, tap, } from 'rxjs'; -import { User } from 'src/app/openapi'; +import { + ProjectsService, + ProjectUser, + ProjectUserPermission, + ProjectUserRole, +} from 'src/app/openapi'; import { ProjectWrapperService } from 'src/app/projects/service/project.service'; -import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root', }) export class ProjectUserService { constructor( - private http: HttpClient, - private projectService: ProjectWrapperService, + private projectWrapperService: ProjectWrapperService, + private projectsService: ProjectsService, ) { this.resetProjectUserOnProjectReset(); this.resetProjectUsersOnProjectReset(); this.loadProjectUsersOnProjectChange(); this.loadProjectUserOnProjectChange(); } - BACKEND_URL_PREFIX = environment.backend_url + '/projects'; - - PERMISSIONS = { read: 'read only', write: 'read & write' }; - ROLES = { user: 'User', manager: 'Manager' }; - ADVANCED_ROLES = { administrator: 'Administrator', ...this.ROLES }; + static PERMISSIONS = { read: 'Read only', write: 'Read & Write' }; + static ROLES = { user: 'User', manager: 'Project Administrator' }; + static ADVANCED_ROLES = { + administrator: 'Administrator', + ...ProjectUserService.ROLES, + }; private _projectUser = new BehaviorSubject( undefined, @@ -56,8 +60,8 @@ export class ProjectUserService { ), ); - resetProjectUserOnProjectReset() { - this.projectService.project$ + private resetProjectUserOnProjectReset() { + this.projectWrapperService.project$ .pipe( filter((project) => project === undefined), tap(() => { @@ -67,8 +71,8 @@ export class ProjectUserService { .subscribe(); } - resetProjectUsersOnProjectReset() { - this.projectService.project$ + private resetProjectUsersOnProjectReset() { + this.projectWrapperService.project$ .pipe( filter((project) => project === undefined), tap(() => { @@ -102,13 +106,11 @@ export class ProjectUserService { loadProjectUserOnProjectChange(): void { this._projectUser.next(undefined); - this.projectService.project$ + this.projectWrapperService.project$ .pipe( filter(Boolean), switchMap((project) => - this.http.get( - `${this.BACKEND_URL_PREFIX}/${project.slug}/users/current`, - ), + this.projectsService.getCurrentProjectUser(project.slug), ), ) .pipe( @@ -122,7 +124,7 @@ export class ProjectUserService { loadProjectUsersOnProjectChange(): void { this._projectUsers.next(undefined); combineLatest([ - this.projectService.project$.pipe(filter(Boolean)), + this.projectWrapperService.project$.pipe(filter(Boolean)), this.projectUser$.pipe( filter( (projectUser) => @@ -139,8 +141,8 @@ export class ProjectUserService { loadProjectUsers(projectSlug: string): void { this._projectUsers.next(undefined); - this.http - .get(`${this.BACKEND_URL_PREFIX}/${projectSlug}/users`) + this.projectsService + .getUsersForProject(projectSlug) .pipe( tap((projectUsers) => { this._projectUsers.next(projectUsers); @@ -153,11 +155,11 @@ export class ProjectUserService { projectSlug: string, username: string, role: SimpleProjectUserRole, - permission: string, + permission: ProjectUserPermission, reason: string, ): Observable { - return this.http - .post(`${this.BACKEND_URL_PREFIX}/${projectSlug}/users`, { + return this.projectsService + .addUserToProject(projectSlug, { username, role, permission, @@ -176,14 +178,11 @@ export class ProjectUserService { role: SimpleProjectUserRole, reason: string, ): Observable { - return this.http - .patch( - `${this.BACKEND_URL_PREFIX}/${projectSlug}/users/${userID}`, - { - role, - reason, - }, - ) + return this.projectsService + .updateProjectUser(projectSlug, userID, { + role, + reason, + }) .pipe(tap(() => this.loadProjectUsers(projectSlug))); } @@ -193,10 +192,10 @@ export class ProjectUserService { permission: ProjectUserPermission, reason: string, ): Observable { - return this.http.patch( - `${this.BACKEND_URL_PREFIX}/${projectSlug}/users/${userID}`, - { permission, reason }, - ); + return this.projectsService.updateProjectUser(projectSlug, userID, { + permission, + reason, + }); } deleteUserFromProject( @@ -204,20 +203,12 @@ export class ProjectUserService { userID: number, reason: string, ): Observable { - return this.http.delete( - `${this.BACKEND_URL_PREFIX}/${projectSlug}/users/${userID}`, - { body: reason }, + return this.projectsService.removeUserFromProject( + projectSlug, + userID, + reason, ); } } -export interface ProjectUser { - project_name: string; - permission: ProjectUserPermission; - role: ProjectUserRole; - user: User; -} - -export type ProjectUserPermission = 'read' | 'write'; -export type ProjectUserRole = 'user' | 'manager' | 'administrator'; export type SimpleProjectUserRole = 'user' | 'manager'; diff --git a/frontend/src/app/projects/project-overview/project-overview.component.html b/frontend/src/app/projects/project-overview/project-overview.component.html index fba8577b1..d1860b701 100644 --- a/frontend/src/app/projects/project-overview/project-overview.component.html +++ b/frontend/src/app/projects/project-overview/project-overview.component.html @@ -64,7 +64,7 @@ }}
- {{ project.users.leads }} project lead(s), + {{ project.users.leads }} project admin(s), {{ project.users.contributors }} contributor(s), {{ project.users.subscribers }} subscriber(s) diff --git a/frontend/src/app/sessions/user-sessions-wrapper/create-session/create-readonly-session/create-readonly-session.component.html b/frontend/src/app/sessions/user-sessions-wrapper/create-session/create-readonly-session/create-readonly-session.component.html index bb6c13b95..6b2696745 100644 --- a/frontend/src/app/sessions/user-sessions-wrapper/create-session/create-readonly-session/create-readonly-session.component.html +++ b/frontend/src/app/sessions/user-sessions-wrapper/create-session/create-readonly-session/create-readonly-session.component.html @@ -3,8 +3,8 @@ ~ SPDX-License-Identifier: Apache-2.0 -->
-

Read-only Sessions

-
+

Read-only Sessions

+

Start a read-only session. Select the tool and the version. We'll show diff --git a/frontend/src/app/sessions/user-sessions-wrapper/create-sessions/create-readonly-session/create-readonly-session-dialog.component.html b/frontend/src/app/sessions/user-sessions-wrapper/create-sessions/create-readonly-session/create-readonly-session-dialog.component.html index e9accea91..51a16a918 100644 --- a/frontend/src/app/sessions/user-sessions-wrapper/create-sessions/create-readonly-session/create-readonly-session-dialog.component.html +++ b/frontend/src/app/sessions/user-sessions-wrapper/create-sessions/create-readonly-session/create-readonly-session-dialog.component.html @@ -51,8 +51,8 @@

Open Read-Only Session


} @empty {
- No models have read-only session support. Please contact your - administrator or project lead. + No models have read-only session support. Please contact your global + administrator or project administrator.
} diff --git a/frontend/src/app/settings/core/user-settings/user-settings.component.html b/frontend/src/app/settings/core/user-settings/user-settings.component.html index 20bba48ac..45d5949c0 100644 --- a/frontend/src/app/settings/core/user-settings/user-settings.component.html +++ b/frontend/src/app/settings/core/user-settings/user-settings.component.html @@ -30,7 +30,7 @@

Manage Users

{{ user.name }}
- {{ projectUserService.ADVANCED_ROLES[user.role] }} + {{ advanced_roles[user.role] }}
@@ -60,7 +60,7 @@

Manage Users

{{ user.name }}
- {{ projectUserService.ADVANCED_ROLES[user.role] }} + {{ advanced_roles[user.role] }}
diff --git a/frontend/src/app/settings/core/user-settings/user-settings.component.ts b/frontend/src/app/settings/core/user-settings/user-settings.component.ts index e735866c4..7880f4035 100644 --- a/frontend/src/app/settings/core/user-settings/user-settings.component.ts +++ b/frontend/src/app/settings/core/user-settings/user-settings.component.ts @@ -95,6 +95,10 @@ export class UserSettingsComponent implements OnInit { return this.createUserFormGroup.controls.idpIdentifier; } + get advanced_roles() { + return ProjectUserService.ADVANCED_ROLES; + } + userNameAlreadyExistsValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { if (this.users.find((user) => user.name == control.value)) { diff --git a/frontend/src/storybook/decorators.ts b/frontend/src/storybook/decorators.ts index ab6171420..c981e1cf9 100644 --- a/frontend/src/storybook/decorators.ts +++ b/frontend/src/storybook/decorators.ts @@ -5,5 +5,6 @@ import { componentWrapperDecorator } from '@storybook/angular'; export const dialogWrapper = componentWrapperDecorator( - (story) => `
${story}
`, + (story) => + `
${story}
`, ); diff --git a/frontend/src/storybook/project-users.ts b/frontend/src/storybook/project-users.ts new file mode 100644 index 000000000..508f9c91b --- /dev/null +++ b/frontend/src/storybook/project-users.ts @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { BehaviorSubject } from 'rxjs'; +import { + ProjectUser, + ProjectUserPermission, + ProjectUserRole, +} from 'src/app/openapi'; +import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; + +export class MockProjectUserService implements Partial { + role: ProjectUserRole; + permission: ProjectUserPermission | undefined; + + private _projectUsers = new BehaviorSubject( + undefined, + ); + public readonly projectUsers$ = this._projectUsers.asObservable(); + + constructor( + role: ProjectUserRole, + permission: ProjectUserPermission | undefined = undefined, + projectUsers: ProjectUser[] | undefined = undefined, + ) { + this.role = role; + this.permission = permission; + this._projectUsers.next(projectUsers); + } + + verifyRole(requiredRole: ProjectUserRole): boolean { + const roles = ['user', 'manager', 'administrator']; + return roles.indexOf(requiredRole) <= roles.indexOf(this.role); + } + + verifyPermission(requiredPermission: string): boolean { + if (this.permission === undefined) return false; + const permissions = ['read', 'write']; + return ( + permissions.indexOf(requiredPermission) <= + permissions.indexOf(this.permission) + ); + } +}