diff --git a/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.html b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.html index 0719a18d94..52eda57f2c 100644 --- a/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.html +++ b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.html @@ -1,3 +1,92 @@
- Access control page!!! +
+
+

+ This form allows you to perform changes to the access condition of all the items owned by collection under this community. + Changes can be performed on the access condition for the metadata (item) or for the content (bitstream). +

+ +
+
+
+

Item's Metadata

+ +
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+
+

Bitstreams

+ +
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+ +
+ +
+ + +
+
+
diff --git a/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.ts b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.ts index 8675e3a83f..0791e29233 100644 --- a/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.ts +++ b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.component.ts @@ -1,37 +1,56 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; -import { RemoteData } from '../../../core/data/remote-data'; -import { ActivatedRoute } from '@angular/router'; -import { first, map } from 'rxjs/operators'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +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'; @Component({ selector: 'ds-collection-access-control', 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 { - /** - * The initial DSO object - */ - public dsoRD$: Observable>; + @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) + ); + + ngOnInit(): void { - /** - * Initialize instance variables - * - * @param {ActivatedRoute} route - */ - constructor( - private route: ActivatedRoute - ) { } - /** - * Initialize the component, setting up the collection - */ - ngOnInit(): void { - this.dsoRD$ = this.route.parent.parent.data.pipe(first(), map((data) => data.dso)); + 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); } } + +const initialState = { + item: { + toggleStatus: false, + accessMode: '', + }, + bitstream: { + toggleStatus: false, + accessMode: '', + }, +}; diff --git a/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.service.ts b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.service.ts new file mode 100644 index 0000000000..9cc7b8d85a --- /dev/null +++ b/src/app/collection-page/edit-collection-page/collection-access-control/collection-access-control.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; +import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component'; +import { Observable, of } from 'rxjs'; + +export interface AccessControlDropdownDataResponse { + id: string; + itemAccessConditionOptions: AccessControlItem[]; + bitstreamAccessConditionOptions: AccessControlItem[]; +} + +@Injectable() +export class CollectionAccessControlService { + dropdownData$: Observable = 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' + } + ] +}; diff --git a/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts b/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts index 3817122368..5af7d3189a 100644 --- a/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts +++ b/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts @@ -14,6 +14,10 @@ import { ResourcePoliciesModule } from '../../shared/resource-policies/resource- import { FormModule } from '../../shared/form/form.module'; import { ComcolModule } from '../../shared/comcol/comcol.module'; import { CollectionAccessControlComponent } from './collection-access-control/collection-access-control.component'; +import { + AccessControlArrayFormModule +} from '../../shared/access-control-array-form/access-control-array-form.component'; +import { UiSwitchModule } from 'ngx-ui-switch'; /** * Module that contains all components related to the Edit Collection page administrator functionality @@ -27,6 +31,8 @@ import { CollectionAccessControlComponent } from './collection-access-control/co ResourcePoliciesModule, FormModule, ComcolModule, + AccessControlArrayFormModule, + UiSwitchModule, ], declarations: [ EditCollectionPageComponent, diff --git a/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.html b/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.html index cec7f44321..52eda57f2c 100644 --- a/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.html +++ b/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.html @@ -1 +1,92 @@ -

community-access-control works!

+
+
+
+

+ This form allows you to perform changes to the access condition of all the items owned by collection under this community. + Changes can be performed on the access condition for the metadata (item) or for the content (bitstream). +

+ +
+
+
+

Item's Metadata

+ +
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+
+

Bitstreams

+ +
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+ +
+ +
+ + +
+
+
+
diff --git a/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.ts b/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.ts index 543d63564e..202c04b7b5 100644 --- a/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.ts +++ b/src/app/community-page/edit-community-page/community-access-control/community-access-control.component.ts @@ -1,15 +1,56 @@ -import { Component, OnInit } from '@angular/core'; +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'; @Component({ selector: 'ds-community-access-control', 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 { - constructor() { } + @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) + ); 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); } } + +const initialState = { + item: { + toggleStatus: false, + accessMode: '', + }, + bitstream: { + toggleStatus: false, + accessMode: '', + }, +}; diff --git a/src/app/community-page/edit-community-page/community-access-control/community-access-control.service.ts b/src/app/community-page/edit-community-page/community-access-control/community-access-control.service.ts new file mode 100644 index 0000000000..d78d42ba90 --- /dev/null +++ b/src/app/community-page/edit-community-page/community-access-control/community-access-control.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; +import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component'; +import { Observable, of } from 'rxjs'; + +export interface AccessControlDropdownDataResponse { + id: string; + itemAccessConditionOptions: AccessControlItem[]; + bitstreamAccessConditionOptions: AccessControlItem[]; +} + +@Injectable() +export class CommunityAccessControlService { + dropdownData$: Observable = 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' + } + ] +}; diff --git a/src/app/community-page/edit-community-page/edit-community-page.module.ts b/src/app/community-page/edit-community-page/edit-community-page.module.ts index a9f020a9e6..8aa52086ee 100644 --- a/src/app/community-page/edit-community-page/edit-community-page.module.ts +++ b/src/app/community-page/edit-community-page/edit-community-page.module.ts @@ -11,6 +11,10 @@ import { CommunityFormModule } from '../community-form/community-form.module'; import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module'; import { ComcolModule } from '../../shared/comcol/comcol.module'; import { CommunityAccessControlComponent } from './community-access-control/community-access-control.component'; +import { UiSwitchModule } from 'ngx-ui-switch'; +import { + AccessControlArrayFormModule +} from '../../shared/access-control-array-form/access-control-array-form.component'; /** * Module that contains all components related to the Edit Community page administrator functionality @@ -23,6 +27,8 @@ import { CommunityAccessControlComponent } from './community-access-control/comm CommunityFormModule, ComcolModule, ResourcePoliciesModule, + UiSwitchModule, + AccessControlArrayFormModule, ], declarations: [ EditCommunityPageComponent, diff --git a/src/app/item-page/edit-item-page/edit-item-page.module.ts b/src/app/item-page/edit-item-page/edit-item-page.module.ts index d922cee0a5..65862b3de8 100644 --- a/src/app/item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/item-page/edit-item-page/edit-item-page.module.ts @@ -39,6 +39,10 @@ import { IdentifierDataComponent } from '../../shared/object-list/identifier-dat import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component'; import { DsoSharedModule } from '../../dso-shared/dso-shared.module'; import { ItemAccessControlComponent } from './item-access-control/item-access-control.component'; +import { + AccessControlArrayFormModule +} from '../../shared/access-control-array-form/access-control-array-form.component'; +import { UiSwitchModule } from 'ngx-ui-switch'; /** @@ -56,6 +60,8 @@ import { ItemAccessControlComponent } from './item-access-control/item-access-co NgbModule, ItemVersionsModule, DsoSharedModule, + AccessControlArrayFormModule, + UiSwitchModule, ], declarations: [ EditItemPageComponent, diff --git a/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.html b/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.html index 416b785722..f5a02b0452 100644 --- a/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.html +++ b/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.html @@ -1 +1,110 @@ -

item-access-control works!

+
+
+
+

+ This form allows you to perform changes to the access condition of all the items owned by collection under this community. + Changes can be performed on the access condition for the metadata (item) or for the content (bitstream). +

+ +
+
+
+

Item's Metadata

+ +
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+
+

Bitstreams

+ +
+ +
+
Limit the changes to specific bitstreams
+
+
+ + +
+
+ + +
+
+
+ +
+
Mode
+
+
+ + +
+
+ + +
+
+
+ +
+
Access conditions
+ +
+ You have not specified any access conditions, the new items access conditions will be inherited from the owning collection. +
+
+ + + + +
+
+ +
+ +
+ + +
+
+
+
diff --git a/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.ts b/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.ts index 5b42e5bf4e..6882dfb2a1 100644 --- a/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.ts +++ b/src/app/item-page/edit-item-page/item-access-control/item-access-control.component.ts @@ -1,15 +1,64 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { + AccessControlArrayFormComponent +} from '../../../shared/access-control-array-form/access-control-array-form.component'; +import { + CollectionAccessControlService +} from '../../../collection-page/edit-collection-page/collection-access-control/collection-access-control.service'; +import { shareReplay } from 'rxjs'; +import { ItemAccessControlService } from './item-access-control.service'; @Component({ selector: 'ds-item-access-control', 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 { - constructor() { } + @ViewChild('bitstreamAccessCmp', { static: true }) bitstreamAccessCmp: AccessControlArrayFormComponent; + @ViewChild('itemAccessCmp', { static: true }) itemAccessCmp: AccessControlArrayFormComponent; + + constructor(private itemAccessControlService: ItemAccessControlService) {} + + state = initialState; + + dropdownData$ = this.itemAccessControlService.dropdownData$.pipe( + shareReplay(1) + ); ngOnInit(): void { + + } + + 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 + }); } } + +const initialState = { + item: { + toggleStatus: false, + accessMode: '', + }, + bitstream: { + toggleStatus: false, + accessMode: '', + changesLimit: '', // 'all' | 'selected' + selectedBitstreams: [] + }, +}; diff --git a/src/app/item-page/edit-item-page/item-access-control/item-access-control.service.ts b/src/app/item-page/edit-item-page/item-access-control/item-access-control.service.ts new file mode 100644 index 0000000000..3eeacfe1ce --- /dev/null +++ b/src/app/item-page/edit-item-page/item-access-control/item-access-control.service.ts @@ -0,0 +1,71 @@ +import { Injectable } from '@angular/core'; +import { AccessControlItem } from '../../../shared/access-control-array-form/access-control-array-form.component'; +import { Observable, of } from 'rxjs'; + +export interface AccessControlDropdownDataResponse { + id: string; + itemAccessConditionOptions: AccessControlItem[]; + bitstreamAccessConditionOptions: AccessControlItem[]; +} + +@Injectable() +export class ItemAccessControlService { + dropdownData$: Observable = of(accessControlDropdownData); + + + execute(payload: any) { + console.log('execute', payload); + + const blob = new Blob([JSON.stringify(payload, null, 2)], { + type: 'application/json', + }); + + const file = new File([blob], 'data.json', { + type: 'application/json', + }); + + const url = URL.createObjectURL(file); + window.open(url, '_blank'); + + } +} + +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' + } + ] +}; diff --git a/src/app/shared/access-control-array-form/access-control-array-form.component.html b/src/app/shared/access-control-array-form/access-control-array-form.component.html new file mode 100644 index 0000000000..dc8caf403c --- /dev/null +++ b/src/app/shared/access-control-array-form/access-control-array-form.component.html @@ -0,0 +1,68 @@ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ + + +
diff --git a/src/app/shared/access-control-array-form/access-control-array-form.component.scss b/src/app/shared/access-control-array-form/access-control-array-form.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/access-control-array-form/access-control-array-form.component.spec.ts b/src/app/shared/access-control-array-form/access-control-array-form.component.spec.ts new file mode 100644 index 0000000000..7c3ed06be1 --- /dev/null +++ b/src/app/shared/access-control-array-form/access-control-array-form.component.spec.ts @@ -0,0 +1,101 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AccessControlArrayFormComponent, AccessControlItemValue } from './access-control-array-form.component'; +import { ReactiveFormsModule } from '@angular/forms'; +import { SharedBrowseByModule } from '../browse-by/shared-browse-by.module'; +import { CommonModule } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; +import { ControlMaxStartDatePipe } from './control-max-start-date.pipe'; +import { ControlMaxEndDatePipe } from './control-max-end-date.pipe'; +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +fdescribe('AccessControlArrayFormComponent', () => { + let component: AccessControlArrayFormComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ CommonModule, ReactiveFormsModule, SharedBrowseByModule, TranslateModule, NgbDatepickerModule ], + declarations: [ AccessControlArrayFormComponent, ControlMaxStartDatePipe, ControlMaxEndDatePipe ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AccessControlArrayFormComponent); + component = fixture.componentInstance; + component.dropdownOptions = [{name: 'Option1'}, {name: 'Option2'}]; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should have only one empty control access item in the form', () => { + const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]')); + expect(accessControlItems.length).toEqual(1); + }); + + it('should add access control item', () => { + component.addAccessControlItem(); + expect(component.accessControl.length).toEqual(2); + }); + + it('should remove access control item', () => { + component.removeAccessControlItem(0); + expect(component.accessControl.length).toEqual(0); + + component.addAccessControlItem(); + component.removeAccessControlItem(0); + expect(component.accessControl.length).toEqual(0); + }); + + it('should set access control item value', () => { + const item: AccessControlItemValue = { itemName: 'item1', startDate: '2022-01-01', endDate: '2022-02-01' }; + component.addAccessControlItem(item.itemName); + component.accessControl.controls[0].patchValue(item); + expect(component.form.value.accessControl[0]).toEqual(item); + }); + + it('should reset form value', () => { + const item: AccessControlItemValue = { itemName: 'item1', startDate: '2022-01-01', endDate: '2022-02-01' }; + component.addAccessControlItem(item.itemName); + component.accessControl.controls[1].patchValue(item); + component.reset(); + expect(component.form.value.accessControl[1].value).toEqual(undefined); + }); + + + it('should display a select dropdown with options', () => { + const selectElement: DebugElement = fixture.debugElement.query(By.css('select#accesscontroloption')); + expect(selectElement).toBeTruthy(); + + const options = selectElement.nativeElement.querySelectorAll('option'); + expect(options.length).toEqual(3); // 2 options + default empty option + + expect(options[0].value).toEqual(''); + expect(options[1].value).toEqual('Option1'); + expect(options[2].value).toEqual('Option2'); + }); + + it('should add new access control items when clicking "Add more" button', () => { + const addButton: DebugElement = fixture.debugElement.query(By.css('button#add-btn')); + addButton.nativeElement.click(); + fixture.detectChanges(); + + const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]')); + expect(accessControlItems.length).toEqual(2); + }); + + it('should remove access control items when clicking remove button', () => { + const removeButton: DebugElement = fixture.debugElement.query(By.css('button.btn-outline-danger')); + removeButton.nativeElement.click(); + fixture.detectChanges(); + + const accessControlItems = fixture.debugElement.queryAll(By.css('[data-testId="access-control-item"]')); + expect(accessControlItems.length).toEqual(0); + }); +}); diff --git a/src/app/shared/access-control-array-form/access-control-array-form.component.ts b/src/app/shared/access-control-array-form/access-control-array-form.component.ts new file mode 100644 index 0000000000..00ff52c695 --- /dev/null +++ b/src/app/shared/access-control-array-form/access-control-array-form.component.ts @@ -0,0 +1,88 @@ +import { Component, Input, NgModule, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormArray, FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { SharedBrowseByModule } from '../browse-by/shared-browse-by.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; +import { ControlMaxStartDatePipe } from './control-max-start-date.pipe'; +import { ControlMaxEndDatePipe } from './control-max-end-date.pipe'; + +// type of the dropdown item that comes from backend +export interface AccessControlItem { + name: string + hasStartDate?: boolean + maxStartDate?: string + hasEndDate?: boolean + maxEndDate?: string +} + +// will be used on the form value +export interface AccessControlItemValue { + itemName: string | null; // item name + startDate?: string; + endDate?: string; +} + +export interface AccessControlArrayFormValue { + accessControl: AccessControlItemValue[]; +} + +@Component({ + selector: 'ds-access-control-array-form', + templateUrl: './access-control-array-form.component.html', + styleUrls: [ './access-control-array-form.component.scss' ] +}) +export class AccessControlArrayFormComponent implements OnInit { + @Input() dropdownOptions: AccessControlItem[] = []; + @Input() accessControlItems: AccessControlItemValue[] = []; + + form = this.fb.group({ + accessControl: this.fb.array([]) + }); + + constructor(private fb: FormBuilder) { + } + + ngOnInit(): void { + if (this.accessControlItems.length === 0) { + this.addAccessControlItem(); + } else { + for (const item of this.accessControlItems) { + this.addAccessControlItem(item.itemName); + } + } + } + + get accessControl() { + return this.form.get('accessControl') as FormArray; + } + + addAccessControlItem(itemName: string = null) { + this.accessControl.push(this.fb.group({ + itemName, + startDate: null, + endDate: null + })); + } + + removeAccessControlItem(index: number) { + this.accessControl.removeAt(index); + } + + getValue() { + return this.form.value; + } + + reset() { + this.accessControl.reset([]); + } + +} + +@NgModule({ + imports: [ CommonModule, ReactiveFormsModule, SharedBrowseByModule, TranslateModule, NgbDatepickerModule ], + declarations: [ AccessControlArrayFormComponent, ControlMaxStartDatePipe, ControlMaxEndDatePipe ], + exports: [ AccessControlArrayFormComponent ], +}) +export class AccessControlArrayFormModule { +} diff --git a/src/app/shared/access-control-array-form/control-max-end-date.pipe.ts b/src/app/shared/access-control-array-form/control-max-end-date.pipe.ts new file mode 100644 index 0000000000..0ddff2a042 --- /dev/null +++ b/src/app/shared/access-control-array-form/control-max-end-date.pipe.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; +import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap/datepicker/ngb-date-struct'; +import { AccessControlItem } from './access-control-array-form.component'; + +@Pipe({ + // eslint-disable-next-line @angular-eslint/pipe-prefix + name: 'maxEndDate', + pure: false +}) +export class ControlMaxEndDatePipe implements PipeTransform { + transform(control: AbstractControl, dropdownOptions: AccessControlItem[]): NgbDateStruct | null { + const { itemName } = control.value; + const item = dropdownOptions.find((x) => x.name === itemName); + if (!item?.hasEndDate) { + return null; + } + const date = new Date(item.maxEndDate); + return { + year: date.getFullYear(), + month: date.getMonth() + 1, + day: date.getDate() + } as NgbDateStruct; + } + +} diff --git a/src/app/shared/access-control-array-form/control-max-start-date.pipe.ts b/src/app/shared/access-control-array-form/control-max-start-date.pipe.ts new file mode 100644 index 0000000000..01a9607a16 --- /dev/null +++ b/src/app/shared/access-control-array-form/control-max-start-date.pipe.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; +import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap/datepicker/ngb-date-struct'; +import { AccessControlItem } from './access-control-array-form.component'; + +@Pipe({ + // eslint-disable-next-line @angular-eslint/pipe-prefix + name: 'maxStartDate', + pure: false +}) +export class ControlMaxStartDatePipe implements PipeTransform { + transform(control: AbstractControl, dropdownOptions: AccessControlItem[]): NgbDateStruct | null { + const { itemName } = control.value; + const item = dropdownOptions.find((x) => x.name === itemName); + if (!item?.hasStartDate) { + return null; + } + const date = new Date(item.maxStartDate); + return { + year: date.getFullYear(), + month: date.getMonth() + 1, + day: date.getDate() + } as NgbDateStruct; + } + +}