From 0910006dc196b3e3fa38cb9d8de8a691e691269e Mon Sep 17 00:00:00 2001 From: Tobias Messner Date: Thu, 12 Sep 2024 15:06:29 +0200 Subject: [PATCH 1/2] chore: More migration to new Angular control flow --- .../create-project.component.css | 4 - .../create-project.component.html | 98 ++-- .../create-project.component.ts | 4 +- .../create-project/create-project.stories.ts | 82 ++++ .../init-model/init-model.component.css | 4 - .../init-model/init-model.component.html | 99 ++-- .../models/init-model/init-model.component.ts | 6 +- .../models/init-model/init-model.stories.ts | 49 ++ .../edit-project-metadata.component.css | 4 - .../edit-project-metadata.component.html | 25 +- .../edit-project-metadata.component.ts | 4 +- .../edit-project-metadata.stories.ts | 28 ++ .../project-details.component.css | 12 - .../project-details.component.ts | 3 - .../project-audit-log.component.html | 9 +- .../project-audit-log.component.ts | 4 +- .../project-audit-log.stories.ts | 128 +++++ .../project-user-settings.stories.ts | 34 +- .../create-readonly-session.component.html | 2 +- .../pipelines-overview.component.html | 457 ++++++++++-------- .../pipelines-overview.component.ts | 3 +- .../pipelines-overview.stories.ts | 118 +++++ frontend/src/storybook/monitoring.ts | 104 ++++ frontend/src/storybook/project-users.ts | 29 ++ frontend/src/storybook/project.ts | 28 +- 25 files changed, 938 insertions(+), 400 deletions(-) delete mode 100644 frontend/src/app/projects/create-project/create-project.component.css create mode 100644 frontend/src/app/projects/create-project/create-project.stories.ts delete mode 100644 frontend/src/app/projects/models/init-model/init-model.component.css create mode 100644 frontend/src/app/projects/models/init-model/init-model.stories.ts delete mode 100644 frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.css create mode 100644 frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.stories.ts delete mode 100644 frontend/src/app/projects/project-detail/project-details.component.css create mode 100644 frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts create mode 100644 frontend/src/app/settings/core/pipelines-overview/pipelines-overview.stories.ts create mode 100644 frontend/src/storybook/monitoring.ts diff --git a/frontend/src/app/projects/create-project/create-project.component.css b/frontend/src/app/projects/create-project/create-project.component.css deleted file mode 100644 index 8535c6938a..0000000000 --- a/frontend/src/app/projects/create-project/create-project.component.css +++ /dev/null @@ -1,4 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/frontend/src/app/projects/create-project/create-project.component.html b/frontend/src/app/projects/create-project/create-project.component.html index 2f9a82c0cc..e835217a5a 100644 --- a/frontend/src/app/projects/create-project/create-project.component.html +++ b/frontend/src/app/projects/create-project/create-project.component.html @@ -25,14 +25,15 @@

Create new project

formControlName="name" data-testId="input-name" /> - - A project with a name similar to “{{ - form.controls.name.errors!.uniqueSlug.value - }}” already exists. - - - A project name is required. - + @if (form.controls.name.errors?.uniqueSlug) { + + A project with a name similar to “{{ + form.controls.name.errors!.uniqueSlug.value + }}” already exists. + + } @else if (form.controls.name.errors?.required) { + A project name is required. + }
@@ -93,39 +94,40 @@

Create new project

(Optional) Add team members

-
- -
-
-
-
-
- +
+
+
+
+
+ - + @if ( + projectUserService.nonAdminProjectUsers$ | async; + as users + ) { + {{ + !users || users.length === 0 ? "Skip for now" : "Continue" + }} + } + navigate_next + +
+
-
-
+ } @@ -156,20 +158,14 @@

[color]="getColorByModelCreationStep()" data-testId="a-skipModelAndFinishProjectCreation" > - - Abort model creation and finish - - - Abort model creation and finish - - - Finish project creation - + @if (modelCreationStep === "create-model") { + Abort model creation and finish + } @else if (modelCreationStep === "complete") { + Finish project creation + } @else { + Abort model creation and finish + } + check diff --git a/frontend/src/app/projects/create-project/create-project.component.ts b/frontend/src/app/projects/create-project/create-project.component.ts index bd64c45583..422c3b409e 100644 --- a/frontend/src/app/projects/create-project/create-project.component.ts +++ b/frontend/src/app/projects/create-project/create-project.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 { NgFor, AsyncPipe } from '@angular/common'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormControl, @@ -32,7 +32,6 @@ import { ProjectWrapperService } from '../service/project.service'; @Component({ selector: 'app-create-project', templateUrl: './create-project.component.html', - styleUrls: ['./create-project.component.css'], standalone: true, imports: [ MatStepper, @@ -43,7 +42,6 @@ import { ProjectWrapperService } from '../service/project.service'; MatFormField, MatLabel, MatInput, - NgIf, MatError, MatRadioGroup, NgFor, diff --git a/frontend/src/app/projects/create-project/create-project.stories.ts b/frontend/src/app/projects/create-project/create-project.stories.ts new file mode 100644 index 0000000000..901151d65c --- /dev/null +++ b/frontend/src/app/projects/create-project/create-project.stories.ts @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { userEvent, within } from '@storybook/test'; +import { + mockProject, + MockProjectWrapperService, +} from '../../../storybook/project'; +import { + mockProjectUsers, + MockProjectUserService, +} from '../../../storybook/project-users'; +import { ProjectUserService } from '../project-detail/project-users/service/project-user.service'; +import { ProjectWrapperService } from '../service/project.service'; +import { CreateProjectComponent } from './create-project.component'; + +const meta: Meta = { + title: 'Project Components / Create Project', + component: CreateProjectComponent, +}; + +export default meta; +type Story = StoryObj; + +export const CreateProject: Story = { + args: {}, +}; + +export const AddTeamMembers: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ProjectWrapperService, + useFactory: () => + new MockProjectWrapperService(mockProject, [mockProject]), + }, + { + provide: ProjectUserService, + useFactory: () => + new MockProjectUserService('user', undefined, mockProjectUsers), + }, + ], + }), + ], + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const nameField = canvas.getByTestId('input-name'); + await userEvent.type(nameField, 'Test Project'); + const createProject = canvas.getByTestId('button-create-project'); + await userEvent.click(createProject); + }, +}; + +export const AddModel: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ProjectWrapperService, + useFactory: () => + new MockProjectWrapperService(mockProject, [mockProject]), + }, + { + provide: ProjectUserService, + useFactory: () => + new MockProjectUserService('user', undefined, mockProjectUsers), + }, + ], + }), + ], + play: async (context) => { + const canvas = within(context.canvasElement); + await AddTeamMembers.play!(context); + const skipMembers = canvas.getByTestId('button-skipAddMembers'); + await userEvent.click(skipMembers); + }, +}; diff --git a/frontend/src/app/projects/models/init-model/init-model.component.css b/frontend/src/app/projects/models/init-model/init-model.component.css deleted file mode 100644 index 8535c6938a..0000000000 --- a/frontend/src/app/projects/models/init-model/init-model.component.css +++ /dev/null @@ -1,4 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/frontend/src/app/projects/models/init-model/init-model.component.html b/frontend/src/app/projects/models/init-model/init-model.component.html index 71d81b9be2..a50efb9bfa 100644 --- a/frontend/src/app/projects/models/init-model/init-model.component.html +++ b/frontend/src/app/projects/models/init-model/init-model.component.html @@ -4,53 +4,56 @@ -->
-
-
- - Modelling tool - - - - Version - - - {{ version.name }} - (recommended) - (deprecated) - - - - - Model nature - - - {{ nature.name }} - - - -
-
- + @if (modelService.model$ | async) { +
+
+ + Modelling tool + + + + Version + + + {{ version.name }} + @if (version.config.is_recommended) { + (recommended) + } + @if (version.config.is_deprecated) { + (deprecated) + } + + + + + Model nature + + + {{ nature.name }} + + + +
+
+ +
-
+ }
diff --git a/frontend/src/app/projects/models/init-model/init-model.component.ts b/frontend/src/app/projects/models/init-model/init-model.component.ts index 9668d8d686..2457d78c4b 100644 --- a/frontend/src/app/projects/models/init-model/init-model.component.ts +++ b/frontend/src/app/projects/models/init-model/init-model.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 { NgFor, AsyncPipe } from '@angular/common'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormControl, @@ -27,17 +27,14 @@ import { Tool, } from 'src/app/openapi'; import { ModelWrapperService } from 'src/app/projects/models/service/model.service'; -import { GitModelService } from '../../project-detail/model-overview/model-detail/git-model.service'; import { ProjectWrapperService } from '../../service/project.service'; @UntilDestroy() @Component({ selector: 'app-init-model', templateUrl: './init-model.component.html', - styleUrls: ['./init-model.component.css'], standalone: true, imports: [ - NgIf, FormsModule, ReactiveFormsModule, MatFormField, @@ -65,7 +62,6 @@ export class InitModelComponent implements OnInit { constructor( public projectService: ProjectWrapperService, public modelService: ModelWrapperService, - public gitModelService: GitModelService, private toolsService: ToolsService, ) {} diff --git a/frontend/src/app/projects/models/init-model/init-model.stories.ts b/frontend/src/app/projects/models/init-model/init-model.stories.ts new file mode 100644 index 0000000000..c2ca1a529d --- /dev/null +++ b/frontend/src/app/projects/models/init-model/init-model.stories.ts @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { + mockModel, + MockModelWrapperService, +} from '../../../../storybook/model'; +import { + mockProject, + MockProjectWrapperService, +} from '../../../../storybook/project'; +import { ProjectWrapperService } from '../../service/project.service'; +import { ModelWrapperService } from '../service/model.service'; +import { InitModelComponent } from './init-model.component'; + +const meta: Meta = { + title: 'Model Components/Init Model', + component: InitModelComponent, +}; + +export default meta; +type Story = StoryObj; + +export const General: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: ModelWrapperService, + useFactory: () => new MockModelWrapperService(mockModel, []), + }, + { + provide: ProjectWrapperService, + useFactory: () => + new MockProjectWrapperService(undefined, [ + { + ...mockProject, + name: 'Internal project', + visibility: 'internal', + }, + ]), + }, + ], + }), + ], +}; diff --git a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.css b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.css deleted file mode 100644 index 8535c6938a..0000000000 --- a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.css +++ /dev/null @@ -1,4 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.html b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.html index c6cdc9ca28..ab528ae535 100644 --- a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.html +++ b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.html @@ -8,19 +8,18 @@
Name - - The project name is required. - A project with a similar name already exists. - If you proceed, the project slug will be changed to - {{ newSlug }} - Please make sure to update all - references. + + @if (form.controls.name.errors?.required) { + The project name is required. + } @else if (form.controls.name.errors?.uniqueSlug) { + A project with a similar name already exists. + } @else if (project?.slug !== newSlug && form.controls.name.valid) { + If you proceed, the project slug will be changed to + {{ newSlug }} - Please make sure to update all + references. + }
diff --git a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.ts b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.ts index fa2afa34a8..cb9993ea4b 100644 --- a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.ts +++ b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf, NgFor } from '@angular/common'; +import { NgFor } from '@angular/common'; import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { FormControl, @@ -34,7 +34,6 @@ import { ProjectWrapperService } from '../../service/project.service'; @Component({ selector: 'app-edit-project-metadata', templateUrl: './edit-project-metadata.component.html', - styleUrls: ['./edit-project-metadata.component.css'], standalone: true, imports: [ FormsModule, @@ -42,7 +41,6 @@ import { ProjectWrapperService } from '../../service/project.service'; MatFormField, MatLabel, MatInput, - NgIf, MatError, MatHint, MatRadioGroup, diff --git a/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.stories.ts b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.stories.ts new file mode 100644 index 0000000000..fc5f339932 --- /dev/null +++ b/frontend/src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.stories.ts @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, StoryObj } from '@storybook/angular'; +import { userEvent, within } from '@storybook/test'; +import { EditProjectMetadataComponent } from './edit-project-metadata.component'; + +const meta: Meta = { + title: 'Project Components/Project Details/Edit Project Metadata', + component: EditProjectMetadataComponent, +}; + +export default meta; +type Story = StoryObj; + +export const General: Story = { + args: {}, +}; + +export const WithTitle: Story = { + args: {}, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const nameInput = canvas.getByTestId('name-input'); + await userEvent.type(nameInput, 'Name'); + }, +}; diff --git a/frontend/src/app/projects/project-detail/project-details.component.css b/frontend/src/app/projects/project-detail/project-details.component.css deleted file mode 100644 index c355968ae2..0000000000 --- a/frontend/src/app/projects/project-detail/project-details.component.css +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -#title { - margin-left: 10px; -} - -.metadata-item { - flex-basis: 50%; -} diff --git a/frontend/src/app/projects/project-detail/project-details.component.ts b/frontend/src/app/projects/project-detail/project-details.component.ts index fc0ce26c00..e2c74ac5a6 100644 --- a/frontend/src/app/projects/project-detail/project-details.component.ts +++ b/frontend/src/app/projects/project-detail/project-details.component.ts @@ -2,7 +2,6 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf } from '@angular/common'; import { Component } from '@angular/core'; import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; import { CreateReadonlySessionComponent } from '../../sessions/user-sessions-wrapper/create-session/create-readonly-session/create-readonly-session.component'; @@ -14,13 +13,11 @@ import { ProjectUserSettingsComponent } from './project-users/project-user-setti @Component({ selector: 'app-project-details', templateUrl: './project-details.component.html', - styleUrls: ['./project-details.component.css'], standalone: true, imports: [ ProjectMetadataComponent, CreateReadonlySessionComponent, ModelOverviewComponent, - NgIf, ProjectUserSettingsComponent, ], }) diff --git a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.html b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.html index 23b74a327e..dc421e2b69 100644 --- a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.html +++ b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.html @@ -25,16 +25,15 @@ let idx = index " > - + @if (event === undefined || event === "loading") { - + - - + } @else { @@ -57,7 +56,7 @@ - + }
diff --git a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.ts b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.ts index e59c9c20b6..a2cb7dc8c3 100644 --- a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.ts +++ b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.component.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgFor, NgIf, AsyncPipe, DatePipe } from '@angular/common'; +import { NgFor, AsyncPipe, DatePipe } from '@angular/common'; import { AfterViewInit, Component, @@ -22,7 +22,7 @@ import { TextLineSkeletonLoaderComponent } from '../../../../helpers/skeleton-lo templateUrl: './project-audit-log.component.html', styleUrls: ['./project-audit-log.component.css'], standalone: true, - imports: [NgFor, NgIf, TextLineSkeletonLoaderComponent, AsyncPipe, DatePipe], + imports: [NgFor, TextLineSkeletonLoaderComponent, AsyncPipe, DatePipe], }) @UntilDestroy() export class ProjectAuditLogComponent implements OnInit, AfterViewInit { diff --git a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts new file mode 100644 index 0000000000..10320bbf9c --- /dev/null +++ b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts @@ -0,0 +1,128 @@ +/* + * 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 { BehaviorSubject } from 'rxjs'; +import { dialogWrapper } from '../../../../../storybook/decorators'; +import { mockProject } from '../../../../../storybook/project'; +import { mockUser } from '../../../../../storybook/user'; +import { EventType, HistoryEvent } from '../../../../openapi'; +import { Page, PageWrapper } from '../../../../schemes'; +import { ProjectAuditLogComponent } from './project-audit-log.component'; +import { ProjectAuditLogService } from './service/project-audit-log.service'; + +const meta: Meta = { + title: 'Project Components / Audit Log', + component: ProjectAuditLogComponent, +}; + +export default meta; +type Story = StoryObj; + +const mockHistoryEvents: Page = { + items: [ + { + id: 1, + execution_time: new Date(2024, 1, 1).toISOString(), + event_type: EventType.CreatedUser, + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Another Test Reason', + }, + { + id: 2, + execution_time: new Date(2024, 1, 1).toISOString(), + event_type: EventType.AssignedProjectPermissionReadOnly, + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Test Reason', + }, + { + id: 3, + execution_time: new Date(2024, 1, 1).toISOString(), + event_type: EventType.CreatedUser, + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Test Reason', + }, + { + id: 4, + execution_time: new Date(2024, 1, 1).toISOString(), + event_type: EventType.RemovedFromProject, + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Test Reason', + }, + { + id: 5, + execution_time: new Date(2024, 1, 1).toISOString(), + event_type: EventType.AddedToProject, + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Test Reason', + }, + ], + total: 5, + page: 1, + size: 5, + pages: 1, +}; + +class MockProjectAuditLogService implements Partial { + private _projectHistoryEventPages = new BehaviorSubject< + PageWrapper + >({ + pages: [mockHistoryEvents], + total: 1, + }); + public readonly projectHistoryEventsPages$ = + this._projectHistoryEventPages.asObservable(); + + constructor(historyEvents: Page) { + this._projectHistoryEventPages.next({ + pages: [historyEvents], + total: 1, + }); + } +} + +export const Loading: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MAT_DIALOG_DATA, + useValue: [], + }, + ], + }), + dialogWrapper, + ], +}; + +export const General: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MAT_DIALOG_DATA, + useValue: [], + }, + { + provide: ProjectAuditLogService, + useFactory: () => new MockProjectAuditLogService(mockHistoryEvents), + }, + ], + }), + dialogWrapper, + ], +}; 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 index d279c4771a..a7f62b439c 100644 --- 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 @@ -4,8 +4,10 @@ */ 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 { + mockProjectUsers, + MockProjectUserService, +} from 'src/storybook/project-users'; import { ProjectUserSettingsComponent } from './project-user-settings.component'; const meta: Meta = { @@ -28,33 +30,7 @@ export const Overview: Story = { { 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: 'projectuserWithReallyLongName' }, - }, - { - role: 'manager', - permission: 'write', - user: { ...mockUser, name: 'projectadmin1' }, - }, - ]), + new MockProjectUserService('user', undefined, mockProjectUsers), }, ], }), 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 6b26967451..4b1e0b6269 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,7 +3,7 @@ ~ SPDX-License-Identifier: Apache-2.0 -->
-

Read-only Sessions

+

Read-only Sessions

diff --git a/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.html b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.html index 56ebfc9c1c..75f70e9817 100644 --- a/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.html +++ b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.html @@ -5,234 +5,275 @@

General monitoring

- -
-
- check Guacamole is - alive -
-
- error Guacamole is not - alive -
-
- check The database is - alive -
-
- error The database is - not alive -
-
- check The Kubernetes - operator is alive -
-
- error The Kubernetes - operator is not alive -
-
-
- -

Projects Monitoring

-
- -
-
- Project
- {{ projectStatus.project_slug }} - open_in_new -
- warning - {{ warning }} -
-
- check - All checks were successful. -
-
-
-
- -

Models monitoring

- -
-
- Loading the monitoring overview can take up to one minute. -
+ @if (!generalHealth) { -
-
-
- Project
- {{ modelStatus.project_slug }} - open_in_new - Model
- {{ modelStatus.model_slug }} open_in_new -
- -
- check The primary - linked Git repository is accessible -
-
- settings No Git - repository is linked to this model -
-
- error The primary - linked Git repository is not accessible + } @else { +
+ @if (generalHealth.guacamole) { +
+ check Guacamole is + alive
-
-
- -
- check Last backup - has status '{{ modelStatus.pipeline_status }}'' -
-
- sync Last backup - has status '{{ modelStatus.pipeline_status }}'' -
-
- error Last backup - has status '{{ modelStatus.pipeline_status }}'' + } @else { +
+ error Guacamole is + not alive
-
- settings No last - backup pipeline run has been found. -
-
-
- -
- check The last - model badge update was successful + } + + @if (generalHealth.database) { +
+ check The database + is alive
-
- error The last - model badge update or fetching has failed + } @else { +
+ error The database + is not alive
-
- settings - No model badge configured + } + + @if (generalHealth.operator) { +
+ check The + Kubernetes operator is alive
-
- settings - The model badge is currently not supported for the linked Git - instance. + } @else { +
+ error The + Kubernetes operator is not alive
-
+ } +
+ } +
+ +

Projects Monitoring

+
+ @if (!projectStatuses) { + + } @else { + @for (projectStatus of projectStatuses; track projectStatus.project_slug) {
-
- check Last diagram - cache update was successful -
-
- error Last diagram - cache update or fetching has failed -
-
- settings - No diagram cache configured -
-
- settings - The diagram cache is currently not supported for the linked Git server - instance + Project
+ {{ projectStatus.project_slug }} + open_in_new + @for (warning of projectStatus.warnings; track warning) { +
+ warning + {{ warning }} +
+ } @empty { +
+ check + All checks were successful. +
+ }
+ } + } +
+ +

Models monitoring

+
+ @if (!toolmodelStatuses) { +
+ Loading the monitoring overview can take up to one minute. +
+ +
+ } @else { + @for (modelStatus of toolmodelStatuses; track $index) {
- -
- warning - {{ warning }} +
+ Project
+ {{ modelStatus.project_slug }} + open_in_new + Model
+ {{ modelStatus.model_slug }} + open_in_new +
+ + @switch (modelStatus.primary_git_repository_status) { + @case ("accessible") { +
+ check The + primary linked Git repository is accessible +
+ } + @case ("unset") { +
+ settings No + Git repository is linked to this model +
+ } + @case ("inaccessible") { +
+ error The + primary linked Git repository is not accessible +
+ } + } +
+
+ + @if (modelStatus.pipeline_status === "success") { +
+ check Last + backup has status '{{ modelStatus.pipeline_status }}'' +
+ } @else if ( + modelStatus.pipeline_status === "pending" || + modelStatus.pipeline_status === "scheduled" || + modelStatus.pipeline_status === "running" + ) { +
+ sync Last + backup has status '{{ modelStatus.pipeline_status }}'' +
+ } @else if ( + modelStatus.pipeline_status === "timeout" || + modelStatus.pipeline_status === "failure" || + modelStatus.pipeline_status === "unknown" + ) { +
+ error Last + backup has status '{{ modelStatus.pipeline_status }}'' +
+ } @else if (modelStatus.pipeline_status === null) { +
+ settings No + last backup pipeline run has been found. +
+ } +
+
+ + @switch (modelStatus.model_badge_status) { + @case ("success") { +
+ check The + last model badge update was successful +
+ } + @case ("failure") { +
+ error The + last model badge update or fetching has failed +
+ } + @case ("unconfigured") { +
+ settings + No model badge configured +
+ } + @case ("unsupported") { +
+ settings + The model badge is currently not supported for the linked Git + instance. +
+ } + } +
+
+ + @switch (modelStatus.diagram_cache_status) { + @case ("success") { +
+ check Last + diagram cache update was successful +
+ } + @case ("failure") { +
+ error Last + diagram cache update or fetching has failed +
+ } + @case ("unconfigured") { +
+ settings + No diagram cache configured +
+ } + @case ("unsupported") { +
+ settings + The diagram cache is currently not supported for the linked + Git server instance +
+ } + } +
+ +
+ + @for (warning of modelStatus.warnings; track $index) { +
+ warning + {{ warning }} +
+ } +
-
-
+ } + }
diff --git a/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.ts b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.ts index d2916d6ba1..cde639c7eb 100644 --- a/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.ts +++ b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.component.ts @@ -2,7 +2,6 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { NgIf, NgFor } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { MatIcon } from '@angular/material/icon'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -18,7 +17,7 @@ import { templateUrl: './pipelines-overview.component.html', styleUrls: ['./pipelines-overview.component.css'], standalone: true, - imports: [NgIf, NgxSkeletonLoaderModule, MatIcon, NgFor], + imports: [NgxSkeletonLoaderModule, MatIcon], }) export class PipelinesOverviewComponent implements OnInit { constructor(private monitoringService: MonitoringService) {} diff --git a/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.stories.ts b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.stories.ts new file mode 100644 index 0000000000..936b6be293 --- /dev/null +++ b/frontend/src/app/settings/core/pipelines-overview/pipelines-overview.stories.ts @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { + mockGeneralHealthBad, + mockGeneralHealthGood, + mockProjectStatusesBad, + mockProjectStatusesGood, + mockToolmodelStatusesBad, + mockToolmodelStatusesGood, +} from '../../../../storybook/monitoring'; +import { PipelinesOverviewComponent } from './pipelines-overview.component'; +import { + GeneralHealth, + MonitoringService, + ProjectStatus, + ToolmodelStatus, +} from './service/monitoring.service'; + +const meta: Meta = { + title: 'Settings Components/Pipelines Overview', + component: PipelinesOverviewComponent, +}; + +export default meta; +type Story = StoryObj; + +class MockMonitoringService { + private _generalHealth = new BehaviorSubject( + undefined, + ); + private _toolmodelStatuses = new BehaviorSubject< + ToolmodelStatus[] | undefined + >(undefined); + private _projectStatuses = new BehaviorSubject( + undefined, + ); + + public readonly generalHealth$ = this._generalHealth.asObservable(); + public readonly toolmodelStatuses$ = this._toolmodelStatuses.asObservable(); + public readonly projectStatuses$ = this._projectStatuses.asObservable(); + + constructor( + generalHealth: GeneralHealth | undefined, + toolmodelStatuses: ToolmodelStatus[] | undefined, + projectStatuses: ProjectStatus[] | undefined, + ) { + this._generalHealth.next(generalHealth); + this._toolmodelStatuses.next(toolmodelStatuses); + this._projectStatuses.next(projectStatuses); + } + + fetchGeneralHealth(): Observable { + return this.generalHealth$; + } + + fetchModelHealth(): Observable { + return this.toolmodelStatuses$; + } + + fetchProjectHealth(): Observable { + return this.projectStatuses$; + } +} + +export const Loading: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MonitoringService, + }, + ], + }), + ], +}; + +export const GoodHealth: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MonitoringService, + useFactory: () => + new MockMonitoringService( + mockGeneralHealthGood, + mockToolmodelStatusesGood, + mockProjectStatusesGood, + ), + }, + ], + }), + ], +}; + +export const BadHealth: Story = { + args: {}, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MonitoringService, + useFactory: () => + new MockMonitoringService( + mockGeneralHealthBad, + mockToolmodelStatusesBad, + mockProjectStatusesBad, + ), + }, + ], + }), + ], +}; diff --git a/frontend/src/storybook/monitoring.ts b/frontend/src/storybook/monitoring.ts new file mode 100644 index 0000000000..4f4f08b327 --- /dev/null +++ b/frontend/src/storybook/monitoring.ts @@ -0,0 +1,104 @@ +/* + * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { + GeneralHealth, + ProjectStatus, + ToolmodelStatus, +} from 'src/app/settings/core/pipelines-overview/service/monitoring.service'; + +export const mockGeneralHealthGood: GeneralHealth = { + guacamole: true, + database: true, + operator: true, +}; + +export const mockGeneralHealthBad: GeneralHealth = { + guacamole: false, + database: false, + operator: false, +}; + +export const mockToolmodelStatusesGood: ToolmodelStatus[] = [ + { + model_slug: 'mock-model-1', + project_slug: 'mock-project-1', + diagram_cache_status: 'success', + model_badge_status: 'success', + pipeline_status: 'success', + primary_git_repository_status: 'accessible', + warnings: [], + }, +]; + +export const mockToolmodelStatusesBad: ToolmodelStatus[] = [ + { + model_slug: 'mock-model-1', + project_slug: 'mock-project-1', + diagram_cache_status: 'failure', + model_badge_status: 'failure', + pipeline_status: 'failure', + primary_git_repository_status: 'inaccessible', + warnings: ['Test Warning'], + }, + { + model_slug: 'mock-model-2', + project_slug: 'mock-project-2', + diagram_cache_status: 'unconfigured', + model_badge_status: 'unconfigured', + pipeline_status: 'pending', + primary_git_repository_status: 'unset', + warnings: [], + }, + { + model_slug: 'mock-model-3', + project_slug: 'mock-project-3', + diagram_cache_status: 'unsupported', + model_badge_status: 'unsupported', + pipeline_status: 'running', + primary_git_repository_status: 'accessible', + warnings: [], + }, + { + model_slug: 'mock-model-4', + project_slug: 'mock-project-4', + diagram_cache_status: 'unsupported', + model_badge_status: 'unsupported', + pipeline_status: 'timeout', + primary_git_repository_status: 'accessible', + warnings: [], + }, + { + model_slug: 'mock-model-5', + project_slug: 'mock-project-5', + diagram_cache_status: 'unsupported', + model_badge_status: 'unsupported', + pipeline_status: 'scheduled', + primary_git_repository_status: 'accessible', + warnings: [], + }, + { + model_slug: 'mock-model-6', + project_slug: 'mock-project-6', + diagram_cache_status: 'unsupported', + model_badge_status: 'unsupported', + pipeline_status: 'unknown', + primary_git_repository_status: 'accessible', + warnings: [], + }, +]; + +export const mockProjectStatusesGood: ProjectStatus[] = [ + { + project_slug: 'mock-project-1', + warnings: [], + }, +]; + +export const mockProjectStatusesBad: ProjectStatus[] = [ + { + project_slug: 'mock-project-1', + warnings: ['Test Warning'], + }, +]; diff --git a/frontend/src/storybook/project-users.ts b/frontend/src/storybook/project-users.ts index 508f9c91b4..1ca82d8ea6 100644 --- a/frontend/src/storybook/project-users.ts +++ b/frontend/src/storybook/project-users.ts @@ -9,6 +9,35 @@ import { ProjectUserRole, } from 'src/app/openapi'; import { ProjectUserService } from 'src/app/projects/project-detail/project-users/service/project-user.service'; +import { mockUser } from './user'; + +export const mockProjectUsers: ProjectUser[] = [ + { + 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: 'projectuserWithReallyLongName' }, + }, + { + role: 'manager', + permission: 'write', + user: { ...mockUser, name: 'projectadmin1' }, + }, +]; export class MockProjectUserService implements Partial { role: ProjectUserRole; diff --git a/frontend/src/storybook/project.ts b/frontend/src/storybook/project.ts index 7852ad91f6..18953302fa 100644 --- a/frontend/src/storybook/project.ts +++ b/frontend/src/storybook/project.ts @@ -2,9 +2,13 @@ * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors * SPDX-License-Identifier: Apache-2.0 */ -import { BehaviorSubject } from 'rxjs'; -import { Project } from 'src/app/openapi'; -import { ProjectWrapperService } from 'src/app/projects/service/project.service'; +import { AsyncValidatorFn, ValidationErrors } from '@angular/forms'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { Project, Visibility } from 'src/app/openapi'; +import { + ProjectVisibilityDescriptions, + ProjectWrapperService, +} from 'src/app/projects/service/project.service'; export const mockProject: Readonly = { name: 'mockProject', @@ -34,4 +38,22 @@ export class MockProjectWrapperService this._project.next(project); this._projects.next(projects); } + asyncSlugValidator(): AsyncValidatorFn { + return (): Observable => { + return of(null); + }; + } + getProjectVisibilityDescription(visibility: Visibility): string { + return ProjectVisibilityDescriptions[visibility]; + } + + getAvailableVisibilities(): Visibility[] { + return Object.keys(ProjectVisibilityDescriptions) as Visibility[]; + } + createProject(project: Project): Observable { + return of(project); + } + clearProject(): void { + return; + } } From 7ac0abbe4d7be7e43498f542bb2a660ba23ab3ce Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Wed, 9 Oct 2024 15:52:50 +0200 Subject: [PATCH 2/2] test: Group historyEvents in audit log story --- .../create-project/create-project.stories.ts | 2 +- .../project-audit-log.stories.ts | 66 +++++++------------ 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/frontend/src/app/projects/create-project/create-project.stories.ts b/frontend/src/app/projects/create-project/create-project.stories.ts index 901151d65c..7b1234975b 100644 --- a/frontend/src/app/projects/create-project/create-project.stories.ts +++ b/frontend/src/app/projects/create-project/create-project.stories.ts @@ -17,7 +17,7 @@ import { ProjectWrapperService } from '../service/project.service'; import { CreateProjectComponent } from './create-project.component'; const meta: Meta = { - title: 'Project Components / Create Project', + title: 'Project Components/Create Project', component: CreateProjectComponent, }; diff --git a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts index 10320bbf9c..9331ac930e 100644 --- a/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts +++ b/frontend/src/app/projects/project-detail/project-users/project-audit-log/project-audit-log.stories.ts @@ -14,59 +14,59 @@ import { ProjectAuditLogComponent } from './project-audit-log.component'; import { ProjectAuditLogService } from './service/project-audit-log.service'; const meta: Meta = { - title: 'Project Components / Audit Log', + title: 'Project Components/Audit Log', component: ProjectAuditLogComponent, + decorators: [ + moduleMetadata({ + providers: [ + { + provide: MAT_DIALOG_DATA, + useValue: [], + }, + ], + }), + dialogWrapper, + ], }; export default meta; type Story = StoryObj; +const mockHistoryEventBase = { + execution_time: new Date(2024, 1, 1).toISOString(), + user: mockUser, + executor: mockUser, + project: mockProject, + reason: 'Test Reason', +}; + const mockHistoryEvents: Page = { items: [ { + ...mockHistoryEventBase, id: 1, - execution_time: new Date(2024, 1, 1).toISOString(), event_type: EventType.CreatedUser, - user: mockUser, - executor: mockUser, - project: mockProject, reason: 'Another Test Reason', }, { + ...mockHistoryEventBase, id: 2, - execution_time: new Date(2024, 1, 1).toISOString(), event_type: EventType.AssignedProjectPermissionReadOnly, - user: mockUser, - executor: mockUser, - project: mockProject, - reason: 'Test Reason', }, { + ...mockHistoryEventBase, id: 3, - execution_time: new Date(2024, 1, 1).toISOString(), event_type: EventType.CreatedUser, - user: mockUser, - executor: mockUser, - project: mockProject, - reason: 'Test Reason', }, { + ...mockHistoryEventBase, id: 4, - execution_time: new Date(2024, 1, 1).toISOString(), event_type: EventType.RemovedFromProject, - user: mockUser, - executor: mockUser, - project: mockProject, - reason: 'Test Reason', }, { + ...mockHistoryEventBase, id: 5, - execution_time: new Date(2024, 1, 1).toISOString(), event_type: EventType.AddedToProject, - user: mockUser, - executor: mockUser, - project: mockProject, - reason: 'Test Reason', }, ], total: 5, @@ -95,17 +95,6 @@ class MockProjectAuditLogService implements Partial { export const Loading: Story = { args: {}, - decorators: [ - moduleMetadata({ - providers: [ - { - provide: MAT_DIALOG_DATA, - useValue: [], - }, - ], - }), - dialogWrapper, - ], }; export const General: Story = { @@ -113,16 +102,11 @@ export const General: Story = { decorators: [ moduleMetadata({ providers: [ - { - provide: MAT_DIALOG_DATA, - useValue: [], - }, { provide: ProjectAuditLogService, useFactory: () => new MockProjectAuditLogService(mockHistoryEvents), }, ], }), - dialogWrapper, ], };