[CST-9636] Reactor to use one component for all the access-control pages

This commit is contained in:
Enea Jahollari
2023-05-10 14:34:29 +02:00
parent 06fef61f02
commit 52d72766ca
19 changed files with 393 additions and 660 deletions

View File

@@ -1,120 +1,7 @@
<div class="container"> <ds-access-control-form-container
<div class="card"> *ngIf="itemRD$ | async as itemRD"
<div class="card-body"> [itemRD]="itemRD"
<p>{{'collection-access-control-title' | translate}}</p> [showLimitToSpecificBitstreams]="false">
<p title>{{'collection-access-control-title' | translate}}</p>
</ds-access-control-form-container>
<div class="row mt-5">
<div class="col-12 col-md-6 border-right">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-item-header-toggle' | translate }}
</h4>
<ui-switch
[(ngModel)]="state.item.toggleStatus"
(ngModelChange)="handleStatusChange('item', $event)">
</ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemReplace" value="replace"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemAdd" value="add"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#itemAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
<div class="col-12 col-md-6">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-bitstream-header-toggle' | translate }}
</h4>
<ui-switch [(ngModel)]="state.bitstream.toggleStatus"></ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamReplace" value="replace"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamAdd" value="add"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#bitstreamAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
</div>
<hr>
<div class="d-flex justify-content-end">
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">
{{ 'access-control-reset' | translate }}
</button>
<button class="btn btn-lg btn-primary" (click)="submit()">
{{ 'access-control-execute' | translate }}
</button>
</div>
</div>
</div>
</div>

View File

@@ -1,64 +1,24 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { shareReplay } from 'rxjs'; import { Observable } from 'rxjs';
import { import { RemoteData } from '../../../core/data/remote-data';
AccessControlArrayFormComponent import { Community } from '../../../core/shared/community.model';
} from '../../../shared/access-control-array-form/access-control-array-form.component'; import { ActivatedRoute } from '@angular/router';
import { CollectionAccessControlService } from './collection-access-control.service'; import { map } from 'rxjs/operators';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
@Component({ @Component({
selector: 'ds-collection-access-control', selector: 'ds-collection-access-control',
templateUrl: './collection-access-control.component.html', templateUrl: './collection-access-control.component.html',
styleUrls: ['./collection-access-control.component.scss'], styleUrls: ['./collection-access-control.component.scss'],
providers: [CollectionAccessControlService]
}) })
export class CollectionAccessControlComponent implements OnInit { export class CollectionAccessControlComponent implements OnInit {
itemRD$: Observable<RemoteData<Community>>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent; constructor(private route: ActivatedRoute) {}
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(private collectionAccessControlService: CollectionAccessControlService) {}
state = initialState;
dropdownData$ = this.collectionAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
ngOnInit(): void { ngOnInit(): void {
this.itemRD$ = this.route.parent.parent.data.pipe(
} map((data) => data.dso)
).pipe(getFirstSucceededRemoteData()) as Observable<RemoteData<Community>>;
reset() {
this.bitstreamAccessCmp.reset();
this.itemAccessCmp.reset();
this.state = initialState;
}
submit() {
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
const itemAccess = this.itemAccessCmp.getValue();
console.log('bitstreamAccess', bitstreamAccess);
console.log('itemAccess', itemAccess);
}
handleStatusChange(type: 'item' | 'bitstream', active: boolean) {
if (type === 'bitstream') {
active ? this.bitstreamAccessCmp.enable() : this.bitstreamAccessCmp.disable();
} else if (type === 'item') {
active ? this.itemAccessCmp.enable() : this.itemAccessCmp.disable();
} }
} }
}
const initialState = {
item: {
toggleStatus: false,
accessMode: '',
},
bitstream: {
toggleStatus: false,
accessMode: '',
},
};

View File

@@ -1,54 +0,0 @@
import { Injectable } from '@angular/core';
import { AccessControlItem } from 'src/app/core/shared/bulk-access-condition-options.model';
import { Observable, of } from 'rxjs';
export interface AccessControlDropdownDataResponse {
id: string;
itemAccessConditionOptions: AccessControlItem[];
bitstreamAccessConditionOptions: AccessControlItem[];
}
@Injectable()
export class CollectionAccessControlService {
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);
}
const accessControlDropdownData: AccessControlDropdownDataResponse = {
'id': 'default',
'itemAccessConditionOptions': [
{
'name': 'openaccess'
},
{
'name': 'administrator'
},
{
'name': 'embargo',
'hasStartDate': true,
'maxStartDate': '2018-06-24T00:40:54.970+0000'
},
{
'name': 'lease',
'hasEndDate': true,
'maxEndDate': '2017-12-24T00:40:54.970+0000'
}
],
'bitstreamAccessConditionOptions': [
{
'name': 'openaccess'
},
{
'name': 'administrator'
},
{
'name': 'embargo',
'hasStartDate': true,
'maxStartDate': '2018-06-24T00:40:54.970+0000'
},
{
'name': 'lease',
'hasEndDate': true,
'maxEndDate': '2017-12-24T00:40:54.970+0000'
}
]
};

View File

@@ -18,6 +18,9 @@ import {
AccessControlArrayFormModule AccessControlArrayFormModule
} from '../../shared/access-control-array-form/access-control-array-form.component'; } from '../../shared/access-control-array-form/access-control-array-form.component';
import { UiSwitchModule } from 'ngx-ui-switch'; import { UiSwitchModule } from 'ngx-ui-switch';
import {
AccessControlFormContainerModule
} from '../../shared/access-control-form-container/access-control-form-container.component';
/** /**
* Module that contains all components related to the Edit Collection page administrator functionality * Module that contains all components related to the Edit Collection page administrator functionality
@@ -33,6 +36,7 @@ import { UiSwitchModule } from 'ngx-ui-switch';
ComcolModule, ComcolModule,
AccessControlArrayFormModule, AccessControlArrayFormModule,
UiSwitchModule, UiSwitchModule,
AccessControlFormContainerModule,
], ],
declarations: [ declarations: [
EditCollectionPageComponent, EditCollectionPageComponent,

View File

@@ -1,120 +1,6 @@
<div class="container"> <ds-access-control-form-container
<div class="card"> *ngIf="itemRD$ | async as itemRD"
<div class="card-body"> [itemRD]="itemRD"
<p>{{ 'community-access-control-title' | translate }}</p> [showLimitToSpecificBitstreams]="false">
<p title>{{'community-access-control-title' | translate }}</p>
<div class="row mt-5"> </ds-access-control-form-container>
<div class="col-12 col-md-6 border-right">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-item-header-toggle' | translate }}
</h4>
<ui-switch
[(ngModel)]="state.item.toggleStatus"
(ngModelChange)="handleStatusChange('item', $event)">
</ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemReplace" value="replace"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemAdd" value="add"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#itemAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
<div class="col-12 col-md-6">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-bitstream-header-toggle' | translate }}
</h4>
<ui-switch [(ngModel)]="state.bitstream.toggleStatus"></ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamReplace" value="replace"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamAdd" value="add"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#bitstreamAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
</div>
<hr>
<div class="d-flex justify-content-end">
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">
{{ 'access-control-reset' | translate }}
</button>
<button class="btn btn-lg btn-primary" (click)="submit()">
{{ 'access-control-execute' | translate }}
</button>
</div>
</div>
</div>
</div>

View File

@@ -1,63 +1,26 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { CommunityAccessControlService } from './community-access-control.service'; import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs'; import { RemoteData } from '../../../core/data/remote-data';
import { import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
AccessControlArrayFormComponent import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
} from '../../../shared/access-control-array-form/access-control-array-form.component'; import { ActivatedRoute } from '@angular/router';
import { map } from 'rxjs/operators';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { Community } from '../../../core/shared/community.model';
@Component({ @Component({
selector: 'ds-community-access-control', selector: 'ds-community-access-control',
templateUrl: './community-access-control.component.html', templateUrl: './community-access-control.component.html',
styleUrls: ['./community-access-control.component.scss'], styleUrls: ['./community-access-control.component.scss'],
providers: [CommunityAccessControlService]
}) })
export class CommunityAccessControlComponent implements OnInit { export class CommunityAccessControlComponent implements OnInit {
itemRD$: Observable<RemoteData<Community>>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent; constructor(private route: ActivatedRoute) {}
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(private communityAccessControlService: CommunityAccessControlService) {}
state = initialState;
dropdownData$ = this.communityAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
ngOnInit(): void { ngOnInit(): void {
this.itemRD$ = this.route.parent.parent.data.pipe(
} map((data) => data.dso)
).pipe(getFirstSucceededRemoteData()) as Observable<RemoteData<Community>>;
reset() {
this.bitstreamAccessCmp.reset();
this.itemAccessCmp.reset();
this.state = initialState;
}
submit() {
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
const itemAccess = this.itemAccessCmp.getValue();
console.log('bitstreamAccess', bitstreamAccess);
console.log('itemAccess', itemAccess);
}
handleStatusChange(type: 'item' | 'bitstream', active: boolean) {
if (type === 'bitstream') {
active ? this.bitstreamAccessCmp.enable() : this.bitstreamAccessCmp.disable();
} else if (type === 'item') {
active ? this.itemAccessCmp.enable() : this.itemAccessCmp.disable();
} }
} }
}
const initialState = {
item: {
toggleStatus: false,
accessMode: '',
},
bitstream: {
toggleStatus: false,
accessMode: '',
},
};

View File

@@ -15,6 +15,9 @@ import { UiSwitchModule } from 'ngx-ui-switch';
import { import {
AccessControlArrayFormModule AccessControlArrayFormModule
} from '../../shared/access-control-array-form/access-control-array-form.component'; } from '../../shared/access-control-array-form/access-control-array-form.component';
import {
AccessControlFormContainerModule
} from '../../shared/access-control-form-container/access-control-form-container.component';
/** /**
* Module that contains all components related to the Edit Community page administrator functionality * Module that contains all components related to the Edit Community page administrator functionality
@@ -29,6 +32,7 @@ import {
ResourcePoliciesModule, ResourcePoliciesModule,
UiSwitchModule, UiSwitchModule,
AccessControlArrayFormModule, AccessControlArrayFormModule,
AccessControlFormContainerModule,
], ],
declarations: [ declarations: [
EditCommunityPageComponent, EditCommunityPageComponent,

View File

@@ -1,7 +1,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgbTooltipModule, NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { SharedModule } from '../../shared/shared.module'; import { SharedModule } from '../../shared/shared.module';
import { EditItemPageRoutingModule } from './edit-item-page.routing.module'; import { EditItemPageRoutingModule } from './edit-item-page.routing.module';
@@ -20,14 +20,22 @@ import { SearchPageModule } from '../../search-page/search-page.module';
import { ItemCollectionMapperComponent } from './item-collection-mapper/item-collection-mapper.component'; import { ItemCollectionMapperComponent } from './item-collection-mapper/item-collection-mapper.component';
import { ItemRelationshipsComponent } from './item-relationships/item-relationships.component'; import { ItemRelationshipsComponent } from './item-relationships/item-relationships.component';
import { EditRelationshipComponent } from './item-relationships/edit-relationship/edit-relationship.component'; import { EditRelationshipComponent } from './item-relationships/edit-relationship/edit-relationship.component';
import { EditRelationshipListComponent } from './item-relationships/edit-relationship-list/edit-relationship-list.component'; import {
EditRelationshipListComponent
} from './item-relationships/edit-relationship-list/edit-relationship-list.component';
import { AbstractItemUpdateComponent } from './abstract-item-update/abstract-item-update.component'; import { AbstractItemUpdateComponent } from './abstract-item-update/abstract-item-update.component';
import { ItemMoveComponent } from './item-move/item-move.component'; import { ItemMoveComponent } from './item-move/item-move.component';
import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component'; import {
ItemEditBitstreamBundleComponent
} from './item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component';
import { BundleDataService } from '../../core/data/bundle-data.service'; import { BundleDataService } from '../../core/data/bundle-data.service';
import { DragDropModule } from '@angular/cdk/drag-drop'; import { DragDropModule } from '@angular/cdk/drag-drop';
import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component'; import {
import { PaginatedDragAndDropBitstreamListComponent } from './item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component'; ItemEditBitstreamDragHandleComponent
} from './item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component';
import {
PaginatedDragAndDropBitstreamListComponent
} from './item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component';
import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.component'; import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.component';
import { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component'; import { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component';
import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component'; import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component';
@@ -43,10 +51,10 @@ import {
AccessControlArrayFormModule AccessControlArrayFormModule
} from '../../shared/access-control-array-form/access-control-array-form.component'; } from '../../shared/access-control-array-form/access-control-array-form.component';
import { UiSwitchModule } from 'ngx-ui-switch'; import { UiSwitchModule } from 'ngx-ui-switch';
import {
ItemAccessControlSelectBitstreamsModalComponent
} from './item-access-control/item-access-control-select-bitstreams-modal/item-access-control-select-bitstreams-modal.component';
import { ResultsBackButtonModule } from '../../shared/results-back-button/results-back-button.module'; import { ResultsBackButtonModule } from '../../shared/results-back-button/results-back-button.module';
import {
AccessControlFormContainerModule
} from '../../shared/access-control-form-container/access-control-form-container.component';
/** /**
@@ -67,6 +75,7 @@ import { ResultsBackButtonModule } from '../../shared/results-back-button/result
AccessControlArrayFormModule, AccessControlArrayFormModule,
UiSwitchModule, UiSwitchModule,
ResultsBackButtonModule, ResultsBackButtonModule,
AccessControlFormContainerModule,
], ],
declarations: [ declarations: [
EditItemPageComponent, EditItemPageComponent,
@@ -95,7 +104,6 @@ import { ResultsBackButtonModule } from '../../shared/results-back-button/result
IdentifierDataComponent, IdentifierDataComponent,
ItemRegisterDoiComponent, ItemRegisterDoiComponent,
ItemAccessControlComponent, ItemAccessControlComponent,
ItemAccessControlSelectBitstreamsModalComponent
], ],
providers: [ providers: [
BundleDataService, BundleDataService,

View File

@@ -1,159 +1,6 @@
<div class="container"> <ds-access-control-form-container
<div class="card">
<div class="card-body">
<p>{{ 'item-access-control-title' | translate }}</p>
<div class="row mt-5">
<div class="col-12 col-md-6 border-right">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-item-header-toggle' | translate }}
</h4>
<ui-switch
[(ngModel)]="state.item.toggleStatus"
(ngModelChange)="handleStatusChange('item', $event)">
</ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{ 'access-control-mode' | translate }}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemReplace" value="replace"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemAdd" value="add"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#itemAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
<div class="col-12 col-md-6">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{'access-control-bitstream-header-toggle' | translate}}
</h4>
<ui-switch
[(ngModel)]="state.bitstream.toggleStatus"
(ngModelChange)="handleStatusChange('bitstream', $event)">
</ui-switch>
</div>
<div class="row mt-3">
<div class="col-12">
{{'access-control-limit-to-specific' | translate}}
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="radio"
name="changesLimit" id="processAll" value="all"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.changesLimit">
<label class="form-check-label" for="processAll">
{{'access-control-process-all-bitstreams' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="changesLimit" id="processSelected" value="selected"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.changesLimit">
<label class="form-check-label" for="processSelected">
{{ state.bitstream.selectedBitstreams.length }}
{{'access-control-bitstreams-selected' | translate}}
<button
*ngIf="itemRD$ | async as itemRD" *ngIf="itemRD$ | async as itemRD"
[disabled]="!state.bitstream.toggleStatus && state.bitstream.changesLimit !== 'selected'" [itemRD]="itemRD"
(click)="openSelectBitstreamsModal(itemRD.payload)" class="btn btn-outline-dark" type="button"> [showLimitToSpecificBitstreams]="true">
<i class="fa fa-search"></i> <p title>{{ 'item-access-control-title' | translate }}</p>
</button> </ds-access-control-form-container>
</label>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamReplace" value="replace"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamAdd" value="add"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>
{{'access-control-access-conditions' | translate}}
</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#bitstreamAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
</div>
<hr>
<div class="d-flex justify-content-end">
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">
{{ 'access-control-reset' | translate }}
</button>
<button class="btn btn-lg btn-primary" (click)="submit()">
{{ 'access-control-execute' | translate }}
</button>
</div>
</div>
</div>
</div>

View File

@@ -1,48 +1,24 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { import { Observable } from 'rxjs';
AccessControlArrayFormComponent
} from '../../../shared/access-control-array-form/access-control-array-form.component';
import { concatMap, Observable, shareReplay } from 'rxjs';
import { ItemAccessControlService } from './item-access-control.service'; import { ItemAccessControlService } from './item-access-control.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { import { map } from 'rxjs/operators';
ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID,
ItemAccessControlSelectBitstreamsModalComponent
} from './item-access-control-select-bitstreams-modal/item-access-control-select-bitstreams-modal.component';
import { map, take } from 'rxjs/operators';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators'; import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service'; import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
@Component({ @Component({
selector: 'ds-item-access-control', selector: 'ds-item-access-control',
templateUrl: './item-access-control.component.html', templateUrl: './item-access-control.component.html',
styleUrls: [ './item-access-control.component.scss' ], styleUrls: [ './item-access-control.component.scss' ],
providers: [ ItemAccessControlService ]
}) })
export class ItemAccessControlComponent implements OnInit, OnDestroy { export class ItemAccessControlComponent implements OnInit {
itemRD$: Observable<RemoteData<Item>>; itemRD$: Observable<RemoteData<Item>>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent; constructor(private route: ActivatedRoute) {}
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(
private itemAccessControlService: ItemAccessControlService,
private selectableListService: SelectableListService,
protected modalService: NgbModal,
private route: ActivatedRoute,
private cdr: ChangeDetectorRef
) {}
state = initialState;
dropdownData$ = this.itemAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
ngOnInit(): void { ngOnInit(): void {
this.itemRD$ = this.route.parent.parent.data.pipe( this.itemRD$ = this.route.parent.parent.data.pipe(
@@ -50,59 +26,4 @@ export class ItemAccessControlComponent implements OnInit, OnDestroy {
).pipe(getFirstSucceededRemoteData()) as Observable<RemoteData<Item>>; ).pipe(getFirstSucceededRemoteData()) as Observable<RemoteData<Item>>;
} }
reset() {
this.bitstreamAccessCmp.reset();
this.itemAccessCmp.reset();
this.state = initialState;
} }
submit() {
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
const itemAccess = this.itemAccessCmp.getValue();
this.itemAccessControlService.execute({
bitstreamAccess,
itemAccess,
state: this.state
});
}
handleStatusChange(type: 'item' | 'bitstream', active: boolean) {
if (type === 'bitstream') {
active ? this.bitstreamAccessCmp.enable() : this.bitstreamAccessCmp.disable();
} else if (type === 'item') {
active ? this.itemAccessCmp.enable() : this.itemAccessCmp.disable();
}
}
openSelectBitstreamsModal(item: Item) {
const ref = this.modalService.open(ItemAccessControlSelectBitstreamsModalComponent);
ref.componentInstance.selectedBitstreams = this.state.bitstream.selectedBitstreams;
ref.componentInstance.item = item;
ref.closed.pipe(
concatMap(() => this.selectableListService.getSelectableList(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID)),
take(1)
).subscribe((list) => {
this.state.bitstream.selectedBitstreams = list.selection;
this.cdr.detectChanges();
});
}
ngOnDestroy(): void {
this.selectableListService.deselectAll(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID);
}
}
const initialState = {
item: {
toggleStatus: false,
accessMode: '',
},
bitstream: {
toggleStatus: false,
accessMode: '',
changesLimit: '', // 'all' | 'selected'
selectedBitstreams: [] as ListableObject[],
},
};

View File

@@ -8,7 +8,7 @@ export interface AccessControlDropdownDataResponse {
bitstreamAccessConditionOptions: AccessControlItem[]; bitstreamAccessConditionOptions: AccessControlItem[];
} }
@Injectable() @Injectable({ providedIn: 'root' })
export class ItemAccessControlService { export class ItemAccessControlService {
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData); dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);

View File

@@ -0,0 +1,163 @@
<div class="container">
<div class="card">
<div class="card-body">
<ng-content select="[title]"></ng-content>
<!-- <p>-->
<!-- {{ 'item-access-control-title' | translate }}-->
<!-- </p>-->
<div class="row mt-5">
<div class="col-12 col-md-6 border-right">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{ 'access-control-item-header-toggle' | translate }}
</h4>
<ui-switch
[(ngModel)]="state.item.toggleStatus"
(ngModelChange)="handleStatusChange('item', $event)">
</ui-switch>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{ 'access-control-mode' | translate }}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemReplace" value="replace"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="itemMode" id="itemAdd" value="add"
[disabled]="!state.item.toggleStatus"
[(ngModel)]="state.item.accessMode">
<label class="form-check-label" for="itemAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>{{'access-control-access-conditions' | translate}}</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#itemAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.itemAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
<div class="col-12 col-md-6">
<div class="d-flex align-items-center">
<h4 class="mb-0 mr-4">
{{'access-control-bitstream-header-toggle' | translate}}
</h4>
<ui-switch
[(ngModel)]="state.bitstream.toggleStatus"
(ngModelChange)="handleStatusChange('bitstream', $event)">
</ui-switch>
</div>
<div *ngIf="showLimitToSpecificBitstreams" class="row mt-3">
<div class="col-12">
{{'access-control-limit-to-specific' | translate}}
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="radio"
name="changesLimit" id="processAll" value="all"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.changesLimit">
<label class="form-check-label" for="processAll">
{{'access-control-process-all-bitstreams' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="changesLimit" id="processSelected" value="selected"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.changesLimit">
<label class="form-check-label" for="processSelected">
{{ state.bitstream.selectedBitstreams.length }}
{{'access-control-bitstreams-selected' | translate}}
<button
*ngIf="itemRD"
[disabled]="!state.bitstream.toggleStatus && state.bitstream.changesLimit !== 'selected'"
(click)="openSelectBitstreamsModal(itemRD.payload)" class="btn btn-outline-dark" type="button">
<i class="fa fa-search"></i>
</button>
</label>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 col-md-3">
{{'access-control-mode' | translate}}
</div>
<div class="col-12 col-md-8">
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamReplace" value="replace"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamReplace">
{{'access-control-replace-all' | translate}}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="bitstreamMode" id="bitstreamAdd" value="add"
[disabled]="!state.bitstream.toggleStatus"
[(ngModel)]="state.bitstream.accessMode">
<label class="form-check-label" for="bitstreamAdd">
{{'access-control-add-to-existing' | translate}}
</label>
</div>
</div>
</div>
<div class="mt-3">
<h5>
{{'access-control-access-conditions' | translate}}
</h5>
<div class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}}
</div>
</div>
<ds-access-control-array-form
#bitstreamAccessCmp
[dropdownOptions]="(dropdownData$ | async)?.bitstreamAccessConditionOptions || []">
</ds-access-control-array-form>
</div>
</div>
<hr>
<div class="d-flex justify-content-end">
<button class="btn btn-lg btn-outline-primary mr-3" (click)="reset()">
{{ 'access-control-reset' | translate }}
</button>
<button class="btn btn-lg btn-primary" (click)="submit()">
{{ 'access-control-execute' | translate }}
</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AccessControlFormContainerComponent } from './access-control-form-container.component';
describe('AccessControlFormContainerComponent', () => {
let component: AccessControlFormContainerComponent;
let fixture: ComponentFixture<AccessControlFormContainerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AccessControlFormContainerComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AccessControlFormContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,119 @@
import { ChangeDetectorRef, Component, Input, NgModule, ViewChild } from '@angular/core';
import { concatMap, shareReplay } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { Item } from '../../core/shared/item.model';
import {
AccessControlArrayFormComponent,
AccessControlArrayFormModule
} from '../access-control-array-form/access-control-array-form.component';
import {
ItemAccessControlService
} from '../../item-page/edit-item-page/item-access-control/item-access-control.service';
import { SelectableListService } from '../object-list/selectable-list/selectable-list.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { take } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
import { ListableObject } from '../object-collection/shared/listable-object.model';
import { SharedModule } from '../shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { UiSwitchModule } from 'ngx-ui-switch';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import {
ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID,
ItemAccessControlSelectBitstreamsModalComponent
} from './item-access-control-select-bitstreams-modal/item-access-control-select-bitstreams-modal.component';
@Component({
selector: 'ds-access-control-form-container',
templateUrl: './access-control-form-container.component.html',
styleUrls: ['./access-control-form-container.component.scss']
})
export class AccessControlFormContainerComponent<T extends DSpaceObject> {
@Input() showLimitToSpecificBitstreams = false;
@Input() itemRD: RemoteData<T>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(
private itemAccessControlService: ItemAccessControlService,
private selectableListService: SelectableListService,
protected modalService: NgbModal,
private cdr: ChangeDetectorRef
) {}
state = initialState;
dropdownData$ = this.itemAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
reset() {
this.bitstreamAccessCmp.reset();
this.itemAccessCmp.reset();
this.state = initialState;
}
submit() {
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
const itemAccess = this.itemAccessCmp.getValue();
this.itemAccessControlService.execute({
bitstreamAccess,
itemAccess,
state: this.state
});
}
handleStatusChange(type: 'item' | 'bitstream', active: boolean) {
if (type === 'bitstream') {
active ? this.bitstreamAccessCmp.enable() : this.bitstreamAccessCmp.disable();
} else if (type === 'item') {
active ? this.itemAccessCmp.enable() : this.itemAccessCmp.disable();
}
}
openSelectBitstreamsModal(item: Item) {
const ref = this.modalService.open(ItemAccessControlSelectBitstreamsModalComponent);
ref.componentInstance.selectedBitstreams = this.state.bitstream.selectedBitstreams;
ref.componentInstance.item = item;
ref.closed.pipe(
concatMap(() => this.selectableListService.getSelectableList(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID)),
take(1)
).subscribe((list) => {
this.state.bitstream.selectedBitstreams = list.selection;
this.cdr.detectChanges();
});
}
// eslint-disable-next-line @angular-eslint/use-lifecycle-interface
ngOnDestroy(): void {
this.selectableListService.deselectAll(ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID);
}
}
const initialState = {
item: {
toggleStatus: false,
accessMode: '',
},
bitstream: {
toggleStatus: false,
accessMode: '',
changesLimit: '', // 'all' | 'selected'
selectedBitstreams: [] as ListableObject[],
},
};
@NgModule({
imports: [ CommonModule, AccessControlArrayFormModule, SharedModule, TranslateModule, UiSwitchModule ],
exports: [AccessControlFormContainerComponent],
declarations: [ AccessControlFormContainerComponent, ItemAccessControlSelectBitstreamsModalComponent ],
})
export class AccessControlFormContainerModule {}

View File

@@ -1,17 +1,17 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { TranslateService } from '@ngx-translate/core';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { Item } from '../../../../core/shared/item.model'; import { PaginatedList } from 'src/app/core/data/paginated-list.model';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { RemoteData } from 'src/app/core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { Bitstream } from 'src/app/core/shared/bitstream.model';
import { Bitstream } from '../../../../core/shared/bitstream.model'; import { Context } from 'src/app/core/shared/context.model';
import { RemoteData } from '../../../../core/data/remote-data'; import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; import { Item } from '../../../core/shared/item.model';
import { hasValue } from '../../../../shared/empty.util'; import { BitstreamDataService } from '../../../core/data/bitstream-data.service';
import { Context } from '../../../../core/shared/context.model'; import { PaginationService } from '../../../core/pagination/pagination.service';
import { TranslateService } from '@ngx-translate/core';
import { hasValue } from '../../empty.util';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
export const ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID = 'item-access-control-select-bitstreams' export const ITEM_ACCESS_CONTROL_SELECT_BITSTREAMS_LIST_ID = 'item-access-control-select-bitstreams'