mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[CST-9636] Create page for bulk access
This commit is contained in:
@@ -6,8 +6,13 @@ import { GroupsRegistryComponent } from './group-registry/groups-registry.compon
|
|||||||
import { GROUP_EDIT_PATH } from './access-control-routing-paths';
|
import { GROUP_EDIT_PATH } from './access-control-routing-paths';
|
||||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
import { GroupPageGuard } from './group-registry/group-page.guard';
|
import { GroupPageGuard } from './group-registry/group-page.guard';
|
||||||
import { GroupAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/group-administrator.guard';
|
import {
|
||||||
import { SiteAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
|
GroupAdministratorGuard
|
||||||
|
} from '../core/data/feature-authorization/feature-authorization-guard/group-administrator.guard';
|
||||||
|
import {
|
||||||
|
SiteAdministratorGuard
|
||||||
|
} from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
|
||||||
|
import { BulkAccessComponent } from './bulk-access/bulk-access.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -47,7 +52,16 @@ import { SiteAdministratorGuard } from '../core/data/feature-authorization/featu
|
|||||||
},
|
},
|
||||||
data: { title: 'admin.access-control.groups.title.singleGroup', breadcrumbKey: 'admin.access-control.groups.singleGroup' },
|
data: { title: 'admin.access-control.groups.title.singleGroup', breadcrumbKey: 'admin.access-control.groups.singleGroup' },
|
||||||
canActivate: [GroupPageGuard]
|
canActivate: [GroupPageGuard]
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: 'bulk-access',
|
||||||
|
component: BulkAccessComponent,
|
||||||
|
resolve: {
|
||||||
|
breadcrumb: I18nBreadcrumbResolver
|
||||||
|
},
|
||||||
|
data: { title: 'admin.access-control.bulk-access.title', breadcrumbKey: 'admin.access-control.bulk-access' },
|
||||||
|
canActivate: [SiteAdministratorGuard]
|
||||||
|
},
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -12,6 +12,11 @@ import { GroupsRegistryComponent } from './group-registry/groups-registry.compon
|
|||||||
import { FormModule } from '../shared/form/form.module';
|
import { FormModule } from '../shared/form/form.module';
|
||||||
import { DYNAMIC_ERROR_MESSAGES_MATCHER, DynamicErrorMessagesMatcher } from '@ng-dynamic-forms/core';
|
import { DYNAMIC_ERROR_MESSAGES_MATCHER, DynamicErrorMessagesMatcher } from '@ng-dynamic-forms/core';
|
||||||
import { AbstractControl } from '@angular/forms';
|
import { AbstractControl } from '@angular/forms';
|
||||||
|
import { BulkAccessComponent } from './bulk-access/bulk-access.component';
|
||||||
|
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { BulkAccessBrowseComponent } from './bulk-access/browse/bulk-access-browse.component';
|
||||||
|
import { BulkAccessSettingsComponent } from './bulk-access/settings/bulk-access-settings.component';
|
||||||
|
import { SearchModule } from '../shared/search/search.module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Condition for displaying error messages on email form field
|
* Condition for displaying error messages on email form field
|
||||||
@@ -28,6 +33,8 @@ export const ValidateEmailErrorStateMatcher: DynamicErrorMessagesMatcher =
|
|||||||
RouterModule,
|
RouterModule,
|
||||||
AccessControlRoutingModule,
|
AccessControlRoutingModule,
|
||||||
FormModule,
|
FormModule,
|
||||||
|
NgbAccordionModule,
|
||||||
|
SearchModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
MembersListComponent,
|
MembersListComponent,
|
||||||
@@ -39,6 +46,9 @@ export const ValidateEmailErrorStateMatcher: DynamicErrorMessagesMatcher =
|
|||||||
GroupFormComponent,
|
GroupFormComponent,
|
||||||
SubgroupsListComponent,
|
SubgroupsListComponent,
|
||||||
MembersListComponent,
|
MembersListComponent,
|
||||||
|
BulkAccessComponent,
|
||||||
|
BulkAccessBrowseComponent,
|
||||||
|
BulkAccessSettingsComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BulkAccessBrowseComponent } from './bulk-access-browse.component';
|
||||||
|
|
||||||
|
describe('BrowseComponent', () => {
|
||||||
|
let component: BulkAccessBrowseComponent;
|
||||||
|
let fixture: ComponentFixture<BulkAccessBrowseComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ BulkAccessBrowseComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BulkAccessBrowseComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,67 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||||
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
|
||||||
|
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
|
||||||
|
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
|
||||||
|
import { SelectableListState } from '../../../shared/object-list/selectable-list/selectable-list.reducer';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
|
||||||
|
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
|
||||||
|
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
|
||||||
|
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||||
|
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-bulk-access-browse',
|
||||||
|
templateUrl: './bulk-access-browse.component.html',
|
||||||
|
styleUrls: ['./bulk-access-browse.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: SEARCH_CONFIG_SERVICE,
|
||||||
|
useClass: SearchConfigurationService
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class BulkAccessBrowseComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* The active nav id
|
||||||
|
*/
|
||||||
|
activateId = 'search';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selection list id
|
||||||
|
*/
|
||||||
|
listId: string = 'bulk-access-list';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of the objects already selected
|
||||||
|
*/
|
||||||
|
objectsSelected$: BehaviorSubject<RemoteData<PaginatedList<ListableObject>>> = new BehaviorSubject<RemoteData<PaginatedList<ListableObject>>>(null);
|
||||||
|
|
||||||
|
paginationOptions: PaginationComponentOptions;
|
||||||
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(private selectableListService: SelectableListService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.paginationOptions = Object.assign(new PaginationComponentOptions(), {
|
||||||
|
id: 'elp',
|
||||||
|
pageSize: 10,
|
||||||
|
currentPage: 1
|
||||||
|
});
|
||||||
|
this.subs.push(
|
||||||
|
this.selectableListService.getSelectableList(this.listId).pipe(
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((list: SelectableListState) => {
|
||||||
|
console.log(list);
|
||||||
|
return createSuccessfulRemoteDataObject(buildPaginatedList(new PageInfo(), list?.selection || []))
|
||||||
|
})
|
||||||
|
).subscribe(this.objectsSelected$)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<ds-bulk-access-browse></ds-bulk-access-browse>
|
||||||
|
<div class="clearfix mb-3"></div>
|
||||||
|
<ds-bulk-access-settings></ds-bulk-access-settings>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BulkAccessComponent } from './bulk-access.component';
|
||||||
|
|
||||||
|
describe('BulkAccessComponent', () => {
|
||||||
|
let component: BulkAccessComponent;
|
||||||
|
let fixture: ComponentFixture<BulkAccessComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ BulkAccessComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BulkAccessComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
15
src/app/access-control/bulk-access/bulk-access.component.ts
Normal file
15
src/app/access-control/bulk-access/bulk-access.component.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-bulk-access',
|
||||||
|
templateUrl: './bulk-access.component.html',
|
||||||
|
styleUrls: ['./bulk-access.component.scss']
|
||||||
|
})
|
||||||
|
export class BulkAccessComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<ngb-accordion #acc="ngbAccordion" [activeIds]="'settings'">
|
||||||
|
<ngb-panel [id]="'settings'">
|
||||||
|
<ng-template ngbPanelHeader>
|
||||||
|
<div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('settings')" data-test="settings">
|
||||||
|
<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-settings.header' | translate }}
|
||||||
|
</button>
|
||||||
|
<div class="text-right d-flex">
|
||||||
|
<div class="ml-3 d-inline-block">
|
||||||
|
<span *ngIf="acc.isExpanded('settings')" class="fas fa-chevron-up fa-fw"></span>
|
||||||
|
<span *ngIf="!acc.isExpanded('settings')" class="fas fa-chevron-down fa-fw"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<p>bulk-access-settings works!</p>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BulkAccessSettingsComponent } from './bulk-access-settings.component';
|
||||||
|
|
||||||
|
describe('BulkAccessSettingsComponent', () => {
|
||||||
|
let component: BulkAccessSettingsComponent;
|
||||||
|
let fixture: ComponentFixture<BulkAccessSettingsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ BulkAccessSettingsComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BulkAccessSettingsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-bulk-access-settings',
|
||||||
|
templateUrl: './bulk-access-settings.component.html',
|
||||||
|
styleUrls: ['./bulk-access-settings.component.scss']
|
||||||
|
})
|
||||||
|
export class BulkAccessSettingsComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -659,6 +659,17 @@ export class MenuResolver implements Resolve<boolean> {
|
|||||||
link: '/access-control/groups'
|
link: '/access-control/groups'
|
||||||
} as LinkMenuItemModel,
|
} as LinkMenuItemModel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'access_control_bulk',
|
||||||
|
parentID: 'access_control',
|
||||||
|
active: false,
|
||||||
|
visible: isSiteAdmin,
|
||||||
|
model: {
|
||||||
|
type: MenuItemType.LINK,
|
||||||
|
text: 'menu.section.access_control_bulk',
|
||||||
|
link: '/access-control/bulk-access'
|
||||||
|
} as LinkMenuItemModel,
|
||||||
|
},
|
||||||
// TODO: enable this menu item once the feature has been implemented
|
// TODO: enable this menu item once the feature has been implemented
|
||||||
// {
|
// {
|
||||||
// id: 'access_control_authorizations',
|
// id: 'access_control_authorizations',
|
||||||
|
@@ -227,6 +227,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access": "Bulk access",
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access.title": "Bulk Access",
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access-browse.header": "Step 1: select objects",
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access-browse.search.header": "Search",
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access-browse.selected.header": "Current selection({{number}})",
|
||||||
|
|
||||||
|
"admin.access-control.bulk-access-settings.header": "Step 2: operation to perform",
|
||||||
|
|
||||||
"admin.access-control.epeople.actions.delete": "Delete EPerson",
|
"admin.access-control.epeople.actions.delete": "Delete EPerson",
|
||||||
|
|
||||||
"admin.access-control.epeople.actions.impersonate": "Impersonate EPerson",
|
"admin.access-control.epeople.actions.impersonate": "Impersonate EPerson",
|
||||||
@@ -2878,6 +2890,8 @@
|
|||||||
|
|
||||||
"menu.section.access_control_authorizations": "Authorizations",
|
"menu.section.access_control_authorizations": "Authorizations",
|
||||||
|
|
||||||
|
"menu.section.access_control_bulk": "Bulk access",
|
||||||
|
|
||||||
"menu.section.access_control_groups": "Groups",
|
"menu.section.access_control_groups": "Groups",
|
||||||
|
|
||||||
"menu.section.access_control_people": "People",
|
"menu.section.access_control_people": "People",
|
||||||
|
Reference in New Issue
Block a user