From 0c89231291f2bb3903588134cbc92d5dd9e28728 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Mon, 27 May 2024 17:14:14 +0200 Subject: [PATCH 01/44] feature(policy): add policy management view in administration --- .../services/policy-mock/policy.handler.ts | 4 + .../services/policy-mock/policy.model.ts | 105 ++++++++++++------ .../core/user/table-settings.service.ts | 3 + .../app/modules/page/admin/admin.module.ts | 44 ++++---- .../app/modules/page/admin/admin.routing.ts | 9 ++ .../modules/page/admin/core/admin.model.ts | 9 +- .../admin/presentation/admin.component.scss | 3 +- .../admin/presentation/admin.component.ts | 5 + .../policies/policies.facade.ts | 62 +++++++++++ .../policies/policies.state.ts | 35 ++++++ .../page/policies/model/policy.model.ts | 32 ++++-- .../autocomplete-strategy.ts | 21 ++++ .../table-type.model.ts | 3 +- .../policies-configuration.model.ts | 16 +++ .../components/table/table.component.html | 41 ++++++- .../components/table/table.component.ts | 11 ++ .../modules/shared/service/policy.service.ts | 43 +++++++ frontend/src/assets/locales/de/common.json | 8 +- .../src/assets/locales/de/page.admin.json | 3 + frontend/src/assets/locales/en/common.json | 7 +- .../src/assets/locales/en/page.admin.json | 3 + frontend/src/theme/base.scss | 4 +- 22 files changed, 395 insertions(+), 76 deletions(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts create mode 100644 frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts diff --git a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts index a4a019abe6..e85cd30185 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts @@ -24,6 +24,10 @@ export const policyHandler = (_ => { return [ rest.get(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { return res(ctx.status(200), ctx.json(getPolicies())); + }), + + rest.post(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(getPolicies())); }) ] })(); diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index e80e7d4637..9889cd7493 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,3 +1,7 @@ +import { CalendarDateModel } from '@core/model/calendar-date.model'; +import { PaginationResponse } from '@core/model/pagination.model'; +import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; + /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation * @@ -17,36 +21,75 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ // For now Mocks are built by current response (any). This is because Policy Model changes frequently -export const getPolicies = () => [ - { - policyId: "Mocked_Policy_Id", - createdOn: 1706690077.834424001, - validUntil: 1727740799.990000000, - permissions: [ +export const getPolicies = (): PaginationResponse => { + return { + page: 0, + pageCount: 0, + pageSize: 10, + totalItems: 1, + + content: [ { - action: "USE", - constraints: [ + policyId: 'Mocked_Policy_1', + validUntil: new CalendarDateModel('2024-02-26T13:38:07+01:00'), + permissions: [ { - and: [ - { - leftOperand: "PURPOSE", - operatorTypeResponse: "EQ", - rightOperands: [ - "ID 3.0 Trace" - ] - }, - { - leftOperand: "PURPOSE", - operatorTypeResponse: "EQ", - rightOperands: [ - "ID 3.0 Trace" - ] - } - ], - or: [] - } - ] - } - ] - } -] + action: PolicyAction.USE, + constraint: { + and: [ + { + leftOperand: 'PURPOSE', + operator: { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'ID 3.0 Trace', + }, + ], + or: [ + { + leftOperand: 'PURPOSE', + operator: { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'ID 3.0 Trace', + }, + ], + }, + }, + ], + }, + { + policyId: 'Mocked_Policy_2', + validUntil: new CalendarDateModel('2024-02-24T13:38:07+01:00'), + permissions: [ + { + action: PolicyAction.ACCESS, + constraint: { + and: [ + { + leftOperand: 'PURPOSE', + operator: { + '@id': OperatorType.IN, + }, + 'odrl:rightOperand': 'BMW', + }, + ], + or: [ + { + leftOperand: 'PURPOSE', + operator: { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'ID 3.0 Trace', + }, + ], + }, + }, + ], + }, + + ], + + }; +}; + diff --git a/frontend/src/app/modules/core/user/table-settings.service.ts b/frontend/src/app/modules/core/user/table-settings.service.ts index ae3d6b893e..5d4a15bbe4 100644 --- a/frontend/src/app/modules/core/user/table-settings.service.ts +++ b/frontend/src/app/modules/core/user/table-settings.service.ts @@ -23,6 +23,7 @@ import { NotificationsReceivedConfigurationModel } from '@shared/components/part import { NotificationsSentConfigurationModel } from '@shared/components/parts-table/notifications-sent-configuration.model'; import { PartsAsBuiltConfigurationModel } from '@shared/components/parts-table/parts-as-built-configuration.model'; import { PartsAsPlannedConfigurationModel } from '@shared/components/parts-table/parts-as-planned-configuration.model'; +import { PoliciesConfigurationModel } from '@shared/components/parts-table/policies-configuration.model'; import { TableViewConfig } from '@shared/components/parts-table/table-view-config.model'; import { ToastService } from '@shared/components/toasts/toast.service'; import { Subject } from 'rxjs'; @@ -112,6 +113,8 @@ export class TableSettingsService { return new NotificationsSentConfigurationModel().filterConfiguration(); case TableType.RECEIVED_NOTIFICATION: return new NotificationsReceivedConfigurationModel().filterConfiguration(); + case TableType.POLICIES: + return new PoliciesConfigurationModel().filterConfiguration(); } } diff --git a/frontend/src/app/modules/page/admin/admin.module.ts b/frontend/src/app/modules/page/admin/admin.module.ts index d0331225a8..63d888c3ad 100644 --- a/frontend/src/app/modules/page/admin/admin.module.ts +++ b/frontend/src/app/modules/page/admin/admin.module.ts @@ -19,29 +19,33 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import {CommonModule} from '@angular/common'; -import {NgModule} from '@angular/core'; -import {getI18nPageProvider} from '@core/i18n'; -import {AdminFacade} from '@page/admin/core/admin.facade'; -import {AdminService} from '@page/admin/core/admin.service'; -import {ContractDetailComponent} from '@page/admin/presentation/contracts/contract-detail/contract-detail.component'; -import {ContractsComponent} from '@page/admin/presentation/contracts/contracts.component'; -import {ContractsFacade} from '@page/admin/presentation/contracts/contracts.facade'; -import {ContractsState} from '@page/admin/presentation/contracts/contracts.state'; -import {ModalModule} from '@shared/modules/modal/modal.module'; -import {SharedModule} from '@shared/shared.module'; -import {TemplateModule} from '@shared/template.module'; -import {AdminRoutingModule} from './admin.routing'; -import {AdminComponent} from './presentation/admin.component'; -import {BpnConfigurationComponent} from './presentation/bpn-configuration/bpn-configuration.component'; -import {SaveBpnConfigModal} from './presentation/bpn-configuration/save-modal/save-modal.component'; -import {ImportJsonComponent} from './presentation/import-json/import-json.component'; -import {NgxJsonViewerModule} from "ngx-json-viewer"; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { getI18nPageProvider } from '@core/i18n'; +import { AdminFacade } from '@page/admin/core/admin.facade'; +import { AdminService } from '@page/admin/core/admin.service'; +import { ContractDetailComponent } from '@page/admin/presentation/contracts/contract-detail/contract-detail.component'; +import { ContractsComponent } from '@page/admin/presentation/contracts/contracts.component'; +import { ContractsFacade } from '@page/admin/presentation/contracts/contracts.facade'; +import { ContractsState } from '@page/admin/presentation/contracts/contracts.state'; +import { PoliciesComponent } from '@page/admin/presentation/policy-management/policies/policies.component'; +import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; +import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; +import { ModalModule } from '@shared/modules/modal/modal.module'; +import { PolicyService } from '@shared/service/policy.service'; +import { SharedModule } from '@shared/shared.module'; +import { TemplateModule } from '@shared/template.module'; +import { NgxJsonViewerModule } from 'ngx-json-viewer'; +import { AdminRoutingModule } from './admin.routing'; +import { AdminComponent } from './presentation/admin.component'; +import { BpnConfigurationComponent } from './presentation/bpn-configuration/bpn-configuration.component'; +import { SaveBpnConfigModal } from './presentation/bpn-configuration/save-modal/save-modal.component'; +import { ImportJsonComponent } from './presentation/import-json/import-json.component'; @NgModule({ - declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent ], + declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent, PoliciesComponent ], imports: [CommonModule, TemplateModule, SharedModule, AdminRoutingModule, ModalModule, NgxJsonViewerModule], - providers: [ ...getI18nPageProvider('page.admin'), AdminService, AdminFacade, ContractsFacade, ContractsState ], + providers: [ ...getI18nPageProvider('page.admin'), AdminService, AdminFacade, ContractsFacade, ContractsState, PoliciesFacade, PoliciesState, PolicyService ], }) export class AdminModule { } diff --git a/frontend/src/app/modules/page/admin/admin.routing.ts b/frontend/src/app/modules/page/admin/admin.routing.ts index bfa17d45d8..8b9eb1fe42 100644 --- a/frontend/src/app/modules/page/admin/admin.routing.ts +++ b/frontend/src/app/modules/page/admin/admin.routing.ts @@ -27,6 +27,7 @@ import { BpnConfigurationComponent } from '@page/admin/presentation/bpn-configur import { ContractDetailComponent } from '@page/admin/presentation/contracts/contract-detail/contract-detail.component'; import { ContractsComponent } from '@page/admin/presentation/contracts/contracts.component'; import { ImportJsonComponent } from '@page/admin/presentation/import-json/import-json.component'; +import { PoliciesComponent } from '@page/admin/presentation/policy-management/policies/policies.component'; import { I18NEXT_NAMESPACE_RESOLVER } from 'angular-i18next'; export /** @type {*} */ @@ -67,6 +68,14 @@ const ADMIN_ROUTING: Routes = [ resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, canActivate: [ RoleGuard ], }, + { + path: KnownAdminRoutes.POLICY_MANAGEMENT, + pathMatch: 'full', + component: PoliciesComponent, + data: { i18nextNamespaces: [ 'page.admin' ] }, + resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, + canActivate: [ RoleGuard ], + }, ]; @NgModule({ diff --git a/frontend/src/app/modules/page/admin/core/admin.model.ts b/frontend/src/app/modules/page/admin/core/admin.model.ts index 3f2e83e1f1..42536dd88d 100644 --- a/frontend/src/app/modules/page/admin/core/admin.model.ts +++ b/frontend/src/app/modules/page/admin/core/admin.model.ts @@ -20,15 +20,16 @@ ********************************************************************************/ -import {FormArray, FormControl, FormGroup} from '@angular/forms'; -import {CalendarDateModel} from '@core/model/calendar-date.model'; -import {Pagination, PaginationResponse} from '@core/model/pagination.model'; +import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { CalendarDateModel } from '@core/model/calendar-date.model'; +import { Pagination, PaginationResponse } from '@core/model/pagination.model'; export enum KnownAdminRoutes { BPN = 'configure-bpn', IMPORT = 'configure-import', CONTRACT = 'contracts', - CONTRACT_DETAIL_VIEW = 'contracts/:contractId' + CONTRACT_DETAIL_VIEW = 'contracts/:contractId', + POLICY_MANAGEMENT = 'policies', } diff --git a/frontend/src/app/modules/page/admin/presentation/admin.component.scss b/frontend/src/app/modules/page/admin/presentation/admin.component.scss index ad692e9da4..03169a2691 100644 --- a/frontend/src/app/modules/page/admin/presentation/admin.component.scss +++ b/frontend/src/app/modules/page/admin/presentation/admin.component.scss @@ -38,6 +38,7 @@ border: none; overflow: visible; position: relative; + height: 80vh; } .sidenav--item { @@ -82,7 +83,7 @@ .sidenav--toggle-button { position: absolute; - bottom: 30px; + bottom: 40vh; right: -20px; z-index: 1; } diff --git a/frontend/src/app/modules/page/admin/presentation/admin.component.ts b/frontend/src/app/modules/page/admin/presentation/admin.component.ts index cb4a9390eb..d1b049c9f6 100644 --- a/frontend/src/app/modules/page/admin/presentation/admin.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/admin.component.ts @@ -52,6 +52,11 @@ export class AdminComponent { icon: 'assignment_ind', link: '/admin/contracts', }, + { + name: 'routing.adminPolicies', + icon: 'description', + link: '/admin/policies', + }, ]; constructor(router: Router) { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts new file mode 100644 index 0000000000..09712ab752 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -0,0 +1,62 @@ +import { Injectable } from '@angular/core'; +import { Pagination } from '@core/model/pagination.model'; +import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; +import { provideDataObject } from '@page/parts/core/parts.helper'; +import { Policy } from '@page/policies/model/policy.model'; +import { TableHeaderSort } from '@shared/components/table/table.model'; +import { View } from '@shared/model/view.model'; +import { PolicyService } from '@shared/service/policy.service'; +import { Observable, Subject, Subscription } from 'rxjs'; + +@Injectable() +export class PoliciesFacade { + private policiesSubscription: Subscription; + private selectedPoliciesSubscription: Subscription; + private readonly unsubscribeTrigger = new Subject(); + + + constructor(private readonly policyService: PolicyService, + private readonly policiesState: PoliciesState, + ) { + } + + get policies$(): Observable>> { + return this.policiesState.policies$; + } + + public setPolicies(page, pageSize = 50, sorting: TableHeaderSort[]): void { + this.policiesSubscription?.unsubscribe(); + this.policiesSubscription = this.policyService.getPaginatedPolicies(page, pageSize, sorting).subscribe({ + next: data => (this.policiesState.policies = { data: provideDataObject(data) }), + error: error => (this.policiesState.policies = { error }), + }); + } + + get selectedPolicy$(): Observable> { + return this.policiesState.selectedPolicy$; + } + + get selectedPolicy(): Policy { + return this.policiesState.selectedPolicy?.data; + } + + + public set selectedPolicy(policy: Policy) { + this.policiesState.selectedPolicy = { data: policy }; + } + + public setSelectedPolicyById(policyId: string): void { + this.selectedPoliciesSubscription = this.policyService.getPaginatedPolicies(0, 10, [ null, null ], { policyId: [ policyId ] }).subscribe({ + next: data => (this.policiesState.selectedPolicy = { data: data.content[0] as unknown as Policy }), + error: error => (this.policiesState.selectedPolicy = { error }), + }); + } + + + public unsubscribePolicies(): void { + this.policiesSubscription?.unsubscribe(); + this.selectedPoliciesSubscription?.unsubscribe(); + this.unsubscribeTrigger.next(); + } + +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts new file mode 100644 index 0000000000..ef770de1b6 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import { Pagination } from '@core/model/pagination.model'; +import { Policy } from '@page/policies/model/policy.model'; +import { State } from '@shared/model/state'; +import { View } from '@shared/model/view.model'; +import { Observable } from 'rxjs'; + +@Injectable() +export class PoliciesState { + private readonly _policies$ = new State>>({ loader: true }); + private readonly _selectedPolicy$: State> = new State>({ loader: true }); + + public get policies$(): Observable>> { + return this._policies$.observable; + } + + public set policies({ data, loader, error }: View>) { + const policiesView: View> = { data, loader, error }; + this._policies$.update(policiesView); + } + + get selectedPolicy$(): Observable> { + return this._selectedPolicy$.observable; + } + + set selectedPolicy({ data, loader, error }: View) { + const selectedPolicyView: View = { data, loader, error }; + this._selectedPolicy$.update(selectedPolicyView); + } + + get selectedPolicy(): View { + return this._selectedPolicy$.snapshot; + } + +} diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index 1d68e5e0f1..c48040b8b6 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -1,3 +1,5 @@ +import { CalendarDateModel } from '@core/model/calendar-date.model'; + /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation * @@ -20,25 +22,33 @@ // TODO: Align with BE to a first valid Policy Model, changes seem to be happen frequently export interface Policy { policyId: string; - createdOn: string; - validUntil: string; - permissions?: PolicyPermission[]; + validUntil: CalendarDateModel; + permissions: PolicyPermission[]; } export interface PolicyPermission { - action: PolicyType; - constraints?: Constraint[]; + action: PolicyAction; + constraint: Constraint; } -export enum PolicyType { - ACCESS="ACCESS", - USE="USE" +export enum PolicyAction { + ACCESS = 'access', + USE = 'use' } export interface Constraint { - leftOperand: string; - operator: OperatorType; - rightOperand: string[]; + and: PolicyConstraint[], + or: PolicyConstraint[] +} + +export interface PolicyConstraint { + leftOperand: string, + 'odrl:rightOperand': string, + operator: PolicyConstraintOperator +} + +export interface PolicyConstraintOperator { + '@id': OperatorType; } export enum OperatorType { diff --git a/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts b/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts index 15183bcac9..c92c980146 100644 --- a/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts +++ b/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts @@ -21,6 +21,7 @@ import { AdminService } from '@page/admin/core/admin.service'; import { NotificationChannel, TableType } from '@shared/components/multi-select-autocomplete/table-type.model'; import { NotificationService } from '@shared/service/notification.service'; import { PartsService } from '@shared/service/parts.service'; +import { PolicyService } from '@shared/service/policy.service'; import { of } from 'rxjs'; export abstract class AutocompleteStrategy { @@ -94,12 +95,32 @@ export class ContractsStrategy extends AutocompleteStrategy { } } +@Injectable({ + providedIn: 'any', +}) +export class PoliciesStrategy extends AutocompleteStrategy { + policyService: PolicyService; + + constructor(policyService: PolicyService) { + super(); + this.policyService = policyService; + } + + retrieveSuggestionValues(tableType: TableType, filterColumns: string, searchElement: string): any { + return this.policyService.getDistinctFilterValues( + filterColumns, + searchElement, + ); + } +} + export const AutocompleteStrategyMap = new Map([ [ TableType.AS_BUILT_OWN, PartsStrategy ], [ TableType.AS_PLANNED_OWN, PartsStrategy ], [ TableType.RECEIVED_NOTIFICATION, NotificationStrategy ], [ TableType.SENT_NOTIFICATION, NotificationStrategy ], [ TableType.CONTRACTS, ContractsStrategy ], + [ TableType.POLICIES, PoliciesStrategy ], ]); diff --git a/frontend/src/app/modules/shared/components/multi-select-autocomplete/table-type.model.ts b/frontend/src/app/modules/shared/components/multi-select-autocomplete/table-type.model.ts index 27a8a5a6d7..c2c495de62 100644 --- a/frontend/src/app/modules/shared/components/multi-select-autocomplete/table-type.model.ts +++ b/frontend/src/app/modules/shared/components/multi-select-autocomplete/table-type.model.ts @@ -22,7 +22,8 @@ export enum TableType { AS_PLANNED_OWN = 'AS_PLANNED_OWN', RECEIVED_NOTIFICATION = 'RECEIVED_NOTIFICATION', SENT_NOTIFICATION = 'SENT_NOTIFICATION', - CONTRACTS='CONTRACTS' + CONTRACTS = 'CONTRACTS', + POLICIES = 'POLICIES' } export enum NotificationChannel { diff --git a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts new file mode 100644 index 0000000000..1d4586188f --- /dev/null +++ b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts @@ -0,0 +1,16 @@ +import { TableFilterConfiguration } from '@shared/components/parts-table/parts-config.model'; + +export class PoliciesConfigurationModel extends TableFilterConfiguration { + constructor() { + const sortableColumns = { + select: false, + policyId: true, + validUntil: true, + menu: false, + }; + + const dateFields = [ 'validUntil' ]; + const singleSearchFields = []; + super(sortableColumns, dateFields, singleSearchFields, true); + } +} diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index 841eea23b6..f8ce9d85c6 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -27,8 +27,10 @@ settings -
+
+
+ + +
+ +
+
+ + +

{{ tableHeader | i18n }}

-
+

{{ selectedPartsInfoLabel | i18n : {count: selection?.selected?.length || 0} }}

- diff --git a/frontend/src/app/modules/shared/components/table/table.component.ts b/frontend/src/app/modules/shared/components/table/table.component.ts index 5395d40b7b..51fa85a5b1 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.ts +++ b/frontend/src/app/modules/shared/components/table/table.component.ts @@ -60,6 +60,7 @@ export class TableComponent { @ViewChild('tableElement', { read: ElementRef }) tableElementRef: ElementRef; @Input() additionalTableHeader = false; @Input() tableHeaderMenuEnabled = false; + @Input() basicTableHeaderMenuEnabled = false; @Input() set tableConfig(tableConfig: TableConfig) { @@ -380,6 +381,15 @@ export class TableComponent { this.router.navigate([ 'inbox/create' ]); } + // TODO: handle navigation to view and deletion trigger + navigateTo() { + return; + } + + emitDeletionEvent() { + + } + private menuActionsWithAddedDefaultActions(menuActionsConfig: MenuActionConfig[] = []): MenuActionConfig[] { const viewDetailsMenuAction: MenuActionConfig = { label: 'actions.viewDetails', @@ -402,4 +412,5 @@ export class TableComponent { protected readonly MainAspectType = MainAspectType; + } diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 2154cb5f92..03f186b20c 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -1,7 +1,10 @@ +import { HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiService } from '@core/api/api.service'; +import { Pagination } from '@core/model/pagination.model'; import { environment } from '@env'; import { Policy } from '@page/policies/model/policy.model'; +import { TableHeaderSort } from '@shared/components/table/table.model'; import { Observable } from 'rxjs'; @Injectable({ @@ -16,7 +19,47 @@ export class PolicyService { .getBy(`${this.url}/policies`); } + getPaginatedPolicies(page: number, pageSize: number, sorting?: TableHeaderSort[], filter?: any): Observable> { + + const body = { + pageAble: { + page: page, + size: pageSize, + sorting: sorting ? sorting : undefined, + }, + searchCriteria: {}, + }; + + if (filter) { + body.searchCriteria = { filter: this.createFilterList(filter) }; + } + + return this.apiService.post>(`${ this.url }/policies`, body); + } + publishAssets(assetIds: string[],policyId: string) { return this.apiService.post(`${this.url}/assets/publish`, {assetIds, policyId}); } + + + private createFilterList(filter: Object) { + let filterList = []; + Object.entries(filter).forEach(([ entry, values ]) => { + if (values.length) { + values.forEach(value => { + filterList.push(`${ entry },EQUAL,${ value },AND`); + }); + } + }); + return filterList; + } + + getDistinctFilterValues(filterColumns: string, searchElement: string) { + let params = new HttpParams() + .set('fieldName', filterColumns) + .set('startWith', searchElement) + .set('size', 200); + + return this.apiService.getBy(`${ this.url }/policies/distinctFilterValues`, params); + } } diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index 4916cb9200..6becdce202 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -12,6 +12,7 @@ "adminRegistry": "Registry-Abfragen", "adminBpn": "BPN - EDC Konfiguration", "adminImport": "Datenbereitstellung", + "adminPolicies" : "Richtlinienverwaltung", "partMismatch": "Die ausgewählten Teile müssen vom selben Eigentümer sein, um ein Qualitätsthema zu erstellen (Eigen, Lieferant)", "unauthorized": "Die Funktion ist aufgrund einer fehlenden Rolle deaktiviert. Bitten Sie Ihren Administrator, die erforderliche Rolle für die Funktion bereitzustellen.", "notAllowedForAsPlanned": "Diese Funktion ist für Produkte im Lebenszyklus \"AsPlanned\" nicht verfügbar.", @@ -120,6 +121,8 @@ "unauthorized" : "Die Funktion ist aufgrund einer fehlenden Rolle deaktiviert. Bitten Sie Ihren Administrator, die erforderliche Rolle für die Funktion bereitzustellen.", "noFunctionality" : "Funktionalität wurde noch nicht implementiert.", "onlyNotificationInStatusCreatedAllowed" : "Aktion erfordert eine Selektion an Qualitätsthemen im Status \"Erstellt\".", + "createPolicy" : "Richtlinie erstellen", + "deletePolicy" : "Selektierte Richtlinien löschen", "column": { "id": "ID", "idShort": "Kurz-ID", @@ -162,8 +165,9 @@ "importNote": "Importbemerkung", "importDate": "Importdatum", "type": "Typ", - "title": "Titel" - + "title" : "Titel", + "policyId" : "Policy ID", + "validUntil" : "Gültig bis" } }, "dataLoading": { diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 6656742029..c9d4e0f56f 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -55,6 +55,9 @@ "policyDetail": "Richtlinien details", "jsonViewer": "Json Ansicht", "jsonTreeViewer": "Json-Baumansicht" + }, + "policyManagement" : { + "policyManagement" : "Richtlinienverwaltung" } } } diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index de01b0d767..5274af99aa 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -11,6 +11,7 @@ "adminRegistry": "Registry lookups", "adminBpn": "BPN - EDC configuration", "adminImport": "Data provisioning", + "adminPolicies" : "Policy management", "partMismatch": "Selected parts must have same owner to create quality topic (Own, Supplier)", "unauthorized": "Functionality is disabled because of missing role. Ask your administrator to provide the required role for the functionality.", "notAllowedForAsPlanned": "This function is not available for Parts in the Lifecycle \"AsPlanned\".", @@ -117,6 +118,8 @@ "unauthorized" : "Functionality is disabled because of missing role. Ask your administrator to provide the required role for the functionality.", "noFunctionality" : "Functionality is not implemented yet", "onlyNotificationInStatusCreatedAllowed" : "Action only allowed with a selection of notifications in status \"Queued\".", + "createPolicy" : "Create policy", + "deletePolicy" : "Delete selected policies", "column": { "id": "ID", "idShort": "ID Short", @@ -158,7 +161,9 @@ "importNote": "Import Note", "importDate": "Import Date", "type": "Type", - "title": "Title" + "title" : "Title", + "policyId" : "Policy ID", + "validUntil" : "Valid until" } }, "dataLoading": { diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index ff2b82f53a..de9a7ff601 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -55,6 +55,9 @@ "policyDetail": "Policy detail", "jsonViewer": "Json Viewer", "jsonTreeViewer": "Json Tree Viewer" + }, + "policyManagement" : { + "policyManagement" : "Policy management" } } } diff --git a/frontend/src/theme/base.scss b/frontend/src/theme/base.scss index 296abff8d0..4f29d58125 100644 --- a/frontend/src/theme/base.scss +++ b/frontend/src/theme/base.scss @@ -205,7 +205,7 @@ app-parts{ } } -app-notifications-tab { +app-notifications-tab, app-policies { .table-wrapper { background-color: white; @media screen and (max-height: 1049px) { @@ -268,7 +268,7 @@ app-multiselect { bottom: 0; } -app-parts, app-notifications-tab { +app-parts, app-notifications-tab, app-policies { .mat-mdc-table .mdc-data-table__row:last-child { border-bottom: 1px solid lightgrey; From 131869fb33b54a918f0820523173c835f5af09e5 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Tue, 28 May 2024 08:37:43 +0200 Subject: [PATCH 02/44] feature(policy): add policy management view in administration --- .../policies/policies.component.html | 41 +++++++++ .../policies/policies.component.scss | 0 .../policies/policies.component.spec.ts | 21 +++++ .../policies/policies.component.ts | 86 +++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html new file mode 100644 index 0000000000..11b8699ab7 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html @@ -0,0 +1,41 @@ + + +

{{ "pageAdmin.policyManagement.policyManagement" | i18n }}

+
+ + + + + + + + + + + + + + + +
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts new file mode 100644 index 0000000000..afba4712b7 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PoliciesComponent } from './policies.component'; + +describe('PoliciesComponent', () => { + let component: PoliciesComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ PoliciesComponent ], + }); + fixture = TestBed.createComponent(PoliciesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts new file mode 100644 index 0000000000..63e95829a9 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts @@ -0,0 +1,86 @@ +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { Pagination } from '@core/model/pagination.model'; +import { KnownAdminRoutes } from '@page/admin/core/admin.model'; +import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; +import { Policy } from '@page/policies/model/policy.model'; +import { TableType } from '@shared/components/multi-select-autocomplete/table-type.model'; +import { + CreateHeaderFromColumns, + TableConfig, + TableEventConfig, + TableHeaderSort, +} from '@shared/components/table/table.model'; +import { View } from '@shared/model/view.model'; +import { Observable } from 'rxjs'; +import { take } from 'rxjs/operators'; + +@Component({ + selector: 'app-policies', + templateUrl: './policies.component.html', + styleUrls: [ './policies.component.scss' ], +}) +export class PoliciesComponent { + policiesView$: Observable>>; + tableConfig: TableConfig; + selectedPolicies: Policy[]; + policyFilter: any; + pagination: TableEventConfig; + multiSortList: TableHeaderSort[] = []; + + constructor(public readonly policyFacade: PoliciesFacade, private readonly router: Router) { + } + + ngOnInit() { + + this.pagination = { page: 0, pageSize: 10, sorting: [ '', null ] }; + this.tableConfig = { + displayedColumns: [ 'select', 'policyId', 'validUntil', 'menu' ], + header: CreateHeaderFromColumns([ 'policyId', 'validUntil', 'menu' ], 'pageAdmin.policies'), + menuActionsConfig: [], + sortableColumns: { + select: false, + policyId: true, + validUntil: false, + }, + hasPagination: true, + }; + + this.policiesView$ = this.policyFacade.policies$; + this.policiesView$.pipe(take(2)).subscribe(data => { + console.log(data); + if (data?.data?.content.length) { + return; + } else { + this.policyFacade.setPolicies(0, 10, [ null, null ]); + } + }); + + + } + + filterActivated(policyFilter: any): void { + this.policyFilter = policyFilter; + } + + onTableConfigChange(pagination: TableEventConfig): void { + this.pagination = pagination; + this.policyFacade.setPolicies(pagination.page, pagination.pageSize, [ pagination.sorting ]); + } + + multiSelection(selectedPolicies: Policy[]) { + this.selectedPolicies = selectedPolicies; + } + + openDetailedView(selectedPolicy: Record) { + this.policyFacade.selectedPolicy = selectedPolicy as unknown as Policy; + this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/' + this.policyFacade.selectedPolicy.policyId ]); + } + + openEditView(event: any) { + return; + } + + + protected readonly TableType = TableType; +} From 517760a0b332504270188035944f01b00366b0d9 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 29 May 2024 10:32:26 +0200 Subject: [PATCH 03/44] feature(policy): add policy management view in administration list view done --- .../services/policy-mock/policy.model.ts | 35 +++++---- .../app/modules/page/admin/admin.module.ts | 6 +- .../policies/policies.component.html | 6 +- .../policies/policies.component.ts | 74 ++++++++++++++++--- .../policies/policies.facade.ts | 19 ++++- .../page/policies/model/policy.model.ts | 13 ++-- .../policies-configuration.model.ts | 7 +- .../components/table/table.component.html | 14 ++-- .../components/table/table.component.scss | 11 +++ .../components/table/table.component.ts | 17 ++--- .../modules/shared/helper/filter-helper.ts | 4 +- .../app/modules/shared/helper/table-helper.ts | 4 +- .../modules/shared/service/policy.service.ts | 63 +++++++++++++--- frontend/src/assets/locales/de/common.json | 7 +- .../src/assets/locales/de/page.admin.json | 7 +- frontend/src/assets/locales/en/common.json | 7 +- .../src/assets/locales/en/page.admin.json | 7 +- 17 files changed, 232 insertions(+), 69 deletions(-) diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 9889cd7493..066a8c595e 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,4 +1,3 @@ -import { CalendarDateModel } from '@core/model/calendar-date.model'; import { PaginationResponse } from '@core/model/pagination.model'; import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; @@ -26,12 +25,17 @@ export const getPolicies = (): PaginationResponse => { page: 0, pageCount: 0, pageSize: 10, - totalItems: 1, + totalItems: 2, content: [ { + bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], + policyName: 'Mocked_Policy_Name_1', policyId: 'Mocked_Policy_1', - validUntil: new CalendarDateModel('2024-02-26T13:38:07+01:00'), + accessType: PolicyAction.ACCESS, + createdOn: '2024-02-26T13:38:07+01:00', + validUntil: '2024-02-26T13:38:07+01:00', + constraints: [ 'Membership = active', 'AND FrameworkAgreement.traceability in [active]', 'AND PURPOSE = ID 3.1 Trace' ], permissions: [ { action: PolicyAction.USE, @@ -40,18 +44,18 @@ export const getPolicies = (): PaginationResponse => { { leftOperand: 'PURPOSE', operator: { - '@id': OperatorType.EQ, + id: OperatorType.EQ, }, - 'odrl:rightOperand': 'ID 3.0 Trace', + rightOperand: 'ID 3.0 Trace', }, ], or: [ { leftOperand: 'PURPOSE', operator: { - '@id': OperatorType.EQ, + id: OperatorType.EQ, }, - 'odrl:rightOperand': 'ID 3.0 Trace', + rightOperand: 'ID 3.0 Trace', }, ], }, @@ -59,28 +63,33 @@ export const getPolicies = (): PaginationResponse => { ], }, { + bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], + policyName: 'Mocked_Policy_Name_2', policyId: 'Mocked_Policy_2', - validUntil: new CalendarDateModel('2024-02-24T13:38:07+01:00'), + accessType: PolicyAction.USE, + createdOn: '2024-02-26T13:38:07+01:00', + validUntil: '2024-02-26T13:38:07+01:00', + constraints: [ 'PURPOSE = ID 3.1 Trace', 'OR PURPOSE = ID 3.0 Trace' ], permissions: [ { - action: PolicyAction.ACCESS, + action: PolicyAction.USE, constraint: { and: [ { leftOperand: 'PURPOSE', operator: { - '@id': OperatorType.IN, + id: OperatorType.IN, }, - 'odrl:rightOperand': 'BMW', + rightOperand: 'BMW', }, ], or: [ { leftOperand: 'PURPOSE', operator: { - '@id': OperatorType.EQ, + id: OperatorType.EQ, }, - 'odrl:rightOperand': 'ID 3.0 Trace', + rightOperand: 'ID 3.0 Trace', }, ], }, diff --git a/frontend/src/app/modules/page/admin/admin.module.ts b/frontend/src/app/modules/page/admin/admin.module.ts index 63d888c3ad..fc99524ec4 100644 --- a/frontend/src/app/modules/page/admin/admin.module.ts +++ b/frontend/src/app/modules/page/admin/admin.module.ts @@ -21,6 +21,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { MatLineModule } from '@angular/material/core'; import { getI18nPageProvider } from '@core/i18n'; import { AdminFacade } from '@page/admin/core/admin.facade'; import { AdminService } from '@page/admin/core/admin.service'; @@ -28,6 +29,7 @@ import { ContractDetailComponent } from '@page/admin/presentation/contracts/cont import { ContractsComponent } from '@page/admin/presentation/contracts/contracts.component'; import { ContractsFacade } from '@page/admin/presentation/contracts/contracts.facade'; import { ContractsState } from '@page/admin/presentation/contracts/contracts.state'; +import { DeletionDialogComponent } from '@page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component'; import { PoliciesComponent } from '@page/admin/presentation/policy-management/policies/policies.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; @@ -43,8 +45,8 @@ import { SaveBpnConfigModal } from './presentation/bpn-configuration/save-modal/ import { ImportJsonComponent } from './presentation/import-json/import-json.component'; @NgModule({ - declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent, PoliciesComponent ], - imports: [CommonModule, TemplateModule, SharedModule, AdminRoutingModule, ModalModule, NgxJsonViewerModule], + declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent, PoliciesComponent, DeletionDialogComponent ], + imports: [ CommonModule, TemplateModule, SharedModule, AdminRoutingModule, ModalModule, NgxJsonViewerModule, MatLineModule ], providers: [ ...getI18nPageProvider('page.admin'), AdminService, AdminFacade, ContractsFacade, ContractsState, PoliciesFacade, PoliciesState, PolicyService ], }) export class AdminModule { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html index 11b8699ab7..a74b219810 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html @@ -1,7 +1,6 @@ -

{{ "pageAdmin.policyManagement.policyManagement" | i18n }}

+
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts index 63e95829a9..281804358c 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts @@ -1,16 +1,22 @@ import { Component } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { Pagination } from '@core/model/pagination.model'; +import { RoleService } from '@core/user/role.service'; import { KnownAdminRoutes } from '@page/admin/core/admin.model'; +import { DeletionDialogComponent } from '@page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { Policy } from '@page/policies/model/policy.model'; import { TableType } from '@shared/components/multi-select-autocomplete/table-type.model'; +import { TableSortingUtil } from '@shared/components/table/table-sorting.util'; import { CreateHeaderFromColumns, TableConfig, TableEventConfig, TableHeaderSort, } from '@shared/components/table/table.model'; +import { ToastService } from '@shared/components/toasts/toast.service'; +import { setMultiSorting } from '@shared/helper/table-helper'; import { View } from '@shared/model/view.model'; import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; @@ -27,32 +33,49 @@ export class PoliciesComponent { policyFilter: any; pagination: TableEventConfig; multiSortList: TableHeaderSort[] = []; + ctrlKeyState: boolean = false; - constructor(public readonly policyFacade: PoliciesFacade, private readonly router: Router) { + constructor(public readonly policyFacade: PoliciesFacade, private readonly router: Router, private readonly toastService: ToastService, public dialog: MatDialog, private readonly roleService: RoleService) { + window.addEventListener('keydown', (event) => { + this.ctrlKeyState = setMultiSorting(event); + }); + window.addEventListener('keyup', (event) => { + this.ctrlKeyState = setMultiSorting(event); + }); } ngOnInit() { this.pagination = { page: 0, pageSize: 10, sorting: [ '', null ] }; this.tableConfig = { - displayedColumns: [ 'select', 'policyId', 'validUntil', 'menu' ], - header: CreateHeaderFromColumns([ 'policyId', 'validUntil', 'menu' ], 'pageAdmin.policies'), - menuActionsConfig: [], + displayedColumns: [ 'select', 'bpnSelection', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], + header: CreateHeaderFromColumns([ 'select', 'bpnSelection', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], 'pageAdmin.policies'), + menuActionsConfig: [ { + label: 'actions.edit', + icon: 'edit', + action: (selectedPolicy: Record) => this.openEditView(selectedPolicy), + isAuthorized: this.roleService.isAdmin(), + } ], sortableColumns: { select: false, + bpnSelection: true, + policyName: true, policyId: true, - validUntil: false, + accessType: true, + createdOn: true, + validUntil: true, + constraints: true, + menu: false, }, hasPagination: true, }; this.policiesView$ = this.policyFacade.policies$; this.policiesView$.pipe(take(2)).subscribe(data => { - console.log(data); if (data?.data?.content.length) { return; } else { - this.policyFacade.setPolicies(0, 10, [ null, null ]); + this.policyFacade.setPolicies(0, 10); } }); @@ -61,11 +84,13 @@ export class PoliciesComponent { filterActivated(policyFilter: any): void { this.policyFilter = policyFilter; + this.policyFacade.setPolicies(this.pagination.page, this.pagination.pageSize, this.multiSortList, this.policyFilter); } onTableConfigChange(pagination: TableEventConfig): void { this.pagination = pagination; - this.policyFacade.setPolicies(pagination.page, pagination.pageSize, [ pagination.sorting ]); + TableSortingUtil.setTableSortingList(pagination.sorting, this.multiSortList, this.ctrlKeyState); + this.policyFacade.setPolicies(pagination.page, pagination.pageSize, this.multiSortList, this.policyFilter); } multiSelection(selectedPolicies: Policy[]) { @@ -77,8 +102,37 @@ export class PoliciesComponent { this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/' + this.policyFacade.selectedPolicy.policyId ]); } - openEditView(event: any) { - return; + openEditView(selectedPolicy: any) { + this.policyFacade.selectedPolicy = selectedPolicy as unknown as Policy; + this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/edit/' + this.policyFacade.selectedPolicy.policyId ]); + } + + openDeletionDialog() { + const dialogRef = this.dialog.open(DeletionDialogComponent, { + data: { + policyIds: this.selectedPolicies.map(policy => policy.policyId), + title: 'pageAdmin.policyManagement.policyDeletion', + }, + }); + + dialogRef.afterClosed().subscribe(confirmation => { + if (confirmation) { + this.deletePolicies(); + } + }); + } + + + deletePolicies() { + this.policyFacade.deletePolicies(this.selectedPolicies).subscribe({ + next: value => { + this.toastService.success('pageAdmin.policyManagement.deleteSuccess'); + this.policyFacade.setPolicies(this.pagination.page, this.pagination.pageSize, this.multiSortList, this.policyFilter); + }, + error: err => { + this.toastService.error('pageAdmin.policyManagement.deleteError'); + }, + }); } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 09712ab752..a83324ceea 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { CalendarDateModel } from '@core/model/calendar-date.model'; import { Pagination } from '@core/model/pagination.model'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; import { provideDataObject } from '@page/parts/core/parts.helper'; @@ -7,6 +8,7 @@ import { TableHeaderSort } from '@shared/components/table/table.model'; import { View } from '@shared/model/view.model'; import { PolicyService } from '@shared/service/policy.service'; import { Observable, Subject, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; @Injectable() export class PoliciesFacade { @@ -24,9 +26,19 @@ export class PoliciesFacade { return this.policiesState.policies$; } - public setPolicies(page, pageSize = 50, sorting: TableHeaderSort[]): void { + public setPolicies(page: number, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: any): void { this.policiesSubscription?.unsubscribe(); - this.policiesSubscription = this.policyService.getPaginatedPolicies(page, pageSize, sorting).subscribe({ + this.policiesSubscription = this.policyService.getPaginatedPolicies(page, pageSize, sorting, filter).pipe(map(response => { + const assembled = response.content.map(policy => { + return { + ...policy, + createdOn: new CalendarDateModel(policy.createdOn as string), + validUntil: new CalendarDateModel(policy.validUntil as string), + accessType: policy.accessType.toUpperCase(), + }; + }); + return { ...response, content: assembled } as Pagination; + })).subscribe({ next: data => (this.policiesState.policies = { data: provideDataObject(data) }), error: error => (this.policiesState.policies = { error }), }); @@ -59,4 +71,7 @@ export class PoliciesFacade { this.unsubscribeTrigger.next(); } + deletePolicies(selectedPolicies: Policy[]) { + return this.policyService.deletePolicies(selectedPolicies.map(policy => policy.policyId)); + } } diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index c48040b8b6..de797d88ed 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -18,11 +18,14 @@ import { CalendarDateModel } from '@core/model/calendar-date.model'; * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -// TODO: Decide if long term a Policy state, facade, ResponseType and Assembler is needed -// TODO: Align with BE to a first valid Policy Model, changes seem to be happen frequently export interface Policy { + bpnSelection: string[]; + policyName: string; policyId: string; - validUntil: CalendarDateModel; + accessType: PolicyAction, + createdOn: CalendarDateModel | string; + validUntil: CalendarDateModel | string; + constraints: string[] permissions: PolicyPermission[]; } @@ -43,12 +46,12 @@ export interface Constraint { export interface PolicyConstraint { leftOperand: string, - 'odrl:rightOperand': string, + rightOperand: string, operator: PolicyConstraintOperator } export interface PolicyConstraintOperator { - '@id': OperatorType; + id: OperatorType; } export enum OperatorType { diff --git a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts index 1d4586188f..eb0d25c64f 100644 --- a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts +++ b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts @@ -4,12 +4,17 @@ export class PoliciesConfigurationModel extends TableFilterConfiguration { constructor() { const sortableColumns = { select: false, + bpnSelection: true, + policyName: true, policyId: true, + accessType: true, + createdOn: true, validUntil: true, + constraints: true, menu: false, }; - const dateFields = [ 'validUntil' ]; + const dateFields = [ 'createdOn', 'validUntil' ]; const singleSearchFields = []; super(sortableColumns, dateFields, singleSearchFields, true); } diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index f8ce9d85c6..e590411b0a 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -21,7 +21,8 @@
-
{{ tableHeader | i18n }} +
{{ tableHeader | i18n }} settings @@ -55,8 +56,8 @@ > @@ -80,7 +81,7 @@
@@ -159,7 +161,7 @@
+ [ngClass]="{'rows-dashboard': labelId?.startsWith('dashboard'), 'rows-policy': labelId?.startsWith('policies')} ">

{{ tableHeader | i18n }}

diff --git a/frontend/src/app/modules/shared/components/table/table.component.scss b/frontend/src/app/modules/shared/components/table/table.component.scss index 7579ffee22..47d3977286 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.scss +++ b/frontend/src/app/modules/shared/components/table/table.component.scss @@ -255,3 +255,14 @@ tr.error { visibility: hidden; } +.policy-table-header { + font-size: 24px; + font-family: Catena-X SemiBold, sans-serif; + text-transform: uppercase; + color: rgb(17, 17, 17); +} + +.rows-policy { + height: 63vh !important; +} + diff --git a/frontend/src/app/modules/shared/components/table/table.component.ts b/frontend/src/app/modules/shared/components/table/table.component.ts index 51fa85a5b1..5731b0a85d 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.ts +++ b/frontend/src/app/modules/shared/components/table/table.component.ts @@ -147,6 +147,7 @@ export class TableComponent { @Output() multiSelect = new EventEmitter(); @Output() clickSelectAction = new EventEmitter(); @Output() filterActivated = new EventEmitter(); + @Output() deletionClicked = new EventEmitter(); @Input() public autocompleteEnabled = false; @Input() tableSettingsEnabled: boolean = false; @@ -381,13 +382,8 @@ export class TableComponent { this.router.navigate([ 'inbox/create' ]); } - // TODO: handle navigation to view and deletion trigger - navigateTo() { - return; - } - - emitDeletionEvent() { - + navigateToCreationPath() { + this.router.navigate([ this.router.url, 'create' ]); } private menuActionsWithAddedDefaultActions(menuActionsConfig: MenuActionConfig[] = []): MenuActionConfig[] { @@ -410,7 +406,10 @@ export class TableComponent { return [ ...defaultActionsToAdd, ...menuActionsConfig ]; }; - protected readonly MainAspectType = MainAspectType; - + handleItemDeletion() { + this.deletionClicked.emit(); + this.clearCurrentRows(); + } + protected readonly MainAspectType = MainAspectType; } diff --git a/frontend/src/app/modules/shared/helper/filter-helper.ts b/frontend/src/app/modules/shared/helper/filter-helper.ts index 41b64b1b85..76956403f2 100644 --- a/frontend/src/app/modules/shared/helper/filter-helper.ts +++ b/frontend/src/app/modules/shared/helper/filter-helper.ts @@ -26,10 +26,10 @@ import { import { NotificationDeeplinkFilter } from '@shared/model/notification.model'; -export const DATE_FILTER_KEYS = [ 'manufacturingDate', 'functionValidFrom', 'functionValidUntil', 'validityPeriodFrom', 'validityPeriodTo', 'createdDate', 'targetDate', 'creationDate', 'endDate' ]; +export const DATE_FILTER_KEYS = [ 'manufacturingDate', 'functionValidFrom', 'functionValidUntil', 'validityPeriodFrom', 'validityPeriodTo', 'createdDate', 'targetDate', 'creationDate', 'endDate', 'createdOn', 'validUntil' ]; // TODO: Refactor function -export function enrichFilterAndGetUpdatedParams(filter: AssetAsBuiltFilter, params: HttpParams, filterOperator: string): HttpParams { +export function enrichFilterAndGetUpdatedParams(filter: AssetAsBuiltFilter | any, params: HttpParams, filterOperator: string): HttpParams { for (const key in filter) { let operator: string; diff --git a/frontend/src/app/modules/shared/helper/table-helper.ts b/frontend/src/app/modules/shared/helper/table-helper.ts index 7600edb4d8..8134a2e9e2 100644 --- a/frontend/src/app/modules/shared/helper/table-helper.ts +++ b/frontend/src/app/modules/shared/helper/table-helper.ts @@ -36,9 +36,9 @@ export function clearAllRows(selection: any, multiSelect: any): void { } export function clearCurrentRows(selection: any, dataSourceData: unknown[], multiSelect: any): void { - this.removeSelectedValues(selection, dataSourceData); + removeSelectedValues(selection, dataSourceData); - multiSelect.emit(this.selection.selected); + multiSelect.emit([]); } export function setMultiSorting( event: KeyboardEvent): boolean { diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 03f186b20c..b2c259662e 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -3,8 +3,10 @@ import { Injectable } from '@angular/core'; import { ApiService } from '@core/api/api.service'; import { Pagination } from '@core/model/pagination.model'; import { environment } from '@env'; +import { FilterOperator, getFilterOperatorValue } from '@page/parts/model/parts.model'; import { Policy } from '@page/policies/model/policy.model'; import { TableHeaderSort } from '@shared/components/table/table.model'; +import { isDateFilter, isDateRangeFilter, isSameDate, isStartsWithFilter } from '@shared/helper/filter-helper'; import { Observable } from 'rxjs'; @Injectable({ @@ -20,18 +22,18 @@ export class PolicyService { } getPaginatedPolicies(page: number, pageSize: number, sorting?: TableHeaderSort[], filter?: any): Observable> { - + const sort = sorting.length ? sorting.map(array => `${ array[0] },${ array[1] }`) : [ 'createdOn,desc' ]; const body = { pageAble: { page: page, size: pageSize, - sorting: sorting ? sorting : undefined, + sorting: sort, }, searchCriteria: {}, }; if (filter) { - body.searchCriteria = { filter: this.createFilterList(filter) }; + body.searchCriteria = { filter: this.createFilterList(filter, 'AND') }; } return this.apiService.post>(`${ this.url }/policies`, body); @@ -42,15 +44,52 @@ export class PolicyService { } - private createFilterList(filter: Object) { + private createFilterList(filter: Object, filterOperator: string) { + let filterList = []; - Object.entries(filter).forEach(([ entry, values ]) => { - if (values.length) { - values.forEach(value => { - filterList.push(`${ entry },EQUAL,${ value },AND`); - }); + + for (const key in filter) { + let operator: string; + const filterValues: string = filter[key]; + if (!filterValues) { + continue; + } + // has date + if (isDateFilter(key)) { + if (isDateRangeFilter(filterValues)) { + const [ startDate, endDate ] = filterValues.split(','); + if (isSameDate(startDate, endDate)) { + operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); + filterList.push(`${ key },${ operator },${ startDate },${ filterOperator }`); + continue; + } + let endDateOperator = getFilterOperatorValue(FilterOperator.BEFORE_LOCAL_DATE); + operator = getFilterOperatorValue((FilterOperator.AFTER_LOCAL_DATE)); + filterList.push(`${ key },${ operator },${ startDate },${ filterOperator }`); + filterList.push(`${ key },${ endDateOperator },${ endDate },${ filterOperator }`); + continue; + } else if (filterValues && filterValues.length != 0) { + operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); + filterList.push(`${ key },${ operator },${ filterValues },${ filterOperator }`); + } + } + + // has multiple values + if (isStartsWithFilter(key) && Array.isArray(filter[key])) { + operator = getFilterOperatorValue(FilterOperator.EQUAL); + + for (const value of filter[key]) { + filterList.push(`${ key },${ operator },${ value },${ filterOperator }`); + } } - }); + + // has single value + if (isStartsWithFilter(key) && !Array.isArray(filter[key])) { + operator = getFilterOperatorValue(FilterOperator.STARTS_WITH); + filterList.push(`${ key },${ operator },${ filterValues },${ filterOperator }`); + } + + } return filterList; } @@ -62,4 +101,8 @@ export class PolicyService { return this.apiService.getBy(`${ this.url }/policies/distinctFilterValues`, params); } + + deletePolicies(policyIds: string[]) { + return this.apiService.delete(`${ this.url }/policies`, new HttpParams().set('policyIds', policyIds.toString())); + } } diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index 6becdce202..d0b0167cff 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -167,7 +167,12 @@ "type": "Typ", "title" : "Titel", "policyId" : "Policy ID", - "validUntil" : "Gültig bis" + "validUntil" : "Gültig bis", + "createdOn" : "Gültig von", + "policyName" : "Richtlinienname", + "bpnSelection" : "BPN Selektion", + "constraints" : "Bedingungen", + "accessType" : "Zugriffsart" } }, "dataLoading": { diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index c9d4e0f56f..c4d427a6f6 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -57,7 +57,12 @@ "jsonTreeViewer": "Json-Baumansicht" }, "policyManagement" : { - "policyManagement" : "Richtlinienverwaltung" + "policyManagement" : "Richtlinienverwaltung", + "deleteSuccess" : "Selektierte Richtlinien wurden erfolgreich gelöscht.", + "deleteError" : "Fehler bei der Löschung der selektierten Richtlinien.", + "confirm" : "Bestätigen", + "policyDeletion" : "Löschung der Richtlinien", + "deletionText" : "Möchten sie die Löschung der selektierten Richtlinien bestätigen?" } } } diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index 5274af99aa..25a42a470a 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -163,7 +163,12 @@ "type": "Type", "title" : "Title", "policyId" : "Policy ID", - "validUntil" : "Valid until" + "validUntil" : "Valid until", + "createdOn" : "Valid from", + "policyName" : "Policy name", + "bpnSelection" : "BPN selection", + "constraints" : "Constraints", + "accessType" : "Access type" } }, "dataLoading": { diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index de9a7ff601..6c4421e558 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -57,7 +57,12 @@ "jsonTreeViewer": "Json Tree Viewer" }, "policyManagement" : { - "policyManagement" : "Policy management" + "policyManagement" : "Policy management", + "deleteSuccess" : "Successfully deleted the selected policies.", + "deleteError" : "Error while deleting the selected policies.", + "confirm" : "Confirm", + "policyDeletion" : "Deletion of policies", + "deletionText" : "Do you want to confirm the deletion of the selected policies?" } } } From 67297dd69ecdf0b70e91a73b5e3141626811e37c Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 31 May 2024 16:05:14 +0200 Subject: [PATCH 04/44] feature(policy): add policy management detailed view --- .../services/policy-mock/policy.handler.ts | 8 +- .../services/policy-mock/policy.model.ts | 198 ++++++++++++------ .../app/modules/page/admin/admin.module.ts | 3 +- .../app/modules/page/admin/admin.routing.ts | 25 +++ .../modules/page/admin/core/admin.model.ts | 3 + .../policies/policies.component.ts | 8 +- .../policies/policies.facade.ts | 6 +- .../policy-editor/policy-data.ts | 8 + .../policy-editor.component.html | 155 ++++++++++++++ .../policy-editor.component.scss | 14 ++ .../policy-editor.component.spec.ts | 21 ++ .../policy-editor/policy-editor.component.ts | 165 +++++++++++++++ .../page/policies/model/policy.model.ts | 118 ++++++++--- .../policies-configuration.model.ts | 2 +- .../app/modules/shared/model/view.model.ts | 6 + .../modules/shared/service/policy.service.ts | 6 +- .../src/assets/locales/de/page.admin.json | 6 +- .../src/assets/locales/en/page.admin.json | 6 +- 18 files changed, 649 insertions(+), 109 deletions(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts diff --git a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts index e85cd30185..f1807d3596 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts @@ -18,7 +18,7 @@ ********************************************************************************/ import { environment } from '@env'; import { rest } from 'msw'; -import { getPolicies } from './policy.model'; +import { getPolicies, getPolicyById } from './policy.model'; export const policyHandler = (_ => { return [ @@ -28,6 +28,12 @@ export const policyHandler = (_ => { rest.post(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { return res(ctx.status(200), ctx.json(getPolicies())); + }), + + rest.get(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { + const { policyId } = req.params; + const policy = getPolicyById(policyId); + return res(ctx.status(200), ctx.json(policy)); }) ] })(); diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 066a8c595e..65677b9f7a 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,5 +1,11 @@ import { PaginationResponse } from '@core/model/pagination.model'; -import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; +import { + mapToPolicyEntryList, + OperatorType, + Policy, + PolicyAction, + PolicyResponseMap, +} from '@page/policies/model/policy.model'; /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation @@ -23,82 +29,140 @@ import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy. export const getPolicies = (): PaginationResponse => { return { page: 0, - pageCount: 0, pageSize: 10, - totalItems: 2, + totalItems: 1, + pageCount: 1, + content: mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy), + } +}; + +export const getPolicyById = (policyId: string | ReadonlyArray): Policy => { + return mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy).filter(policy => policy.policyId === policyId)[0]; +}; - content: [ - { - bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], - policyName: 'Mocked_Policy_Name_1', - policyId: 'Mocked_Policy_1', - accessType: PolicyAction.ACCESS, - createdOn: '2024-02-26T13:38:07+01:00', - validUntil: '2024-02-26T13:38:07+01:00', - constraints: [ 'Membership = active', 'AND FrameworkAgreement.traceability in [active]', 'AND PURPOSE = ID 3.1 Trace' ], - permissions: [ - { - action: PolicyAction.USE, - constraint: { - and: [ - { - leftOperand: 'PURPOSE', - operator: { - id: OperatorType.EQ, + +export const mockedPolicyResponseMap: PolicyResponseMap = { + 'BPNL1234567890AB': [ + { + 'validUntil': '2025-12-12T23:59:59.999Z', + 'payload': { + '@context': { + 'odrl': 'http://www.w3.org/ns/odrl/2/', + }, + '@id': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', + 'policy': { + 'policyId': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', + 'createdOn': '2024-03-28T03:34:42.9454448Z', + 'validUntil': '2025-12-12T23:59:59.999Z', + 'permissions': [ + { + 'action': PolicyAction.USE, + 'constraint': { + 'and': [ + { + 'leftOperand': 'Membership', + 'operator': { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'active', }, - rightOperand: 'ID 3.0 Trace', - }, - ], - or: [ - { - leftOperand: 'PURPOSE', - operator: { - id: OperatorType.EQ, + { + 'leftOperand': 'PURPOSE', + 'operator': { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'ID 3.1 Trace', }, - rightOperand: 'ID 3.0 Trace', - }, - ], + ], + 'or': null, + }, }, - }, - ], + ], + }, }, - { - bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], - policyName: 'Mocked_Policy_Name_2', - policyId: 'Mocked_Policy_2', - accessType: PolicyAction.USE, - createdOn: '2024-02-26T13:38:07+01:00', - validUntil: '2024-02-26T13:38:07+01:00', - constraints: [ 'PURPOSE = ID 3.1 Trace', 'OR PURPOSE = ID 3.0 Trace' ], - permissions: [ - { - action: PolicyAction.USE, - constraint: { - and: [ - { - leftOperand: 'PURPOSE', - operator: { - id: OperatorType.IN, - }, - rightOperand: 'BMW', + }, + ], + 'BPNA1234567890DF': [], +}; + +const mockedPolicies = { + page: 0, + pageCount: 0, + pageSize: 10, + totalItems: 2, + + content: [ + { + bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], + policyName: 'Mocked_Policy_Name_1', + policyId: 'Mocked_Policy_1', + accessType: PolicyAction.ACCESS, + createdOn: '2024-02-26T13:38:07+01:00', + validUntil: '2024-02-26T13:38:07+01:00', + constraints: [ 'Membership = active', 'AND FrameworkAgreement.traceability in [active]', 'AND PURPOSE = ID 3.1 Trace' ], + permissions: [ + { + action: PolicyAction.USE, + constraint: { + and: [ + { + leftOperand: 'PURPOSE', + operator: { + id: OperatorType.EQ, }, - ], - or: [ - { - leftOperand: 'PURPOSE', - operator: { - id: OperatorType.EQ, - }, - rightOperand: 'ID 3.0 Trace', + rightOperand: 'ID 3.0 Trace', + }, + ], + or: [ + { + leftOperand: 'PURPOSE', + operator: { + id: OperatorType.EQ, }, - ], - }, + rightOperand: 'ID 3.0 Trace', + }, + ], }, - ], - }, + }, + ], + }, + { + bpnSelection: [ 'BPN10000000OEM0A', 'BPN10000000OEM0B' ], + policyName: 'Mocked_Policy_Name_2', + policyId: 'Mocked_Policy_2', + accessType: PolicyAction.USE, + createdOn: '2024-02-26T13:38:07+01:00', + validUntil: '2024-02-26T13:38:07+01:00', + constraints: [ 'PURPOSE = ID 3.1 Trace', 'OR PURPOSE = ID 3.0 Trace' ], + permissions: [ + { + action: PolicyAction.USE, + constraint: { + and: [ + { + leftOperand: 'PURPOSE', + operator: { + id: OperatorType.IN, + }, + rightOperand: 'BMW', + }, + ], + or: [ + { + leftOperand: 'PURPOSE', + operator: { + id: OperatorType.EQ, + }, + rightOperand: 'ID 3.0 Trace', + }, + ], + }, + }, + ], + }, - ], + ], - }; }; + diff --git a/frontend/src/app/modules/page/admin/admin.module.ts b/frontend/src/app/modules/page/admin/admin.module.ts index fc99524ec4..6549348455 100644 --- a/frontend/src/app/modules/page/admin/admin.module.ts +++ b/frontend/src/app/modules/page/admin/admin.module.ts @@ -33,6 +33,7 @@ import { DeletionDialogComponent } from '@page/admin/presentation/policy-managem import { PoliciesComponent } from '@page/admin/presentation/policy-management/policies/policies.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; +import { PolicyEditorComponent } from '@page/admin/presentation/policy-management/policy-editor/policy-editor.component'; import { ModalModule } from '@shared/modules/modal/modal.module'; import { PolicyService } from '@shared/service/policy.service'; import { SharedModule } from '@shared/shared.module'; @@ -45,7 +46,7 @@ import { SaveBpnConfigModal } from './presentation/bpn-configuration/save-modal/ import { ImportJsonComponent } from './presentation/import-json/import-json.component'; @NgModule({ - declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent, PoliciesComponent, DeletionDialogComponent ], + declarations: [ AdminComponent, BpnConfigurationComponent, SaveBpnConfigModal, ImportJsonComponent, ContractsComponent, ContractDetailComponent, PoliciesComponent, DeletionDialogComponent, PolicyEditorComponent ], imports: [ CommonModule, TemplateModule, SharedModule, AdminRoutingModule, ModalModule, NgxJsonViewerModule, MatLineModule ], providers: [ ...getI18nPageProvider('page.admin'), AdminService, AdminFacade, ContractsFacade, ContractsState, PoliciesFacade, PoliciesState, PolicyService ], }) diff --git a/frontend/src/app/modules/page/admin/admin.routing.ts b/frontend/src/app/modules/page/admin/admin.routing.ts index 8b9eb1fe42..298a468063 100644 --- a/frontend/src/app/modules/page/admin/admin.routing.ts +++ b/frontend/src/app/modules/page/admin/admin.routing.ts @@ -28,6 +28,7 @@ import { ContractDetailComponent } from '@page/admin/presentation/contracts/cont import { ContractsComponent } from '@page/admin/presentation/contracts/contracts.component'; import { ImportJsonComponent } from '@page/admin/presentation/import-json/import-json.component'; import { PoliciesComponent } from '@page/admin/presentation/policy-management/policies/policies.component'; +import { PolicyEditorComponent } from '@page/admin/presentation/policy-management/policy-editor/policy-editor.component'; import { I18NEXT_NAMESPACE_RESOLVER } from 'angular-i18next'; export /** @type {*} */ @@ -76,6 +77,30 @@ const ADMIN_ROUTING: Routes = [ resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, canActivate: [ RoleGuard ], }, + { + path: KnownAdminRoutes.POLICY_MANAGEMENT_EDIT, + pathMatch: 'full', + component: PolicyEditorComponent, + data: { i18nextNamespaces: [ 'page.admin' ] }, + resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, + canActivate: [ RoleGuard ], + }, + { + path: KnownAdminRoutes.POLICY_MANAGEMENT_CREATE, + pathMatch: 'full', + component: PolicyEditorComponent, + data: { i18nextNamespaces: [ 'page.admin' ] }, + resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, + canActivate: [ RoleGuard ], + }, + { + path: KnownAdminRoutes.POLICY_MANAGEMENT_DETAIL_VIEW, + pathMatch: 'full', + component: PolicyEditorComponent, + data: { i18nextNamespaces: [ 'page.admin' ] }, + resolve: { i18next: I18NEXT_NAMESPACE_RESOLVER }, + canActivate: [ RoleGuard ], + }, ]; @NgModule({ diff --git a/frontend/src/app/modules/page/admin/core/admin.model.ts b/frontend/src/app/modules/page/admin/core/admin.model.ts index 42536dd88d..0205a23ba5 100644 --- a/frontend/src/app/modules/page/admin/core/admin.model.ts +++ b/frontend/src/app/modules/page/admin/core/admin.model.ts @@ -30,6 +30,9 @@ export enum KnownAdminRoutes { CONTRACT = 'contracts', CONTRACT_DETAIL_VIEW = 'contracts/:contractId', POLICY_MANAGEMENT = 'policies', + POLICY_MANAGEMENT_EDIT = 'policies/edit/:policyId', + POLICY_MANAGEMENT_CREATE = 'policies/create', + POLICY_MANAGEMENT_DETAIL_VIEW = 'policies/:policyId', } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts index 281804358c..b6f695aabb 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts @@ -48,8 +48,8 @@ export class PoliciesComponent { this.pagination = { page: 0, pageSize: 10, sorting: [ '', null ] }; this.tableConfig = { - displayedColumns: [ 'select', 'bpnSelection', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], - header: CreateHeaderFromColumns([ 'select', 'bpnSelection', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], 'pageAdmin.policies'), + displayedColumns: [ 'select', 'bpn', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], + header: CreateHeaderFromColumns([ 'select', 'bpn', 'policyName', 'policyId', 'accessType', 'createdOn', 'validUntil', 'constraints', 'menu' ], 'pageAdmin.policies'), menuActionsConfig: [ { label: 'actions.edit', icon: 'edit', @@ -58,7 +58,7 @@ export class PoliciesComponent { } ], sortableColumns: { select: false, - bpnSelection: true, + bpn: true, policyName: true, policyId: true, accessType: true, @@ -98,12 +98,10 @@ export class PoliciesComponent { } openDetailedView(selectedPolicy: Record) { - this.policyFacade.selectedPolicy = selectedPolicy as unknown as Policy; this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/' + this.policyFacade.selectedPolicy.policyId ]); } openEditView(selectedPolicy: any) { - this.policyFacade.selectedPolicy = selectedPolicy as unknown as Policy; this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/edit/' + this.policyFacade.selectedPolicy.policyId ]); } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index a83324ceea..939e3b5d5c 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -34,7 +34,7 @@ export class PoliciesFacade { ...policy, createdOn: new CalendarDateModel(policy.createdOn as string), validUntil: new CalendarDateModel(policy.validUntil as string), - accessType: policy.accessType.toUpperCase(), + accessType: policy.accessType.map(type => type.toUpperCase()), }; }); return { ...response, content: assembled } as Pagination; @@ -58,8 +58,8 @@ export class PoliciesFacade { } public setSelectedPolicyById(policyId: string): void { - this.selectedPoliciesSubscription = this.policyService.getPaginatedPolicies(0, 10, [ null, null ], { policyId: [ policyId ] }).subscribe({ - next: data => (this.policiesState.selectedPolicy = { data: data.content[0] as unknown as Policy }), + this.policyService.getPolicyById(policyId).subscribe({ + next: data => (this.policiesState.selectedPolicy = { data: data }), error: error => (this.policiesState.selectedPolicy = { error }), }); } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts new file mode 100644 index 0000000000..46b177f413 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts @@ -0,0 +1,8 @@ +import { OperatorType } from '@page/policies/model/policy.model'; + +export const OperatorTypesAsSelectModel: any[] = Object.keys(OperatorType).map(key => { + console.log(key); + return { + label: key, value: key, + }; +}); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html new file mode 100644 index 0000000000..76665f1776 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -0,0 +1,155 @@ + + +

{{ "pageAdmin.policyManagement.policy"| i18n }} {{ "pageAdmin.policyManagement." + viewMode | i18n }}

+
+
+ +
+
+ +
+ arrow_back + {{ 'actions.goBack' | i18n }} +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+ + + + Apply +
+
+
+
+ + +
+ +
+ +
+

Policy Type

+ +
+ +
+

Constraints

+
+ +
+
+
+ + + + + + + + + +
+
+
+
+ + +
+
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss new file mode 100644 index 0000000000..e6c4705065 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss @@ -0,0 +1,14 @@ +.file-input { + background-color: #ececec; + border-radius: 5px; + width: 300px; + padding: 5px; +} + +.hinttext { + color: #878787; +} + +.details-container { + width: 50%; +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts new file mode 100644 index 0000000000..236d490942 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PolicyEditorComponent } from './policy-editor.component'; + +describe('PolicyEditorComponent', () => { + let component: PolicyEditorComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ PolicyEditorComponent ], + }); + fixture = TestBed.createComponent(PolicyEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts new file mode 100644 index 0000000000..cfb794af58 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -0,0 +1,165 @@ +import { Component } from '@angular/core'; +import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { Router } from '@angular/router'; +import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; +import { OperatorTypesAsSelectModel } from '@page/admin/presentation/policy-management/policy-editor/policy-data'; +import { Policy, PolicyAction } from '@page/policies/model/policy.model'; +import { ViewMode } from '@shared/model/view.model'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'app-policy-editor', + templateUrl: './policy-editor.component.html', + styleUrls: [ './policy-editor.component.scss' ], +}) +export class PolicyEditorComponent { + + selectedPolicy: Policy; + selectedPolicySubscription: Subscription; + viewMode: ViewMode; + + templateFile: File | null = null; + templateFileName: string = ''; + policyForm: FormGroup; + + constructor(private readonly router: Router, public readonly policyFacade: PoliciesFacade, private fb: FormBuilder) { + } + + get constraints() { + return this.policyForm.get('constraints') as FormArray; + } + + ngOnInit() { + this.viewMode = this.initializeViewMode(); + + this.policyForm = this.fb.group({ + policyName: new FormControl(''), + validUntil: new FormControl(''), + bpns: new FormControl(''), + accessType: new FormControl(PolicyAction.ACCESS.toUpperCase()), + constraints: this.fb.array([]), + }); + + if (this.viewMode !== ViewMode.CREATE) { + this.setSelectedPolicy(); + this.selectedPolicySubscription = this.policyFacade.selectedPolicy$.subscribe(next => { + this.selectedPolicy = next?.data; + if (next?.data) { + this.policyForm.patchValue({ + policyName: this.selectedPolicy?.policyName, + validUntil: this.selectedPolicy?.validUntil, + bpns: this.selectedPolicy?.bpn, + accessType: this.selectedPolicy?.accessType[0].toUpperCase(), + }); + + + let permissionList = this.selectedPolicy.permissions[0].constraint.and.length ? this.selectedPolicy.permissions[0].constraint.and : this.selectedPolicy.permissions[0].constraint.or; + let constraintsList = permissionList.map((constraint) => this.fb.group({ + leftOperand: this.fb.control(constraint.leftOperand), + operator: this.fb.control(constraint.operator['@id'].toUpperCase()), + rightOperand: this.fb.control(constraint['odrl:rightOperand']), + })); + + this.policyForm.setControl('constraints', this.fb.array(constraintsList)); + } + + + }); + } + + } + + private initializeViewMode(): ViewMode { + const url = this.router.url; + if (url.includes('create')) { + return ViewMode.CREATE; + } else if (url.includes('edit')) { + return ViewMode.EDIT; + } else { + return ViewMode.VIEW; + } + } + + private setSelectedPolicy(): void { + const policyIdFromUrl = this.router.url.split('/').pop(); + this.policyFacade.setSelectedPolicyById(this.router.url.split('/').pop()); + } + + addConstraintFormGroup() { + this.constraints.push(this.fb.group({ + leftOperand: new FormControl(''), + operator: new FormControl(null), + rightOperand: new FormControl(''), + })); + } + + removeConstraintFormGroup(index: number) { + this.constraints.removeAt(index); + } + + moveConstraintUp(index: number): void { + if (index <= 0) { + return; + } + const constraints = this.policyForm.get('constraints') as FormArray; + const constraint = constraints.at(index); + constraints.removeAt(index); + constraints.insert(index - 1, constraint); + } + + moveConstraintDown(index: number): void { + const constraints = this.policyForm.get('constraints') as FormArray; + if (index >= constraints.length - 1) { + return; + } + const constraint = constraints.at(index); + constraints.removeAt(index); + constraints.insert(index + 1, constraint); + } + + + navigateBack() { + this.router.navigate([ 'admin/policies' ]); + } + + savePolicy() { + + } + + onFileSelected(event: Event) { + const input = event.target as HTMLInputElement; + if (input.files && input.files.length > 0) { + this.templateFile = input.files[0]; + this.templateFileName = this.templateFile.name; + } + } + + selectTemplateFile() { + + } + + navigateToEditView() { + this.router.navigate([ 'admin/policies/', 'edit', this.selectedPolicy.policyId ]); + } + + downloadTemplateAsJsonFile() { + if (this.templateFile) { + const url = URL.createObjectURL(this.templateFile); + const a = document.createElement('a'); + a.href = url; + a.download = this.templateFile.name; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + } + + protected readonly ViewMode = ViewMode; + + protected readonly PolicyAction = PolicyAction; + + protected readonly OperatorTypesAsSelectModel = OperatorTypesAsSelectModel; + + +} diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index de797d88ed..6dbbb7f71a 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -18,20 +18,47 @@ import { CalendarDateModel } from '@core/model/calendar-date.model'; * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +// RESPONSE + +export interface PolicyResponseMap { + [key: string]: PolicyEntry[]; +} + +export interface PolicyEntry { + validUntil: string; + payload: PolicyPayload; +} + +export interface PolicyPayload { + '@context': { + odrl: string; + }; + '@id': string; + policy: Policy; +} + + export interface Policy { - bpnSelection: string[]; - policyName: string; + // props in response policyId: string; - accessType: PolicyAction, createdOn: CalendarDateModel | string; validUntil: CalendarDateModel | string; - constraints: string[] permissions: PolicyPermission[]; + + // additional props + policyName?: string; + bpn?: string; + constraints?: string[] + accessType?: PolicyAction[], + } export interface PolicyPermission { action: PolicyAction; - constraint: Constraint; + constraint: { + and: PolicyConstraint[]; + or: null | PolicyConstraint[]; + }; } export enum PolicyAction { @@ -39,33 +66,68 @@ export enum PolicyAction { USE = 'use' } -export interface Constraint { - and: PolicyConstraint[], - or: PolicyConstraint[] +export interface PolicyConstraint { + leftOperand: string; + operator: { '@id': OperatorType }; + 'odrl:rightOperand': string; } -export interface PolicyConstraint { - leftOperand: string, - rightOperand: string, - operator: PolicyConstraintOperator +export enum OperatorType { + EQ = 'eq', + NEQ = 'neq', + LT = 'lt', + GT = 'gt', + IN = 'in', + LTEQ = 'lteq', + GTEQ = 'gteq', + ISA = 'isA', + HASPART = 'hasPart', + ISPARTOF = 'isPartOf', + ISONEOF = 'isOneOf', + ISALLOF = 'isAllOf', + ISNONEOF = 'isNoneOf', } -export interface PolicyConstraintOperator { - id: OperatorType; +export function mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyEntry[] { + const list: PolicyEntry[] = []; + for (const [ key, value ] of Object.entries(policyResponse)) { + value.forEach((entry) => { + entry.payload.policy.bpn = key; + entry.payload.policy.policyName = entry.payload['@id']; + entry.payload.policy.accessType = entry.payload.policy.permissions.map(rule => rule.action); + entry.payload.policy.constraints = mapDisplayPropsToPolicyRootLevel(entry); + list.push(entry); + }); + } + return list; } -export enum OperatorType { - EQ = 'eq', - NEQ = 'neq', - LT = 'lt', - GT = 'gt', - IN = 'in', - LTEQ = 'lteq', - GTEQ = 'gteq', - ISA = 'isA', - HASPART = 'hasPart', - ISPARTOF = 'isPartOf', - ISONEOF = 'isOneOf', - ISALLOF = 'isAllOf', - ISNONEOF = 'isNoneOf', +function mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { + entry.payload.policy.policyName = entry.payload['@id']; + entry.payload.policy.accessType = entry.payload.policy.permissions.map(rule => rule.action); + let constrainsList = []; + entry.payload.policy.permissions.forEach(permission => { + permission.constraint.and.forEach(andConstraint => { + constrainsList.push(andConstraint.leftOperand); + constrainsList.push(andConstraint.operator['@id']); + constrainsList.push(andConstraint['odrl:rightOperand']); + }); + permission.constraint?.or?.forEach(orConstraint => { + constrainsList.push(orConstraint.leftOperand); + constrainsList.push(orConstraint.operator['@id']); + constrainsList.push(orConstraint['odrl:rightOperand']); + }); + }); + return constrainsList; +} + +export function getPolicyFromEntryList(policyEntryList: PolicyEntry[]): Policy[] { + return policyEntryList.map(entry => entry.payload.policy); } + +/* +export function assemblePolicy(policy: Policy): Policy { + +} + + */ diff --git a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts index eb0d25c64f..62beac0bf6 100644 --- a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts +++ b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts @@ -4,7 +4,7 @@ export class PoliciesConfigurationModel extends TableFilterConfiguration { constructor() { const sortableColumns = { select: false, - bpnSelection: true, + bpn: true, policyName: true, policyId: true, accessType: true, diff --git a/frontend/src/app/modules/shared/model/view.model.ts b/frontend/src/app/modules/shared/model/view.model.ts index 8ba9bf0a91..9674fd67ba 100644 --- a/frontend/src/app/modules/shared/model/view.model.ts +++ b/frontend/src/app/modules/shared/model/view.model.ts @@ -40,3 +40,9 @@ export class View implements OptionalViewData, OptionalViewError, Optional loader?: boolean; error?: Error; } + +export enum ViewMode { + VIEW = 'view', + EDIT = 'edit', + CREATE = 'create' +} diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index b2c259662e..0d03136442 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -22,7 +22,7 @@ export class PolicyService { } getPaginatedPolicies(page: number, pageSize: number, sorting?: TableHeaderSort[], filter?: any): Observable> { - const sort = sorting.length ? sorting.map(array => `${ array[0] },${ array[1] }`) : [ 'createdOn,desc' ]; + const sort = sorting?.length ? sorting.map(array => `${ array[0] },${ array[1] }`) : [ 'createdOn,desc' ]; const body = { pageAble: { page: page, @@ -39,6 +39,10 @@ export class PolicyService { return this.apiService.post>(`${ this.url }/policies`, body); } + getPolicyById(policyId: string): Observable { + return this.apiService.getBy(`${ this.url }/policies/${ policyId }`); + } + publishAssets(assetIds: string[],policyId: string) { return this.apiService.post(`${this.url}/assets/publish`, {assetIds, policyId}); } diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index c4d427a6f6..43371dd526 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -62,7 +62,11 @@ "deleteError" : "Fehler bei der Löschung der selektierten Richtlinien.", "confirm" : "Bestätigen", "policyDeletion" : "Löschung der Richtlinien", - "deletionText" : "Möchten sie die Löschung der selektierten Richtlinien bestätigen?" + "deletionText" : "Möchten sie die Löschung der selektierten Richtlinien bestätigen?", + "policy" : "Richtlinie", + "create" : "erstellen", + "edit" : "bearbeiten", + "view" : "details" } } } diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index 6c4421e558..ff20837ba1 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -62,7 +62,11 @@ "deleteError" : "Error while deleting the selected policies.", "confirm" : "Confirm", "policyDeletion" : "Deletion of policies", - "deletionText" : "Do you want to confirm the deletion of the selected policies?" + "deletionText" : "Do you want to confirm the deletion of the selected policies?", + "policy" : "Policy", + "create" : "creation", + "edit" : "edit", + "view" : "details" } } } From d14c37af474f72217fa10f5ac68516bbd379c96c Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Mon, 3 Jun 2024 17:03:54 +0200 Subject: [PATCH 05/44] feature(policy): add policy management detailed view --- .../services/policy-mock/policy.model.ts | 12 +- .../policies/policies.component.html | 5 +- .../policies/policies.component.ts | 20 +-- .../policies/policies.facade.ts | 11 +- .../policies/policy.assembler.ts | 16 +++ .../policy-editor/policy-data.ts | 33 ++++- .../policy-editor.component.html | 134 ++++++++++++------ .../policy-editor/policy-editor.component.ts | 37 ++--- .../page/policies/model/policy.model.ts | 52 +++---- .../policies-configuration.model.ts | 14 +- .../components/table/table.component.html | 2 +- frontend/src/assets/locales/de/common.json | 3 +- frontend/src/assets/locales/en/common.json | 3 +- 13 files changed, 220 insertions(+), 122 deletions(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 65677b9f7a..501f15c6ba 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -52,8 +52,8 @@ export const mockedPolicyResponseMap: PolicyResponseMap = { '@id': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', 'policy': { 'policyId': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', - 'createdOn': '2024-03-28T03:34:42.9454448Z', - 'validUntil': '2025-12-12T23:59:59.999Z', + 'createdOn': '2024-05-29T06:18:40Z', + 'validUntil': '2024-05-29T06:18:40Z', 'permissions': [ { 'action': PolicyAction.USE, @@ -97,8 +97,8 @@ const mockedPolicies = { policyName: 'Mocked_Policy_Name_1', policyId: 'Mocked_Policy_1', accessType: PolicyAction.ACCESS, - createdOn: '2024-02-26T13:38:07+01:00', - validUntil: '2024-02-26T13:38:07+01:00', + createdOn: '2024-05-29T06:18:40Z', + validUntil: '2024-05-29T06:18:40Z', constraints: [ 'Membership = active', 'AND FrameworkAgreement.traceability in [active]', 'AND PURPOSE = ID 3.1 Trace' ], permissions: [ { @@ -131,8 +131,8 @@ const mockedPolicies = { policyName: 'Mocked_Policy_Name_2', policyId: 'Mocked_Policy_2', accessType: PolicyAction.USE, - createdOn: '2024-02-26T13:38:07+01:00', - validUntil: '2024-02-26T13:38:07+01:00', + createdOn: '2024-05-29T06:18:40Z', + validUntil: '2024-05-29T06:18:40Z', constraints: [ 'PURPOSE = ID 3.1 Trace', 'OR PURPOSE = ID 3.0 Trace' ], permissions: [ { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html index a74b219810..20d884a336 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html @@ -7,16 +7,15 @@ *viewContainer="policiesView$ | async; main: mainTmp; error: errorTmp; loading: loaderTmp">
) { - this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/' + this.policyFacade.selectedPolicy.policyId ]); + this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/' + selectedPolicy.policyId ]); } openEditView(selectedPolicy: any) { - this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/edit/' + this.policyFacade.selectedPolicy.policyId ]); + this.router.navigate([ 'admin/' + KnownAdminRoutes.POLICY_MANAGEMENT + '/edit/' + selectedPolicy.policyId ]); } openDeletionDialog() { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 939e3b5d5c..0813993c80 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; -import { CalendarDateModel } from '@core/model/calendar-date.model'; import { Pagination } from '@core/model/pagination.model'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { provideDataObject } from '@page/parts/core/parts.helper'; import { Policy } from '@page/policies/model/policy.model'; import { TableHeaderSort } from '@shared/components/table/table.model'; @@ -30,12 +30,7 @@ export class PoliciesFacade { this.policiesSubscription?.unsubscribe(); this.policiesSubscription = this.policyService.getPaginatedPolicies(page, pageSize, sorting, filter).pipe(map(response => { const assembled = response.content.map(policy => { - return { - ...policy, - createdOn: new CalendarDateModel(policy.createdOn as string), - validUntil: new CalendarDateModel(policy.validUntil as string), - accessType: policy.accessType.map(type => type.toUpperCase()), - }; + return PoliciesAssembler.assemblePolicy(policy); }); return { ...response, content: assembled } as Pagination; })).subscribe({ @@ -59,7 +54,7 @@ export class PoliciesFacade { public setSelectedPolicyById(policyId: string): void { this.policyService.getPolicyById(policyId).subscribe({ - next: data => (this.policiesState.selectedPolicy = { data: data }), + next: data => (this.policiesState.selectedPolicy = { data: PoliciesAssembler.assemblePolicy(data) }), error: error => (this.policiesState.selectedPolicy = { error }), }); } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts new file mode 100644 index 0000000000..463bcfe7ae --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -0,0 +1,16 @@ +import { CalendarDateModel } from '@core/model/calendar-date.model'; +import { Policy } from '@page/policies/model/policy.model'; + +export class PoliciesAssembler { + public static assemblePolicy(policy: Policy): Policy { + console.log(policy.createdOn, new CalendarDateModel(policy.createdOn as string)); + const formattedCreatedOn = new CalendarDateModel(policy.createdOn as string); + const formattedValidUntil = new CalendarDateModel(policy.validUntil as string); + return { + ...policy, + createdOn: formattedCreatedOn.isInitial() ? null : formattedCreatedOn.valueOf().toISOString().slice(0, 16), + validUntil: formattedValidUntil.isInitial() ? null : formattedValidUntil.valueOf().toISOString().slice(0, 16), + accessType: policy.accessType, + }; + } +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts index 46b177f413..7287410263 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts @@ -1,6 +1,35 @@ -import { OperatorType } from '@page/policies/model/policy.model'; +import { ConstraintLogicType, OperatorType } from '@page/policies/model/policy.model'; -export const OperatorTypesAsSelectModel: any[] = Object.keys(OperatorType).map(key => { +export const OperatorTypesAsSelectOptionsList: any[] = Object.keys(OperatorType).map(key => { + let convertedOperatorType = ''; + switch (key) { + case OperatorType.EQ: + convertedOperatorType = '='; + break; + case OperatorType.NEQ: + convertedOperatorType = '!='; + break; + case OperatorType.LT: + convertedOperatorType = '<'; + break; + case OperatorType.GT: + convertedOperatorType = '>'; + break; + case OperatorType.LTEQ: + convertedOperatorType = '<='; + break; + case OperatorType.GTEQ: + convertedOperatorType = '>='; + break; + default: + convertedOperatorType = key; + } + return { + label: convertedOperatorType, value: convertedOperatorType, + }; +}); + +export const ConstraintLogicTypeAsSelectOptionsList: any[] = Object.keys(ConstraintLogicType).map(key => { console.log(key); return { label: key, value: key, diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 76665f1776..fef63df07d 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -45,22 +45,26 @@
-
+
+ [matTooltipShowDelay]="500" + class="mr-2" + >
-
+ [matTooltipShowDelay]="500" + class="mr-2" + >
- +
-

Policy Type

+

{{ 'pageAdmin.policyManagement.policyConstraints' | i18n }}

Policy Type
-

Constraints

+

{{ 'pageAdmin.policyManagement.constraints' | i18n }}

+ [matTooltipShowDelay]="500" + class="mb-2" *ngIf="viewMode !== ViewMode.VIEW">
-
-
- - - - - - - - - + +
+
+ +
+
+
+ + + +
+ + +
+
+ + + +
+
+ + +
+
+
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index cfb794af58..6523e602b6 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -2,8 +2,11 @@ import { Component } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; -import { OperatorTypesAsSelectModel } from '@page/admin/presentation/policy-management/policy-editor/policy-data'; -import { Policy, PolicyAction } from '@page/policies/model/policy.model'; +import { + ConstraintLogicTypeAsSelectOptionsList, + OperatorTypesAsSelectOptionsList, +} from '@page/admin/presentation/policy-management/policy-editor/policy-data'; +import { ConstraintLogicType, Policy, PolicyAction } from '@page/policies/model/policy.model'; import { ViewMode } from '@shared/model/view.model'; import { Subscription } from 'rxjs'; @@ -21,6 +24,7 @@ export class PolicyEditorComponent { templateFile: File | null = null; templateFileName: string = ''; policyForm: FormGroup; + minDate: Date = new Date(); constructor(private readonly router: Router, public readonly policyFacade: PoliciesFacade, private fb: FormBuilder) { } @@ -32,14 +36,19 @@ export class PolicyEditorComponent { ngOnInit() { this.viewMode = this.initializeViewMode(); + this.policyForm = this.fb.group({ policyName: new FormControl(''), validUntil: new FormControl(''), bpns: new FormControl(''), - accessType: new FormControl(PolicyAction.ACCESS.toUpperCase()), + accessType: new FormControl(PolicyAction.ACCESS), constraints: this.fb.array([]), + constraintLogicType: new FormControl(ConstraintLogicType.AND), }); + this.policyForm.valueChanges.subscribe(next => console.log(next)); + + if (this.viewMode !== ViewMode.CREATE) { this.setSelectedPolicy(); this.selectedPolicySubscription = this.policyFacade.selectedPolicy$.subscribe(next => { @@ -49,18 +58,21 @@ export class PolicyEditorComponent { policyName: this.selectedPolicy?.policyName, validUntil: this.selectedPolicy?.validUntil, bpns: this.selectedPolicy?.bpn, - accessType: this.selectedPolicy?.accessType[0].toUpperCase(), + accessType: this.selectedPolicy?.accessType, }); let permissionList = this.selectedPolicy.permissions[0].constraint.and.length ? this.selectedPolicy.permissions[0].constraint.and : this.selectedPolicy.permissions[0].constraint.or; let constraintsList = permissionList.map((constraint) => this.fb.group({ leftOperand: this.fb.control(constraint.leftOperand), - operator: this.fb.control(constraint.operator['@id'].toUpperCase()), + operator: this.fb.control('='), rightOperand: this.fb.control(constraint['odrl:rightOperand']), })); this.policyForm.setControl('constraints', this.fb.array(constraintsList)); + if (this.viewMode === ViewMode.VIEW) { + this.policyForm.disable(); + } } @@ -81,14 +93,13 @@ export class PolicyEditorComponent { } private setSelectedPolicy(): void { - const policyIdFromUrl = this.router.url.split('/').pop(); this.policyFacade.setSelectedPolicyById(this.router.url.split('/').pop()); } addConstraintFormGroup() { this.constraints.push(this.fb.group({ leftOperand: new FormControl(''), - operator: new FormControl(null), + operator: new FormControl('='), rightOperand: new FormControl(''), })); } @@ -134,10 +145,6 @@ export class PolicyEditorComponent { } } - selectTemplateFile() { - - } - navigateToEditView() { this.router.navigate([ 'admin/policies/', 'edit', this.selectedPolicy.policyId ]); } @@ -156,10 +163,6 @@ export class PolicyEditorComponent { } protected readonly ViewMode = ViewMode; - - protected readonly PolicyAction = PolicyAction; - - protected readonly OperatorTypesAsSelectModel = OperatorTypesAsSelectModel; - - + protected readonly OperatorTypesAsSelectOptionsList = OperatorTypesAsSelectOptionsList; + protected readonly ConstraintLogicTypeAsSelectOptionsList = ConstraintLogicTypeAsSelectOptionsList; } diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index 6dbbb7f71a..aaff24ccf5 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -49,7 +49,7 @@ export interface Policy { policyName?: string; bpn?: string; constraints?: string[] - accessType?: PolicyAction[], + accessType?: PolicyAction, } @@ -58,12 +58,14 @@ export interface PolicyPermission { constraint: { and: PolicyConstraint[]; or: null | PolicyConstraint[]; + xone?: PolicyConstraint[]; + andsequence?: PolicyConstraint[]; }; } export enum PolicyAction { - ACCESS = 'access', - USE = 'use' + ACCESS = 'ACCESS', + USE = 'USE' } export interface PolicyConstraint { @@ -73,19 +75,26 @@ export interface PolicyConstraint { } export enum OperatorType { - EQ = 'eq', - NEQ = 'neq', - LT = 'lt', - GT = 'gt', - IN = 'in', - LTEQ = 'lteq', - GTEQ = 'gteq', - ISA = 'isA', - HASPART = 'hasPart', - ISPARTOF = 'isPartOf', - ISONEOF = 'isOneOf', - ISALLOF = 'isAllOf', - ISNONEOF = 'isNoneOf', + EQ = 'EQ', + NEQ = 'NEQ', + LT = 'LT', + GT = 'GT', + LTEQ = 'LTEQ', + GTEQ = 'GTEQ', + IN = 'IN', + ISA = 'ISA', + HASPART = 'HASPART', + ISPARTOF = 'ISPARTOF', + ISONEOF = 'ISONEOF', + ISALLOF = 'ISALLOF', + ISNONEOF = 'ISNONEOF', +} + +export enum ConstraintLogicType { + AND = 'AND', + OR = 'OR', + XONE = 'XONE', + ANDSEQUENCE = 'ANDSEQUENCE' } export function mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyEntry[] { @@ -94,7 +103,7 @@ export function mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyE value.forEach((entry) => { entry.payload.policy.bpn = key; entry.payload.policy.policyName = entry.payload['@id']; - entry.payload.policy.accessType = entry.payload.policy.permissions.map(rule => rule.action); + entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; entry.payload.policy.constraints = mapDisplayPropsToPolicyRootLevel(entry); list.push(entry); }); @@ -104,7 +113,7 @@ export function mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyE function mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { entry.payload.policy.policyName = entry.payload['@id']; - entry.payload.policy.accessType = entry.payload.policy.permissions.map(rule => rule.action); + entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; let constrainsList = []; entry.payload.policy.permissions.forEach(permission => { permission.constraint.and.forEach(andConstraint => { @@ -124,10 +133,3 @@ function mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { export function getPolicyFromEntryList(policyEntryList: PolicyEntry[]): Policy[] { return policyEntryList.map(entry => entry.payload.policy); } - -/* -export function assemblePolicy(policy: Policy): Policy { - -} - - */ diff --git a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts index 62beac0bf6..5dc0412b82 100644 --- a/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts +++ b/frontend/src/app/modules/shared/components/parts-table/policies-configuration.model.ts @@ -4,13 +4,13 @@ export class PoliciesConfigurationModel extends TableFilterConfiguration { constructor() { const sortableColumns = { select: false, - bpn: true, - policyName: true, - policyId: true, - accessType: true, - createdOn: true, - validUntil: true, - constraints: true, + bpn: false, + policyName: false, + policyId: false, + accessType: false, + createdOn: false, + validUntil: false, + constraints: false, menu: false, }; diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index e590411b0a..68d9a73647 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -81,7 +81,7 @@
Date: Tue, 4 Jun 2024 17:57:32 +0200 Subject: [PATCH 06/44] feature(policy): add policy management template application and policy creation --- .../services/policy-mock/policy.handler.ts | 2 +- .../services/policy-mock/policy.model.ts | 13 +- .../policies/policies.facade.ts | 6 +- .../policies/policy.assembler.ts | 37 ++++- .../policy-editor/policy-data.ts | 1 - .../policy-editor.component.html | 31 +++- .../policy-editor.component.scss | 31 ++++ .../policy-editor/policy-editor.component.ts | 140 ++++++++++++++---- .../page/policies/model/policy.model.ts | 58 +++----- .../modules/shared/service/policy.service.ts | 6 +- frontend/src/assets/locales/de/common.json | 4 +- .../src/assets/locales/de/page.admin.json | 23 ++- frontend/src/assets/locales/en/common.json | 4 +- .../src/assets/locales/en/page.admin.json | 24 ++- 14 files changed, 295 insertions(+), 85 deletions(-) diff --git a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts index f1807d3596..16d9d646fe 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts @@ -27,7 +27,7 @@ export const policyHandler = (_ => { }), rest.post(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(getPolicies())); + return res(ctx.status(200), ctx.json('success')); }), rest.get(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 501f15c6ba..e4ba8c1e44 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,11 +1,6 @@ import { PaginationResponse } from '@core/model/pagination.model'; -import { - mapToPolicyEntryList, - OperatorType, - Policy, - PolicyAction, - PolicyResponseMap, -} from '@page/policies/model/policy.model'; +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; +import { OperatorType, Policy, PolicyAction, PolicyResponseMap } from '@page/policies/model/policy.model'; /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation @@ -32,12 +27,12 @@ export const getPolicies = (): PaginationResponse => { pageSize: 10, totalItems: 1, pageCount: 1, - content: mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy), + content: PoliciesAssembler.mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy), } }; export const getPolicyById = (policyId: string | ReadonlyArray): Policy => { - return mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy).filter(policy => policy.policyId === policyId)[0]; + return PoliciesAssembler.mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy).filter(policy => policy.policyId === policyId)[0]; }; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 0813993c80..63c4a24202 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -3,7 +3,7 @@ import { Pagination } from '@core/model/pagination.model'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { provideDataObject } from '@page/parts/core/parts.helper'; -import { Policy } from '@page/policies/model/policy.model'; +import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; import { TableHeaderSort } from '@shared/components/table/table.model'; import { View } from '@shared/model/view.model'; import { PolicyService } from '@shared/service/policy.service'; @@ -69,4 +69,8 @@ export class PoliciesFacade { deletePolicies(selectedPolicies: Policy[]) { return this.policyService.deletePolicies(selectedPolicies.map(policy => policy.policyId)); } + + createPolicy(policyEntry: PolicyEntry) { + return this.policyService.createPolicy(policyEntry); + } } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 463bcfe7ae..5ee29ca7ef 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -1,16 +1,47 @@ import { CalendarDateModel } from '@core/model/calendar-date.model'; -import { Policy } from '@page/policies/model/policy.model'; +import { Policy, PolicyAction, PolicyEntry, PolicyResponseMap } from '@page/policies/model/policy.model'; export class PoliciesAssembler { public static assemblePolicy(policy: Policy): Policy { - console.log(policy.createdOn, new CalendarDateModel(policy.createdOn as string)); const formattedCreatedOn = new CalendarDateModel(policy.createdOn as string); const formattedValidUntil = new CalendarDateModel(policy.validUntil as string); return { ...policy, createdOn: formattedCreatedOn.isInitial() ? null : formattedCreatedOn.valueOf().toISOString().slice(0, 16), validUntil: formattedValidUntil.isInitial() ? null : formattedValidUntil.valueOf().toISOString().slice(0, 16), - accessType: policy.accessType, + accessType: policy.accessType.toUpperCase() as PolicyAction, }; } + + public static mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyEntry[] { + const list: PolicyEntry[] = []; + for (const [ key, value ] of Object.entries(policyResponse)) { + value.forEach((entry) => { + entry.payload.policy.bpn = key; + entry.payload.policy.constraints = this.mapDisplayPropsToPolicyRootLevel(entry); + list.push(entry); + }); + } + return list; + } + + public static mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { + entry.payload.policy.policyName = entry.payload['@id']; + entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; + let constrainsList = []; + entry.payload.policy.permissions.forEach(permission => { + permission.constraint.and.forEach(andConstraint => { + constrainsList.push(andConstraint.leftOperand); + constrainsList.push(andConstraint.operator['@id']); + constrainsList.push(andConstraint['odrl:rightOperand']); + }); + permission.constraint?.or?.forEach(orConstraint => { + constrainsList.push(orConstraint.leftOperand); + constrainsList.push(orConstraint.operator['@id']); + constrainsList.push(orConstraint['odrl:rightOperand']); + }); + }); + return constrainsList; + } + } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts index 7287410263..f812fce838 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-data.ts @@ -30,7 +30,6 @@ export const OperatorTypesAsSelectOptionsList: any[] = Object.keys(OperatorType) }); export const ConstraintLogicTypeAsSelectOptionsList: any[] = Object.keys(ConstraintLogicType).map(key => { - console.log(key); return { label: key, value: key, }; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index fef63df07d..e01a82afe6 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -74,19 +74,20 @@ >
- + + label="File" disabled>
{{ 'pageAdmin.policyManagement.apply' | i18n }} @@ -139,13 +140,35 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }}

>
-
+
+
+ {{ "pageAdmin.policyManagement.logic" | i18n }} +
+ {{ "pageAdmin.policyManagement.logicTypeHint" | i18n }} +
+
+
+
+ {{ "pageAdmin.policyManagement.leftOperand" | i18n }} +
+
+ {{ "pageAdmin.policyManagement.operator" | i18n }} +
+
+ {{ "pageAdmin.policyManagement.rightOperand" | i18n }} +
+ {{ "pageAdmin.policyManagement.rightOperandHint" | i18n }} + +
+
+
console.log(next)); - - if (this.viewMode !== ViewMode.CREATE) { this.setSelectedPolicy(); this.selectedPolicySubscription = this.policyFacade.selectedPolicy$.subscribe(next => { this.selectedPolicy = next?.data; if (next?.data) { - this.policyForm.patchValue({ - policyName: this.selectedPolicy?.policyName, - validUntil: this.selectedPolicy?.validUntil, - bpns: this.selectedPolicy?.bpn, - accessType: this.selectedPolicy?.accessType, - }); - - - let permissionList = this.selectedPolicy.permissions[0].constraint.and.length ? this.selectedPolicy.permissions[0].constraint.and : this.selectedPolicy.permissions[0].constraint.or; - let constraintsList = permissionList.map((constraint) => this.fb.group({ - leftOperand: this.fb.control(constraint.leftOperand), - operator: this.fb.control('='), - rightOperand: this.fb.control(constraint['odrl:rightOperand']), - })); - - this.policyForm.setControl('constraints', this.fb.array(constraintsList)); - if (this.viewMode === ViewMode.VIEW) { - this.policyForm.disable(); - } + this.updatePolicyForm(this.selectedPolicy); } @@ -134,7 +123,15 @@ export class PolicyEditorComponent { } savePolicy() { - + const policyEntry = this.mapPolicyFormToPolicyEntry(); + this.policyFacade.createPolicy(policyEntry).subscribe({ + next: next => { + this.toastService.success('pageAdmin.policyManagement.successMessage'); + }, + error: error => { + this.toastService.error('pageAdmin.policyManagement.successMessage'); + }, + }); } onFileSelected(event: Event) { @@ -162,6 +159,99 @@ export class PolicyEditorComponent { } } + applyTemplate() { + if (!this.templateFile) { + return; + } + const reader = new FileReader(); + + reader.onload = () => { + const fileContent = reader.result; + if (typeof fileContent === 'string') { + let policyEntry = PoliciesAssembler.mapToPolicyEntryList(JSON.parse(fileContent)); + let policy = PoliciesAssembler.assemblePolicy(policyEntry[0].payload.policy); + this.updatePolicyForm(policy); + } + }; + + reader.onerror = () => { + this.toastService.error(reader.error?.message); + }; + + reader.readAsText(this.templateFile); + + } + + updatePolicyForm(policy: Policy) { + this.policyForm.patchValue({ + policyName: policy?.policyName, + validUntil: policy?.validUntil, + bpns: policy?.bpn, + accessType: policy?.accessType, + }); + + + let permissionList = policy.permissions[0].constraint.and.length ? policy.permissions[0].constraint.and : policy.permissions[0].constraint.or; + let constraintsList = permissionList.map((constraint) => this.fb.group({ + leftOperand: this.fb.control(constraint.leftOperand), + operator: this.fb.control('='), + rightOperand: this.fb.control(constraint['odrl:rightOperand']), + })); + + this.policyForm.setControl('constraints', this.fb.array(constraintsList)); + if (this.viewMode === ViewMode.VIEW) { + this.policyForm.disable(); + } + } + + mapPolicyFormToPolicyEntry(): PolicyEntry { + let policyEntry: PolicyEntry; + let policyConstraints: PolicyConstraint[]; + + policyConstraints = this.policyForm.get('constraints').getRawValue().map((constraint) => { + return { + 'odrl:leftOperand': constraint.leftOperand, + 'odrl:operator': { + '@id': 'odrl:' + getOperatorType(constraint.operator).toLowerCase(), + }, + 'odrl:rightOperand': constraint.rightOperand, + }; + }); + + policyEntry = { + validUntil: this.policyForm.get('validUntil').getRawValue() + '.000000000Z', + businessPartnerNumber: this.policyForm.get('bpns').getRawValue(), + payload: { + '@context': { + odrl: 'http://www.w3.org/ns/odrl/2/', + }, + '@id': this.policyForm.get('policyName').getRawValue(), + policy: { + policyId: this.policyForm.get('policyName').getRawValue(), + createdOn: new Date(Date.now()).toISOString().replace('Z', '000000Z'), + validUntil: this.policyForm.get('validUntil').getRawValue() + '.000000000Z', + permissions: [ + { + action: this.policyForm.get('accessType').getRawValue().toLowerCase(), + constraint: { + and: this.policyForm.get('constraintLogicType').getRawValue() === ConstraintLogicType.AND ? policyConstraints : null, + or: this.policyForm.get('constraintLogicType').getRawValue() === ConstraintLogicType.OR ? policyConstraints : null, + }, + }, + ], + }, + }, + }; + + if (policyEntry.payload.policy.permissions[0].constraint?.and.length) { + delete policyEntry.payload.policy.permissions[0].constraint?.or; + } else { + delete policyEntry.payload.policy.permissions[0].constraint?.and; + } + + return policyEntry; + } + protected readonly ViewMode = ViewMode; protected readonly OperatorTypesAsSelectOptionsList = OperatorTypesAsSelectOptionsList; protected readonly ConstraintLogicTypeAsSelectOptionsList = ConstraintLogicTypeAsSelectOptionsList; diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index aaff24ccf5..9d06c61847 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -27,6 +27,7 @@ export interface PolicyResponseMap { export interface PolicyEntry { validUntil: string; payload: PolicyPayload; + businessPartnerNumber?: string; } export interface PolicyPayload { @@ -69,9 +70,12 @@ export enum PolicyAction { } export interface PolicyConstraint { - leftOperand: string; - operator: { '@id': OperatorType }; - 'odrl:rightOperand': string; + leftOperand?: string; + 'odrl:leftOperand'?: string; + operator?: { '@id': OperatorType }; + 'odrl:operator'?: { '@id': OperatorType }; + rightOperand?: string; + 'odrl:rightOperand'?: string; } export enum OperatorType { @@ -90,6 +94,21 @@ export enum OperatorType { ISNONEOF = 'ISNONEOF', } +const OperatorSignsToTypes: { [key: string]: OperatorType } = { + '=': OperatorType.EQ, + '!=': OperatorType.NEQ, + '<': OperatorType.LT, + '>': OperatorType.GT, + '<=': OperatorType.LTEQ, + '>=': OperatorType.GTEQ, + ...OperatorType, + // Add more mappings as needed +}; + +export function getOperatorType(sign: string): OperatorType | undefined { + return OperatorSignsToTypes[sign]; +} + export enum ConstraintLogicType { AND = 'AND', OR = 'OR', @@ -97,39 +116,6 @@ export enum ConstraintLogicType { ANDSEQUENCE = 'ANDSEQUENCE' } -export function mapToPolicyEntryList(policyResponse: PolicyResponseMap): PolicyEntry[] { - const list: PolicyEntry[] = []; - for (const [ key, value ] of Object.entries(policyResponse)) { - value.forEach((entry) => { - entry.payload.policy.bpn = key; - entry.payload.policy.policyName = entry.payload['@id']; - entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; - entry.payload.policy.constraints = mapDisplayPropsToPolicyRootLevel(entry); - list.push(entry); - }); - } - return list; -} - -function mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { - entry.payload.policy.policyName = entry.payload['@id']; - entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; - let constrainsList = []; - entry.payload.policy.permissions.forEach(permission => { - permission.constraint.and.forEach(andConstraint => { - constrainsList.push(andConstraint.leftOperand); - constrainsList.push(andConstraint.operator['@id']); - constrainsList.push(andConstraint['odrl:rightOperand']); - }); - permission.constraint?.or?.forEach(orConstraint => { - constrainsList.push(orConstraint.leftOperand); - constrainsList.push(orConstraint.operator['@id']); - constrainsList.push(orConstraint['odrl:rightOperand']); - }); - }); - return constrainsList; -} - export function getPolicyFromEntryList(policyEntryList: PolicyEntry[]): Policy[] { return policyEntryList.map(entry => entry.payload.policy); } diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 0d03136442..c3cfdb004a 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -4,7 +4,7 @@ import { ApiService } from '@core/api/api.service'; import { Pagination } from '@core/model/pagination.model'; import { environment } from '@env'; import { FilterOperator, getFilterOperatorValue } from '@page/parts/model/parts.model'; -import { Policy } from '@page/policies/model/policy.model'; +import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; import { TableHeaderSort } from '@shared/components/table/table.model'; import { isDateFilter, isDateRangeFilter, isSameDate, isStartsWithFilter } from '@shared/helper/filter-helper'; import { Observable } from 'rxjs'; @@ -109,4 +109,8 @@ export class PolicyService { deletePolicies(policyIds: string[]) { return this.apiService.delete(`${ this.url }/policies`, new HttpParams().set('policyIds', policyIds.toString())); } + + createPolicy(policyEntry: PolicyEntry): Observable { + return this.apiService.post(`${ this.url }/policies`, policyEntry); + } } diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index af8b194d71..ceb1c4ba52 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -67,7 +67,9 @@ "goBack": "Zurück", "publishAssets": "Produkte veröffentlichen", "maximizeTable": "Volle Breite", - "userSettings": "Tabellen Einstellung" + "userSettings" : "Tabellen Einstellung", + "uploadFile" : "Vorlage aus Datei hochladen", + "downloadFile" : "Vorlage als Datei herunterladen" }, "publisher": { "selectedAssets": "Ausgewählte Produkte", diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 43371dd526..51406e4a3d 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -66,7 +66,28 @@ "policy" : "Richtlinie", "create" : "erstellen", "edit" : "bearbeiten", - "view" : "details" + "view" : "details", + "selectFileHint" : "Name der selektierten Vorlage", + "applyChange" : "Vorlage anwenden um den Inhalt der Richtlinie mit dieser zu überschreiben", + "chooseFile" : "Selektieren Sie eine Vorlage um Änderungen anzuwenden", + "apply" : "Anwenden", + "policyName" : "Richtlinienname", + "validUntil" : "Gültig bis", + "bpnls" : "BPNLs", + "policyConstraints" : "Richtlinientyp", + "accessType" : "Zugriffstyp", + "constraints" : "Regeln", + "logic" : "Logik", + "logicTypeHint" : "Die Reihenfolge der Regeln wird berücksichtigt", + "constraintLogicType" : "Logik der Regel", + "leftOperand" : "Linker Operand", + "operator" : "Operator", + "rightOperand" : "Rechter Operand", + "rightOperandHint" : "Bitte geben Sie kommagetrennte Zeichenfolgen für die Operatoren IN, ISONEOF, ISALLOF, ISNONEOF an", + "moveDownward" : "Nach unten verschieben", + "moveUpward" : "Nach oben verschieben", + "successMessage" : "Richtlinie wurde erfolgreich gespeichert", + "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern" } } } diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index eeed461775..fed2cb8a23 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -65,7 +65,9 @@ "goBack": "Back", "publishAssets": "Publish assets", "maximizeTable": "Full width", - "userSettings": "Table settings" + "userSettings" : "Table settings", + "uploadFile" : "Upload template file", + "downloadFile" : "Download template as file" }, "publisher": { "selectedAssets": "Assets selected", diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index ff20837ba1..299d6f7cce 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -66,7 +66,29 @@ "policy" : "Policy", "create" : "creation", "edit" : "edit", - "view" : "details" + "view" : "details", + "selectFileHint" : "Selected template filename", + "applyChange" : "Apply template to overwrite content with the provided template", + "chooseFile" : "Select a template file to be able to apply it", + "apply" : "Apply", + "policyName" : "Policy name", + "validUntil" : "Valid until", + "bpnls" : "BPNLs", + "policyConstraints" : "Policy type", + "accessType" : "Access type", + "constraints" : "Constraints", + "logic" : "Logic", + "logicTypeHint" : "Please keep in mind, that the order of constraints matters", + "constraintLogicType" : "Constraint logic", + "leftOperand" : "Left operand", + "operator" : "Operator", + "rightOperand" : "Right operand", + "rightOperandHint" : "Please provide comma separated strings for the operators IN, ISONEOF, ISALLOF, ISNONEOF", + "moveDownward" : "Move downward", + "moveUpward" : "Move upward", + "successMessage" : "Successfully saved policy", + "errorMessage" : "Error while trying to save policy" + } } } From 87bf7442bc82b25f899977f75da5ff9a538fdbe0 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 5 Jun 2024 13:48:49 +0200 Subject: [PATCH 07/44] feature(policy): #832 removed pagination, added create and update api requests --- .../services/policy-mock/policy.handler.ts | 13 ++- .../services/policy-mock/policy.model.ts | 99 ++++++++++--------- .../policies/policies.component.html | 4 +- .../policies/policies.component.ts | 21 +--- .../policies/policies.facade.ts | 18 ++-- .../policies/policies.state.ts | 9 +- .../policies/policy.assembler.ts | 26 ++++- .../policy-editor/policy-editor.component.ts | 25 +++-- .../page/policies/model/policy.model.ts | 9 +- .../autocomplete-strategy.ts | 21 ---- .../components/table/table.component.html | 2 +- .../modules/shared/service/policy.service.ts | 88 +---------------- .../src/assets/locales/de/page.admin.json | 2 +- .../src/assets/locales/en/page.admin.json | 2 +- 14 files changed, 134 insertions(+), 205 deletions(-) diff --git a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts index 16d9d646fe..2ae9a406b3 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts @@ -27,13 +27,22 @@ export const policyHandler = (_ => { }), rest.post(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json('success')); + return res(ctx.status(201), ctx.json('success')); }), rest.get(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { const { policyId } = req.params; const policy = getPolicyById(policyId); return res(ctx.status(200), ctx.json(policy)); - }) + }), + + rest.put(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { + return res(ctx.status(200), ctx.json('success')); + }), + + rest.delete(`*${ environment.apiUrl }/policies/:policyIds`, (req, res, ctx) => { + return res(ctx.status(200), ctx.json('success')); + }), + ] })(); diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index e4ba8c1e44..41d3793366 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,6 +1,4 @@ -import { PaginationResponse } from '@core/model/pagination.model'; -import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; -import { OperatorType, Policy, PolicyAction, PolicyResponseMap } from '@page/policies/model/policy.model'; +import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation @@ -21,64 +19,67 @@ import { OperatorType, Policy, PolicyAction, PolicyResponseMap } from '@page/pol * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ // For now Mocks are built by current response (any). This is because Policy Model changes frequently -export const getPolicies = (): PaginationResponse => { - return { - page: 0, - pageSize: 10, - totalItems: 1, - pageCount: 1, - content: PoliciesAssembler.mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy), - } +export const getPolicies = (): Policy[] => { + return mockedPolicyList; }; export const getPolicyById = (policyId: string | ReadonlyArray): Policy => { - return PoliciesAssembler.mapToPolicyEntryList(mockedPolicyResponseMap).map(entry => entry.payload.policy).filter(policy => policy.policyId === policyId)[0]; + return mockedPolicyList.filter(policy => policy.policyId === policyId)[0]; }; -export const mockedPolicyResponseMap: PolicyResponseMap = { - 'BPNL1234567890AB': [ - { - 'validUntil': '2025-12-12T23:59:59.999Z', - 'payload': { - '@context': { - 'odrl': 'http://www.w3.org/ns/odrl/2/', +export const mockedPolicyList: Policy[] = [ + { + 'policyId': 'default-policy', + 'createdOn': '2024-05-29T06:18:40Z', + 'validUntil': '2029-05-29T06:18:40Z', + 'permissions': [ + { + 'action': PolicyAction.USE, + 'constraints': { + 'and': null, + 'or': [ + { + 'leftOperand': 'cx-policy:FrameworkAgreement', + 'operatorTypeResponse': OperatorType.EQ, + 'rightOperand': 'traceability:1.0', + }, + { + 'leftOperand': 'cx-policy:UsagePurpose', + 'operatorTypeResponse': OperatorType.EQ, + 'rightOperand': 'cx.core.industrycore:1', + }, + ], }, - '@id': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', - 'policy': { - 'policyId': 'e917f5f-8dac-49ac-8d10-5b4d254d2b48', - 'createdOn': '2024-05-29T06:18:40Z', - 'validUntil': '2024-05-29T06:18:40Z', - 'permissions': [ + }, + ], + }, + { + 'policyId': 'default-policy-2', + 'createdOn': '2024-05-29T06:18:40Z', + 'validUntil': '2029-05-29T06:18:40Z', + 'permissions': [ + { + 'action': PolicyAction.USE, + 'constraints': { + 'and': [ { - 'action': PolicyAction.USE, - 'constraint': { - 'and': [ - { - 'leftOperand': 'Membership', - 'operator': { - '@id': OperatorType.EQ, - }, - 'odrl:rightOperand': 'active', - }, - { - 'leftOperand': 'PURPOSE', - 'operator': { - '@id': OperatorType.EQ, - }, - 'odrl:rightOperand': 'ID 3.1 Trace', - }, - ], - 'or': null, - }, + 'leftOperand': 'cx-policy:FrameworkAgreement', + 'operatorTypeResponse': OperatorType.EQ, + 'rightOperand': 'traceability:1.0', + }, + { + 'leftOperand': 'cx-policy:UsagePurpose', + 'operatorTypeResponse': OperatorType.EQ, + 'rightOperand': 'cx.core.industrycore:1', }, ], + 'or': null, }, }, - }, - ], - 'BPNA1234567890DF': [], -}; + ], + }, +]; const mockedPolicies = { page: 0, diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html index 20d884a336..a2fc3018e1 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html @@ -7,7 +7,7 @@ *viewContainer="policiesView$ | async; main: mainTmp; error: errorTmp; loading: loaderTmp"> >>; + policiesView$: Observable>; tableConfig: TableConfig; selectedPolicies: Policy[]; policyFilter: any; @@ -72,27 +70,16 @@ export class PoliciesComponent { this.policiesView$ = this.policyFacade.policies$; this.policiesView$.pipe(take(2)).subscribe(data => { - if (data?.data?.content.length) { + if (data?.data?.length) { return; } else { - this.policyFacade.setPolicies(0, 10); + this.policyFacade.setPolicies(); } }); } - filterActivated(policyFilter: any): void { - this.policyFilter = policyFilter; - this.policyFacade.setPolicies(this.pagination.page, this.pagination.pageSize, this.multiSortList, this.policyFilter); - } - - onTableConfigChange(pagination: TableEventConfig): void { - this.pagination = pagination; - TableSortingUtil.setTableSortingList(pagination.sorting, this.multiSortList, this.ctrlKeyState); - this.policyFacade.setPolicies(pagination.page, pagination.pageSize, this.multiSortList, this.policyFilter); - } - multiSelection(selectedPolicies: Policy[]) { this.selectedPolicies = selectedPolicies; } @@ -125,7 +112,7 @@ export class PoliciesComponent { this.policyFacade.deletePolicies(this.selectedPolicies).subscribe({ next: value => { this.toastService.success('pageAdmin.policyManagement.deleteSuccess'); - this.policyFacade.setPolicies(this.pagination.page, this.pagination.pageSize, this.multiSortList, this.policyFilter); + this.policyFacade.setPolicies(); }, error: err => { this.toastService.error('pageAdmin.policyManagement.deleteError'); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 63c4a24202..93e377577c 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -1,10 +1,7 @@ import { Injectable } from '@angular/core'; -import { Pagination } from '@core/model/pagination.model'; import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; -import { provideDataObject } from '@page/parts/core/parts.helper'; import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; -import { TableHeaderSort } from '@shared/components/table/table.model'; import { View } from '@shared/model/view.model'; import { PolicyService } from '@shared/service/policy.service'; import { Observable, Subject, Subscription } from 'rxjs'; @@ -22,19 +19,18 @@ export class PoliciesFacade { ) { } - get policies$(): Observable>> { + get policies$(): Observable> { return this.policiesState.policies$; } - public setPolicies(page: number, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: any): void { + public setPolicies(): void { this.policiesSubscription?.unsubscribe(); - this.policiesSubscription = this.policyService.getPaginatedPolicies(page, pageSize, sorting, filter).pipe(map(response => { - const assembled = response.content.map(policy => { + this.policiesSubscription = this.policyService.getPolicies().pipe(map(response => { + return response.map(policy => { return PoliciesAssembler.assemblePolicy(policy); }); - return { ...response, content: assembled } as Pagination; })).subscribe({ - next: data => (this.policiesState.policies = { data: provideDataObject(data) }), + next: data => (this.policiesState.policies = { data: data }), error: error => (this.policiesState.policies = { error }), }); } @@ -73,4 +69,8 @@ export class PoliciesFacade { createPolicy(policyEntry: PolicyEntry) { return this.policyService.createPolicy(policyEntry); } + + updatePolicy(policyEntry: PolicyEntry) { + return this.policyService.updatePolicy(policyEntry); + } } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts index ef770de1b6..a3068f0902 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.state.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Pagination } from '@core/model/pagination.model'; import { Policy } from '@page/policies/model/policy.model'; import { State } from '@shared/model/state'; import { View } from '@shared/model/view.model'; @@ -7,15 +6,15 @@ import { Observable } from 'rxjs'; @Injectable() export class PoliciesState { - private readonly _policies$ = new State>>({ loader: true }); + private readonly _policies$ = new State>({ loader: true }); private readonly _selectedPolicy$: State> = new State>({ loader: true }); - public get policies$(): Observable>> { + public get policies$(): Observable> { return this._policies$.observable; } - public set policies({ data, loader, error }: View>) { - const policiesView: View> = { data, loader, error }; + public set policies({ data, loader, error }: View) { + const policiesView: View = { data, loader, error }; this._policies$.update(policiesView); } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 5ee29ca7ef..496208d450 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -7,9 +7,11 @@ export class PoliciesAssembler { const formattedValidUntil = new CalendarDateModel(policy.validUntil as string); return { ...policy, + policyName: policy.policyId, createdOn: formattedCreatedOn.isInitial() ? null : formattedCreatedOn.valueOf().toISOString().slice(0, 16), validUntil: formattedValidUntil.isInitial() ? null : formattedValidUntil.valueOf().toISOString().slice(0, 16), - accessType: policy.accessType.toUpperCase() as PolicyAction, + accessType: policy.permissions[0].action.toUpperCase() as PolicyAction, + constraints: this.mapDisplayPropsToPolicyRootLevelFromPolicy(policy), }; } @@ -18,14 +20,14 @@ export class PoliciesAssembler { for (const [ key, value ] of Object.entries(policyResponse)) { value.forEach((entry) => { entry.payload.policy.bpn = key; - entry.payload.policy.constraints = this.mapDisplayPropsToPolicyRootLevel(entry); + entry.payload.policy.constraints = this.mapDisplayPropsToPolicyRootLevelFromPolicyEntry(entry); list.push(entry); }); } return list; } - public static mapDisplayPropsToPolicyRootLevel(entry: PolicyEntry): string[] { + public static mapDisplayPropsToPolicyRootLevelFromPolicyEntry(entry: PolicyEntry): string[] { entry.payload.policy.policyName = entry.payload['@id']; entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; let constrainsList = []; @@ -44,4 +46,22 @@ export class PoliciesAssembler { return constrainsList; } + public static mapDisplayPropsToPolicyRootLevelFromPolicy(policy: Policy): string[] { + + let constrainsList = []; + policy.permissions.forEach(permission => { + permission.constraints?.and?.forEach(andConstraint => { + constrainsList.push(andConstraint.leftOperand); + constrainsList.push(andConstraint.operatorTypeResponse); + constrainsList.push(andConstraint.rightOperand); + }); + permission.constraints?.or?.forEach(orConstraint => { + constrainsList.push(orConstraint.leftOperand); + constrainsList.push(orConstraint.operatorTypeResponse); + constrainsList.push(orConstraint.rightOperand); + }); + }); + return constrainsList; + } + } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index 67d36d11c1..281151d063 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -63,8 +63,6 @@ export class PolicyEditorComponent { if (next?.data) { this.updatePolicyForm(this.selectedPolicy); } - - }); } @@ -124,13 +122,13 @@ export class PolicyEditorComponent { savePolicy() { const policyEntry = this.mapPolicyFormToPolicyEntry(); - this.policyFacade.createPolicy(policyEntry).subscribe({ - next: next => { + const request = this.viewMode === ViewMode.EDIT ? this.policyFacade.updatePolicy(policyEntry) : this.policyFacade.createPolicy(policyEntry); + request.subscribe({ + next: () => { this.toastService.success('pageAdmin.policyManagement.successMessage'); + this.router.navigate([ 'admin', 'policies', policyEntry.payload.policy.policyId ]); }, - error: error => { - this.toastService.error('pageAdmin.policyManagement.successMessage'); - }, + error: () => this.toastService.error('pageAdmin.policyManagement.successMessage'), }); } @@ -183,15 +181,24 @@ export class PolicyEditorComponent { } updatePolicyForm(policy: Policy) { + + const isFromTemplate = !policy?.permissions[0]?.constraints; this.policyForm.patchValue({ policyName: policy?.policyName, validUntil: policy?.validUntil, bpns: policy?.bpn, accessType: policy?.accessType, + constraintLogicType: policy?.permissions[0]?.constraints?.and?.length ? ConstraintLogicType.AND : ConstraintLogicType.OR, }); + if (isFromTemplate) { + this.policyForm.patchValue({ constraintLogicType: policy?.permissions[0]?.constraint?.and?.length ? ConstraintLogicType.AND : ConstraintLogicType.OR }); + } + let permissionList = policy?.permissions[0]?.constraints?.and?.length ? policy?.permissions[0]?.constraints?.and : policy?.permissions[0]?.constraints?.or; + if (!permissionList) { + permissionList = policy?.permissions[0]?.constraint?.and?.length ? policy?.permissions[0]?.constraint?.and : policy?.permissions[0]?.constraint?.or; + } - let permissionList = policy.permissions[0].constraint.and.length ? policy.permissions[0].constraint.and : policy.permissions[0].constraint.or; let constraintsList = permissionList.map((constraint) => this.fb.group({ leftOperand: this.fb.control(constraint.leftOperand), operator: this.fb.control('='), @@ -243,7 +250,7 @@ export class PolicyEditorComponent { }, }; - if (policyEntry.payload.policy.permissions[0].constraint?.and.length) { + if (policyEntry.payload.policy.permissions[0].constraint?.and?.length) { delete policyEntry.payload.policy.permissions[0].constraint?.or; } else { delete policyEntry.payload.policy.permissions[0].constraint?.and; diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index 9d06c61847..0db4757d2c 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -56,7 +56,13 @@ export interface Policy { export interface PolicyPermission { action: PolicyAction; - constraint: { + constraint?: { + and: PolicyConstraint[]; + or: null | PolicyConstraint[]; + xone?: PolicyConstraint[]; + andsequence?: PolicyConstraint[]; + }; + constraints?: { and: PolicyConstraint[]; or: null | PolicyConstraint[]; xone?: PolicyConstraint[]; @@ -72,6 +78,7 @@ export enum PolicyAction { export interface PolicyConstraint { leftOperand?: string; 'odrl:leftOperand'?: string; + operatorTypeResponse?: OperatorType; operator?: { '@id': OperatorType }; 'odrl:operator'?: { '@id': OperatorType }; rightOperand?: string; diff --git a/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts b/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts index c92c980146..15183bcac9 100644 --- a/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts +++ b/frontend/src/app/modules/shared/components/multi-select-autocomplete/autocomplete-strategy.ts @@ -21,7 +21,6 @@ import { AdminService } from '@page/admin/core/admin.service'; import { NotificationChannel, TableType } from '@shared/components/multi-select-autocomplete/table-type.model'; import { NotificationService } from '@shared/service/notification.service'; import { PartsService } from '@shared/service/parts.service'; -import { PolicyService } from '@shared/service/policy.service'; import { of } from 'rxjs'; export abstract class AutocompleteStrategy { @@ -95,32 +94,12 @@ export class ContractsStrategy extends AutocompleteStrategy { } } -@Injectable({ - providedIn: 'any', -}) -export class PoliciesStrategy extends AutocompleteStrategy { - policyService: PolicyService; - - constructor(policyService: PolicyService) { - super(); - this.policyService = policyService; - } - - retrieveSuggestionValues(tableType: TableType, filterColumns: string, searchElement: string): any { - return this.policyService.getDistinctFilterValues( - filterColumns, - searchElement, - ); - } -} - export const AutocompleteStrategyMap = new Map([ [ TableType.AS_BUILT_OWN, PartsStrategy ], [ TableType.AS_PLANNED_OWN, PartsStrategy ], [ TableType.RECEIVED_NOTIFICATION, NotificationStrategy ], [ TableType.SENT_NOTIFICATION, NotificationStrategy ], [ TableType.CONTRACTS, ContractsStrategy ], - [ TableType.POLICIES, PoliciesStrategy ], ]); diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index 68d9a73647..d60a3f2a9a 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -90,7 +90,7 @@
diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index c3cfdb004a..0be5694994 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -1,12 +1,8 @@ import { HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiService } from '@core/api/api.service'; -import { Pagination } from '@core/model/pagination.model'; import { environment } from '@env'; -import { FilterOperator, getFilterOperatorValue } from '@page/parts/model/parts.model'; import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; -import { TableHeaderSort } from '@shared/components/table/table.model'; -import { isDateFilter, isDateRangeFilter, isSameDate, isStartsWithFilter } from '@shared/helper/filter-helper'; import { Observable } from 'rxjs'; @Injectable({ @@ -17,26 +13,7 @@ export class PolicyService { constructor(private readonly apiService: ApiService) {} getPolicies(): Observable { - return this.apiService - .getBy(`${this.url}/policies`); - } - - getPaginatedPolicies(page: number, pageSize: number, sorting?: TableHeaderSort[], filter?: any): Observable> { - const sort = sorting?.length ? sorting.map(array => `${ array[0] },${ array[1] }`) : [ 'createdOn,desc' ]; - const body = { - pageAble: { - page: page, - size: pageSize, - sorting: sort, - }, - searchCriteria: {}, - }; - - if (filter) { - body.searchCriteria = { filter: this.createFilterList(filter, 'AND') }; - } - - return this.apiService.post>(`${ this.url }/policies`, body); + return this.apiService.get(`${ this.url }/policies`); } getPolicyById(policyId: string): Observable { @@ -47,65 +24,6 @@ export class PolicyService { return this.apiService.post(`${this.url}/assets/publish`, {assetIds, policyId}); } - - private createFilterList(filter: Object, filterOperator: string) { - - let filterList = []; - - for (const key in filter) { - let operator: string; - const filterValues: string = filter[key]; - if (!filterValues) { - continue; - } - // has date - if (isDateFilter(key)) { - if (isDateRangeFilter(filterValues)) { - const [ startDate, endDate ] = filterValues.split(','); - if (isSameDate(startDate, endDate)) { - operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); - filterList.push(`${ key },${ operator },${ startDate },${ filterOperator }`); - continue; - } - let endDateOperator = getFilterOperatorValue(FilterOperator.BEFORE_LOCAL_DATE); - operator = getFilterOperatorValue((FilterOperator.AFTER_LOCAL_DATE)); - filterList.push(`${ key },${ operator },${ startDate },${ filterOperator }`); - filterList.push(`${ key },${ endDateOperator },${ endDate },${ filterOperator }`); - continue; - } else if (filterValues && filterValues.length != 0) { - operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); - filterList.push(`${ key },${ operator },${ filterValues },${ filterOperator }`); - } - } - - // has multiple values - if (isStartsWithFilter(key) && Array.isArray(filter[key])) { - operator = getFilterOperatorValue(FilterOperator.EQUAL); - - for (const value of filter[key]) { - filterList.push(`${ key },${ operator },${ value },${ filterOperator }`); - } - } - - // has single value - if (isStartsWithFilter(key) && !Array.isArray(filter[key])) { - operator = getFilterOperatorValue(FilterOperator.STARTS_WITH); - filterList.push(`${ key },${ operator },${ filterValues },${ filterOperator }`); - } - - } - return filterList; - } - - getDistinctFilterValues(filterColumns: string, searchElement: string) { - let params = new HttpParams() - .set('fieldName', filterColumns) - .set('startWith', searchElement) - .set('size', 200); - - return this.apiService.getBy(`${ this.url }/policies/distinctFilterValues`, params); - } - deletePolicies(policyIds: string[]) { return this.apiService.delete(`${ this.url }/policies`, new HttpParams().set('policyIds', policyIds.toString())); } @@ -113,4 +31,8 @@ export class PolicyService { createPolicy(policyEntry: PolicyEntry): Observable { return this.apiService.post(`${ this.url }/policies`, policyEntry); } + + updatePolicy(policyEntry: PolicyEntry) { + return this.apiService.put(`${ this.url }/policies/` + policyEntry.payload.policy.policyId, policyEntry); + } } diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 51406e4a3d..e73d9dd3ac 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -52,7 +52,7 @@ "selectAtleastOne": "Selektieren Sie mindestens einen Vertrag um exportieren zu können.", "exportAsCSV": ".CSV-Datei Export", "overview": "Übersicht", - "policyDetail": "Richtlinien details", + "policyDetail" : "Vereinbarungsdetails", "jsonViewer": "Json Ansicht", "jsonTreeViewer": "Json-Baumansicht" }, diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index 299d6f7cce..b14151bffd 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -52,7 +52,7 @@ "selectAtleastOne": "Select atleast one contract to use the export functionality.", "exportAsCSV": ".CSV-File Export", "overview": "Overview", - "policyDetail": "Policy detail", + "policyDetail" : "Agreement details", "jsonViewer": "Json Viewer", "jsonTreeViewer": "Json Tree Viewer" }, From fd06eab3b43eeafb5a38d864387eefa208d6b5b9 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 5 Jun 2024 16:59:51 +0200 Subject: [PATCH 08/44] feature(policy): #832 added form validation and policy download --- .../policy-editor.component.html | 9 ++-- .../policy-editor/policy-editor.component.ts | 53 +++++++++++++------ .../shared/pipes/error-message.pipe.ts | 2 + frontend/src/assets/locales/de/common.json | 6 ++- .../src/assets/locales/de/page.admin.json | 3 +- frontend/src/assets/locales/en/common.json | 4 +- .../src/assets/locales/en/page.admin.json | 3 +- 7 files changed, 54 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index e01a82afe6..127ae8fa5c 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -19,7 +19,8 @@
-
+ (click)="savePolicy()" + [isDisabled]="policyForm.invalid || constraints.length < 1" + >
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index 281151d063..a88a5690e9 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -1,6 +1,7 @@ import { Component } from '@angular/core'; -import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import { Router } from '@angular/router'; +import { bpnRegex } from '@page/admin/presentation/bpn-configuration/bpn-configuration.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { @@ -15,6 +16,7 @@ import { PolicyConstraint, PolicyEntry, } from '@page/policies/model/policy.model'; +import { BaseInputHelper } from '@shared/abstraction/baseInput/baseInput.helper'; import { ToastService } from '@shared/components/toasts/toast.service'; import { ViewMode } from '@shared/model/view.model'; import { Subscription } from 'rxjs'; @@ -48,9 +50,9 @@ export class PolicyEditorComponent { this.policyForm = this.fb.group({ - policyName: new FormControl(''), - validUntil: new FormControl(''), - bpns: new FormControl(''), + policyName: new FormControl('', [ Validators.required, Validators.minLength(8), Validators.maxLength(30) ]), + validUntil: new FormControl('', [ Validators.required, this.futureDateValidator ]), + bpns: new FormControl('', [ BaseInputHelper.getCustomPatternValidator(bpnRegex, 'bpn') ]), accessType: new FormControl(PolicyAction.ACCESS), constraints: this.fb.array([]), constraintLogicType: new FormControl(ConstraintLogicType.AND), @@ -128,7 +130,7 @@ export class PolicyEditorComponent { this.toastService.success('pageAdmin.policyManagement.successMessage'); this.router.navigate([ 'admin', 'policies', policyEntry.payload.policy.policyId ]); }, - error: () => this.toastService.error('pageAdmin.policyManagement.successMessage'), + error: () => this.toastService.error('pageAdmin.policyManagement.errorMessage'), }); } @@ -145,16 +147,18 @@ export class PolicyEditorComponent { } downloadTemplateAsJsonFile() { - if (this.templateFile) { - const url = URL.createObjectURL(this.templateFile); - const a = document.createElement('a'); - a.href = url; - a.download = this.templateFile.name; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } + const policy = this.mapPolicyFormToPolicyEntry(); + const data = JSON.stringify(policy, null, 2); + const blob = new Blob([ data ], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'policy-template-' + policy.payload.policy.policyId; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } applyTemplate() { @@ -200,9 +204,9 @@ export class PolicyEditorComponent { } let constraintsList = permissionList.map((constraint) => this.fb.group({ - leftOperand: this.fb.control(constraint.leftOperand), + leftOperand: this.fb.control(constraint.leftOperand, [ Validators.required ]), operator: this.fb.control('='), - rightOperand: this.fb.control(constraint['odrl:rightOperand']), + rightOperand: this.fb.control(constraint['odrl:rightOperand'], [ Validators.required ]), })); this.policyForm.setControl('constraints', this.fb.array(constraintsList)); @@ -259,7 +263,22 @@ export class PolicyEditorComponent { return policyEntry; } + private futureDateValidator = (control: FormControl): ValidationErrors | null => { + if (!control.value) { + return null; + } + + const currentDate = new Date(); + const inputDate = new Date(control.value); + if (inputDate < currentDate) { + return { pastDate: true }; + } + return null; + }; + + protected readonly ViewMode = ViewMode; protected readonly OperatorTypesAsSelectOptionsList = OperatorTypesAsSelectOptionsList; protected readonly ConstraintLogicTypeAsSelectOptionsList = ConstraintLogicTypeAsSelectOptionsList; } + diff --git a/frontend/src/app/modules/shared/pipes/error-message.pipe.ts b/frontend/src/app/modules/shared/pipes/error-message.pipe.ts index 041c627c35..a84659e966 100644 --- a/frontend/src/app/modules/shared/pipes/error-message.pipe.ts +++ b/frontend/src/app/modules/shared/pipes/error-message.pipe.ts @@ -81,7 +81,9 @@ export class ErrorMessagePipe implements PipeTransform { [ 'bpn', _ => getErrorMapping('bpn') ], [ 'invalidBpn', _ => getErrorMapping('invalidBpn' ) ], [ 'email', _ => getErrorMapping('email') ], + [ 'pastDate', _ => getErrorMapping('pastDate') ], [ 'generic', _ => getErrorMapping('generic') ], + [ 'minimumOneConstraint', _ => getErrorMapping('minimumOneConstraint') ], ]); const keys = Object.keys(errors); diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index ceb1c4ba52..75b1123882 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -219,12 +219,14 @@ "maxLength": "Bitte geben Sie maximal {{maxLength}} Zeichen ein. Momentan: {{current}}", "pattern": "Bitte geben Sie die Daten in folgendem Format ein: {{- pattern}}.", "url": "Bitte geben Sie eine valide URL ein.", - "bpn": "Bitte geben Sie eine valide BPN ein. BPN {{applicationBpn}} ist nicht erlaubt.", + "bpn" : "Bitte geben Sie eine valide BPN ein.", "maxDate": "Bitte wählen Sie ein Datum vor dem {{- maxDate}}.", "minDate": "Bitte wählen Sie ein Datum nach dem {{- minDate}}.", "currentDate": "Bitte wählen Sie ein Datum nach dem {{- currentDate}}.", "generic": "Die Eingabe ist ungültig.", - "invalidBpn": "Die eigene BPN darf nicht verwendet werden." + "invalidBpn" : "Die eigene BPN darf nicht verwendet werden.", + "pastDate" : "Bitte wählen Sie ein Datum in Zukunft aus.", + "minimumOneConstraint" : "Bitte fügen Sie mindestens eine valide Richtlinie hinzu." }, "requestAlert": { "headline": "Qualitätswarnung erstellen", diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index e73d9dd3ac..33b56e877a 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -87,7 +87,8 @@ "moveDownward" : "Nach unten verschieben", "moveUpward" : "Nach oben verschieben", "successMessage" : "Richtlinie wurde erfolgreich gespeichert", - "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern" + "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern", + "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus" } } } diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index fed2cb8a23..f8f941ee17 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -220,7 +220,9 @@ "minDate": "Please select a date that is after {{- minDate}}.", "currentDate": "Please select a date that is after {{- currentDate}}.", "generic": "Please enter valid data.", - "invalidBpn": "Must not be own BPN." + "invalidBpn" : "Must not be own BPN.", + "pastDate" : "Please select a date in the future.", + "minimumOneConstraint" : "Please add atleast one valid constraint to the policy" }, "unitTest": { "test01": "This is for unit tests purposes.", diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index b14151bffd..c50b1a52a6 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -87,7 +87,8 @@ "moveDownward" : "Move downward", "moveUpward" : "Move upward", "successMessage" : "Successfully saved policy", - "errorMessage" : "Error while trying to save policy" + "errorMessage" : "Error while trying to save policy", + "invalidForm" : "Please make sure to submit a valid form" } } From 6fa731edb3aa6ae3246b19250e8a17fb79a63ebb Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 15:06:35 +0200 Subject: [PATCH 09/44] feature(policy): #832 added form validation and template error handling --- .../policies/policy.assembler.ts | 76 +++++++++++++++++++ .../policy-editor.component.html | 22 ++++-- .../policy-editor/policy-editor.component.ts | 13 +++- .../page/policies/model/policy.model.ts | 25 ++++++ .../src/assets/locales/de/page.admin.json | 1 + .../src/assets/locales/en/page.admin.json | 1 + 6 files changed, 128 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 496208d450..68e7639618 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -64,4 +64,80 @@ export class PoliciesAssembler { return constrainsList; } + public static validatePoliciesTemplate(data: any) { + + if (typeof data !== 'object' || data === null || !Array.isArray(data[Object.keys(data)[0]])) { + return false; + } + + for (const entry of data[Object.keys(data)[0]]) { + if (typeof entry.validUntil !== 'string') { + return false; + } + + const payload = entry.payload; + if (typeof payload !== 'object' || payload === null) { + return false; + } + + const context = payload['@context']; + if (typeof context !== 'object' || context === null) { + return false; + } + + if (typeof payload['@id'] !== 'string') { + return false; + } + + const policy = payload.policy; + if (typeof policy !== 'object' || policy === null) { + return false; + } + + if (typeof policy.policyId !== 'string' || + typeof policy.createdOn !== 'string' || + typeof policy.validUntil !== 'string' || + !Array.isArray(policy.permissions)) { + return false; + } + + for (const permission of policy.permissions) { + if (typeof permission.action !== 'string') { + return false; + } + + const constraint = permission.constraint; + if (typeof constraint !== 'object' || constraint === null || !Array.isArray(constraint.and) || (constraint.or !== null && !Array.isArray(constraint.or))) { + return false; + } + + if (constraint.and !== null) { + for (const andConstraint of constraint.and) { + if (typeof andConstraint.leftOperand !== 'string' || + typeof andConstraint.operator !== 'object' || + andConstraint.operator === null || + typeof andConstraint.operator['@id'] !== 'string' || + typeof andConstraint['odrl:rightOperand'] !== 'string') { + return false; + } + } + } + + if (constraint.or !== null) { + for (const orConstraint of constraint.or) { + if (typeof orConstraint.leftOperand !== 'string' || + typeof orConstraint.operator !== 'object' || + orConstraint.operator === null || + typeof orConstraint.operator['@id'] !== 'string' || + typeof orConstraint['odrl:rightOperand'] !== 'string') { + return false; + } + } + } + } + } + + return true; + } + } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 127ae8fa5c..00f033a6ad 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -21,11 +21,11 @@
-
+
{{ 'pageAdmin.policyManagement.apply' | i18n }} - + [isDisabled]="!templateFile" + class="mr-2" + >{{ 'pageAdmin.policyManagement.apply' | i18n }} + +
+
+ error + {{ templateError | i18n }}
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index a88a5690e9..b89220da7c 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -11,6 +11,8 @@ import { import { ConstraintLogicType, getOperatorType, + getOperatorTypeSign, + OperatorType, Policy, PolicyAction, PolicyConstraint, @@ -37,6 +39,7 @@ export class PolicyEditorComponent { templateFileName: string = ''; policyForm: FormGroup; minDate: Date = new Date(); + templateError: string = ''; constructor(private readonly router: Router, public readonly policyFacade: PoliciesFacade, private fb: FormBuilder, private readonly toastService: ToastService) { } @@ -139,6 +142,7 @@ export class PolicyEditorComponent { if (input.files && input.files.length > 0) { this.templateFile = input.files[0]; this.templateFileName = this.templateFile.name; + this.templateError = ''; } } @@ -170,6 +174,10 @@ export class PolicyEditorComponent { reader.onload = () => { const fileContent = reader.result; if (typeof fileContent === 'string') { + if (!PoliciesAssembler.validatePoliciesTemplate(JSON.parse(fileContent))) { + this.templateError = 'pageAdmin.policyManagement.templateErrorMessage'; + return; + } let policyEntry = PoliciesAssembler.mapToPolicyEntryList(JSON.parse(fileContent)); let policy = PoliciesAssembler.assemblePolicy(policyEntry[0].payload.policy); this.updatePolicyForm(policy); @@ -205,10 +213,11 @@ export class PolicyEditorComponent { let constraintsList = permissionList.map((constraint) => this.fb.group({ leftOperand: this.fb.control(constraint.leftOperand, [ Validators.required ]), - operator: this.fb.control('='), - rightOperand: this.fb.control(constraint['odrl:rightOperand'], [ Validators.required ]), + operator: this.fb.control(constraint?.operator?.['@id'] ? getOperatorTypeSign(OperatorType[constraint?.operator?.['@id'].toUpperCase()]) : getOperatorTypeSign(constraint?.operatorTypeResponse)), + rightOperand: this.fb.control(constraint['odrl:rightOperand'] ?? constraint.rightOperand, [ Validators.required ]), })); + this.policyForm.setControl('constraints', this.fb.array(constraintsList)); if (this.viewMode === ViewMode.VIEW) { this.policyForm.disable(); diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index 0db4757d2c..95293238b3 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -116,6 +116,31 @@ export function getOperatorType(sign: string): OperatorType | undefined { return OperatorSignsToTypes[sign]; } +export function getOperatorTypeSign(type: OperatorType): string { + switch (type) { + case OperatorType.EQ: + return '='; + break; + case OperatorType.NEQ: + return '!='; + break; + case OperatorType.LT: + return '<'; + break; + case OperatorType.GT: + return '>'; + break; + case OperatorType.LTEQ: + return '<='; + break; + case OperatorType.GTEQ: + return '>='; + break; + default: + return type.toString(); + } +} + export enum ConstraintLogicType { AND = 'AND', OR = 'OR', diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 33b56e877a..17a8ac1804 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -88,6 +88,7 @@ "moveUpward" : "Nach oben verschieben", "successMessage" : "Richtlinie wurde erfolgreich gespeichert", "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern", + "templateErrorMessage" : "Die selektierte Vorlagendatei ist nicht konform für Richtlinien. Bitte wählen Sie eine valide .JSON Vorlagendatei aus.", "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus" } } diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index c50b1a52a6..809e9ba6f7 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -88,6 +88,7 @@ "moveUpward" : "Move upward", "successMessage" : "Successfully saved policy", "errorMessage" : "Error while trying to save policy", + "templateErrorMessage" : "The selected template file is not compliant. Please provide a valid .JSON template file.", "invalidForm" : "Please make sure to submit a valid form" } From 9dc3c25c64c3e610fd2ca07f92c57637cbaf1280 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 16:35:25 +0200 Subject: [PATCH 10/44] feature(policy): #832 added form validation and template error handling --- .../bpn-configuration.component.ts | 9 +++++---- .../policy-management/policies/policy.assembler.ts | 14 +++++++++++--- .../policy-editor/policy-editor.component.html | 1 + .../policy-editor/policy-editor.component.scss | 9 ++++++++- .../policy-editor/policy-editor.component.ts | 5 ++--- .../shared/components/table/table.component.html | 4 ++-- .../shared/components/table/table.component.ts | 1 - frontend/src/assets/locales/de/page.admin.json | 3 ++- frontend/src/assets/locales/en/page.admin.json | 3 ++- 9 files changed, 33 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/bpn-configuration/bpn-configuration.component.ts b/frontend/src/app/modules/page/admin/presentation/bpn-configuration/bpn-configuration.component.ts index 689c4959e7..4868e3de8c 100644 --- a/frontend/src/app/modules/page/admin/presentation/bpn-configuration/bpn-configuration.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/bpn-configuration/bpn-configuration.component.ts @@ -21,15 +21,16 @@ import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { BpnConfig, BpnConfigFormGroup } from '@page/admin/core/admin.model'; import { AdminFacade } from '@page/admin/core/admin.facade'; -import { BehaviorSubject, combineLatest, Observable, of, Subject, Subscription, tap } from 'rxjs'; -import { BaseInputHelper } from '@shared/abstraction/baseInput/baseInput.helper'; -import { BpnConfigEntry, ChangedInformation } from './bpn-configuration.model'; +import { BpnConfig, BpnConfigFormGroup } from '@page/admin/core/admin.model'; import { SaveBpnConfigModal } from '@page/admin/presentation/bpn-configuration/save-modal/save-modal.component'; +import { BaseInputHelper } from '@shared/abstraction/baseInput/baseInput.helper'; +import { BehaviorSubject, combineLatest, Observable, of, Subject, Subscription, tap } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { BpnConfigEntry, ChangedInformation } from './bpn-configuration.model'; export const bpnRegex = /^BPN[ALS][0-9A-Za-z]{10}[0-9A-Za-z]{2}$/; +export const bpnListRegex = /^(BPN[ALS][0-9A-Za-z]{10}[0-9A-Za-z]{2})(,\s*BPN[ALS][0-9A-Za-z]{10}[0-9A-Za-z]{2})*$/; @Component({ selector: 'app-bpn-configuration', diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 68e7639618..1c7a9fe3c8 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -1,5 +1,11 @@ import { CalendarDateModel } from '@core/model/calendar-date.model'; -import { Policy, PolicyAction, PolicyEntry, PolicyResponseMap } from '@page/policies/model/policy.model'; +import { + getOperatorTypeSign, + Policy, + PolicyAction, + PolicyEntry, + PolicyResponseMap, +} from '@page/policies/model/policy.model'; export class PoliciesAssembler { public static assemblePolicy(policy: Policy): Policy { @@ -52,13 +58,15 @@ export class PoliciesAssembler { policy.permissions.forEach(permission => { permission.constraints?.and?.forEach(andConstraint => { constrainsList.push(andConstraint.leftOperand); - constrainsList.push(andConstraint.operatorTypeResponse); + constrainsList.push(getOperatorTypeSign(andConstraint.operatorTypeResponse)); constrainsList.push(andConstraint.rightOperand); + constrainsList.push(' AND '); }); permission.constraints?.or?.forEach(orConstraint => { constrainsList.push(orConstraint.leftOperand); - constrainsList.push(orConstraint.operatorTypeResponse); + constrainsList.push(getOperatorTypeSign(orConstraint.operatorTypeResponse)); constrainsList.push(orConstraint.rightOperand); + constrainsList.push(' OR '); }); }); return constrainsList; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 00f033a6ad..fd8cfa0368 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -117,6 +117,7 @@
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss index 3d96a54ca1..4e83213ab5 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.scss @@ -2,7 +2,7 @@ background-color: #ececec; border-radius: 5px; width: 300px; - padding: 5px; + padding: 8px; } .hinttext { @@ -43,3 +43,10 @@ .label-row-view-mode { width: 100%; } + +.sub-label { + font-size: 12px; + font-weight: normal; + font-family: Catena-X Light, sans-serif; + color: #777777; +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index b89220da7c..ad38eced3a 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import { Router } from '@angular/router'; -import { bpnRegex } from '@page/admin/presentation/bpn-configuration/bpn-configuration.component'; +import { bpnListRegex } from '@page/admin/presentation/bpn-configuration/bpn-configuration.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { @@ -32,7 +32,6 @@ export class PolicyEditorComponent { selectedPolicy: Policy; selectedPolicySubscription: Subscription; - newPolicy: Policy; viewMode: ViewMode; templateFile: File | null = null; @@ -55,7 +54,7 @@ export class PolicyEditorComponent { this.policyForm = this.fb.group({ policyName: new FormControl('', [ Validators.required, Validators.minLength(8), Validators.maxLength(30) ]), validUntil: new FormControl('', [ Validators.required, this.futureDateValidator ]), - bpns: new FormControl('', [ BaseInputHelper.getCustomPatternValidator(bpnRegex, 'bpn') ]), + bpns: new FormControl('', [ Validators.required, Validators.maxLength(84), BaseInputHelper.getCustomPatternValidator(bpnListRegex, 'bpn') ]), accessType: new FormControl(PolicyAction.ACCESS), constraints: this.fb.array([]), constraintLogicType: new FormControl(ConstraintLogicType.AND), diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index d60a3f2a9a..e590411b0a 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -81,7 +81,7 @@
diff --git a/frontend/src/app/modules/shared/components/table/table.component.ts b/frontend/src/app/modules/shared/components/table/table.component.ts index 5731b0a85d..3c47718dde 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.ts +++ b/frontend/src/app/modules/shared/components/table/table.component.ts @@ -408,7 +408,6 @@ export class TableComponent { handleItemDeletion() { this.deletionClicked.emit(); - this.clearCurrentRows(); } protected readonly MainAspectType = MainAspectType; diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 17a8ac1804..b2d598a4c8 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -89,7 +89,8 @@ "successMessage" : "Richtlinie wurde erfolgreich gespeichert", "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern", "templateErrorMessage" : "Die selektierte Vorlagendatei ist nicht konform für Richtlinien. Bitte wählen Sie eine valide .JSON Vorlagendatei aus.", - "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus" + "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus", + "bpnsHint" : "Liste von BPNs separiert durch ein Kommazeichen" } } } diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index 809e9ba6f7..cef576728a 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -89,7 +89,8 @@ "successMessage" : "Successfully saved policy", "errorMessage" : "Error while trying to save policy", "templateErrorMessage" : "The selected template file is not compliant. Please provide a valid .JSON template file.", - "invalidForm" : "Please make sure to submit a valid form" + "invalidForm" : "Please make sure to submit a valid form", + "bpnsHint" : "Please provide a list of BPNs separated by comma" } } From 6e016988d9d4a46b703c12d759059b6f3ab18d25 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 17:09:04 +0200 Subject: [PATCH 11/44] feature(policy): #832 support for single or multiple bpns --- frontend/src/app/mocks/services/policy-mock/policy.model.ts | 2 ++ .../policy-editor/policy-editor.component.ts | 4 +++- frontend/src/app/modules/page/policies/model/policy.model.ts | 3 ++- frontend/src/app/modules/shared/service/policy.service.ts | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 41d3793366..0aa2b20380 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -31,6 +31,7 @@ export const getPolicyById = (policyId: string | ReadonlyArray): Policy export const mockedPolicyList: Policy[] = [ { 'policyId': 'default-policy', + 'bpn': 'BPNL00000003CML1,BPNL00000003CNKC', 'createdOn': '2024-05-29T06:18:40Z', 'validUntil': '2029-05-29T06:18:40Z', 'permissions': [ @@ -56,6 +57,7 @@ export const mockedPolicyList: Policy[] = [ }, { 'policyId': 'default-policy-2', + 'bpn': 'BPNL00000003CML1', 'createdOn': '2024-05-29T06:18:40Z', 'validUntil': '2029-05-29T06:18:40Z', 'permissions': [ diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index ad38eced3a..e2ad1eec45 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -237,9 +237,11 @@ export class PolicyEditorComponent { }; }); + const policyBpns = this.policyForm.get('bpns').getRawValue().trim().split(','); + policyEntry = { validUntil: this.policyForm.get('validUntil').getRawValue() + '.000000000Z', - businessPartnerNumber: this.policyForm.get('bpns').getRawValue(), + businessPartnerNumber: policyBpns.length > 1 ? policyBpns : policyBpns[0], payload: { '@context': { odrl: 'http://www.w3.org/ns/odrl/2/', diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index 95293238b3..d8f32b3063 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -27,7 +27,8 @@ export interface PolicyResponseMap { export interface PolicyEntry { validUntil: string; payload: PolicyPayload; - businessPartnerNumber?: string; + businessPartnerNumber?: string[] | string; + policyIds?: string[]; } export interface PolicyPayload { diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 0be5694994..253e7a6807 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -33,6 +33,7 @@ export class PolicyService { } updatePolicy(policyEntry: PolicyEntry) { + policyEntry.policyIds = [ policyEntry.payload.policy.policyId ]; return this.apiService.put(`${ this.url }/policies/` + policyEntry.payload.policy.policyId, policyEntry); } } From dba021e1ff7aebae829056a51b11584245d37b85 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 17:10:54 +0200 Subject: [PATCH 12/44] feature(policy): #832 support for single or multiple bpns --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f342303f59..ade8189618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha - #859 added autocomplete on subset of assets in notification creation/edit view - #997 added publish assets state check to parts table - #XXX added border to dashboard notifications table and view all count +- #832 added policymanagement list view, creator and editor ### Changed - #778 return empty PageResult when no contract agreement Ids are found instead of http 404 in /contacts API From debe905d9f3cd9eee315165f2beb0cf23d2d8f43 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 17:11:42 +0200 Subject: [PATCH 13/44] feature(policy): #832 support for single or multiple bpns --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 534dd223b8..781f9f46c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha ## [11.0.2 - 29.05.2024] ### Added - #1010 Made submodel path configurable +- #832 added policymanagement list view, creator and editor ### Changed - #1010 Updated IRS Helm Version from 5.1.6 to 5.1.7 @@ -29,7 +30,6 @@ _**For better traceability add the corresponding GitHub issue number in each cha - #859 added autocomplete on subset of assets in notification creation/edit view - #997 added publish assets state check to parts table - #XXX added border to dashboard notifications table and view all count -- #832 added policymanagement list view, creator and editor ### Changed - #778 return empty PageResult when no contract agreement Ids are found instead of http 404 in /contacts API From 24eda6fea4e656bf9fbd141b2f588cbad5891886 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 6 Jun 2024 17:12:34 +0200 Subject: [PATCH 14/44] feature(policy): #832 support for single or multiple bpns --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 781f9f46c0..299bdea130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,15 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). _**For better traceability add the corresponding GitHub issue number in each changelog entry, please.**_ ## [UNRELEASED - DD.MM.YYYY] +### Added + +- #832 added policymanagement list view, creator and editor + +### Changed + ## [11.0.2 - 29.05.2024] ### Added - #1010 Made submodel path configurable -- #832 added policymanagement list view, creator and editor ### Changed - #1010 Updated IRS Helm Version from 5.1.6 to 5.1.7 From 00acde40087a054de0588ad53dce822a3e2f6c33 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 7 Jun 2024 11:03:38 +0200 Subject: [PATCH 15/44] feature(policy): #832 fixed tests --- .../contracts/contracts.component.spec.ts | 180 +++++++++--------- .../deletion-dialog.component.html | 28 +++ .../deletion-dialog.component.scss | 83 ++++++++ .../deletion-dialog.component.spec.ts | 47 +++++ .../deletion-dialog.component.ts | 23 +++ .../policies/policies.component.spec.ts | 51 +++-- .../policy-editor.component.spec.ts | 58 ++++-- .../asset-publisher.component.spec.ts | 4 +- 8 files changed, 361 insertions(+), 113 deletions(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.html create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.scss create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.spec.ts create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts diff --git a/frontend/src/app/modules/page/admin/presentation/contracts/contracts.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/contracts/contracts.component.spec.ts index cf4d151bdd..141ea7e247 100644 --- a/frontend/src/app/modules/page/admin/presentation/contracts/contracts.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/contracts/contracts.component.spec.ts @@ -12,113 +12,117 @@ import { ContractsComponent } from './contracts.component'; describe('ContractTableComponent', () => { - const mockAdminFacade = { - getContracts: jasmine.createSpy().and.returnValue(of(getContracts)) - }; - - const renderContractTableComponent = () => renderComponent(ContractsComponent, {imports: [AdminModule], providers: [{provide: AdminFacade, useValue: mockAdminFacade}]}) - let createElementSpy: jasmine.Spy - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ContractsComponent], - providers: [AdminFacade, AdminService] - }); - createElementSpy = spyOn(document, 'createElement').and.callThrough(); - + const mockAdminFacade = { + getContracts: jasmine.createSpy().and.returnValue(of(getContracts)), + }; + + const renderContractTableComponent = () => renderComponent(ContractsComponent, { + imports: [ AdminModule ], + providers: [ { provide: AdminFacade, useValue: mockAdminFacade } ], + }); + + let createElementSpy: jasmine.Spy; + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ ContractsComponent ], + providers: [ AdminFacade, AdminService ], }); + createElementSpy = spyOn(document, 'createElement').and.callThrough(); + + }); + + it('should create', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; + expect(componentInstance).toBeTruthy(); + }); + + it('should filter and change table config', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; + + const mockFilter = { + contractId: [ 'hello' ], + counterpartyAddress: [], + creationDate: [], + endDate: [], + state: [], + }; + const myPagination = { page: 0, pageSize: 10, sorting: [ '', null ] as TableHeaderSort }; + componentInstance.onTableConfigChange(myPagination); + expect(componentInstance.pagination.pageSize).toEqual(10); - it('should create', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; - expect(componentInstance).toBeTruthy(); - }); - - it('should filter and change table config', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; - - const mockFilter = { - contractId: ["hello"], - counterpartyAddress: [], - creationDate: [], - endDate: [], - state: [] - } - const myPagination = {page: 0, pageSize: 10, sorting: ['', null] as TableHeaderSort} - componentInstance.onTableConfigChange(myPagination) - expect(componentInstance.pagination.pageSize).toEqual(10); - - componentInstance.filterActivated(mockFilter); + componentInstance.filterActivated(mockFilter); - expect(JSON.stringify(componentInstance.contractFilter)).toContain("hello"); + expect(JSON.stringify(componentInstance.contractFilter)).toContain('hello'); - }); + }); - it('select a contract', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; - let mockSelectedContract = assembleContract(getContracts().content[0]); - componentInstance.multiSelection([mockSelectedContract]); - expect(componentInstance.selectedContracts.length).toEqual(1); - expect(componentInstance.selectedContracts[0].contractId).toEqual(mockSelectedContract.contractId) - }); + it('select a contract', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; + let mockSelectedContract = assembleContract(getContracts().content[0]); + componentInstance.multiSelection([ mockSelectedContract ]); + expect(componentInstance.selectedContracts.length).toEqual(1); + expect(componentInstance.selectedContracts[0].contractId).toEqual(mockSelectedContract.contractId); + }); - it('should export contracts as csv', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; + it('should export contracts as csv', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; - let mockSelectedContract = assembleContract(getContracts().content[0]); - componentInstance.multiSelection([mockSelectedContract]); + let mockSelectedContract = assembleContract(getContracts().content[0]); + componentInstance.multiSelection([ mockSelectedContract ]); - let convertSpy = spyOn(componentInstance, 'convertArrayOfObjectsToCSV'); - let downloadSpy = spyOn(componentInstance, 'downloadCSV') - componentInstance.exportContractsAsCSV(); - expect(convertSpy).toHaveBeenCalledWith([assembleContract(getContracts().content[0])]); - expect(downloadSpy).toHaveBeenCalled(); + let convertSpy = spyOn(componentInstance, 'convertArrayOfObjectsToCSV'); + let downloadSpy = spyOn(componentInstance, 'downloadCSV'); + componentInstance.exportContractsAsCSV(); + expect(convertSpy).toHaveBeenCalledWith([ assembleContract(getContracts().content[0]) ]); + expect(downloadSpy).toHaveBeenCalled(); - }); + }); - it('should convert data to csv', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; + it('should convert data to csv', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; - let result = componentInstance.convertArrayOfObjectsToCSV([getContracts().content[0]]) + let result = componentInstance.convertArrayOfObjectsToCSV([ getContracts().content[0] ]); - expect(result).toEqual("contractId,counterpartyAddress,creationDate,endDate,state,policy\n" + - "abc1,https://trace-x-edc-e2e-a.dev.demo.catena-x.net/api/v1/dsp,2024-02-26T13:38:07+01:00,,Finalized,jsontextaspolicy"); + expect(result).toEqual('contractId,counterpartyAddress,creationDate,endDate,state,policy\n' + + 'abc1,https://trace-x-edc-e2e-a.dev.demo.catena-x.net/api/v1/dsp,2024-02-26T13:38:07+01:00,,Finalized,jsontextaspolicy'); - }); - it('should download CSV file', async () => { - const {fixture} = await renderContractTableComponent(); - const {componentInstance} = fixture; - const csvContent = 'header1,header2\nvalue1,value2\nvalue3,value4'; // Sample CSV content - const fileName = 'test.csv'; + }); + it('should download CSV file', async () => { + const { fixture } = await renderContractTableComponent(); + const { componentInstance } = fixture; + const csvContent = 'header1,header2\nvalue1,value2\nvalue3,value4'; // Sample CSV content + const fileName = 'test.csv'; - // Mock the required browser APIs - const link = document.createElement('a'); - spyOn(link, 'setAttribute'); - spyOn(link, 'click'); - spyOn(document.body, 'appendChild').and.callThrough(); - spyOn(document.body, 'removeChild').and.callThrough(); + // Mock the required browser APIs + const link = document.createElement('a'); + spyOn(link, 'setAttribute'); + spyOn(link, 'click'); + spyOn(document.body, 'appendChild').and.callThrough(); + spyOn(document.body, 'removeChild').and.callThrough(); - createElementSpy.and.returnValue(link); + createElementSpy.and.returnValue(link); - componentInstance.downloadCSV(csvContent, fileName); + componentInstance.downloadCSV(csvContent, fileName); - // Check if a link was created with correct attributes - expect(createElementSpy).toHaveBeenCalledWith('a'); - expect(link.setAttribute).toHaveBeenCalledWith('href', jasmine.any(String)); - expect(link.setAttribute).toHaveBeenCalledWith('download', fileName); - expect(link.style.visibility).toBe('hidden'); + // Check if a link was created with correct attributes + expect(createElementSpy).toHaveBeenCalledWith('a'); + expect(link.setAttribute).toHaveBeenCalledWith('href', jasmine.any(String)); + expect(link.setAttribute).toHaveBeenCalledWith('download', fileName); + expect(link.style.visibility).toBe('hidden'); - // Check if the link was appended to the document body - expect(document.body.appendChild).toHaveBeenCalledWith(link); + // Check if the link was appended to the document body + expect(document.body.appendChild).toHaveBeenCalledWith(link); - // Check if the link was clicked - expect(link.click).toHaveBeenCalled(); + // Check if the link was clicked + expect(link.click).toHaveBeenCalled(); - // Ensure that the link is removed from the document body after being clicked - expect(document.body.removeChild).toHaveBeenCalledWith(link); - }); + // Ensure that the link is removed from the document body after being clicked + expect(document.body.removeChild).toHaveBeenCalledWith(link); + }); }); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.html new file mode 100644 index 0000000000..bd7b6a8a77 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.html @@ -0,0 +1,28 @@ + +
+
+

{{ title | i18n }}

+ close + +
+
+

{{ 'pageAdmin.policyManagement.deletionText' | i18n }}

+ + +

{{ item }}

+
+
+
+
+
+ + +
+ +
+
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.scss b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.scss new file mode 100644 index 0000000000..bac5930034 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.scss @@ -0,0 +1,83 @@ +.dialog--content { + display: flex; + flex-direction: column; + width: 25vw; +} + +.dialog--header--container { + display: flex; + padding-bottom: 24px; +} + +.dialog--header--text { + font-weight: 500; + line-height: 1.6; + flex: 1; + font-family: LibreFranklin-SemiBold, -apple-system, + BlinkMacSystemFont, "Segoe UI", + Roboto, "Helvetica Neue", + Arial, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol"; + font-size: 24px; + text-align: center; + margin-left: 32px; +} + +.mat-icon { + width: 32px; + height: 32px; + font-size: 30px; + margin-top: 4px; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; +} + +.dialog--content--container { + display: flex; + font-size: 20px; + line-height: 1.6; +} + +.dialog--actions--container { + background-color: rgb(237, 240, 244); + width: 100%; + display: flex; + justify-content: center; + + .dialog--actions--save--button { + display: inline-flex; + -webkit-box-align: center; + align-items: center; + -webkit-box-pack: center; + justify-content: center; + position: relative; + box-sizing: border-box; + -webkit-tap-highlight-color: transparent; + outline: 0px; + border: 0px; + margin: 0px; + cursor: pointer; + user-select: none; + vertical-align: middle; + appearance: none; + text-decoration: none; + font-family: LibreFranklin, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-weight: 500; + line-height: 1.5; + color: rgb(255, 255, 255); + min-width: 64px; + transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + + background-color: rgb(15, 113, 203); + border-radius: 50px; + font-size: 18px; + padding: 14px 32px; + box-shadow: rgba(15, 113, 203, 0.4) 0px 0px 0px 3px; + } + + .dialog--actions--save--button:hover, .dialog--actions--save--button:active, .dialog--actions--save--button:focus { + background-color: rgb(13, 85, 175) + } +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.spec.ts new file mode 100644 index 0000000000..baf3a1946a --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.spec.ts @@ -0,0 +1,47 @@ +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { renderComponent } from '@tests/test-render.utils'; + +import { DeletionDialogComponent } from './deletion-dialog.component'; + +describe('DeletionDialogComponent', () => { + const dialogRefMock = { + close: jasmine.createSpy('close'), + }; + + const dataMock = { + policyIds: [ 'policy1', 'policy2' ], + title: 'Delete Policies', + }; + + const renderDeletionDialogComponent = () => renderComponent(DeletionDialogComponent, { + imports: [ MatDialogModule ], + providers: [ + { provide: MatDialogRef, useValue: dialogRefMock }, + { provide: MAT_DIALOG_DATA, useValue: dataMock }, + ], + }); + + it('should create', async () => { + const { fixture } = await renderDeletionDialogComponent(); + const { componentInstance } = fixture; + + expect(componentInstance).toBeTruthy(); + }); + + it('should initialize with provided data', async () => { + const { fixture } = await renderDeletionDialogComponent(); + const { componentInstance } = fixture; + + expect(componentInstance.policyIds).toEqual(dataMock.policyIds); + expect(componentInstance.title).toEqual(dataMock.title); + }); + + it('should call dialogRef.close(true) on save', async () => { + const { fixture } = await renderDeletionDialogComponent(); + const { componentInstance } = fixture; + + componentInstance.save(); + expect(dialogRefMock.close).toHaveBeenCalledWith(true); + }); +}); + diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts new file mode 100644 index 0000000000..33d14c6f18 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts @@ -0,0 +1,23 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'app-deletion-dialog', + templateUrl: './deletion-dialog.component.html', + styleUrls: [ './deletion-dialog.component.scss' ], +}) +export class DeletionDialogComponent { + policyIds: string[]; + title: string; + + constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) { + this.policyIds = data?.policyIds; + this.title = data?.title; + } + + + save() { + this.dialogRef.close(true); + console.log('save'); + } +} diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts index afba4712b7..c618117088 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.spec.ts @@ -1,21 +1,48 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatDialogModule } from '@angular/material/dialog'; +import { RouterTestingModule } from '@angular/router/testing'; +import { RoleService } from '@core/user/role.service'; +import { AdminModule } from '@page/admin/admin.module'; +import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; +import { ToastService } from '@shared/components/toasts/toast.service'; +import { renderComponent } from '@tests/test-render.utils'; +import { of } from 'rxjs'; +import { getPolicies } from '../../../../../../mocks/services/policy-mock/policy.model'; import { PoliciesComponent } from './policies.component'; describe('PoliciesComponent', () => { - let component: PoliciesComponent; - let fixture: ComponentFixture; + const policyFacadeMock = { + policies$: of(getPolicies()), + setPolicies: jasmine.createSpy('setPolicies'), + deletePolicies: jasmine.createSpy('deletePolicies').and.returnValue(of({})), + }; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ PoliciesComponent ], - }); - fixture = TestBed.createComponent(PoliciesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + const toastServiceMock = { + success: jasmine.createSpy('success'), + error: jasmine.createSpy('error'), + }; + + const roleServiceMock = { + isAdmin: jasmine.createSpy('isAdmin').and.returnValue(true), + }; + + const renderPoliciesComponent = () => renderComponent(PoliciesComponent, { + imports: [ + AdminModule, + MatDialogModule, + RouterTestingModule, + ], + providers: [ + { provide: PoliciesFacade, useValue: policyFacadeMock }, + { provide: ToastService, useValue: toastServiceMock }, + { provide: RoleService, useValue: roleServiceMock }, + ], }); - it('should create', () => { - expect(component).toBeTruthy(); + it('should create', async () => { + const { fixture } = await renderPoliciesComponent(); + const { componentInstance } = fixture; + + expect(componentInstance).toBeTruthy(); }); }); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts index 236d490942..a5f0e04e5d 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -1,21 +1,57 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { AdminModule } from '@page/admin/admin.module'; +import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; +import { Policy } from '@page/policies/model/policy.model'; +import { View } from '@shared/model/view.model'; +import { renderComponent } from '@tests/test-render.utils'; +import { of } from 'rxjs'; import { PolicyEditorComponent } from './policy-editor.component'; describe('PolicyEditorComponent', () => { - let component: PolicyEditorComponent; - let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ PolicyEditorComponent ], + + const renderPolicyEditorComponent = async (policyFacadeMock: any) => { + + return await renderComponent(PolicyEditorComponent, { + imports: [ AdminModule ], + providers: [ { + provide: PoliciesFacade, + useValue: policyFacadeMock, + }, + { + provide: Router, + useValue: { + url: 'https://test.net/admin/policies/edit/default', + }, + }, + ], }); - fixture = TestBed.createComponent(PolicyEditorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + } + + it('should create', async function() { + const dummyPolicy: View = { + data: { + policyId: 'default', + createdOn: new Date().toISOString(), + validUntil: new Date().toISOString(), + permissions: [], + }, + }; + + const policyFacadeMock = jasmine.createSpyObj('policyFacade', [ 'setSelectedPolicyById' ]); + policyFacadeMock.setSelectedPolicyById.and.returnValue(undefined); + + Object.defineProperty(policyFacadeMock, 'selectedPolicy$', { + get: () => of(dummyPolicy), + }); + + + const component = await renderPolicyEditorComponent(policyFacadeMock); + + + - it('should create', () => { expect(component).toBeTruthy(); }); }); diff --git a/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.spec.ts b/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.spec.ts index 179dec1717..cdf60e65d5 100644 --- a/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.spec.ts +++ b/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.spec.ts @@ -27,7 +27,7 @@ describe('AssetPublisherComponent', () => { const { fixture } = await renderAssetPublisherComponent(); const { componentInstance } = fixture; - const dummyPolicy: Policy = { policyId: 'id-1', createdOn: 'testdate', validUntil: 'testdate' }; + const dummyPolicy: Policy = { policyId: 'id-1', createdOn: 'testdate', validUntil: 'testdate', permissions: [] }; policyServiceSpy.publishAssets.and.returnValue(of({})); policyServiceSpy.getPolicies.and.returnValue(of([dummyPolicy])); @@ -49,7 +49,7 @@ describe('AssetPublisherComponent', () => { it('should set policies when requesting policies', async function() { const { fixture } = await renderAssetPublisherComponent(); const { componentInstance } = fixture; - const dummyPolicy: Policy = { policyId: 'id-1', createdOn: 'testdate', validUntil: 'testdate' }; + const dummyPolicy: Policy = { policyId: 'id-1', createdOn: 'testdate', validUntil: 'testdate', permissions: [] }; const submittedSpy = spyOn(componentInstance.submitted, 'emit'); From d1e0dab7d475163da6fa3d92bb1d6fcc4fb77e2b Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 7 Jun 2024 12:41:38 +0200 Subject: [PATCH 16/44] feature(policy): #832 mapped get policies --- .../policy-management/policies/policies.facade.ts | 4 +--- .../policy-management/policies/policy.assembler.ts | 9 ++++++--- .../asset-publisher/asset-publisher.component.ts | 6 +++++- .../src/app/modules/shared/service/policy.service.ts | 6 +++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 93e377577c..2a5d20d52a 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -26,9 +26,7 @@ export class PoliciesFacade { public setPolicies(): void { this.policiesSubscription?.unsubscribe(); this.policiesSubscription = this.policyService.getPolicies().pipe(map(response => { - return response.map(policy => { - return PoliciesAssembler.assemblePolicy(policy); - }); + return PoliciesAssembler.mapToPolicyEntryList(response).map(entry => entry.payload.policy).map(policy => PoliciesAssembler.assemblePolicy(policy)); })).subscribe({ next: data => (this.policiesState.policies = { data: data }), error: error => (this.policiesState.policies = { error }), diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 1c7a9fe3c8..db5098fd03 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -1,6 +1,7 @@ import { CalendarDateModel } from '@core/model/calendar-date.model'; import { getOperatorTypeSign, + OperatorType, Policy, PolicyAction, PolicyEntry, @@ -17,7 +18,7 @@ export class PoliciesAssembler { createdOn: formattedCreatedOn.isInitial() ? null : formattedCreatedOn.valueOf().toISOString().slice(0, 16), validUntil: formattedValidUntil.isInitial() ? null : formattedValidUntil.valueOf().toISOString().slice(0, 16), accessType: policy.permissions[0].action.toUpperCase() as PolicyAction, - constraints: this.mapDisplayPropsToPolicyRootLevelFromPolicy(policy), + constraints: policy.constraints ?? this.mapDisplayPropsToPolicyRootLevelFromPolicy(policy), }; } @@ -40,13 +41,15 @@ export class PoliciesAssembler { entry.payload.policy.permissions.forEach(permission => { permission.constraint.and.forEach(andConstraint => { constrainsList.push(andConstraint.leftOperand); - constrainsList.push(andConstraint.operator['@id']); + constrainsList.push(getOperatorTypeSign(OperatorType[andConstraint.operator['@id'].toUpperCase()])); constrainsList.push(andConstraint['odrl:rightOperand']); + constrainsList.push(' AND '); }); permission.constraint?.or?.forEach(orConstraint => { constrainsList.push(orConstraint.leftOperand); - constrainsList.push(orConstraint.operator['@id']); + constrainsList.push(getOperatorTypeSign(OperatorType[orConstraint.operator['@id'].toUpperCase()])); constrainsList.push(orConstraint['odrl:rightOperand']); + constrainsList.push(' OR '); }); }); return constrainsList; diff --git a/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.ts b/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.ts index b5ac0d0ee1..0d6f9ffbbb 100644 --- a/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.ts +++ b/frontend/src/app/modules/shared/components/asset-publisher/asset-publisher.component.ts @@ -1,9 +1,11 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { ImportState, Part } from '@page/parts/model/parts.model'; import { Policy } from '@page/policies/model/policy.model'; import { PolicyService } from '@shared/service/policy.service'; import { Observable, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; @Component({ selector: 'app-asset-publisher', @@ -55,7 +57,9 @@ export class AssetPublisherComponent { } private getPolicies() { - this.policiesSubscription = this.policyService.getPolicies().subscribe(data => { + this.policiesSubscription = this.policyService.getPolicies().pipe(map(response => { + return PoliciesAssembler.mapToPolicyEntryList(response).map(entry => entry.payload.policy).map(policy => PoliciesAssembler.assemblePolicy(policy)); + })).subscribe(data => { this.policiesList = data; }) } diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 253e7a6807..54cfaecc36 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -2,7 +2,7 @@ import { HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiService } from '@core/api/api.service'; import { environment } from '@env'; -import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; +import { Policy, PolicyEntry, PolicyResponseMap } from '@page/policies/model/policy.model'; import { Observable } from 'rxjs'; @Injectable({ @@ -12,8 +12,8 @@ export class PolicyService { private readonly url = environment.apiUrl; constructor(private readonly apiService: ApiService) {} - getPolicies(): Observable { - return this.apiService.get(`${ this.url }/policies`); + getPolicies(): Observable { + return this.apiService.get(`${ this.url }/policies`); } getPolicyById(policyId: string): Observable { From 0c4b85b3b50097f1784150ccba16ea87dbe1628d Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 11:45:32 +0200 Subject: [PATCH 17/44] feature(policy): #832 implemented feedback --- .../policy-editor/policy-editor.component.html | 7 ++++--- .../policy-editor/policy-editor.component.ts | 17 ++++++++++------- frontend/src/assets/locales/de/common.json | 2 +- frontend/src/assets/locales/de/page.admin.json | 6 ++++-- frontend/src/assets/locales/en/common.json | 2 +- frontend/src/assets/locales/en/page.admin.json | 6 ++++-- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index fd8cfa0368..77e8ec8d55 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -20,7 +20,7 @@
@@ -135,8 +136,8 @@

{{ 'pageAdmin.policyManagement.policyConstraints' | i18n }}

-

{{ 'pageAdmin.policyManagement.constraints' | i18n }}

-
{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + constraints.length + ')' }} +
(PolicyAction.ACCESS), constraints: this.fb.array([]), constraintLogicType: new FormControl(ConstraintLogicType.AND), @@ -68,6 +69,8 @@ export class PolicyEditorComponent { this.updatePolicyForm(this.selectedPolicy); } }); + } else { + this.addConstraintFormGroup(); } } @@ -84,14 +87,14 @@ export class PolicyEditorComponent { } private setSelectedPolicy(): void { - this.policyFacade.setSelectedPolicyById(this.router.url.split('/').pop()); + this.policyFacade.setSelectedPolicyById(this.route.snapshot.paramMap.get('policyId')); } addConstraintFormGroup() { this.constraints.push(this.fb.group({ - leftOperand: new FormControl(''), + leftOperand: new FormControl('', [ Validators.required ]), operator: new FormControl('='), - rightOperand: new FormControl(''), + rightOperand: new FormControl('', [ Validators.required ]), })); } diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index 75b1123882..442732a5d1 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -68,7 +68,7 @@ "publishAssets": "Produkte veröffentlichen", "maximizeTable": "Volle Breite", "userSettings" : "Tabellen Einstellung", - "uploadFile" : "Vorlage aus Datei hochladen", + "uploadFile" : "Richtlinien JSON-Datei hochladen", "downloadFile" : "Vorlage als Datei herunterladen" }, "publisher": { diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index b2d598a4c8..6734c3dbe0 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -68,7 +68,7 @@ "edit" : "bearbeiten", "view" : "details", "selectFileHint" : "Name der selektierten Vorlage", - "applyChange" : "Vorlage anwenden um den Inhalt der Richtlinie mit dieser zu überschreiben", + "applyChange" : "Inhalt der hochgeladenen Datei anwenden und existierende Daten überschreiben", "chooseFile" : "Selektieren Sie eine Vorlage um Änderungen anzuwenden", "apply" : "Anwenden", "policyName" : "Richtlinienname", @@ -90,7 +90,9 @@ "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern", "templateErrorMessage" : "Die selektierte Vorlagendatei ist nicht konform für Richtlinien. Bitte wählen Sie eine valide .JSON Vorlagendatei aus.", "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus", - "bpnsHint" : "Liste von BPNs separiert durch ein Kommazeichen" + "bpnsHint" : "Liste von BPNs separiert durch ein Kommazeichen", + "savePolicy" : "Richtlinie speichern", + "addConstraint" : "Regel hinzufügen" } } } diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index f8f941ee17..0aae79a643 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -66,7 +66,7 @@ "publishAssets": "Publish assets", "maximizeTable": "Full width", "userSettings" : "Table settings", - "uploadFile" : "Upload template file", + "uploadFile" : "Upload policy JSON file", "downloadFile" : "Download template as file" }, "publisher": { diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index cef576728a..5bc4032f5f 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -68,7 +68,7 @@ "edit" : "edit", "view" : "details", "selectFileHint" : "Selected template filename", - "applyChange" : "Apply template to overwrite content with the provided template", + "applyChange" : "Apply content of file overwriting existing data", "chooseFile" : "Select a template file to be able to apply it", "apply" : "Apply", "policyName" : "Policy name", @@ -90,7 +90,9 @@ "errorMessage" : "Error while trying to save policy", "templateErrorMessage" : "The selected template file is not compliant. Please provide a valid .JSON template file.", "invalidForm" : "Please make sure to submit a valid form", - "bpnsHint" : "Please provide a list of BPNs separated by comma" + "bpnsHint" : "Please provide a list of BPNs separated by comma", + "savePolicy" : "Save policy", + "addConstraint" : "Add constraint" } } From 1e414ebcbc2c0ea80288cb601a4dfa52eb86f5f5 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 13:21:47 +0200 Subject: [PATCH 18/44] feature(policy): #832 implemented feedback --- .../policy-management/policies/policy.assembler.ts | 12 ++++++++---- .../policy-editor/policy-editor.component.html | 9 +++++---- .../policy-editor/policy-editor.component.ts | 4 ++-- frontend/src/assets/locales/de/common.json | 2 +- frontend/src/assets/locales/de/page.admin.json | 10 +++++----- frontend/src/assets/locales/en/common.json | 2 +- frontend/src/assets/locales/en/page.admin.json | 10 +++++----- 7 files changed, 27 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index db5098fd03..a63d8a7091 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -39,17 +39,21 @@ export class PoliciesAssembler { entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; let constrainsList = []; entry.payload.policy.permissions.forEach(permission => { - permission.constraint.and.forEach(andConstraint => { + permission.constraint.and.forEach((andConstraint, index) => { constrainsList.push(andConstraint.leftOperand); constrainsList.push(getOperatorTypeSign(OperatorType[andConstraint.operator['@id'].toUpperCase()])); constrainsList.push(andConstraint['odrl:rightOperand']); - constrainsList.push(' AND '); + if (index !== permission.constraint.and.length - 1) { + constrainsList.push(' AND '); + } }); - permission.constraint?.or?.forEach(orConstraint => { + permission.constraint?.or?.forEach((orConstraint, index) => { constrainsList.push(orConstraint.leftOperand); constrainsList.push(getOperatorTypeSign(OperatorType[orConstraint.operator['@id'].toUpperCase()])); constrainsList.push(orConstraint['odrl:rightOperand']); - constrainsList.push(' OR '); + if (index !== permission.constraint.or.length - 1) { + constrainsList.push(' OR '); + } }); }); return constrainsList; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 77e8ec8d55..dd78634994 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -45,6 +45,7 @@
@@ -79,7 +80,7 @@ + label="File" disabled *ngIf="templateFileName.length">
@@ -189,7 +190,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + [label]="'pageAdmin.policyManagement.rightOperand' | i18n" class="flex-1">
{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' +
1 ? policyBpns : policyBpns[0], + businessPartnerNumber: policyBpns?.length > 1 ? policyBpns : policyBpns?.[0], payload: { '@context': { odrl: 'http://www.w3.org/ns/odrl/2/', diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index 442732a5d1..3392a0067e 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -119,7 +119,7 @@ "viewDetails" : "Details anzeigen", "more" : "Mehr Aktionen", "editNotification" : "Qualitätsthemen bearbeiten", - "selectAtLeastOne" : "Aktionen erfordern mindestens eine Selektion in der Tabelle", + "selectAtLeastOne" : "Erfordert mindestens eine Selektion in der Tabelle", "selectOnlyOne" : "Aktion erfordert eine einzige Selektion in der Tabelle", "unauthorized" : "Die Funktion ist aufgrund einer fehlenden Rolle deaktiviert. Bitten Sie Ihren Administrator, die erforderliche Rolle für die Funktion bereitzustellen.", "noFunctionality" : "Funktionalität wurde noch nicht implementiert.", diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 6734c3dbe0..0f43b5b080 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -61,8 +61,8 @@ "deleteSuccess" : "Selektierte Richtlinien wurden erfolgreich gelöscht.", "deleteError" : "Fehler bei der Löschung der selektierten Richtlinien.", "confirm" : "Bestätigen", - "policyDeletion" : "Löschung der Richtlinien", - "deletionText" : "Möchten sie die Löschung der selektierten Richtlinien bestätigen?", + "policyDeletion" : "Löschen bestätigen", + "deletionText" : "Möchten sie die selektierten Richtlinien löschen?", "policy" : "Richtlinie", "create" : "erstellen", "edit" : "bearbeiten", @@ -73,17 +73,17 @@ "apply" : "Anwenden", "policyName" : "Richtlinienname", "validUntil" : "Gültig bis", - "bpnls" : "BPNLs", + "bpnls" : "BPNs", "policyConstraints" : "Richtlinientyp", "accessType" : "Zugriffstyp", "constraints" : "Regeln", "logic" : "Logik", - "logicTypeHint" : "Die Reihenfolge der Regeln wird berücksichtigt", + "logicTypeHint" : "Bitte beachten Sie, dass die Reihenfolge der Regeln relevant ist", "constraintLogicType" : "Logik der Regel", "leftOperand" : "Linker Operand", "operator" : "Operator", "rightOperand" : "Rechter Operand", - "rightOperandHint" : "Bitte geben Sie kommagetrennte Zeichenfolgen für die Operatoren IN, ISONEOF, ISALLOF, ISNONEOF an", + "rightOperandHint" : "Bitte geben Sie kommagetrennten Text für die Operatoren IN, ISONEOF, ISALLOF, ISNONEOF an", "moveDownward" : "Nach unten verschieben", "moveUpward" : "Nach oben verschieben", "successMessage" : "Richtlinie wurde erfolgreich gespeichert", diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index 0aae79a643..3538e19c9f 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -116,7 +116,7 @@ "viewDetails" : "View details", "more" : "More actions", "editNotification" : "Edit quality topics", - "selectAtLeastOne" : "Actions require atleast one selection in the table", + "selectAtLeastOne" : "Requires at least one selection in the policies table", "selectOnlyOne" : "Action requires only one selection from the table", "unauthorized" : "Functionality is disabled because of missing role. Ask your administrator to provide the required role for the functionality.", "noFunctionality" : "Functionality is not implemented yet", diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index 5bc4032f5f..9b4b725866 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -61,8 +61,8 @@ "deleteSuccess" : "Successfully deleted the selected policies.", "deleteError" : "Error while deleting the selected policies.", "confirm" : "Confirm", - "policyDeletion" : "Deletion of policies", - "deletionText" : "Do you want to confirm the deletion of the selected policies?", + "policyDeletion" : "Confirm deletion", + "deletionText" : "Do you want to delete the selected policies?", "policy" : "Policy", "create" : "creation", "edit" : "edit", @@ -73,17 +73,17 @@ "apply" : "Apply", "policyName" : "Policy name", "validUntil" : "Valid until", - "bpnls" : "BPNLs", + "bpnls" : "BPNs", "policyConstraints" : "Policy type", "accessType" : "Access type", "constraints" : "Constraints", "logic" : "Logic", - "logicTypeHint" : "Please keep in mind, that the order of constraints matters", + "logicTypeHint" : "Please note that the order of the constraints is relevant", "constraintLogicType" : "Constraint logic", "leftOperand" : "Left operand", "operator" : "Operator", "rightOperand" : "Right operand", - "rightOperandHint" : "Please provide comma separated strings for the operators IN, ISONEOF, ISALLOF, ISNONEOF", + "rightOperandHint" : "Please provide comma separated text for the operators IN, ISONEOF, ISALLOF, ISNONEOF", "moveDownward" : "Move downward", "moveUpward" : "Move upward", "successMessage" : "Successfully saved policy", From db24bc804eeb16d712e96bf2dc11602d40cfa8ba Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 13:53:49 +0200 Subject: [PATCH 19/44] feature(policy): #832 implemented feedback --- .../policy-management/policy-editor/policy-editor.component.ts | 3 ++- frontend/src/assets/locales/de/page.admin.json | 1 + frontend/src/assets/locales/en/page.admin.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index e8720588c3..9652563b2b 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -159,7 +159,7 @@ export class PolicyEditorComponent { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; - a.download = 'policy-template-' + policy.payload.policy.policyId; + a.download = policy.payload.policy.policyId.length ? 'policy-template-' + policy.payload.policy.policyId : 'policy-template'; document.body.appendChild(a); a.click(); document.body.removeChild(a); @@ -182,6 +182,7 @@ export class PolicyEditorComponent { } let policyEntry = PoliciesAssembler.mapToPolicyEntryList(JSON.parse(fileContent)); let policy = PoliciesAssembler.assemblePolicy(policyEntry[0].payload.policy); + this.toastService.success('pageAdmin.policyManagement.changeSuccessMessage'); this.updatePolicyForm(policy); } }; diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 0f43b5b080..4c864d6ebe 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -87,6 +87,7 @@ "moveDownward" : "Nach unten verschieben", "moveUpward" : "Nach oben verschieben", "successMessage" : "Richtlinie wurde erfolgreich gespeichert", + "changeSuccessMessage" : "JSON-Datei erfolgreich angewandt", "errorMessage" : "Fehler beim Versuch die Richtlinie abzuspeichern", "templateErrorMessage" : "Die selektierte Vorlagendatei ist nicht konform für Richtlinien. Bitte wählen Sie eine valide .JSON Vorlagendatei aus.", "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus", diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index 9b4b725866..a579d57347 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -87,6 +87,7 @@ "moveDownward" : "Move downward", "moveUpward" : "Move upward", "successMessage" : "Successfully saved policy", + "changeSuccessMessage" : "JSON file successfully applied", "errorMessage" : "Error while trying to save policy", "templateErrorMessage" : "The selected template file is not compliant. Please provide a valid .JSON template file.", "invalidForm" : "Please make sure to submit a valid form", From f27db7ebeae4225f106dbfefca7ca1aa0934163e Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 16:20:17 +0200 Subject: [PATCH 20/44] feature(policy): #832 implemented feedback --- .../policy-management/policies/policy.assembler.ts | 2 +- .../policy-editor/policy-editor.component.html | 2 +- .../policy-editor/policy-editor.component.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index a63d8a7091..03179a52a7 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -39,7 +39,7 @@ export class PoliciesAssembler { entry.payload.policy.accessType = entry.payload.policy.permissions[0].action; let constrainsList = []; entry.payload.policy.permissions.forEach(permission => { - permission.constraint.and.forEach((andConstraint, index) => { + permission.constraint?.and?.forEach((andConstraint, index) => { constrainsList.push(andConstraint.leftOperand); constrainsList.push(getOperatorTypeSign(OperatorType[andConstraint.operator['@id'].toUpperCase()])); constrainsList.push(andConstraint['odrl:rightOperand']); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index dd78634994..d6d3fa6259 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -50,7 +50,7 @@

-
+
1 ? policyBpns : policyBpns?.[0], payload: { '@context': { @@ -254,7 +254,7 @@ export class PolicyEditorComponent { policy: { policyId: this.policyForm.get('policyName').getRawValue(), createdOn: new Date(Date.now()).toISOString().replace('Z', '000000Z'), - validUntil: this.policyForm.get('validUntil').getRawValue() + '.000000000Z', + validUntil: this.policyForm.get('validUntil').getRawValue() + ':00.000000000Z', permissions: [ { action: this.policyForm.get('accessType').getRawValue().toLowerCase(), From d6c5e04017326477703e2d206e00f7fc9b3c1c32 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 16:54:09 +0200 Subject: [PATCH 21/44] feature(policy): #832 commented out template up and download feature --- .../policy-editor.component.html | 2 + .../policy-editor/policy-editor.component.ts | 96 ++++++++++--------- 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index d6d3fa6259..5f5c891918 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -50,6 +50,7 @@
+
diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index 4ced3fd799..2ba12c9938 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -3,7 +3,6 @@ import { FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, Valid import { ActivatedRoute, Router } from '@angular/router'; import { bpnListRegex } from '@page/admin/presentation/bpn-configuration/bpn-configuration.component'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; -import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; import { ConstraintLogicTypeAsSelectOptionsList, OperatorTypesAsSelectOptionsList, @@ -139,62 +138,69 @@ export class PolicyEditorComponent { }); } - onFileSelected(event: Event) { - const input = event.target as HTMLInputElement; - if (input.files && input.files.length > 0) { - this.templateFile = input.files[0]; - this.templateFileName = this.templateFile.name; - this.templateError = ''; + /* + + onFileSelected(event: Event) { + const input = event.target as HTMLInputElement; + if (input.files && input.files.length > 0) { + this.templateFile = input.files[0]; + this.templateFileName = this.templateFile.name; + this.templateError = ''; + } } - } + + */ navigateToEditView() { this.router.navigate([ 'admin/policies/', 'edit', this.selectedPolicy.policyId ]); } - downloadTemplateAsJsonFile() { - const policy = this.mapPolicyFormToPolicyEntry(); - const data = JSON.stringify(policy, null, 2); - const blob = new Blob([ data ], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = policy.payload.policy.policyId.length ? 'policy-template-' + policy.payload.policy.policyId : 'policy-template'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - - } + /* + downloadTemplateAsJsonFile() { + const policy = this.mapPolicyFormToPolicyEntry(); + const data = JSON.stringify(policy, null, 2); + const blob = new Blob([ data ], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = policy.payload.policy.policyId.length ? 'policy-template-' + policy.payload.policy.policyId : 'policy-template'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); - applyTemplate() { - if (!this.templateFile) { - return; } - const reader = new FileReader(); - - reader.onload = () => { - const fileContent = reader.result; - if (typeof fileContent === 'string') { - if (!PoliciesAssembler.validatePoliciesTemplate(JSON.parse(fileContent))) { - this.templateError = 'pageAdmin.policyManagement.templateErrorMessage'; - return; - } - let policyEntry = PoliciesAssembler.mapToPolicyEntryList(JSON.parse(fileContent)); - let policy = PoliciesAssembler.assemblePolicy(policyEntry[0].payload.policy); - this.toastService.success('pageAdmin.policyManagement.changeSuccessMessage'); - this.updatePolicyForm(policy); - } - }; - reader.onerror = () => { - this.toastService.error(reader.error?.message); - }; - reader.readAsText(this.templateFile); - } + applyTemplate() { + if (!this.templateFile) { + return; + } + const reader = new FileReader(); + + reader.onload = () => { + const fileContent = reader.result; + if (typeof fileContent === 'string') { + if (!PoliciesAssembler.validatePoliciesTemplate(JSON.parse(fileContent))) { + this.templateError = 'pageAdmin.policyManagement.templateErrorMessage'; + return; + } + let policyEntry = PoliciesAssembler.mapToPolicyEntryList(JSON.parse(fileContent)); + let policy = PoliciesAssembler.assemblePolicy(policyEntry[0].payload.policy); + this.toastService.success('pageAdmin.policyManagement.changeSuccessMessage'); + this.updatePolicyForm(policy); + } + }; + reader.onerror = () => { + this.toastService.error(reader.error?.message); + }; + + reader.readAsText(this.templateFile); + + } + */ updatePolicyForm(policy: Policy) { const isFromTemplate = !policy?.permissions[0]?.constraints; From 2e73975ed45c299711dd5d946633a30193801aa0 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 17:01:30 +0200 Subject: [PATCH 22/44] feature(policy): #832 fix code issues --- .../policy-management/policies/policies.component.scss | 0 .../policy-management/policies/policies.component.ts | 2 +- .../policy-management/policies/policy.assembler.ts | 3 +++ .../policy-editor/policy-editor.component.html | 5 +++++ .../src/app/modules/page/policies/model/policy.model.ts | 6 ------ .../modules/shared/components/table/table.component.html | 1 + 6 files changed, 10 insertions(+), 7 deletions(-) delete mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts index 269ff208ae..20af5a5fd6 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts @@ -22,7 +22,7 @@ import { take } from 'rxjs/operators'; @Component({ selector: 'app-policies', templateUrl: './policies.component.html', - styleUrls: [ './policies.component.scss' ], + styleUrls: [], }) export class PoliciesComponent { policiesView$: Observable>; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 03179a52a7..57f2db42a0 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -79,6 +79,7 @@ export class PoliciesAssembler { return constrainsList; } + /* public static validatePoliciesTemplate(data: any) { if (typeof data !== 'object' || data === null || !Array.isArray(data[Object.keys(data)[0]])) { @@ -155,4 +156,6 @@ export class PoliciesAssembler { return true; } + */ + } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 5f5c891918..2699a3bc21 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -92,6 +92,7 @@ > {{ 'pageAdmin.policyManagement.apply' | i18n }} @@ -148,6 +149,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + class="mb-2" *ngIf="viewMode !== ViewMode.VIEW">

@@ -199,6 +201,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + > @@ -213,6 +216,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + @@ -226,6 +230,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + > diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index d8f32b3063..fc79e80227 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -121,22 +121,16 @@ export function getOperatorTypeSign(type: OperatorType): string { switch (type) { case OperatorType.EQ: return '='; - break; case OperatorType.NEQ: return '!='; - break; case OperatorType.LT: return '<'; - break; case OperatorType.GT: return '>'; - break; case OperatorType.LTEQ: return '<='; - break; case OperatorType.GTEQ: return '>='; - break; default: return type.toString(); } diff --git a/frontend/src/app/modules/shared/components/table/table.component.html b/frontend/src/app/modules/shared/components/table/table.component.html index e590411b0a..fa62579a30 100644 --- a/frontend/src/app/modules/shared/components/table/table.component.html +++ b/frontend/src/app/modules/shared/components/table/table.component.html @@ -90,6 +90,7 @@ From 733262ac9d716afdaf907b44273e82d00a8b43c7 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 17:12:51 +0200 Subject: [PATCH 23/44] feature(policy): #832 fix test --- .../policy-editor/policy-editor.component.spec.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts index a5f0e04e5d..c13a27e406 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -1,4 +1,4 @@ -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { AdminModule } from '@page/admin/admin.module'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { Policy } from '@page/policies/model/policy.model'; @@ -25,6 +25,18 @@ describe('PolicyEditorComponent', () => { url: 'https://test.net/admin/policies/edit/default', }, }, + { + provide: ActivatedRoute, + useValue: { + params: of({ id: 'default' }), + queryParams: of({}), + snapshot: { + paramMap: { + get: (key: string) => 'default', + }, + }, + }, + }, ], }); } From 1992551fa3fe6210a7adc8c52a70601be16dbad4 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Wed, 12 Jun 2024 17:55:56 +0200 Subject: [PATCH 24/44] feature(policy): #832 added tests --- .../policies/policies.assembler.spec.ts | 120 ++++++++++++++++++ .../policies/policy.assembler.ts | 18 ++- 2 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.assembler.spec.ts diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.assembler.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.assembler.spec.ts new file mode 100644 index 0000000000..2a6c4e5cfa --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.assembler.spec.ts @@ -0,0 +1,120 @@ +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; +import { OperatorType, Policy, PolicyAction, PolicyEntry, PolicyResponseMap } from '@page/policies/model/policy.model'; + +// Mock data +const mockPolicy: Policy = { + policyId: 'policy123', + createdOn: '2024-01-01T00:00:00Z', + validUntil: '2024-12-31T23:59:59Z', + permissions: [ + { + action: 'use' as PolicyAction, + constraint: { + and: [ + { + leftOperand: 'left1', + operator: { '@id': OperatorType.EQ }, + operatorTypeResponse: OperatorType.EQ, + 'odrl:rightOperand': 'right1', + }, + ], + or: [ + { + leftOperand: 'left2', + operator: { '@id': OperatorType.NEQ }, + operatorTypeResponse: OperatorType.NEQ, + 'odrl:rightOperand': 'right2', + }, + ], + }, + }, + ], + constraints: [], +}; + +const mockPolicy2: Policy = { + policyId: 'policy123', + createdOn: '2024-01-01T00:00:00Z', + validUntil: '2024-12-31T23:59:59Z', + permissions: [ + { + action: 'use' as PolicyAction, + constraints: { + and: [ + { + leftOperand: 'left1', + operator: { '@id': OperatorType.EQ }, + operatorTypeResponse: OperatorType.EQ, + rightOperand: 'right1', + }, + ], + or: [ + { + leftOperand: 'left2', + operator: { '@id': OperatorType.NEQ }, + operatorTypeResponse: OperatorType.NEQ, + rightOperand: 'right2', + }, + ], + }, + }, + ], + constraints: [], +}; + +const mockPolicyResponse: PolicyResponseMap = { + 'bpn123': [ + { + payload: { + '@context': { + odrl: 'test', + }, + '@id': 'entry123', + policy: mockPolicy, + }, + validUntil: '2024-01-01T00:00:00Z', + }, + ], +}; + +describe('PoliciesAssembler', () => { + it('should assemble policy', () => { + const assembledPolicy = PoliciesAssembler.assemblePolicy(mockPolicy); + expect(assembledPolicy.policyName).toBe(mockPolicy.policyId); + expect(assembledPolicy.createdOn).toBe('2024-01-01T00:00'); + expect(assembledPolicy.validUntil).toBe('2024-12-31T23:59'); + expect(assembledPolicy.accessType).toBe('USE'); + expect(assembledPolicy.constraints).toEqual([]); + }); + + it('should map policy response to policy entry list', () => { + const policyEntryList = PoliciesAssembler.mapToPolicyEntryList(mockPolicyResponse); + expect(policyEntryList.length).toBe(1); + expect(policyEntryList[0].payload.policy.bpn).toBe('bpn123'); + expect(policyEntryList[0].payload.policy.policyName).toBe('entry123'); + }); + + it('should map display props to policy root level from policy entry', () => { + const policyEntry: PolicyEntry = { + validUntil: '2024-01-01T00:00:00Z', + payload: { + '@context': { + odrl: 'test', + }, + '@id': 'entry123', + policy: mockPolicy, + }, + }; + const constraints = PoliciesAssembler.mapDisplayPropsToPolicyRootLevelFromPolicyEntry(policyEntry); + expect(constraints).toEqual([ + 'left1', '=', 'right1', 'left2', '!=', 'right2', + ]); + }); + + it('should map display props to policy root level from policy', () => { + const constraints = PoliciesAssembler.mapDisplayPropsToPolicyRootLevelFromPolicy(mockPolicy2); + expect(constraints).toEqual([ + 'left1', '=', 'right1', 'left2', '!=', 'right2', + ]); + }); +}); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 57f2db42a0..34ab133b1d 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -56,26 +56,32 @@ export class PoliciesAssembler { } }); }); + console.log(constrainsList); return constrainsList; } public static mapDisplayPropsToPolicyRootLevelFromPolicy(policy: Policy): string[] { - + console.log(JSON.stringify(policy)); let constrainsList = []; - policy.permissions.forEach(permission => { - permission.constraints?.and?.forEach(andConstraint => { + policy.permissions.forEach((permission) => { + permission.constraints?.and?.forEach((andConstraint, index) => { constrainsList.push(andConstraint.leftOperand); constrainsList.push(getOperatorTypeSign(andConstraint.operatorTypeResponse)); constrainsList.push(andConstraint.rightOperand); - constrainsList.push(' AND '); + if (index !== permission.constraints.and.length - 1) { + constrainsList.push(' AND '); + } }); - permission.constraints?.or?.forEach(orConstraint => { + permission.constraints?.or?.forEach((orConstraint, index) => { constrainsList.push(orConstraint.leftOperand); constrainsList.push(getOperatorTypeSign(orConstraint.operatorTypeResponse)); constrainsList.push(orConstraint.rightOperand); - constrainsList.push(' OR '); + if (index !== permission.constraints.or.length - 1) { + constrainsList.push(' OR '); + } }); }); + console.log(constrainsList); return constrainsList; } From e1b8ebcb00155510fc3b313aea6a9e5f2be34e87 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 13 Jun 2024 12:35:42 +0200 Subject: [PATCH 25/44] feature(policy): #832 added PUT mapping --- .../policies/policy.assembler.ts | 3 --- .../policy-editor.component.html | 10 ++++---- .../policy-editor/policy-editor.component.ts | 24 ++++++++++++++----- .../page/policies/model/policy.model.ts | 1 + .../modules/shared/service/policy.service.ts | 9 ++++++- .../src/assets/locales/de/page.admin.json | 2 ++ .../src/assets/locales/en/page.admin.json | 2 ++ 7 files changed, 36 insertions(+), 15 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 34ab133b1d..5a042f7831 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -56,12 +56,10 @@ export class PoliciesAssembler { } }); }); - console.log(constrainsList); return constrainsList; } public static mapDisplayPropsToPolicyRootLevelFromPolicy(policy: Policy): string[] { - console.log(JSON.stringify(policy)); let constrainsList = []; policy.permissions.forEach((permission) => { permission.constraints?.and?.forEach((andConstraint, index) => { @@ -81,7 +79,6 @@ export class PoliciesAssembler { } }); }); - console.log(constrainsList); return constrainsList; } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index 2699a3bc21..e84f07fc64 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -121,8 +121,8 @@ >

@@ -197,7 +197,7 @@

{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + matTooltipPosition="before" [class.mdc-tooltip--multiline]="true" [matTooltipShowDelay]="500" - *ngIf="viewMode !== ViewMode.VIEW" + *ngIf="viewMode === ViewMode.CREATE" > {{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + matTooltipPosition="before" [class.mdc-tooltip--multiline]="true" [matTooltipShowDelay]="500" - *ngIf="viewMode !== ViewMode.VIEW" + *ngIf="viewMode === ViewMode.CREATE" > {{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + matTooltipPosition="above" [class.mdc-tooltip--multiline]="true" [matTooltipShowDelay]="500" - *ngIf="viewMode !== ViewMode.VIEW" + *ngIf="viewMode === ViewMode.CREATE" > (PolicyAction.ACCESS), constraints: this.fb.array([]), constraintLogicType: new FormControl(ConstraintLogicType.AND), @@ -65,9 +65,11 @@ export class PolicyEditorComponent { this.selectedPolicySubscription = this.policyFacade.selectedPolicy$.subscribe(next => { this.selectedPolicy = next?.data; if (next?.data) { + console.log(next.data); this.updatePolicyForm(this.selectedPolicy); } }); + } else { this.addConstraintFormGroup(); } @@ -207,7 +209,7 @@ export class PolicyEditorComponent { this.policyForm.patchValue({ policyName: policy?.policyName, validUntil: policy?.validUntil, - bpns: policy?.bpn, + bpns: policy?.bpn ?? policy?.businessPartnerNumber, accessType: policy?.accessType, constraintLogicType: policy?.permissions[0]?.constraints?.and?.length ? ConstraintLogicType.AND : ConstraintLogicType.OR, }); @@ -228,9 +230,21 @@ export class PolicyEditorComponent { this.policyForm.setControl('constraints', this.fb.array(constraintsList)); + + if (this.viewMode === ViewMode.VIEW) { this.policyForm.disable(); } + + if (this.viewMode === ViewMode.EDIT) { + this.policyForm.disable(); + this.constraints.controls.forEach(control => { + control.disable(); + }); + this.policyForm.get('validUntil').enable(); + this.policyForm.get('bpns').enable(); + } + } mapPolicyFormToPolicyEntry(): PolicyEntry { @@ -247,11 +261,9 @@ export class PolicyEditorComponent { }; }); - const policyBpns = this.policyForm.get('bpns').getRawValue()?.trim()?.split(','); - policyEntry = { validUntil: this.policyForm.get('validUntil').getRawValue() + ':00.000000000Z', - businessPartnerNumber: policyBpns?.length > 1 ? policyBpns : policyBpns?.[0], + businessPartnerNumber: this.viewMode === ViewMode.CREATE ? this.policyForm.get('bpns').getRawValue() : this.policyForm.get('bpns').getRawValue()?.trim()?.split(','), payload: { '@context': { odrl: 'http://www.w3.org/ns/odrl/2/', diff --git a/frontend/src/app/modules/page/policies/model/policy.model.ts b/frontend/src/app/modules/page/policies/model/policy.model.ts index fc79e80227..956d0fc0d7 100644 --- a/frontend/src/app/modules/page/policies/model/policy.model.ts +++ b/frontend/src/app/modules/page/policies/model/policy.model.ts @@ -52,6 +52,7 @@ export interface Policy { bpn?: string; constraints?: string[] accessType?: PolicyAction, + businessPartnerNumber?: string | string[] } diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index 54cfaecc36..df768a71e2 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -34,6 +34,13 @@ export class PolicyService { updatePolicy(policyEntry: PolicyEntry) { policyEntry.policyIds = [ policyEntry.payload.policy.policyId ]; - return this.apiService.put(`${ this.url }/policies/` + policyEntry.payload.policy.policyId, policyEntry); + + const body = { + policyIds: [ policyEntry.payload.policy.policyId ], + validUntil: policyEntry.validUntil, + businessPartnerNumber: policyEntry.businessPartnerNumber, + }; + + return this.apiService.put(`${ this.url }/policies`, body); } } diff --git a/frontend/src/assets/locales/de/page.admin.json b/frontend/src/assets/locales/de/page.admin.json index 4c864d6ebe..7616c7517c 100644 --- a/frontend/src/assets/locales/de/page.admin.json +++ b/frontend/src/assets/locales/de/page.admin.json @@ -74,6 +74,7 @@ "policyName" : "Richtlinienname", "validUntil" : "Gültig bis", "bpnls" : "BPNs", + "bpn" : "BPN", "policyConstraints" : "Richtlinientyp", "accessType" : "Zugriffstyp", "constraints" : "Regeln", @@ -92,6 +93,7 @@ "templateErrorMessage" : "Die selektierte Vorlagendatei ist nicht konform für Richtlinien. Bitte wählen Sie eine valide .JSON Vorlagendatei aus.", "invalidForm" : "Bitte füllen Sie die Eingabefelder korrekt aus", "bpnsHint" : "Liste von BPNs separiert durch ein Kommazeichen", + "bpnHint" : "", "savePolicy" : "Richtlinie speichern", "addConstraint" : "Regel hinzufügen" } diff --git a/frontend/src/assets/locales/en/page.admin.json b/frontend/src/assets/locales/en/page.admin.json index a579d57347..adb2c3693f 100644 --- a/frontend/src/assets/locales/en/page.admin.json +++ b/frontend/src/assets/locales/en/page.admin.json @@ -74,6 +74,7 @@ "policyName" : "Policy name", "validUntil" : "Valid until", "bpnls" : "BPNs", + "bpn" : "BPN", "policyConstraints" : "Policy type", "accessType" : "Access type", "constraints" : "Constraints", @@ -92,6 +93,7 @@ "templateErrorMessage" : "The selected template file is not compliant. Please provide a valid .JSON template file.", "invalidForm" : "Please make sure to submit a valid form", "bpnsHint" : "Please provide a list of BPNs separated by comma", + "bpnHint" : "Please provide a BPN", "savePolicy" : "Save policy", "addConstraint" : "Add constraint" From e018f18fc7a4d0df7c2c27b61c886153f3909ac8 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 13 Jun 2024 13:56:42 +0200 Subject: [PATCH 26/44] feature(policy): #832 fix test --- .../policy-editor/policy-editor.component.html | 2 +- .../policy-editor/policy-editor.component.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index e84f07fc64..b1eca346fc 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -5,7 +5,7 @@ -
+
Date: Thu, 13 Jun 2024 14:29:07 +0200 Subject: [PATCH 27/44] feature(policy): #832 added tests --- .../policy-editor.component.spec.ts | 183 +++++++++++++----- .../policy-editor/policy-editor.component.ts | 2 +- 2 files changed, 139 insertions(+), 46 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts index c13a27e406..cc4eb3656d 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -1,69 +1,162 @@ -import { ActivatedRoute, Router } from '@angular/router'; -import { AdminModule } from '@page/admin/admin.module'; +import { APP_INITIALIZER } from '@angular/core'; +import { FormBuilder } from '@angular/forms'; +import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; import { Policy } from '@page/policies/model/policy.model'; -import { View } from '@shared/model/view.model'; +import { ToastService } from '@shared/components/toasts/toast.service'; +import { ViewMode } from '@shared/model/view.model'; import { renderComponent } from '@tests/test-render.utils'; -import { of } from 'rxjs'; - +import { I18NEXT_SERVICE, ITranslationService } from 'angular-i18next'; +import { of, Subject } from 'rxjs'; import { PolicyEditorComponent } from './policy-editor.component'; -describe('PolicyEditorComponent', () => { +fdescribe('PolicyEditorComponent', () => { + let mockPoliciesFacade: Partial; + let mockToastService: Partial; + let mockRouter: Partial; + let mockRoute: Partial; + let selectedPolicySubject: Subject<{ data: Policy }>; + beforeEach(() => { + selectedPolicySubject = new Subject(); + mockPoliciesFacade = { + selectedPolicy$: selectedPolicySubject.asObservable(), + setSelectedPolicyById: jasmine.createSpy(), + createPolicy: jasmine.createSpy().and.returnValue(of({})), + updatePolicy: jasmine.createSpy().and.returnValue(of({})), + }; + mockToastService = { + success: jasmine.createSpy(), + error: jasmine.createSpy(), + }; + mockRouter = { + navigate: jasmine.createSpy(), + url: 'admin/policies/create', + }; - const renderPolicyEditorComponent = async (policyFacadeMock: any) => { - return await renderComponent(PolicyEditorComponent, { - imports: [ AdminModule ], - providers: [ { - provide: PoliciesFacade, - useValue: policyFacadeMock, + mockRoute = { + snapshot: { + paramMap: convertToParamMap({ policyId: '1' }), + url: [], + params: {}, + queryParams: {}, + fragment: null, + data: {}, + outlet: 'primary', + component: PolicyEditorComponent, + root: null, + parent: null, + firstChild: null, + children: [], + pathFromRoot: [], + toString: () => '', + routeConfig: null, + title: '', + queryParamMap: convertToParamMap({}), }, + }; + }); + + const renderPolicyEditorComponent = () => + renderComponent(PolicyEditorComponent, { + imports: [ RouterTestingModule ], + providers: [ + { provide: PoliciesFacade, useValue: mockPoliciesFacade }, + { provide: ToastService, useValue: mockToastService }, + { provide: Router, useValue: mockRouter }, + { provide: ActivatedRoute, useValue: mockRoute }, + FormBuilder, { - provide: Router, - useValue: { - url: 'https://test.net/admin/policies/edit/default', - }, - }, - { - provide: ActivatedRoute, - useValue: { - params: of({ id: 'default' }), - queryParams: of({}), - snapshot: { - paramMap: { - get: (key: string) => 'default', - }, - }, + provide: APP_INITIALIZER, + useFactory: (i18next: ITranslationService) => { + return () => + i18next.init({ + lng: 'en', + supportedLngs: [ 'en', 'de' ], + resources: {}, + }); }, + deps: [ I18NEXT_SERVICE ], + multi: true, }, ], }); - } - - it('should create', async function() { - const dummyPolicy: View = { - data: { - policyId: 'default', - createdOn: new Date().toISOString(), - validUntil: new Date().toISOString(), - permissions: [], - }, - }; - const policyFacadeMock = jasmine.createSpyObj('policyFacade', [ 'setSelectedPolicyById' ]); - policyFacadeMock.setSelectedPolicyById.and.returnValue(undefined); + it('should create', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + expect(componentInstance).toBeTruthy(); + }); - Object.defineProperty(policyFacadeMock, 'selectedPolicy$', { - get: () => of(dummyPolicy), - }); + it('should initialize the form in create mode', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + expect(componentInstance.viewMode).toBe(ViewMode.CREATE); + expect(componentInstance.policyForm).toBeTruthy(); + expect(componentInstance.policyForm.get('policyName').valid).toBeFalsy(); // Validators required + expect(componentInstance.policyForm.get('bpns').valid).toBeFalsy(); // Validators required + expect(componentInstance.policyForm.get('validUntil').valid).toBeFalsy(); // Validators required + }); + + it('should add and remove constraints', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + expect(componentInstance.constraints.length).toBe(1); + + componentInstance.addConstraintFormGroup(); + expect(componentInstance.constraints.length).toBe(2); + + componentInstance.removeConstraintFormGroup(0); + expect(componentInstance.constraints.length).toBe(1); + }); + + it('should move constraints up and down', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + componentInstance.addConstraintFormGroup(); + componentInstance.addConstraintFormGroup(); + componentInstance.constraints.at(0).get('leftOperand').setValue('constraint 1'); + componentInstance.constraints.at(1).get('leftOperand').setValue('constraint 2'); - const component = await renderPolicyEditorComponent(policyFacadeMock); + componentInstance.moveConstraintDown(0); + expect(componentInstance.constraints.at(0).get('leftOperand').value).toBe('constraint 2'); + expect(componentInstance.constraints.at(1).get('leftOperand').value).toBe('constraint 1'); + componentInstance.moveConstraintUp(1); + expect(componentInstance.constraints.at(0).get('leftOperand').value).toBe('constraint 1'); + expect(componentInstance.constraints.at(1).get('leftOperand').value).toBe('constraint 2'); + }); + it('should navigate back', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + componentInstance.navigateBack(); + expect(mockRouter.navigate).toHaveBeenCalledWith([ 'admin/policies' ]); + }); + it('should save policy in create mode', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + componentInstance.policyForm.patchValue({ + policyName: 'Test Policy', + validUntil: new Date().toISOString(), + bpns: 'BPN0001', + accessType: 'access', + constraintLogicType: 'AND', + }); + componentInstance.addConstraintFormGroup(); + componentInstance.constraints.at(0).patchValue({ + leftOperand: 'leftOperand', + operator: '=', + rightOperand: 'rightOperand', + }); - expect(component).toBeTruthy(); + componentInstance.savePolicy(); + expect(mockPoliciesFacade.createPolicy).toHaveBeenCalled(); + expect(mockToastService.success).toHaveBeenCalled(); + expect(mockRouter.navigate).toHaveBeenCalled(); }); }); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index bdf4048674..fd3521b53d 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -39,7 +39,7 @@ export class PolicyEditorComponent { minDate: Date = new Date(); templateError: string = ''; - constructor(private readonly router: Router, private readonly route: ActivatedRoute, public readonly policyFacade: PoliciesFacade, private fb: FormBuilder, private readonly toastService: ToastService) { + constructor(private router: Router, private route: ActivatedRoute, public policyFacade: PoliciesFacade, private fb: FormBuilder, private toastService: ToastService) { } get constraints() { From 951e2c799102e59ad9dc1e82eef700b231385586 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 13 Jun 2024 14:42:37 +0200 Subject: [PATCH 28/44] feature(policy): #832 added tests --- .../policy-editor/policy-editor.component.spec.ts | 2 +- frontend/src/app/modules/shared/service/policy.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts index cc4eb3656d..41ec709878 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -11,7 +11,7 @@ import { I18NEXT_SERVICE, ITranslationService } from 'angular-i18next'; import { of, Subject } from 'rxjs'; import { PolicyEditorComponent } from './policy-editor.component'; -fdescribe('PolicyEditorComponent', () => { +describe('PolicyEditorComponent', () => { let mockPoliciesFacade: Partial; let mockToastService: Partial; let mockRouter: Partial; diff --git a/frontend/src/app/modules/shared/service/policy.service.ts b/frontend/src/app/modules/shared/service/policy.service.ts index df768a71e2..161a8c005b 100644 --- a/frontend/src/app/modules/shared/service/policy.service.ts +++ b/frontend/src/app/modules/shared/service/policy.service.ts @@ -38,7 +38,7 @@ export class PolicyService { const body = { policyIds: [ policyEntry.payload.policy.policyId ], validUntil: policyEntry.validUntil, - businessPartnerNumber: policyEntry.businessPartnerNumber, + businessPartnerNumbers: policyEntry.businessPartnerNumber, }; return this.apiService.put(`${ this.url }/policies`, body); From a28e3ee0bda92be3a1372b0d0e073176487492ec Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 13 Jun 2024 16:41:30 +0200 Subject: [PATCH 29/44] feature(policy): #832 added tests --- .../policy-editor.component.spec.ts | 95 ++++++++++++++++++- .../policy-editor/policy-editor.component.ts | 4 +- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts index 41ec709878..8c71377cbc 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.spec.ts @@ -3,7 +3,8 @@ import { FormBuilder } from '@angular/forms'; import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade'; -import { Policy } from '@page/policies/model/policy.model'; +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; +import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; import { ToastService } from '@shared/components/toasts/toast.service'; import { ViewMode } from '@shared/model/view.model'; import { renderComponent } from '@tests/test-render.utils'; @@ -18,6 +19,38 @@ describe('PolicyEditorComponent', () => { let mockRoute: Partial; let selectedPolicySubject: Subject<{ data: Policy }>; + const mockPolicy: Policy = { + policyName: 'policy123', + policyId: 'policy123', + createdOn: '2024-01-01T00:00:00Z', + validUntil: '2024-12-31T23:59:59Z', + bpn: 'Test BPN', + permissions: [ + { + action: 'use' as PolicyAction, + constraint: { + and: [ + { + leftOperand: 'left1', + operator: { '@id': OperatorType.EQ }, + operatorTypeResponse: OperatorType.EQ, + 'odrl:rightOperand': 'right1', + }, + ], + or: [ + { + leftOperand: 'left2', + operator: { '@id': OperatorType.NEQ }, + operatorTypeResponse: OperatorType.NEQ, + 'odrl:rightOperand': 'right2', + }, + ], + }, + }, + ], + constraints: [], + }; + beforeEach(() => { selectedPolicySubject = new Subject(); mockPoliciesFacade = { @@ -100,6 +133,26 @@ describe('PolicyEditorComponent', () => { expect(componentInstance.policyForm.get('validUntil').valid).toBeFalsy(); // Validators required }); + it('should initialize the view mode correctly', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + Object.defineProperty(mockRouter, 'url', { + get: jasmine.createSpy().and.returnValue('admin/policies/create'), + }); + expect(componentInstance.initializeViewMode()).toBe(ViewMode.CREATE); + Object.defineProperty(mockRouter, 'url', { + get: jasmine.createSpy().and.returnValue('admin/policies/edit/1'), + }); + + expect(componentInstance.initializeViewMode()).toBe(ViewMode.EDIT); + + Object.defineProperty(mockRouter, 'url', { + get: jasmine.createSpy().and.returnValue('admin/policies/1'), + }); + + expect(componentInstance.initializeViewMode()).toBe(ViewMode.VIEW); + }); + it('should add and remove constraints', async () => { const { fixture } = await renderPolicyEditorComponent(); const { componentInstance } = fixture; @@ -159,4 +212,44 @@ describe('PolicyEditorComponent', () => { expect(mockToastService.success).toHaveBeenCalled(); expect(mockRouter.navigate).toHaveBeenCalled(); }); + + it('should update policy form correctly in create mode', async () => { + const { fixture } = await renderPolicyEditorComponent(); + const { componentInstance } = fixture; + componentInstance.selectedPolicy = mockPolicy; + const policy: Policy = PoliciesAssembler.assemblePolicy(mockPolicy); + + componentInstance.viewMode = ViewMode.CREATE; + componentInstance.policyForm = componentInstance.fb.group({ + policyName: '', + validUntil: null, + bpns: '', + accessType: '', + constraintLogicType: '', + constraints: componentInstance.fb.array([]), + }); + + componentInstance.updatePolicyForm(policy); + + // Assert the form values are updated correctly + expect(componentInstance.policyForm.getRawValue().policyName).toBe('policy123'); + expect(componentInstance.policyForm.getRawValue().validUntil).toBe(policy.validUntil); + expect(componentInstance.policyForm.getRawValue().bpns).toBe('Test BPN'); + expect(componentInstance.policyForm.getRawValue().accessType).toBe('USE'); + expect(componentInstance.policyForm.getRawValue().constraintLogicType).toBe('AND'); + expect(componentInstance.policyForm.getRawValue().constraints.length).toBe(1); + + componentInstance.viewMode = ViewMode.VIEW; + + componentInstance.updatePolicyForm(policy); + expect(componentInstance.policyForm.disabled).toBe(true); + + componentInstance.viewMode = ViewMode.EDIT; + componentInstance.updatePolicyForm(policy); + expect(componentInstance.policyForm.get('validUntil').disabled).toBe(false); + expect(componentInstance.policyForm.get('bpns').disabled).toBe(false); + expect(componentInstance.constraints.disabled).toBe(true); + + }); + }); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts index fd3521b53d..6fa720b42b 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.ts @@ -39,7 +39,7 @@ export class PolicyEditorComponent { minDate: Date = new Date(); templateError: string = ''; - constructor(private router: Router, private route: ActivatedRoute, public policyFacade: PoliciesFacade, private fb: FormBuilder, private toastService: ToastService) { + constructor(private router: Router, private route: ActivatedRoute, public policyFacade: PoliciesFacade, public fb: FormBuilder, private toastService: ToastService) { } get constraints() { @@ -76,7 +76,7 @@ export class PolicyEditorComponent { } - private initializeViewMode(): ViewMode { + initializeViewMode(): ViewMode { const url = this.router.url; if (url.includes('create')) { return ViewMode.CREATE; From 030abd4f20d2eb62f83487be988b73233e8b09ce Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Thu, 13 Jun 2024 17:41:55 +0200 Subject: [PATCH 30/44] feature(policy): #832 added tests --- .../services/policy-mock/policy.model.ts | 37 +++- .../policies/policies.facade.spec.ts | 164 ++++++++++++++++++ 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts diff --git a/frontend/src/app/mocks/services/policy-mock/policy.model.ts b/frontend/src/app/mocks/services/policy-mock/policy.model.ts index 0aa2b20380..84e0a8f605 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.model.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.model.ts @@ -1,4 +1,4 @@ -import { OperatorType, Policy, PolicyAction } from '@page/policies/model/policy.model'; +import { OperatorType, Policy, PolicyAction, PolicyResponseMap } from '@page/policies/model/policy.model'; /******************************************************************************** * Copyright (c) 2022, 2023, 2024 Contributors to the Eclipse Foundation @@ -163,4 +163,39 @@ const mockedPolicies = { }; +export const MockPolicyResponseMap: PolicyResponseMap = { + 'default': [ + { + 'validUntil': '2024-06-30T11:07:00Z', + 'payload': { + '@context': { + 'odrl': 'http://www.w3.org/ns/odrl/2/', + }, + '@id': 'asdadasdas', + 'policy': { + 'policyId': 'asdadasdas', + 'createdOn': '2024-06-13T09:07:32.229901783Z', + 'validUntil': '2024-06-30T11:07:00Z', + 'permissions': [ + { + 'action': PolicyAction.USE, + 'constraint': { + 'and': null, + 'or': [ + { + 'leftOperand': 'asd', + 'operator': { + '@id': OperatorType.EQ, + }, + 'odrl:rightOperand': 'dsa', + }, + ], + }, + }, + ], + }, + }, + }, + ], +}; diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts new file mode 100644 index 0000000000..d6c6a90532 --- /dev/null +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts @@ -0,0 +1,164 @@ +import { TestBed } from '@angular/core/testing'; +import { PoliciesState } from '@page/admin/presentation/policy-management/policies/policies.state'; // Adjust the path as necessary +import { PoliciesAssembler } from '@page/admin/presentation/policy-management/policies/policy.assembler'; // Adjust the path as necessary +import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; // Adjust the path as necessary +import { PolicyService } from '@shared/service/policy.service'; // Adjust the path as necessary +import { of, throwError } from 'rxjs'; +import { PoliciesFacade } from './policies.facade'; // Adjust the path as necessary + +fdescribe('PoliciesFacade', () => { + let facade: PoliciesFacade; + let policyServiceSpy: jasmine.SpyObj; + let policiesStateSpy: jasmine.SpyObj; + + beforeEach(() => { + const policyServiceMock = jasmine.createSpyObj('PolicyService', [ 'getPolicies', 'getPolicyById', 'deletePolicies', 'createPolicy', 'updatePolicy' ]); + const policiesStateMock = jasmine.createSpyObj('PoliciesState', [ 'policies$', 'selectedPolicy$', 'policies', 'selectedPolicy' ]); + + TestBed.configureTestingModule({ + providers: [ + PoliciesFacade, + { provide: PolicyService, useValue: policyServiceMock }, + { provide: PoliciesState, useValue: policiesStateMock }, + ], + }); + + facade = TestBed.inject(PoliciesFacade); + policyServiceSpy = TestBed.inject(PolicyService) as jasmine.SpyObj; + policiesStateSpy = TestBed.inject(PoliciesState) as jasmine.SpyObj; + }); + + it('should be created', () => { + expect(facade).toBeTruthy(); + }); + + describe('setPolicies', () => { + /* + it('should fetch policies and update the state', () => { + policyServiceSpy.getPolicies.and.returnValue(of(MockPolicyResponseMap)); + spyOn(PoliciesAssembler, 'mapToPolicyEntryList').and.returnValue(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)); + spyOn(PoliciesAssembler, 'assemblePolicy').and.returnValue(PoliciesAssembler.assemblePolicy(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)[0].payload.policy)); + + facade.setPolicies(); + + expect(policyServiceSpy.getPolicies).toHaveBeenCalled(); + expect(policiesStateSpy.policies).toEqual({ data: [PoliciesAssembler.assemblePolicy(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)[0].payload.policy)] }); + }); + + */ + + it('should handle error when fetching policies', () => { + const mockError = new Error('Test error'); + policyServiceSpy.getPolicies.and.returnValue(throwError(mockError)); + + facade.setPolicies(); + + expect(policyServiceSpy.getPolicies).toHaveBeenCalled(); + expect(policiesStateSpy.policies).toEqual({ error: mockError }); + }); + }); + + describe('selectedPolicy', () => { + it('should get selected policy', () => { + const mockPolicy = { policyName: 'Test Policy' } as Policy; + policiesStateSpy.selectedPolicy = { data: mockPolicy }; + + expect(facade.selectedPolicy).toBe(mockPolicy); + }); + + it('should set selected policy', () => { + const mockPolicy = { policyName: 'Test Policy' } as Policy; + + facade.selectedPolicy = mockPolicy; + + expect(policiesStateSpy.selectedPolicy).toEqual({ data: mockPolicy }); + }); + }); + + describe('setSelectedPolicyById', () => { + it('should fetch and set selected policy by ID', () => { + const mockPolicy = { policyName: 'Test Policy' } as Policy; + policyServiceSpy.getPolicyById.and.returnValue(of(mockPolicy)); + spyOn(PoliciesAssembler, 'assemblePolicy').and.returnValue(mockPolicy); + + facade.setSelectedPolicyById('test-id'); + + expect(policyServiceSpy.getPolicyById).toHaveBeenCalledWith('test-id'); + expect(policiesStateSpy.selectedPolicy).toEqual({ data: mockPolicy }); + }); + + it('should handle error when fetching policy by ID', () => { + const mockError = new Error('Test error'); + policyServiceSpy.getPolicyById.and.returnValue(throwError(mockError)); + + facade.setSelectedPolicyById('test-id'); + + expect(policyServiceSpy.getPolicyById).toHaveBeenCalledWith('test-id'); + expect(policiesStateSpy.selectedPolicy).toEqual({ error: mockError }); + }); + }); + + describe('unsubscribePolicies', () => { + it('should unsubscribe from policies subscriptions', () => { + const mockPoliciesSubscription = jasmine.createSpyObj('Subscription', [ 'unsubscribe' ]); + const mockSelectedPoliciesSubscription = jasmine.createSpyObj('Subscription', [ 'unsubscribe' ]); + facade['policiesSubscription'] = mockPoliciesSubscription; + facade['selectedPoliciesSubscription'] = mockSelectedPoliciesSubscription; + + facade.unsubscribePolicies(); + + expect(mockPoliciesSubscription.unsubscribe).toHaveBeenCalled(); + expect(mockSelectedPoliciesSubscription.unsubscribe).toHaveBeenCalled(); + // Test unsubscribeTrigger if necessary + }); + }); + + describe('deletePolicies', () => { + it('should call policyService.deletePolicies with policy IDs', () => { + const mockPolicies = [ { policyId: '1' }, { policyId: '2' } ] as Policy[]; + const mockDeleteResponse = of(null); + policyServiceSpy.deletePolicies.and.returnValue(mockDeleteResponse); + + const result = facade.deletePolicies(mockPolicies); + + expect(policyServiceSpy.deletePolicies).toHaveBeenCalledWith([ '1', '2' ]); + expect(result).toBe(mockDeleteResponse); + }); + }); + + describe('createPolicy', () => { + it('should call policyService.createPolicy with policy entry', () => { + const mockPolicyEntry = { + policyName: 'New Policy', + validUntil: null, + payload: null, + businessPartnerNumber: '', + } as PolicyEntry; + const mockCreateResponse = of(null); + policyServiceSpy.createPolicy.and.returnValue(mockCreateResponse); + + const result = facade.createPolicy(mockPolicyEntry); + + expect(policyServiceSpy.createPolicy).toHaveBeenCalledWith(mockPolicyEntry); + expect(result).toBe(mockCreateResponse); + }); + }); + + describe('updatePolicy', () => { + it('should call policyService.updatePolicy with policy entry', () => { + const mockPolicyEntry = { + policyName: 'New Policy', + validUntil: null, + payload: null, + businessPartnerNumber: '', + } as PolicyEntry; + const mockUpdateResponse = of(null); + policyServiceSpy.updatePolicy.and.returnValue(mockUpdateResponse); + + const result = facade.updatePolicy(mockPolicyEntry); + + expect(policyServiceSpy.updatePolicy).toHaveBeenCalledWith(mockPolicyEntry); + expect(result).toBe(mockUpdateResponse); + }); + }); +}); From 24f90db418f30bae84d9a01397d79c503a4454ee Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 14 Jun 2024 10:21:57 +0200 Subject: [PATCH 31/44] feature(policy): #832 implemented feedback --- .../services/policy-mock/policy.handler.ts | 4 +-- .../policies/policies.facade.spec.ts | 35 ++++++++----------- .../policies/policies.facade.ts | 10 ++++-- .../policies/policy.assembler.ts | 4 +++ .../policy-editor.component.html | 2 +- .../policy-editor/policy-editor.component.ts | 8 +++++ .../modules/shared/service/policy.service.ts | 5 ++- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts index 2ae9a406b3..504045f0ea 100644 --- a/frontend/src/app/mocks/services/policy-mock/policy.handler.ts +++ b/frontend/src/app/mocks/services/policy-mock/policy.handler.ts @@ -36,11 +36,11 @@ export const policyHandler = (_ => { return res(ctx.status(200), ctx.json(policy)); }), - rest.put(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { + rest.put(`*${ environment.apiUrl }/policies`, (req, res, ctx) => { return res(ctx.status(200), ctx.json('success')); }), - rest.delete(`*${ environment.apiUrl }/policies/:policyIds`, (req, res, ctx) => { + rest.delete(`*${ environment.apiUrl }/policies/:policyId`, (req, res, ctx) => { return res(ctx.status(200), ctx.json('success')); }), diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts index d6c6a90532..405e02ee72 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.spec.ts @@ -6,13 +6,13 @@ import { PolicyService } from '@shared/service/policy.service'; // Adjust the pa import { of, throwError } from 'rxjs'; import { PoliciesFacade } from './policies.facade'; // Adjust the path as necessary -fdescribe('PoliciesFacade', () => { +describe('PoliciesFacade', () => { let facade: PoliciesFacade; let policyServiceSpy: jasmine.SpyObj; let policiesStateSpy: jasmine.SpyObj; beforeEach(() => { - const policyServiceMock = jasmine.createSpyObj('PolicyService', [ 'getPolicies', 'getPolicyById', 'deletePolicies', 'createPolicy', 'updatePolicy' ]); + const policyServiceMock = jasmine.createSpyObj('PolicyService', [ 'getPolicies', 'getPolicyById', 'deletePolicy', 'createPolicy', 'updatePolicy' ]); const policiesStateMock = jasmine.createSpyObj('PoliciesState', [ 'policies$', 'selectedPolicy$', 'policies', 'selectedPolicy' ]); TestBed.configureTestingModule({ @@ -33,19 +33,6 @@ fdescribe('PoliciesFacade', () => { }); describe('setPolicies', () => { - /* - it('should fetch policies and update the state', () => { - policyServiceSpy.getPolicies.and.returnValue(of(MockPolicyResponseMap)); - spyOn(PoliciesAssembler, 'mapToPolicyEntryList').and.returnValue(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)); - spyOn(PoliciesAssembler, 'assemblePolicy').and.returnValue(PoliciesAssembler.assemblePolicy(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)[0].payload.policy)); - - facade.setPolicies(); - - expect(policyServiceSpy.getPolicies).toHaveBeenCalled(); - expect(policiesStateSpy.policies).toEqual({ data: [PoliciesAssembler.assemblePolicy(PoliciesAssembler.mapToPolicyEntryList(MockPolicyResponseMap)[0].payload.policy)] }); - }); - - */ it('should handle error when fetching policies', () => { const mockError = new Error('Test error'); @@ -109,20 +96,28 @@ fdescribe('PoliciesFacade', () => { expect(mockPoliciesSubscription.unsubscribe).toHaveBeenCalled(); expect(mockSelectedPoliciesSubscription.unsubscribe).toHaveBeenCalled(); - // Test unsubscribeTrigger if necessary }); }); describe('deletePolicies', () => { it('should call policyService.deletePolicies with policy IDs', () => { const mockPolicies = [ { policyId: '1' }, { policyId: '2' } ] as Policy[]; - const mockDeleteResponse = of(null); - policyServiceSpy.deletePolicies.and.returnValue(mockDeleteResponse); + const mockDeleteResponse1 = of(null); + const mockDeleteResponse2 = of(null); + + policyServiceSpy.deletePolicy.withArgs('1').and.returnValue(mockDeleteResponse1); + policyServiceSpy.deletePolicy.withArgs('2').and.returnValue(mockDeleteResponse2); const result = facade.deletePolicies(mockPolicies); - expect(policyServiceSpy.deletePolicies).toHaveBeenCalledWith([ '1', '2' ]); - expect(result).toBe(mockDeleteResponse); + // Expect the policyService.deletePolicy to be called with each policyId + expect(policyServiceSpy.deletePolicy).toHaveBeenCalledWith('1'); + expect(policyServiceSpy.deletePolicy).toHaveBeenCalledWith('2'); + + // Expect the result to be an observable that emits an array of results + result.subscribe(responses => { + expect(responses).toEqual([ null, null ]); + }); }); }); diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts index 2a5d20d52a..dbb29869cd 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.facade.ts @@ -4,7 +4,7 @@ import { PoliciesAssembler } from '@page/admin/presentation/policy-management/po import { Policy, PolicyEntry } from '@page/policies/model/policy.model'; import { View } from '@shared/model/view.model'; import { PolicyService } from '@shared/service/policy.service'; -import { Observable, Subject, Subscription } from 'rxjs'; +import { forkJoin, Observable, Subject, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() @@ -60,8 +60,12 @@ export class PoliciesFacade { this.unsubscribeTrigger.next(); } - deletePolicies(selectedPolicies: Policy[]) { - return this.policyService.deletePolicies(selectedPolicies.map(policy => policy.policyId)); + deletePolicies(selectedPolicies: Policy[]): Observable { + const deleteRequests = selectedPolicies.map(policy => + this.policyService.deletePolicy(policy.policyId), + ); + + return forkJoin(deleteRequests); } createPolicy(policyEntry: PolicyEntry) { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts index 5a042f7831..e0931ca9d4 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policy.assembler.ts @@ -82,6 +82,10 @@ export class PoliciesAssembler { return constrainsList; } + /** + * This Feature is commented out for now, because uploading/downloading Templates/Policies is + * currently not a requirement but could be one in future. + */ /* public static validatePoliciesTemplate(data: any) { diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html index b1eca346fc..d9388a0fc3 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policy-editor/policy-editor.component.html @@ -50,7 +50,7 @@
- @#tZEqDO)!i2<6k)*RqW`Sg9a<|OIM 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≪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
&CV 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 ADF6Tf literal 0 HcmV?d00001 diff --git a/docs/src/images/user-manual/policy-management/policy-constraints.png b/docs/src/images/user-manual/policy-management/policy-constraints.png new file mode 100644 index 0000000000000000000000000000000000000000..4dfbd00720fb1fc51ab97d33665eef0ad3aeb29f GIT binary patch literal 41302 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

8L>=thEX*o7;IfbtA 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 xC1|zm&;mU)sY3vIuF$9{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' + matTooltipPosition="above" [class.mdc-tooltip--multiline]="true" [matTooltipShowDelay]="500" - class="mb-2" *ngIf="viewMode !== ViewMode.VIEW"> + class="mb-2" *ngIf="viewMode === ViewMode.CREATE"> Date: Mon, 17 Jun 2024 10:18:42 +0200 Subject: [PATCH 44/44] feature(policy): #832 add user manual --- .../deletion-dialog/deletion-dialog.component.ts | 1 - .../policy-management/policies/policies.component.html | 1 + .../policy-management/policies/policies.component.ts | 4 +++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts index 33d14c6f18..8c1a2e7ea7 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/deletion-dialog/deletion-dialog.component.ts @@ -18,6 +18,5 @@ export class DeletionDialogComponent { save() { this.dialogRef.close(true); - console.log('save'); } } diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html index a2fc3018e1..bbf81bbe5f 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.html @@ -18,6 +18,7 @@ [showHover]="false" [tableType]="TableType.POLICIES" [tableSettingsEnabled]="true" + [deselectTrigger]="deselectPartTrigger$ | async" (selected)="openDetailedView($event)" (editClicked)="openEditView($event)" (multiSelect)="multiSelection($event)" diff --git a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts index 20af5a5fd6..2b1935e920 100644 --- a/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts +++ b/frontend/src/app/modules/page/admin/presentation/policy-management/policies/policies.component.ts @@ -16,7 +16,7 @@ import { import { ToastService } from '@shared/components/toasts/toast.service'; import { setMultiSorting } from '@shared/helper/table-helper'; import { View } from '@shared/model/view.model'; -import { Observable } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { take } from 'rxjs/operators'; @Component({ @@ -32,6 +32,7 @@ export class PoliciesComponent { pagination: TableEventConfig; multiSortList: TableHeaderSort[] = []; ctrlKeyState: boolean = false; + deselectPartTrigger$ = new Subject(); constructor(public readonly policyFacade: PoliciesFacade, private readonly router: Router, private readonly toastService: ToastService, public dialog: MatDialog, private readonly roleService: RoleService) { window.addEventListener('keydown', (event) => { @@ -103,6 +104,7 @@ export class PoliciesComponent { dialogRef.afterClosed().subscribe(confirmation => { if (confirmation) { this.deletePolicies(); + this.deselectPartTrigger$.next(this.selectedPolicies); } }); }