diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/pool-task-search-result/pool-task-admin-workflow-search-result-grid-element.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/pool-task-search-result/pool-task-admin-workflow-search-result-grid-element.component.ts index e386ec45ae..70659a3f03 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/pool-task-search-result/pool-task-admin-workflow-search-result-grid-element.component.ts +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/pool-task-search-result/pool-task-admin-workflow-search-result-grid-element.component.ts @@ -25,8 +25,12 @@ import { Observable } from 'rxjs'; import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model'; import { RemoteData } from '../../../../../core/data/remote-data'; import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators'; +import { SearchResult } from '../../../../../shared/search/search-result.model'; +import { TaskObject } from '../../../../../core/tasks/models/task-object.model'; +import { ClaimedTaskSearchResult } from '../../../../../shared/object-collection/shared/claimed-task-search-result.model'; @listableObjectComponent(PoolTaskSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch) +@listableObjectComponent(ClaimedTaskSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch) @Component({ selector: 'ds-pool-task-admin-workflow-search-result-grid-element', styleUrls: ['./pool-task-admin-workflow-search-result-grid-element.component.scss'], @@ -35,7 +39,7 @@ import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../ /** * The component for displaying a list element for an pool task search result on the admin search page */ -export class PoolTaskAdminWorkflowSearchResultGridElementComponent extends SearchResultGridElementComponent implements OnInit { +export class PoolTaskAdminWorkflowSearchResultGridElementComponent extends SearchResultGridElementComponent, TaskObject> implements OnInit { public wfi$: Observable; ngOnInit(): void { diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.html index e894eedb94..c60347b08a 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.html +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.html @@ -1,6 +1,7 @@ - +> diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.ts index 8a6934e755..db23a3c4aa 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.ts +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/pool-task-item-search-result/pool-task-admin-workflow-search-result-list-element.component.ts @@ -4,13 +4,20 @@ import { listableObjectComponent } from '../../../../../shared/object-collection import { Context } from '../../../../../core/shared/context.model'; import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { PoolTaskSearchResult } from '../../../../../shared/object-collection/shared/pool-task-search-result.model'; -import { PoolTask } from '../../../../../core/tasks/models/pool-task-object.model'; import { Observable, pipe } from 'rxjs'; import { RemoteData } from '../../../../../core/data/remote-data'; import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model'; import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators'; +import { ClaimedTaskSearchResult } from '../../../../../shared/object-collection/shared/claimed-task-search-result.model'; +import { TaskObject } from '../../../../../core/tasks/models/task-object.model'; +import { SearchResult } from '../../../../../shared/search/search-result.model'; +import { followLink } from '../../../../../shared/utils/follow-link-config.model'; +import { LinkService } from '../../../../../core/cache/builders/link.service'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { tap } from 'rxjs/operators'; @listableObjectComponent(PoolTaskSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch) +@listableObjectComponent(ClaimedTaskSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch) @Component({ selector: 'ds-pooltask-admin-workflow-search-result-list-element', styleUrls: ['./pool-task-admin-workflow-search-result-list-element.component.scss'], @@ -19,11 +26,16 @@ import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../ /** * The component for displaying a list element for an pool task search result on the admin search page */ -export class PoolTaskAdminWorkflowSearchResultListElementComponent extends SearchResultListElementComponent { +export class PoolTaskAdminWorkflowSearchResultListElementComponent extends SearchResultListElementComponent, TaskObject> { public wfi$: Observable; + constructor(private linkService: LinkService, protected truncatableService: TruncatableService) { + super(truncatableService); + } + ngOnInit(): void { super.ngOnInit(); + this.dso = this.linkService.resolveLink(this.dso, followLink('workflowitem')); this.wfi$ = (this.dso.workflowitem as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()); } } diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-admin-workflow-list-element.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-admin-workflow-list-element.component.html index 736aba2fce..f3502fe0ab 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-admin-workflow-list-element.component.html +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-admin-workflow-list-element.component.html @@ -1,7 +1,8 @@
{{ "admin.workflow.item.workflow" | translate }}
- { +export class WorkflowItemAdminWorkflowListElementComponent extends AbstractListableElementComponent implements OnInit { + public item$: Observable; + constructor(private linkService: LinkService) { + super(); + } + + ngOnInit(): void { + this.object = this.linkService.resolveLink(this.object, followLink('item')); + this.item$ = (this.object.item as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()); + } } diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.html index 3f80b127a8..3004eb925c 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.html +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.html @@ -1,7 +1,7 @@ - + {{"admin.search.item.delete" | translate}} - + {{"admin.search.item.send-back" | translate}} diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.ts index a19f154f13..58f89e31e6 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.ts +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/workflow-item-admin-workflow-actions.component.ts @@ -1,8 +1,6 @@ import { Component, Input } from '@angular/core'; -import { getItemEditPath } from '../../../+item-page/item-page-routing.module'; -import { URLCombiner } from '../../../core/url-combiner/url-combiner'; -import { ITEM_EDIT_WITHDRAW_PATH } from '../../../+item-page/edit-item-page/edit-item-page.routing.module'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; +import { getWorkflowItemDeletePath, getWorkflowItemSendBackPath } from '../../../+workflowitems-edit-page/workflowitems-edit-page-routing.module'; @Component({ selector: 'ds-workflow-item-admin-workflow-actions-element', @@ -27,13 +25,13 @@ export class WorkflowItemAdminWorkflowActionsComponent { * Returns the path to the delete page of this workflow item */ getDeletePath(): string { - return getDeletePath(this.wfi.id) + return getWorkflowItemDeletePath(this.wfi.id) } /** * Returns the path to the send back page of this workflow item */ getSendBackPath(): string { - return getSendPath(this.wfi.id); + return getWorkflowItemSendBackPath(this.wfi.id); } } 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 2cbd0c57d1..b6aaf5faac 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 @@ -38,7 +38,6 @@ import { ItemVersionHistoryComponent } from './item-version-history/item-version EditItemPageComponent, ItemOperationComponent, AbstractSimpleItemActionComponent, - ModifyItemOverviewComponent, ItemWithdrawComponent, ItemReinstateComponent, ItemPrivateComponent, diff --git a/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.html b/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.html index f8d7e427b0..5b1b8c45b3 100644 --- a/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.html +++ b/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.html @@ -1 +1,6 @@ - +
+ + + + +
diff --git a/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.ts b/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.ts index 2b3bb3e934..4c6f0ff885 100644 --- a/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.ts +++ b/src/app/+workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component.ts @@ -1,5 +1,15 @@ import { Component, OnInit } from '@angular/core'; import { WorkflowItem } from '../../core/submission/models/workflowitem.model'; +import { Item } from '../../core/shared/item.model'; +import { Observable } from 'rxjs'; +import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../core/shared/operators'; +import { RemoteData } from '../../core/data/remote-data'; +import { ActivatedRoute, Data, Router } from '@angular/router'; +import { map, switchMap, take } from 'rxjs/operators'; +import { WorkflowItemDataService } from '../../core/submission/workflowitem-data.service'; +import { TranslateService } from '@ngx-translate/core'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { RouteService } from '../../core/services/route.service'; @Component({ selector: 'ds-workflow-item-delete', @@ -7,10 +17,42 @@ import { WorkflowItem } from '../../core/submission/models/workflowitem.model'; styleUrls: ['./workflow-item-delete.component.scss'] }) export class WorkflowItemDeleteComponent implements OnInit { - wfi: WorkflowItem; - constructor() { } + public wfi$: Observable; + public item$: Observable; - ngOnInit() { + constructor(private route: ActivatedRoute, + private workflowItemService: WorkflowItemDataService, + private router: Router, + private routeService: RouteService, + private notificationsService: NotificationsService, + private translationService: TranslateService) { } + ngOnInit() { + this.route.data.subscribe((t) => console.log(t)); + this.wfi$ = this.route.data.pipe(map((data: Data) => data.wfi as RemoteData), getRemoteDataPayload()); + this.item$ = this.wfi$.pipe(switchMap((wfi: WorkflowItem) => (wfi.item as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()))); + } + + delete() { + this.wfi$.pipe( + take(1), + switchMap((wfi: WorkflowItem) => this.workflowItemService.delete(wfi.id)) + ).subscribe((successful: boolean) => { + if (successful) { + const title = this.translationService.get('workflowitem.delete.notification.success.title'); + const content = this.translationService.get('workflowitem.delete.notification.success.content'); + this.notificationsService.success(title, content) + } else { + const title = this.translationService.get('workflowitem.delete.notification.error.title'); + const content = this.translationService.get('workflowitem.delete.notification.error.content'); + this.notificationsService.error(title, content) + } + this.previousPage(); + }) + } + + previousPage() { + this.routeService.getPreviousUrl(); + } } diff --git a/src/app/+workflowitems-edit-page/workflow-item-page.resolver.ts b/src/app/+workflowitems-edit-page/workflow-item-page.resolver.ts new file mode 100644 index 0000000000..5ae11efff6 --- /dev/null +++ b/src/app/+workflowitems-edit-page/workflow-item-page.resolver.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; +import { RemoteData } from '../core/data/remote-data'; +import { ItemDataService } from '../core/data/item-data.service'; +import { Item } from '../core/shared/item.model'; +import { hasValue } from '../shared/empty.util'; +import { find } from 'rxjs/operators'; +import { followLink } from '../shared/utils/follow-link-config.model'; +import { WorkflowItemDataService } from '../core/submission/workflowitem-data.service'; +import { WorkflowItem } from '../core/submission/models/workflowitem.model'; + +/** + * This class represents a resolver that requests a specific item before the route is activated + */ +@Injectable() +export class WorkflowItemPageResolver implements Resolve> { + constructor(private workflowItemService: WorkflowItemDataService) { + } + + /** + * Method for resolving an item based on the parameters in the current route + * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot + * @param {RouterStateSnapshot} state The current RouterStateSnapshot + * @returns Observable<> Emits the found item based on the parameters in the current route, + * or an error if something went wrong + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable> { + return this.workflowItemService.findById(route.params.id, + followLink('item'), + ).pipe( + find((RD) => hasValue(RD.error) || RD.hasSucceeded), + ); + } +} diff --git a/src/app/+workflowitems-edit-page/workflowitems-edit-page-routing.module.ts b/src/app/+workflowitems-edit-page/workflowitems-edit-page-routing.module.ts index d5df70698c..88402ec177 100644 --- a/src/app/+workflowitems-edit-page/workflowitems-edit-page-routing.module.ts +++ b/src/app/+workflowitems-edit-page/workflowitems-edit-page-routing.module.ts @@ -3,21 +3,64 @@ import { RouterModule } from '@angular/router'; import { AuthenticatedGuard } from '../core/auth/authenticated.guard'; import { SubmissionEditComponent } from '../submission/edit/submission-edit.component'; +import { URLCombiner } from '../core/url-combiner/url-combiner'; +import { getWorkflowItemModulePath } from '../app-routing.module'; +import { WorkflowItemDeleteComponent } from './workflow-item-delete/workflow-item-delete.component'; +import { WorkflowItemPageResolver } from './workflow-item-page.resolver'; + +export function getWorkflowItemPageRoute(wfiId: string) { + return new URLCombiner(getWorkflowItemModulePath(), wfiId).toString(); +} + +export function getWorkflowItemEditPath(wfiId: string) { + return new URLCombiner(getWorkflowItemModulePath(), wfiId, WORKFLOW_ITEM_EDIT_PATH).toString() +} + +export function getWorkflowItemDeletePath(wfiId: string) { + return new URLCombiner(getWorkflowItemModulePath(), wfiId, WORKFLOW_ITEM_DELETE_PATH).toString() +} + +export function getWorkflowItemSendBackPath(wfiId: string) { + return new URLCombiner(getWorkflowItemModulePath(), wfiId, WORKFLOW_ITEM_SEND_BACK_PATH).toString() +} + +const WORKFLOW_ITEM_EDIT_PATH = 'edit'; +const WORKFLOW_ITEM_DELETE_PATH = 'delete'; +const WORKFLOW_ITEM_SEND_BACK_PATH = 'sendback'; @NgModule({ imports: [ RouterModule.forChild([ - { path: '', redirectTo: '/home', pathMatch: 'full' }, { - canActivate: [AuthenticatedGuard], - path: ':id/edit', - component: SubmissionEditComponent, - data: { title: 'submission.edit.title' } - } - ]) - ] + path: ':id', + resolve: { wfi: WorkflowItemPageResolver }, + children: [ + { + canActivate: [AuthenticatedGuard], + path: WORKFLOW_ITEM_EDIT_PATH, + component: SubmissionEditComponent, + data: { title: 'submission.edit.title' } + }, + { + canActivate: [AuthenticatedGuard], + path: WORKFLOW_ITEM_DELETE_PATH, + component: WorkflowItemDeleteComponent, + data: { title: 'workflow-item.delete.title' } + }, + { + canActivate: [AuthenticatedGuard], + path: WORKFLOW_ITEM_SEND_BACK_PATH, + component: WorkflowItemDeleteComponent, + data: { title: 'workflow-item.sendback.title' } + } + ] + }] + ) + ], + providers: [WorkflowItemPageResolver] }) /** * This module defines the default component to load when navigating to the workflowitems edit page path. */ -export class WorkflowItemsEditPageRoutingModule { } +export class WorkflowItemsEditPageRoutingModule { +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 06811abd08..0ce8530bf2 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -41,6 +41,12 @@ export function getProfileModulePath() { return `/${PROFILE_MODULE_PATH}`; } +const WORKFLOW_ITEM_MODULE_PATH = 'workflowitems'; + +export function getWorkflowItemModulePath() { + return `/${WORKFLOW_ITEM_MODULE_PATH}`; +} + export function getDSOPath(dso: DSpaceObject): string { switch ((dso as any).type) { case Community.type.value: @@ -79,7 +85,7 @@ export function getDSOPath(dso: DSpaceObject): string { loadChildren: './+workspaceitems-edit-page/workspaceitems-edit-page.module#WorkspaceitemsEditPageModule' }, { - path: 'workflowitems', + path: WORKFLOW_ITEM_MODULE_PATH, loadChildren: './+workflowitems-edit-page/workflowitems-edit-page.module#WorkflowItemsEditPageModule' }, { diff --git a/src/app/core/submission/workflowitem-data.service.ts b/src/app/core/submission/workflowitem-data.service.ts index a2dfca5eb3..370b2df6dd 100644 --- a/src/app/core/submission/workflowitem-data.service.ts +++ b/src/app/core/submission/workflowitem-data.service.ts @@ -9,10 +9,14 @@ import { DataService } from '../data/data.service'; import { RequestService } from '../data/request.service'; import { WorkflowItem } from './models/workflowitem.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { FindListOptions } from '../data/request.models'; +import { DeleteByIDRequest, FindListOptions } from '../data/request.models'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { Observable } from 'rxjs'; +import { find, map } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { RequestEntry } from '../data/request.reducer'; /** * A service that provides methods to make REST requests with workflowitems endpoint. @@ -35,4 +39,38 @@ export class WorkflowItemDataService extends DataService { super(); } + /** + * Delete an existing Workspace Item on the server + * @param id The Workspace Item's id to be removed + * @return an observable that emits true when the deletion was successful, false when it failed + */ + delete(id: string): Observable { + return this.deleteWFI(id, true) + } + + sendBack(id: string): Observable { + return this.deleteWFI(id, false) + } + + private deleteWFI(id: string, expunge: boolean): Observable { + const requestId = this.requestService.generateRequestId(); + + const hrefObs = this.halService.getEndpoint(this.linkPath).pipe( + map((endpoint: string) => this.getIDHref(endpoint, id)), + map((endpoint: string) => endpoint + '?expunge=' + expunge) + ); + + hrefObs.pipe( + find((href: string) => hasValue(href)), + map((href: string) => { + const request = new DeleteByIDRequest(requestId, href, id); + this.requestService.configure(request); + }) + ).subscribe(); + + return this.requestService.getByUUID(requestId).pipe( + find((request: RequestEntry) => request.completed), + map((request: RequestEntry) => request.response.isSuccessful) + ); + } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 698d9c936c..88c26792ad 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -186,6 +186,7 @@ import { LogInPasswordComponent } from './log-in/methods/password/log-in-passwor import { LogInComponent } from './log-in/log-in.component'; import { MissingTranslationHelper } from './translate/missing-translation.helper'; import { ItemVersionsNoticeComponent } from './item/item-versions/notice/item-versions-notice.component'; +import { ModifyItemOverviewComponent } from '../+item-page/edit-item-page/modify-item-overview/modify-item-overview.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -357,7 +358,8 @@ const COMPONENTS = [ LogInContainerComponent, ItemVersionsComponent, PublicationSearchResultListElementComponent, - ItemVersionsNoticeComponent + ItemVersionsNoticeComponent, + ModifyItemOverviewComponent, ]; const ENTRY_COMPONENTS = [