CST-9639: Fixed error on control remove, fixed cancel button behavior, fixed bad state of access control tab on load, fixed translations, added jsdocs

This commit is contained in:
Enea Jahollari
2023-06-07 13:00:12 +02:00
parent d99b98d140
commit 47e0314c9b
6 changed files with 92 additions and 43 deletions

View File

@@ -7,7 +7,7 @@
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button class="btn btn-outline-primary mr-3" (click)="reset()"> <button class="btn btn-outline-primary mr-3" (click)="reset()">
{{ 'access-control-reset' | translate }} {{ 'access-control-cancel' | translate }}
</button> </button>
<button class="btn btn-primary" [disabled]="!canExport()" (click)="submit()"> <button class="btn btn-primary" [disabled]="!canExport()" (click)="submit()">
{{ 'access-control-execute' | translate }} {{ 'access-control-execute' | translate }}

View File

@@ -1,22 +1,22 @@
<form #ngForm="ngForm"> <form #ngForm="ngForm">
<div *ngIf="mode === 'replace' && allControlsAreEmpty && ngForm.enabled" <div *ngIf="showWarning" class="alert alert-warning">
class="alert alert-warning">
{{'access-control-no-access-conditions-warning-message' | translate}} {{'access-control-no-access-conditions-warning-message' | translate}}
</div> </div>
<ng-container *ngFor="let control of form.accessControls; let i = index"> <ng-container *ngFor="let control of form.accessControls; trackBy: trackById">
<div ngModelGroup="access-control-item-{{i}}" class="access-control-item mt-3"> <div #ngModelGroup="ngModelGroup" ngModelGroup="access-control-item-{{control.id}}" class="access-control-item mt-3">
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div> <div>
<label for="accesscontroloption-{{i}}"> <label for="accesscontroloption-{{control.id}}">
{{'access-control-option-label' | translate}} {{'access-control-option-label' | translate}}
</label> </label>
<select <select
id="accesscontroloption-{{i}}" id="accesscontroloption-{{control.id}}"
[disabled]="ngForm.disabled"
[(ngModel)]="control.itemName" [(ngModel)]="control.itemName"
(ngModelChange)="accessControlChanged(control, $event)" (ngModelChange)="accessControlChanged(control, $event)"
name="itemName-{{i}}" name="itemName-{{control.id}}"
class="form-control"> class="form-control">
<option value=""></option> <option value=""></option>
<option *ngFor="let option of dropdownOptions" [value]="option.name"> <option *ngFor="let option of dropdownOptions" [value]="option.name">
@@ -29,16 +29,16 @@
</div> </div>
<div *ngIf="control.hasStartDate" class="mt-3"> <div *ngIf="control.hasStartDate" class="mt-3">
<label for="accesscontrolstartdate-{{i}}"> <label for="accesscontrolstartdate-{{control.id}}">
{{'access-control-option-start-date' | translate}} {{'access-control-option-start-date' | translate}}
</label> </label>
<div class="input-group"> <div class="input-group">
<input <input
id="accesscontrolstartdate-{{i}}" id="accesscontrolstartdate-{{control.id}}"
class="form-control" class="form-control"
placeholder="yyyy-mm-dd" placeholder="yyyy-mm-dd"
[(ngModel)]="control.startDate" [(ngModel)]="control.startDate"
name="startDate-{{i}}" name="startDate-{{control.id}}"
[minDate]="control.maxStartDate | toDate" [minDate]="control.maxStartDate | toDate"
ngbDatepicker ngbDatepicker
#d="ngbDatepicker" #d="ngbDatepicker"
@@ -57,16 +57,16 @@
</div> </div>
<div *ngIf="control.hasEndDate" class="mt-3"> <div *ngIf="control.hasEndDate" class="mt-3">
<label for="accesscontrolenddate-{{i}}"> <label for="accesscontrolenddate-{{control.id}}">
{{'access-control-option-end-date' | translate}} {{'access-control-option-end-date' | translate}}
</label> </label>
<div class="input-group"> <div class="input-group">
<input <input
id="accesscontrolenddate-{{i}}" id="accesscontrolenddate-{{control.id}}"
class="form-control" class="form-control"
placeholder="yyyy-mm-dd" placeholder="yyyy-mm-dd"
[(ngModel)]="control.endDate" [(ngModel)]="control.endDate"
name="endDate-{{i}}" name="endDate-{{control.id}}"
[maxDate]="control.maxEndDate | toDate" [maxDate]="control.maxEndDate | toDate"
ngbDatepicker ngbDatepicker
#d1="ngbDatepicker" #d1="ngbDatepicker"
@@ -90,8 +90,8 @@
<div class="input-group"> <div class="input-group">
<button type="button" class="btn btn-outline-danger" <button type="button" class="btn btn-outline-danger"
[disabled]="ngForm.disabled" [disabled]="ngForm.disabled || form.accessControls.length === 1"
(click)="removeAccessControlItem(i)"> (click)="removeAccessControlItem(ngModelGroup, control.id)">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
</div> </div>

View File

@@ -1,5 +1,5 @@
import {Component, Input, OnInit, ViewChild} from '@angular/core'; import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {NgForm} from '@angular/forms'; import {NgForm, NgModelGroup} from '@angular/forms';
import {AccessesConditionOption} from '../../../core/config/models/config-accesses-conditions-options.model'; import {AccessesConditionOption} from '../../../core/config/models/config-accesses-conditions-options.model';
import {dateToISOFormat} from '../../date.util'; import {dateToISOFormat} from '../../date.util';
@@ -17,14 +17,13 @@ export class AccessControlArrayFormComponent implements OnInit {
@ViewChild('ngForm', {static: true}) ngForm!: NgForm; @ViewChild('ngForm', {static: true}) ngForm!: NgForm;
form: { accessControls: AccessControlItem[] } = { form: { accessControls: AccessControlItem[] } = {
accessControls: [] accessControls: [emptyAccessControlItem()] // Start with one empty access control item
}; };
ngOnInit(): void { formDisabled = true;
this.addAccessControlItem();
// Disable the form by default ngOnInit(): void {
setTimeout(() => this.disable(), 0); this.disable(); // Disable the form by default
} }
get allControlsAreEmpty() { get allControlsAreEmpty() {
@@ -32,29 +31,31 @@ export class AccessControlArrayFormComponent implements OnInit {
.every(x => x.itemName === null || x.itemName === ''); .every(x => x.itemName === null || x.itemName === '');
} }
get showWarning() {
return this.mode === 'replace' && this.allControlsAreEmpty && !this.formDisabled;
}
/** /**
* Add a new access control item to the form. * Add a new access control item to the form.
* Start and end date are disabled by default. * Start and end date are disabled by default.
* @param itemName The name of the item to add * @param itemName The name of the item to add
*/ */
addAccessControlItem(itemName: string = null) { addAccessControlItem(itemName: string = null) {
this.form.accessControls.push({ this.form.accessControls = [
itemName, ...this.form.accessControls,
startDate: null, {...emptyAccessControlItem(), itemName}
hasStartDate: false, ];
maxStartDate: null,
endDate: null,
hasEndDate: false,
maxEndDate: null,
});
} }
/** /**
* Remove an access control item from the form. * Remove an access control item from the form.
* @param ngModelGroup
* @param index * @param index
*/ */
removeAccessControlItem(index: number) { removeAccessControlItem(ngModelGroup: NgModelGroup, id: number) {
this.form.accessControls.splice(index, 1); this.ngForm.removeFormGroup(ngModelGroup);
this.form.accessControls = this.form.accessControls.filter(item => item.id !== id);
} }
/** /**
@@ -77,19 +78,30 @@ export class AccessControlArrayFormComponent implements OnInit {
*/ */
reset() { reset() {
this.form.accessControls = []; this.form.accessControls = [];
// Add an empty access control item by default
this.addAccessControlItem();
this.disable();
} }
/** /**
* Disable the form. * Disable the form.
* This will be used to disable the form from the parent component. * This will be used to disable the form from the parent component.
*/ */
disable = () => this.ngForm.control.disable(); disable = () => {
this.ngForm.form.disable();
this.formDisabled = true;
};
/** /**
* Enable the form. * Enable the form.
* This will be used to enable the form from the parent component. * This will be used to enable the form from the parent component.
*/ */
enable = () => this.ngForm.control.enable(); enable = () => {
this.ngForm.form.enable();
this.formDisabled = false;
};
accessControlChanged(control: AccessControlItem, selectedItem: string) { accessControlChanged(control: AccessControlItem, selectedItem: string) {
const item = this.dropdownOptions const item = this.dropdownOptions
@@ -105,9 +117,16 @@ export class AccessControlArrayFormComponent implements OnInit {
control.maxEndDate = item?.maxEndDate || null; control.maxEndDate = item?.maxEndDate || null;
} }
trackById(index: number, item: AccessControlItem) {
return item.id;
} }
}
export interface AccessControlItem { export interface AccessControlItem {
id: number; // will be used only locally
itemName: string | null; itemName: string | null;
hasStartDate?: boolean; hasStartDate?: boolean;
@@ -118,3 +137,16 @@ export interface AccessControlItem {
endDate: string | null; endDate: string | null;
maxEndDate?: string | null; maxEndDate?: string | null;
} }
const emptyAccessControlItem = (): AccessControlItem => ({
id: randomID(),
itemName: null,
startDate: null,
hasStartDate: false,
maxStartDate: null,
endDate: null,
hasEndDate: false,
maxEndDate: null,
});
const randomID = () => Math.floor(Math.random() * 1000000);

View File

@@ -153,12 +153,12 @@
<hr *ngIf="showSubmit"> <hr *ngIf="showSubmit">
<div *ngIf="showSubmit" class="d-flex justify-content-end"> <div *ngIf="showSubmit" class="d-flex justify-content-end">
<button class="btn btn-outline-primary mr-3" (click)="reset()"> <button class="btn btn-outline-primary mr-3" (click)="reset()" type="button">
{{ 'access-control-cancel' | translate }} {{ 'access-control-cancel' | translate }}
</button> </button>
<button class="btn btn-primary" <button class="btn btn-primary"
[disabled]="!state.item.toggleStatus && !state.bitstream.toggleStatus" [disabled]="!state.item.toggleStatus && !state.bitstream.toggleStatus"
(click)="submit()"> (click)="submit()" type="submit">
{{ 'access-control-execute' | translate }} {{ 'access-control-execute' | translate }}
</button> </button>
</div> </div>

View File

@@ -21,6 +21,9 @@ export interface BulkAccessPayload {
itemAccess: any; itemAccess: any;
} }
/**
* This service is used to create a payload file and execute the bulk access control script
*/
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class BulkAccessControlService { export class BulkAccessControlService {
constructor( constructor(
@@ -28,10 +31,13 @@ export class BulkAccessControlService {
private router: Router, private router: Router,
private scriptService: ScriptDataService, private scriptService: ScriptDataService,
private translationService: TranslateService private translationService: TranslateService
) { ) {}
}
/**
* Create a payload file from the given payload and return the file and the url to the file
* The created file will be used as input for the bulk access control script
* @param payload The payload to create the file from
*/
createPayloadFile(payload: BulkAccessPayload) { createPayloadFile(payload: BulkAccessPayload) {
const content = convertToBulkAccessControlFileModel(payload); const content = convertToBulkAccessControlFileModel(payload);
@@ -48,6 +54,11 @@ export class BulkAccessControlService {
return { url, file }; return { url, file };
} }
/**
* Execute the bulk access control script with the given uuids and file
* @param uuids
* @param file
*/
executeScript(uuids: string[], file: File): Observable<boolean> { executeScript(uuids: string[], file: File): Observable<boolean> {
console.log('execute', { uuids, file }); console.log('execute', { uuids, file });
@@ -80,6 +91,10 @@ export class BulkAccessControlService {
} }
} }
/**
* Convert the given payload to a BulkAccessControlFileModel
* @param payload
*/
export const convertToBulkAccessControlFileModel = (payload: { state: AccessControlFormState, bitstreamAccess: AccessCondition[], itemAccess: AccessCondition[] }): BulkAccessControlFileModel => { export const convertToBulkAccessControlFileModel = (payload: { state: AccessControlFormState, bitstreamAccess: AccessCondition[], itemAccess: AccessCondition[] }): BulkAccessControlFileModel => {
let finalPayload: BulkAccessControlFileModel = {}; let finalPayload: BulkAccessControlFileModel = {};

View File

@@ -225,7 +225,9 @@
"admin.registries.schema.title": "Metadata Schema Registry", "admin.registries.schema.title": "Metadata Schema Registry",
"admin.access-control.bulk-access.breadcrumbs": "Bulk Access Management",
"administrativeBulkAccess.search.results.head": "Search Results",
"admin.access-control.bulk-access": "Bulk Access Management", "admin.access-control.bulk-access": "Bulk Access Management",
@@ -5399,14 +5401,14 @@
"access-control-option-label": "Access condition type", "access-control-option-label": "Access condition type",
"access-control-option-note": "Select an access condition to apply on the bitstream once the item is deposited", "access-control-option-note": "Choose an access condition to apply to selected objects.",
"access-control-option-start-date": "Grant access from", "access-control-option-start-date": "Grant access from",
"access-control-option-start-date-note": "Select the date from which the relate access condition is applied", "access-control-option-start-date-note": "Select the date from which the related access condition is applied",
"access-control-option-end-date": "Grant access until", "access-control-option-end-date": "Grant access until",
"access-control-option-end-date-note": "Select the date until which the relate access condition is applied", "access-control-option-end-date-note": "Select the date until which the related access condition is applied",
} }