From 18d38ca7376d01bea2a22de8048f07ff0424a380 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 30 Mar 2020 12:36:36 +0200 Subject: [PATCH] Implemented resource policies component --- resources/i18n/en.json5 | 30 ++++ .../resource-policies.component.html | 40 ++++++ .../resource-policies.component.scss | 3 + .../resource-policies.component.ts | 134 ++++++++++++++++++ src/app/shared/shared.module.ts | 6 +- 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/app/shared/resource-policies/resource-policies.component.html create mode 100644 src/app/shared/resource-policies/resource-policies.component.scss create mode 100644 src/app/shared/resource-policies/resource-policies.component.ts diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index 8bfc282d73..b350d2c979 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -1657,6 +1657,36 @@ + "resource-policies.add.for.": "Add a new policy", + + "resource-policies.add.for.bitstream": "Add a new Bitstream policy", + + "resource-policies.add.for.bundle": "Add a new Bundle policy", + + "resource-policies.add.for.item": "Add a new Item policy", + + "resource-policies.table.headers.action": "Action", + + "resource-policies.table.headers.date.end": "End Date", + + "resource-policies.table.headers.date.start": "Start Date", + + "resource-policies.table.headers.group": "Group", + + "resource-policies.table.headers.group.edit": "Edit", + + "resource-policies.table.headers.name": "Name", + + "resource-policies.table.headers.id": "ID", + + "resource-policies.table.headers.title.for.bitstream": "Policies for Bitstream", + + "resource-policies.table.headers.title.for.bundle": "Policies for Bundle", + + "resource-policies.table.headers.title.for.item": "Policies for Item", + + + "search.description": "", "search.switch-configuration.title": "Show", diff --git a/src/app/shared/resource-policies/resource-policies.component.html b/src/app/shared/resource-policies/resource-policies.component.html new file mode 100644 index 0000000000..dbcf3a45e7 --- /dev/null +++ b/src/app/shared/resource-policies/resource-policies.component.html @@ -0,0 +1,40 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ {{ 'resource-policies.table.headers.title.for.' + resourceKey | translate }} {{resourceUUID}} + +

+
{{'resource-policies.table.headers.id' | translate}}{{'resource-policies.table.headers.name' | translate}}{{'resource-policies.table.headers.action' | translate}}{{'resource-policies.table.headers.group' | translate}}{{'resource-policies.table.headers.date.start' | translate}}{{'resource-policies.table.headers.date.end' | translate}}
{{policy.id}}{{policy.name}}{{policy.action}} + {{getGroupName(policy) | async}} + + {{policy.startDate}}{{policy.endDate}}
+
diff --git a/src/app/shared/resource-policies/resource-policies.component.scss b/src/app/shared/resource-policies/resource-policies.component.scss new file mode 100644 index 0000000000..0d9329e760 --- /dev/null +++ b/src/app/shared/resource-policies/resource-policies.component.scss @@ -0,0 +1,3 @@ +td .btn-link:focus { + box-shadow: none !important; +} diff --git a/src/app/shared/resource-policies/resource-policies.component.ts b/src/app/shared/resource-policies/resource-policies.component.ts new file mode 100644 index 0000000000..0596dba586 --- /dev/null +++ b/src/app/shared/resource-policies/resource-policies.component.ts @@ -0,0 +1,134 @@ +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Observable, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { ResourcePolicyService } from '../../core/resource-policy/resource-policy.service'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { getFirstSucceededRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators'; +import { RemoteData } from '../../core/data/remote-data'; +import { ResourcePolicy } from '../../core/resource-policy/models/resource-policy.model'; +import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { Group } from '../../core/eperson/models/group.model'; +import { GroupDataService } from '../../core/eperson/group-data.service'; +import { hasValue, isNotEmpty } from '../empty.util'; + +@Component({ + selector: 'ds-resource-policies', + styleUrls: ['./resource-policies.component.scss'], + templateUrl: './resource-policies.component.html' +}) +/** + * Component that shows the policies for given resource + */ +export class ResourcePoliciesComponent implements OnInit, OnDestroy { + + /** + * The resource UUID + * @type {string} + */ + @Input() public resourceUUID: string; + + /** + * The resource type (e.g. 'item', 'bundle' etc) used as key to build automatically translation label + * @type {string} + */ + @Input() public resourceKey: string; + + /** + * The list of policies for given resource + * @type {Observable>>} + */ + private resourcePolicies$: Observable>>; + + /** + * Array to track all subscriptions and unsubscribe them onDestroy + * @type {Array} + */ + private subs: Subscription[] = []; + + /** + * Initialize instance variables + * + * @param {DSONameService} dsoNameService + * @param {GroupDataService} groupService + * @param {ResourcePolicyService} resourcePolicyService + * @param {Router} router + */ + constructor( + private dsoNameService: DSONameService, + private groupService: GroupDataService, + private resourcePolicyService: ResourcePolicyService, + private router: Router + ) { + } + + /** + * Initialize the component, setting up the resource's policies + */ + ngOnInit(): void { + this.resourcePolicies$ = this.resourcePolicyService.searchByResource(this.resourceUUID).pipe( + getSucceededRemoteData() + ); + + } + + /** + * Return the group's name which the given policy is linked to + * + * @param policy The resource policy + */ + getGroupName(policy: ResourcePolicy): Observable { + return this.groupService.findByHref(policy._links.group.href).pipe( + getFirstSucceededRemoteDataPayload(), + // A group has not dc.title metadata so is not possible to use DSONameService to retrieve name + map((group: Group) => group.name) + ) + } + + /** + * Return all resource's policies + * + * @return an observable that emits all resource's policies + */ + getResourcePolicies(): Observable>> { + return this.resourcePolicies$; + } + + /** + * Check whether the given policy is linked to a group + * + * @param policy The resource policy + * @return an observable that emits true when the policy is linked to a group, false otherwise + */ + hasGroup(policy): Observable { + return this.groupService.findByHref(policy._links.group.href).pipe( + getFirstSucceededRemoteDataPayload(), + map((group: Group) => isNotEmpty(group)) + ) + } + + /** + * Redirect to group edit page + * + * @param policy The resource policy + */ + redirectToGroupEditPage(policy: ResourcePolicy): void { + this.subs.push( + this.groupService.findByHref(policy._links.group.href).pipe( + getFirstSucceededRemoteDataPayload(), + map((group: Group) => group.id) + ).subscribe((groupUUID) => this.router.navigate(['groups', groupUUID, 'edit'])) + ) + } + + /** + * Unsubscribe from all subscriptions + */ + ngOnDestroy(): void { + this.subs + .filter((subscription) => hasValue(subscription)) + .forEach((subscription) => subscription.unsubscribe()) + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 673c969506..313c56089b 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -179,6 +179,8 @@ import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic- import { ItemVersionsComponent } from './item/item-versions/item-versions.component'; import { SortablejsModule } from 'ngx-sortablejs'; import { MissingTranslationHelper } from './translate/missing-translation.helper'; +import { ResourcePoliciesComponent } from './resource-policies/resource-policies.component'; +import { NgForTrackByIdDirective } from './ng-for-track-by-id.directive'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -347,6 +349,7 @@ const COMPONENTS = [ ExistingMetadataListElementComponent, ItemVersionsComponent, PublicationSearchResultListElementComponent, + ResourcePoliciesComponent ]; const ENTRY_COMPONENTS = [ @@ -438,7 +441,8 @@ const DIRECTIVES = [ AutoFocusDirective, RoleDirective, MetadataRepresentationDirective, - ListableObjectDirective + ListableObjectDirective, + NgForTrackByIdDirective ]; @NgModule({