diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html new file mode 100644 index 0000000000..a702a7e6b0 --- /dev/null +++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.html @@ -0,0 +1,4 @@ +
+

{{'admin.curation-tasks.header' |translate }}

+ +
diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts new file mode 100644 index 0000000000..b84f619ff1 --- /dev/null +++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.spec.ts @@ -0,0 +1,28 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminCurationTasksComponent } from './admin-curation-tasks.component'; +import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; + +describe('AdminCurationTasksComponent', () => { + let comp: AdminCurationTasksComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + declarations: [AdminCurationTasksComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminCurationTasksComponent); + comp = fixture.componentInstance; + }); + describe('init', () => { + it('should initialise the comp', () => { + expect(comp).toBeDefined(); + expect(fixture.debugElement.nativeElement.innerHTML).toContain('ds-curation-form'); + }); + }); +}); diff --git a/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts new file mode 100644 index 0000000000..9a80f341b9 --- /dev/null +++ b/src/app/+admin/admin-curation-tasks/admin-curation-tasks.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +/** + * Component responsible for rendering the system wide Curation Task UI + */ +@Component({ + selector: 'ds-admin-curation-task', + templateUrl: './admin-curation-tasks.component.html', +}) +export class AdminCurationTasksComponent { + +} diff --git a/src/app/+admin/admin-routing.module.ts b/src/app/+admin/admin-routing.module.ts index b199129c4e..43b3a4ab34 100644 --- a/src/app/+admin/admin-routing.module.ts +++ b/src/app/+admin/admin-routing.module.ts @@ -6,6 +6,7 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component'; import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service'; import { URLCombiner } from '../core/url-combiner/url-combiner'; +import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component'; const REGISTRIES_MODULE_PATH = 'registries'; export const ACCESS_CONTROL_MODULE_PATH = 'access-control'; @@ -41,6 +42,12 @@ export function getAccessControlModulePath() { component: AdminWorkflowPageComponent, data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' } }, + { + path: 'curation-tasks', + resolve: { breadcrumb: I18nBreadcrumbResolver }, + component: AdminCurationTasksComponent, + data: { title: 'admin.curation-tasks.title', breadcrumbKey: 'admin.curation-tasks' } + }, ]) ], providers: [ diff --git a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts index ade3e33aed..eb86de5f3c 100644 --- a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts @@ -469,7 +469,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { model: { type: MenuItemType.LINK, text: 'menu.section.curation_task', - link: '' + link: 'admin/curation-tasks' } as LinkMenuItemModel, icon: 'filter', index: 7 diff --git a/src/app/+admin/admin.module.ts b/src/app/+admin/admin.module.ts index 25b8bd4648..85749afe03 100644 --- a/src/app/+admin/admin.module.ts +++ b/src/app/+admin/admin.module.ts @@ -16,6 +16,7 @@ import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './adm import { WorkflowItemAdminWorkflowActionsComponent } from './admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component'; import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component'; import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component'; +import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component'; @NgModule({ imports: [ @@ -35,6 +36,7 @@ import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow CommunityAdminSearchResultGridElementComponent, CollectionAdminSearchResultGridElementComponent, ItemAdminSearchResultActionsComponent, + AdminCurationTasksComponent, WorkflowItemSearchResultAdminWorkflowListElementComponent, WorkflowItemSearchResultAdminWorkflowGridElementComponent, diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html index e69de29bb2..38c9d22f4e 100644 --- a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html +++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.html @@ -0,0 +1,6 @@ +
+

{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}

+ +
diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts new file mode 100644 index 0000000000..91c264cd0f --- /dev/null +++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.spec.ts @@ -0,0 +1,69 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core'; +import { CollectionCurateComponent } from './collection-curate.component'; +import { of as observableOf } from 'rxjs'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { Collection } from '../../../core/shared/collection.model'; +import { ActivatedRoute } from '@angular/router'; +import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; + +describe('CollectionCurateComponent', () => { + let comp: CollectionCurateComponent; + let fixture: ComponentFixture; + let debugEl: DebugElement; + + let routeStub; + let dsoNameService; + + const collection = Object.assign(new Collection(), { + handle: '123456789/1', metadata: {'dc.title': ['Collection Name']} + }); + + beforeEach(async(() => { + routeStub = { + parent: { + data: observableOf({ + dso: createSuccessfulRemoteDataObject(collection) + }) + } + }; + + dsoNameService = jasmine.createSpyObj('dsoNameService', { + getName: 'Collection Name' + }); + + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + declarations: [CollectionCurateComponent], + providers: [ + {provide: ActivatedRoute, useValue: routeStub}, + {provide: DSONameService, useValue: dsoNameService} + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CollectionCurateComponent); + comp = fixture.componentInstance; + debugEl = fixture.debugElement; + + fixture.detectChanges(); + }); + describe('init', () => { + it('should initialise the comp', () => { + expect(comp).toBeDefined(); + expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form'); + }); + it('should contain the collection information provided in the route', () => { + comp.dsoRD$.subscribe((value) => { + expect(value.payload.handle + ).toEqual('123456789/1'); + }); + comp.collectionName$.subscribe((value) => { + expect(value).toEqual('Collection Name'); + }); + }); + }); +}); diff --git a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts index d7deaea982..e20f229cd6 100644 --- a/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts +++ b/src/app/+collection-page/edit-collection-page/collection-curate/collection-curate.component.ts @@ -1,4 +1,11 @@ import { Component } from '@angular/core'; +import { filter, map, take } from 'rxjs/operators'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Observable } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; +import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; +import { Collection } from '../../../core/shared/collection.model'; +import { hasValue } from '../../../shared/empty.util'; /** * Component for managing a collection's curation tasks @@ -8,5 +15,26 @@ import { Component } from '@angular/core'; templateUrl: './collection-curate.component.html', }) export class CollectionCurateComponent { - /* TODO: Implement Collection Edit - Curate */ + dsoRD$: Observable>; + collectionName$: Observable; + + constructor( + private route: ActivatedRoute, + private dsoNameService: DSONameService, + ) { + } + + ngOnInit(): void { + this.dsoRD$ = this.route.parent.data.pipe( + take(1), + map((data) => data.dso), + ); + + this.collectionName$ = this.dsoRD$.pipe( + filter((rd: RemoteData) => hasValue(rd)), + map((rd: RemoteData) => { + return this.dsoNameService.getName(rd.payload); + }) + ); + } } diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html index e69de29bb2..6c041d1725 100644 --- a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html +++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.html @@ -0,0 +1,6 @@ +
+

{{'community.curate.header' |translate:{community: (communityName$ |async)} }}

+ +
diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts new file mode 100644 index 0000000000..42dc0f08a9 --- /dev/null +++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.spec.ts @@ -0,0 +1,69 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core'; +import { of as observableOf } from 'rxjs'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { ActivatedRoute } from '@angular/router'; +import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; +import { CommunityCurateComponent } from './community-curate.component'; +import { Community } from '../../../core/shared/community.model'; + +describe('CommunityCurateComponent', () => { + let comp: CommunityCurateComponent; + let fixture: ComponentFixture; + let debugEl: DebugElement; + + let routeStub; + let dsoNameService; + + const community = Object.assign(new Community(), { + handle: '123456789/1', metadata: {'dc.title': ['Community Name']} + }); + + beforeEach(async(() => { + routeStub = { + parent: { + data: observableOf({ + dso: createSuccessfulRemoteDataObject(community) + }) + } + }; + + dsoNameService = jasmine.createSpyObj('dsoNameService', { + getName: 'Community Name' + }); + + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + declarations: [CommunityCurateComponent], + providers: [ + {provide: ActivatedRoute, useValue: routeStub}, + {provide: DSONameService, useValue: dsoNameService} + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CommunityCurateComponent); + comp = fixture.componentInstance; + debugEl = fixture.debugElement; + + fixture.detectChanges(); + }); + describe('init', () => { + it('should initialise the comp', () => { + expect(comp).toBeDefined(); + expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form'); + }); + it('should contain the community information provided in the route', () => { + comp.dsoRD$.subscribe((value) => { + expect(value.payload.handle + ).toEqual('123456789/1'); + }); + comp.communityName$.subscribe((value) => { + expect(value).toEqual('Community Name'); + }); + }); + }); +}); diff --git a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts index 6151d3fe9a..5954b3e95e 100644 --- a/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts +++ b/src/app/+community-page/edit-community-page/community-curate/community-curate.component.ts @@ -1,4 +1,12 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { Community } from '../../../core/shared/community.model'; +import { ActivatedRoute } from '@angular/router'; +import { map, take } from 'rxjs/operators'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Observable } from 'rxjs'; +import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; +import { hasValue } from '../../../shared/empty.util'; +import { filter } from 'rxjs/internal/operators/filter'; /** * Component for managing a community's curation tasks @@ -7,6 +15,29 @@ import { Component } from '@angular/core'; selector: 'ds-community-curate', templateUrl: './community-curate.component.html', }) -export class CommunityCurateComponent { - /* TODO: Implement Community Edit - Curate */ +export class CommunityCurateComponent implements OnInit { + + dsoRD$: Observable>; + communityName$: Observable; + + constructor( + private route: ActivatedRoute, + private dsoNameService: DSONameService, + ) { + } + + ngOnInit(): void { + this.dsoRD$ = this.route.parent.data.pipe( + take(1), + map((data) => data.dso), + ); + + this.communityName$ = this.dsoRD$.pipe( + filter((rd: RemoteData) => hasValue(rd)), + map((rd: RemoteData) => { + return this.dsoNameService.getName(rd.payload); + }) + ); + } + } diff --git a/src/app/curation-form/curation-form.component.html b/src/app/curation-form/curation-form.component.html new file mode 100644 index 0000000000..129a51a037 --- /dev/null +++ b/src/app/curation-form/curation-form.component.html @@ -0,0 +1,20 @@ +
+
+
+
+ + +
+
+ + + {{'curation.form.handle.hint' |translate }} +
+
+ +
+
diff --git a/src/app/curation-form/curation-form.component.spec.ts b/src/app/curation-form/curation-form.component.spec.ts new file mode 100644 index 0000000000..2fada44742 --- /dev/null +++ b/src/app/curation-form/curation-form.component.spec.ts @@ -0,0 +1,148 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { CurationFormComponent } from './curation-form.component'; +import { ScriptDataService } from '../core/data/processes/script-data.service'; +import { ProcessDataService } from '../core/data/processes/process-data.service'; +import { AuthService } from '../core/auth/auth.service'; +import { of as observableOf } from 'rxjs'; +import { RequestEntry } from '../core/data/request.reducer'; +import { DSOSuccessResponse, RestResponse } from '../core/cache/response.models'; +import { Process } from '../process-page/processes/process.model'; +import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils'; +import { EPerson } from '../core/eperson/models/eperson.model'; +import { NotificationsServiceStub } from '../shared/testing/notifications-service.stub'; +import { RouterStub } from '../shared/testing/router.stub'; +import { NotificationsService } from '../shared/notifications/notifications.service'; +import { Router } from '@angular/router'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { By } from '@angular/platform-browser'; + +describe('CurationFormComponent', () => { + let comp: CurationFormComponent; + let fixture: ComponentFixture; + + let scriptDataService: ScriptDataService; + let processDataService: ProcessDataService; + let authService: AuthService; + let notificationsService; + let router; + + const requestEntry = Object.assign(new RequestEntry(), + {response: new DSOSuccessResponse(['process-link'], 200, 'success')}); + const failedRequestEntry = Object.assign(new RequestEntry(), + {response: new RestResponse(false, 400, 'Bad Request')}); + + const process = Object.assign(new Process(), {processId: 'process-id'}); + + beforeEach(async(() => { + + scriptDataService = jasmine.createSpyObj('scriptDataService', { + invoke: observableOf(requestEntry) + }); + + processDataService = jasmine.createSpyObj('processDataService', { + findByHref: createSuccessfulRemoteDataObject$(process) + }); + + authService = jasmine.createSpyObj('authService', { + getAuthenticatedUserFromStore: observableOf(Object.assign(new EPerson(), {email: 'test@mail'})) + }); + + notificationsService = new NotificationsServiceStub(); + router = new RouterStub(); + + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), FormsModule, ReactiveFormsModule], + declarations: [CurationFormComponent], + providers: [ + {provide: ScriptDataService, useValue: scriptDataService}, + {provide: ProcessDataService, useValue: processDataService}, + {provide: AuthService, useValue: authService}, + {provide: NotificationsService, useValue: notificationsService}, + {provide: Router, useValue: router}, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CurationFormComponent); + comp = fixture.componentInstance; + + fixture.detectChanges(); + }); + describe('init', () => { + it('should initialise the comp and contain the different tasks', () => { + expect(comp).toBeDefined(); + + const elements = fixture.debugElement.queryAll(By.css('option')); + expect(elements.length).toEqual(3); + expect(elements[0].nativeElement.innerHTML).toContain('curation-task.task.profileformats.label'); + expect(elements[1].nativeElement.innerHTML).toContain('curation-task.task.requiredmetadata.label'); + expect(elements[2].nativeElement.innerHTML).toContain('curation-task.task.checklinks.label'); + }); + }); + describe('hasHandleValue', () => { + it('should return true when a dsoHandle value was provided', () => { + comp.dsoHandle = 'some-handle'; + fixture.detectChanges(); + + expect(comp.hasHandleValue()).toBeTrue(); + }); + it('should return false when no dsoHandle value was provided', () => { + expect(comp.hasHandleValue()).toBeFalse(); + }); + }); + describe('submit', () => { + it('should submit the selected process and handle to the scriptservice and navigate to the corresponding process page', () => { + comp.dsoHandle = 'test-handle'; + comp.submit(); + + expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [ + {name: '-t', value: 'profileformats'}, + {name: '-i', value: 'test-handle'}, + {name: '-e', value: 'test@mail'}, + ], []); + expect(notificationsService.success).toHaveBeenCalled(); + expect(processDataService.findByHref).toHaveBeenCalledWith('process-link'); + expect(router.navigate).toHaveBeenCalledWith(['/processes', 'process-id']); + }); + it('should the selected process and handle to the scriptservice and stay on the page on error', () => { + (scriptDataService.invoke as jasmine.Spy).and.returnValue(observableOf(failedRequestEntry)); + + comp.dsoHandle = 'test-handle'; + comp.submit(); + + expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [ + {name: '-t', value: 'profileformats'}, + {name: '-i', value: 'test-handle'}, + {name: '-e', value: 'test@mail'}, + ], []); + expect(notificationsService.error).toHaveBeenCalled(); + expect(processDataService.findByHref).not.toHaveBeenCalled(); + expect(router.navigate).not.toHaveBeenCalled(); + }); + }); + it('should use the handle provided by the form when no dsoHandle is provided', () => { + comp.form.get('handle').patchValue('form-handle'); + + comp.submit(); + + expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [ + {name: '-t', value: 'profileformats'}, + {name: '-i', value: 'form-handle'}, + {name: '-e', value: 'test@mail'}, + ], []); + }); + it('should use "all" when the handle provided by the form is empty and when no dsoHandle is provided', () => { + + comp.submit(); + + expect(scriptDataService.invoke).toHaveBeenCalledWith('curate', [ + {name: '-t', value: 'profileformats'}, + {name: '-i', value: 'all'}, + {name: '-e', value: 'test@mail'}, + ], []); + }); +}); diff --git a/src/app/curation-form/curation-form.component.ts b/src/app/curation-form/curation-form.component.ts new file mode 100644 index 0000000000..6f2d9f0b74 --- /dev/null +++ b/src/app/curation-form/curation-form.component.ts @@ -0,0 +1,103 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { ScriptDataService } from '../core/data/processes/script-data.service'; +import { environment } from '../../environments/environment'; +import { CurationTask } from '../../config/curation-task.interface'; +import { FormControl, FormGroup } from '@angular/forms'; +import { getResponseFromEntry } from '../core/shared/operators'; +import { DSOSuccessResponse } from '../core/cache/response.models'; +import { AuthService } from '../core/auth/auth.service'; +import { filter, switchMap, take } from 'rxjs/operators'; +import { EPerson } from '../core/eperson/models/eperson.model'; +import { NotificationsService } from '../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +import { hasValue, isEmpty } from '../shared/empty.util'; +import { RemoteData } from '../core/data/remote-data'; +import { Router } from '@angular/router'; +import { ProcessDataService } from '../core/data/processes/process-data.service'; +import { Process } from '../process-page/processes/process.model'; + +/** + * Component responsible for rendering the Curation Task form + */ +@Component({ + selector: 'ds-curation-form', + templateUrl: './curation-form.component.html' +}) +export class CurationFormComponent implements OnInit { + + tasks: CurationTask[]; + form: FormGroup; + + @Input() + dsoHandle: string; + + constructor( + private scriptDataService: ScriptDataService, + private processDataService: ProcessDataService, + private authService: AuthService, + private notificationsService: NotificationsService, + private translateService: TranslateService, + private router: Router + ) { + } + + ngOnInit(): void { + this.tasks = environment.curationTasks; + + this.form = new FormGroup({ + task: new FormControl(this.tasks[0]), + handle: new FormControl('') + }); + } + + /** + * Determines whether the inputted dsoHandle has a value + */ + hasHandleValue() { + if (hasValue(this.dsoHandle)) { + return true; + } + return false; + } + + /** + * Submit the selected taskName and handle to the script data service to run the corresponding curation script + * Navigate to the process page on success + */ + submit() { + const taskName = (this.form.get('task').value as CurationTask).name; + let handle; + if (this.hasHandleValue()) { + handle = this.dsoHandle; + } else { + handle = this.form.get('handle').value; + if (isEmpty(handle)) { + handle = 'all'; + } + } + this.authService.getAuthenticatedUserFromStore().pipe( + take(1), + switchMap((eperson: EPerson) => { + return this.scriptDataService.invoke('curate', [ + {name: '-t', value: taskName}, + {name: '-i', value: handle}, + {name: '-e', value: eperson.email}, + ], []).pipe(getResponseFromEntry()); + }) + ).subscribe((response: DSOSuccessResponse) => { + if (response.isSuccessful) { + this.notificationsService.success(this.translateService.get('curation.form.submit.success.head'), + this.translateService.get('curation.form.submit.success.content')); + this.processDataService.findByHref(response.resourceSelfLinks[0]).pipe( + filter((processRD: RemoteData) => hasValue(processRD) && hasValue(processRD.payload)), + take(1)) + .subscribe((processRD: RemoteData) => { + this.router.navigate(['/processes', processRD.payload.processId]); + }); + } else { + this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'), + this.translateService.get('curation.form.submit.error.content')); + } + }); + } +} diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html index aa6290ea9f..ad270aab80 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html @@ -16,7 +16,9 @@
- {{ type + '.edit.return' | translate }} + diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index cc61a6d868..93192f6b72 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -207,6 +207,7 @@ import { GroupSearchBoxComponent } from './resource-policies/form/eperson-group- import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component'; import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component'; import { DsSelectComponent } from './ds-select/ds-select.component'; +import { CurationFormComponent } from '../curation-form/curation-form.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -469,6 +470,7 @@ const ENTRY_COMPONENTS = [ ClaimedTaskActionsReturnToPoolComponent, ClaimedTaskActionsEditMetadataComponent, FileDownloadLinkComponent, + CurationFormComponent, ]; const SHARED_ITEM_PAGE_COMPONENTS = [ @@ -526,7 +528,8 @@ const DIRECTIVES = [ ...PIPES, ...COMPONENTS, ...SHARED_ITEM_PAGE_COMPONENTS, - ...DIRECTIVES + ...DIRECTIVES, + CurationFormComponent ], entryComponents: [ ...ENTRY_COMPONENTS diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index b35ced7ce9..48fbe826e5 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -14,7 +14,11 @@ "404.page-not-found": "page not found", + "admin.curation-tasks.breadcrumbs": "System curation tasks", + "admin.curation-tasks.title": "System curation tasks", + + "admin.curation-tasks.header": "System curation tasks", "admin.registries.bitstream-formats.breadcrumbs": "Format registry", @@ -560,6 +564,8 @@ "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + "collection.curate.header": "Curate Collection: {{collection}}", + "collection.delete.cancel": "Cancel", "collection.delete.confirm": "Confirm", @@ -770,6 +776,8 @@ "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + "community.curate.header": "Curate Community: {{community}}", + "community.delete.cancel": "Cancel", "community.delete.confirm": "Confirm", @@ -909,6 +917,32 @@ + "curation-task.task.profileformats.label": "Profile Bitstream Formats", + + "curation-task.task.requiredmetadata.label": "Check for Required Metadata", + + "curation-task.task.checklinks.label": "Check Links in Metadata", + + + + "curation.form.task-select.label": "Task: *", + + "curation.form.submit": "Start", + + "curation.form.submit.success.head": "The curation task has been started successfully", + + "curation.form.submit.success.content": "You will be redirected to the corresponding process page.", + + "curation.form.submit.error.head": "Running the curation task failed", + + "curation.form.submit.error.content": "An error occured when trying to start the curation task.", + + "curation.form.handle.label": "Handle of DSpace Object: *", + + "curation.form.handle.hint": "Hint: Enter [your-handle-prefix]/0 to run a task across entire site (not all tasks may support this capability)", + + + "dso-selector.create.collection.head": "New collection", "dso-selector.create.community.head": "New community", diff --git a/src/config/curation-task.interface.ts b/src/config/curation-task.interface.ts new file mode 100644 index 0000000000..bcdb595756 --- /dev/null +++ b/src/config/curation-task.interface.ts @@ -0,0 +1,9 @@ +import { Config } from './config.interface'; + +/** + * An interface to represent a curation task in the configuration. A CurationTask has a name and a label. + */ +export interface CurationTask extends Config { + name: string; + label: string; +} diff --git a/src/config/global-config.interface.ts b/src/config/global-config.interface.ts index acef3404eb..56f5f7e3c8 100644 --- a/src/config/global-config.interface.ts +++ b/src/config/global-config.interface.ts @@ -11,6 +11,7 @@ import { ItemPageConfig } from './item-page-config.interface'; import { CollectionPageConfig } from './collection-page-config.interface'; import { Theme } from './theme.inferface'; import {AuthConfig} from './auth-config.interfaces'; +import { CurationTask } from './curation-task.interface'; export interface GlobalConfig extends Config { ui: ServerConfig; @@ -31,4 +32,5 @@ export interface GlobalConfig extends Config { item: ItemPageConfig; collection: CollectionPageConfig; theme: Theme; + curationTasks: CurationTask[]; } diff --git a/src/environments/environment.common.ts b/src/environments/environment.common.ts index 2b68eadcfb..bdd7e3c738 100644 --- a/src/environments/environment.common.ts +++ b/src/environments/environment.common.ts @@ -212,5 +212,19 @@ export const environment: GlobalConfig = { }, theme: { name: 'default', - } + }, + curationTasks: [ + { + name: 'profileformats', + label: 'curation-task.task.profileformats.label' + }, + { + name: 'requiredmetadata', + label: 'curation-task.task.requiredmetadata.label' + }, + { + name: 'checklinks', + label: 'curation-task.task.checklinks.label' + } + ] }; diff --git a/src/environments/mock-environment.ts b/src/environments/mock-environment.ts index 7bf6d6c846..ad72277ed8 100644 --- a/src/environments/mock-environment.ts +++ b/src/environments/mock-environment.ts @@ -195,5 +195,19 @@ export const environment: Partial = { }, theme: { name: 'default', - } + }, + curationTasks: [ + { + name: 'profileformats', + label: 'curation-task.task.profileformats.label' + }, + { + name: 'requiredmetadata', + label: 'curation-task.task.requiredmetadata.label' + }, + { + name: 'checklinks', + label: 'curation-task.task.checklinks.label' + } + ] };