Merge branch 'feature/CST-9636' of bitbucket.org:4Science/dspace-angular into feature/CST-9636

This commit is contained in:
Giuseppe Digilio
2023-05-10 15:13:07 +02:00
20 changed files with 486 additions and 671 deletions

View File

@@ -17,7 +17,56 @@ import { hasValue } from '../../../shared/empty.util';
@Component({
selector: 'ds-bulk-access-browse',
templateUrl: './bulk-access-browse.component.html',
template: `
<ngb-accordion #acc="ngbAccordion" [activeIds]="'browse'">
<ngb-panel [id]="'browse'">
<ng-template ngbPanelHeader>
<div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('browse')"
data-test="browse">
<button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()"
[attr.aria-expanded]="!acc.isExpanded('browse')"
aria-controls="collapsePanels">
{{ 'admin.access-control.bulk-access-browse.header' | translate }}
</button>
<div class="text-right d-flex">
<div class="ml-3 d-inline-block">
<span *ngIf="acc.isExpanded('browse')" class="fas fa-chevron-up fa-fw"></span>
<span *ngIf="!acc.isExpanded('browse')" class="fas fa-chevron-down fa-fw"></span>
</div>
</div>
</div>
</ng-template>
<ng-template ngbPanelContent>
<ul ngbNav #nav="ngbNav" [(activeId)]="activateId" class="nav-pills">
<li [ngbNavItem]="'search'">
<a ngbNavLink>{{'admin.access-control.bulk-access-browse.search.header' | translate}}</a>
<ng-template ngbNavContent>
<div class="mx-n3">
<ds-themed-search [configuration]="'default'"
[selectable]="true"
[selectionConfig]="{ repeatable: true, listId: listId }"
[showThumbnails]="false"></ds-themed-search>
</div>
</ng-template>
</li>
<li [ngbNavItem]="'selected'">
<a
ngbNavLink>{{'admin.access-control.bulk-access-browse.selected.header' | translate: {number: ((objectsSelected$ | async)?.payload?.totalElements) ? (objectsSelected$ | async)?.payload?.totalElements : '0'} }}</a>
<ng-template ngbNavContent>
<ds-viewable-collection [config]="paginationOptions"
[hideGear]="true"
[objects]="objectsSelected$ | async"
[selectable]="true"
[selectionConfig]="{ repeatable: true, listId: listId }"
[showThumbnails]="false"></ds-viewable-collection>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav" class="mt-5"></div>
</ng-template>
</ngb-panel>
</ngb-accordion>
`,
styleUrls: ['./bulk-access-browse.component.scss'],
providers: [
{
@@ -57,8 +106,7 @@ export class BulkAccessBrowseComponent implements OnInit, OnDestroy {
*/
private subs: Subscription[] = [];
constructor(private selectableListService: SelectableListService) {
}
constructor(private selectableListService: SelectableListService) {}
/**
* Subscribe to selectable list updates

View File

@@ -1,120 +1,7 @@
<div class="container">
<div class="card">
<div class="card-body">
<p>{{'collection-access-control-title' | translate}}</p>
<ds-access-control-form-container
*ngIf="itemRD$ | async as itemRD"
[itemRD]="itemRD"
[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 { shareReplay } from 'rxjs';
import {
AccessControlArrayFormComponent
} from '../../../shared/access-control-array-form/access-control-array-form.component';
import { CollectionAccessControlService } from './collection-access-control.service';
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { Community } from '../../../core/shared/community.model';
import { ActivatedRoute } from '@angular/router';
import { map } from 'rxjs/operators';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
@Component({
selector: 'ds-collection-access-control',
templateUrl: './collection-access-control.component.html',
styleUrls: ['./collection-access-control.component.scss'],
providers: [CollectionAccessControlService]
})
export class CollectionAccessControlComponent implements OnInit {
itemRD$: Observable<RemoteData<Community>>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(private collectionAccessControlService: CollectionAccessControlService) {}
state = initialState;
dropdownData$ = this.collectionAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
}
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();
this.itemRD$ = this.route.parent.parent.data.pipe(
map((data) => data.dso)
).pipe(getFirstSucceededRemoteData()) as Observable<RemoteData<Community>>;
}
}
}
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
} from '../../shared/access-control-array-form/access-control-array-form.component';
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
@@ -33,6 +36,7 @@ import { UiSwitchModule } from 'ngx-ui-switch';
ComcolModule,
AccessControlArrayFormModule,
UiSwitchModule,
AccessControlFormContainerModule,
],
declarations: [
EditCollectionPageComponent,

View File

@@ -1,120 +1,6 @@
<div class="container">
<div class="card">
<div class="card-body">
<p>{{ 'community-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"></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>
<ds-access-control-form-container
*ngIf="itemRD$ | async as itemRD"
[itemRD]="itemRD"
[showLimitToSpecificBitstreams]="false">
<p title>{{'community-access-control-title' | translate }}</p>
</ds-access-control-form-container>

View File

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

View File

@@ -15,6 +15,9 @@ import { UiSwitchModule } from 'ngx-ui-switch';
import {
AccessControlArrayFormModule
} 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
@@ -29,6 +32,7 @@ import {
ResourcePoliciesModule,
UiSwitchModule,
AccessControlArrayFormModule,
AccessControlFormContainerModule,
],
declarations: [
EditCommunityPageComponent,

View File

@@ -1,7 +1,7 @@
import { NgModule } from '@angular/core';
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 { 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 { ItemRelationshipsComponent } from './item-relationships/item-relationships.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 { 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 { DragDropModule } from '@angular/cdk/drag-drop';
import { 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 {
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 { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component';
import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component';
@@ -43,10 +51,10 @@ import {
AccessControlArrayFormModule
} from '../../shared/access-control-array-form/access-control-array-form.component';
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 {
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,
UiSwitchModule,
ResultsBackButtonModule,
AccessControlFormContainerModule,
],
declarations: [
EditItemPageComponent,
@@ -95,7 +104,6 @@ import { ResultsBackButtonModule } from '../../shared/results-back-button/result
IdentifierDataComponent,
ItemRegisterDoiComponent,
ItemAccessControlComponent,
ItemAccessControlSelectBitstreamsModalComponent
],
providers: [
BundleDataService,

View File

@@ -1,159 +1,6 @@
<div class="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
<ds-access-control-form-container
*ngIf="itemRD$ | async as 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>
[itemRD]="itemRD"
[showLimitToSpecificBitstreams]="true">
<p title>{{ 'item-access-control-title' | translate }}</p>
</ds-access-control-form-container>

View File

@@ -1,48 +1,21 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import {
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 { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
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 { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { RemoteData } from '../../../core/data/remote-data';
import { Item } from '../../../core/shared/item.model';
import { ActivatedRoute } from '@angular/router';
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
@Component({
selector: 'ds-item-access-control',
templateUrl: './item-access-control.component.html',
styleUrls: [ './item-access-control.component.scss' ],
providers: [ ItemAccessControlService ]
})
export class ItemAccessControlComponent implements OnInit, OnDestroy {
export class ItemAccessControlComponent implements OnInit {
itemRD$: Observable<RemoteData<Item>>;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
@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)
);
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.itemRD$ = this.route.parent.parent.data.pipe(
@@ -50,59 +23,4 @@ export class ItemAccessControlComponent implements OnInit, OnDestroy {
).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

@@ -0,0 +1,160 @@
<div class="container">
<div class="card">
<div class="card-body">
<ng-content select="[title]"></ng-content>
<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 *ngIf="!hideSubmit">
<div *ngIf="!hideSubmit" 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,144 @@
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 { BulkAccessControlService } from './bulk-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' ],
exportAs: 'dsAccessControlForm'
})
export class AccessControlFormContainerComponent<T extends DSpaceObject> {
@Input() showLimitToSpecificBitstreams = false;
@Input() itemRD: RemoteData<T>;
@Input() hideSubmit = false;
@ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent;
@ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent;
constructor(
private bulkAccessControlService: BulkAccessControlService,
private selectableListService: SelectableListService,
protected modalService: NgbModal,
private cdr: ChangeDetectorRef
) {}
state = initialState;
dropdownData$ = this.bulkAccessControlService.dropdownData$.pipe(
shareReplay(1)
);
getFormValue() {
return {
bitstream: this.bitstreamAccessCmp.getValue(),
item: this.itemAccessCmp.getValue(),
state: this.state
};
}
reset() {
this.bitstreamAccessCmp.reset();
this.itemAccessCmp.reset();
this.state = initialState;
}
submit() {
const bitstreamAccess = this.bitstreamAccessCmp.getValue();
const itemAccess = this.itemAccessCmp.getValue();
const { file } = this.bulkAccessControlService.createPayloadFile({
bitstreamAccess,
itemAccess,
state: this.state
});
this.bulkAccessControlService.executeScript(
[ this.itemRD.payload.uuid ],
file
).pipe(take(1)).subscribe((res) => {
console.log('success', res);
});
}
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
],
declarations: [
AccessControlFormContainerComponent,
ItemAccessControlSelectBitstreamsModalComponent
],
exports: [ AccessControlFormContainerComponent ],
})
export class AccessControlFormContainerModule {}

View File

@@ -1,6 +1,8 @@
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { AccessControlItem } from '../../../core/shared/bulk-access-condition-options.model';
import { AccessControlItem } from '../../core/shared/bulk-access-condition-options.model';
import { ScriptDataService } from '../../core/data/processes/script-data.service';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
export interface AccessControlDropdownDataResponse {
id: string;
@@ -8,12 +10,13 @@ export interface AccessControlDropdownDataResponse {
bitstreamAccessConditionOptions: AccessControlItem[];
}
@Injectable()
export class ItemAccessControlService {
@Injectable({ providedIn: 'root' })
export class BulkAccessControlService {
constructor(private scriptService: ScriptDataService) {}
dropdownData$: Observable<AccessControlDropdownDataResponse> = of(accessControlDropdownData);
execute(payload: any) {
createPayloadFile(payload: any) {
console.log('execute', payload);
const blob = new Blob([JSON.stringify(payload, null, 2)], {
@@ -25,7 +28,19 @@ export class ItemAccessControlService {
});
const url = URL.createObjectURL(file);
window.open(url, '_blank');
window.open(url, '_blank'); // remove this later
return { url, file };
}
executeScript(uuids: string[], file: File) {
console.log('execute', { uuids, file });
const params: ProcessParameter[] = [
{ name: 'uuid', value: uuids.join(',') },
];
return this.scriptService.invoke('bulk-access-control', params, [file]);
}
}

View File

@@ -1,17 +1,17 @@
import { Component, Input, OnInit } from '@angular/core';
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 { Item } from '../../../../core/shared/item.model';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { Bitstream } from '../../../../core/shared/bitstream.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { hasValue } from '../../../../shared/empty.util';
import { Context } from '../../../../core/shared/context.model';
import { PaginatedList } from 'src/app/core/data/paginated-list.model';
import { RemoteData } from 'src/app/core/data/remote-data';
import { Bitstream } from 'src/app/core/shared/bitstream.model';
import { Context } from 'src/app/core/shared/context.model';
import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model';
import { Item } from '../../../core/shared/item.model';
import { BitstreamDataService } from '../../../core/data/bitstream-data.service';
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'