|
| 1 | +import { Component, EventEmitter, Input, OnDestroy, OnInit } from '@angular/core'; |
| 2 | + |
| 3 | + |
| 4 | +import { hasValue } from '../../../shared/empty.util'; |
| 5 | +import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; |
| 6 | +import { combineLatest, Observable, Subscription } from 'rxjs'; |
| 7 | +import { PoolTaskSearchResult } from '../../../shared/object-collection/shared/pool-task-search-result.model'; |
| 8 | +import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service'; |
| 9 | +import { PoolTaskDataService } from '../../../core/tasks/pool-task-data.service'; |
| 10 | +import { ClaimedTaskDataService } from '../../../core/tasks/claimed-task-data.service'; |
| 11 | +import { ProcessTaskResponse } from '../../../core/tasks/models/process-task-response'; |
| 12 | +import { NotificationsService } from '../../../shared/notifications/notifications.service'; |
| 13 | +import { NotificationOptions } from '../../../shared/notifications/models/notification-options.model'; |
| 14 | +import { TranslateService } from '@ngx-translate/core'; |
| 15 | +import { Router } from '@angular/router'; |
| 16 | +import { SearchService } from '../../../core/shared/search/search.service'; |
| 17 | +import { RequestService } from '../../../core/data/request.service'; |
| 18 | +import { ClaimedTaskSearchResult } from '../../../shared/object-collection/shared/claimed-task-search-result.model'; |
| 19 | +import { |
| 20 | + WORKFLOW_TASK_OPTION_APPROVE |
| 21 | +} from '../../../shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component'; |
| 22 | + |
| 23 | + |
| 24 | +/** |
| 25 | + * This gives the option to perform bulk action on workflow items |
| 26 | + */ |
| 27 | +@Component({ |
| 28 | + selector: 'ds-my-dspace-bulk-action', |
| 29 | + templateUrl: './my-dspace-bulk-action.component.html' |
| 30 | +}) |
| 31 | +export class MyDSpaceBulkActionComponent implements OnInit, OnDestroy{ |
| 32 | + |
| 33 | + @Input() |
| 34 | + listId: string; |
| 35 | + |
| 36 | + processing$: EventEmitter<boolean> = new EventEmitter<boolean>(); |
| 37 | + |
| 38 | + claimEnabled$: Observable<boolean>; |
| 39 | + claimedTaskActionsEnabled$: Observable<boolean>; |
| 40 | + |
| 41 | + private successfullItems = 0; |
| 42 | + private errorItems = 0; |
| 43 | + private subs: Subscription[] = []; |
| 44 | + |
| 45 | + private readonly approveOption = WORKFLOW_TASK_OPTION_APPROVE; |
| 46 | + |
| 47 | + constructor( |
| 48 | + protected selectableListService: SelectableListService, |
| 49 | + protected poolTaskDataService: PoolTaskDataService, |
| 50 | + protected claimedTaskService: ClaimedTaskDataService, |
| 51 | + protected notificationsService: NotificationsService, |
| 52 | + protected translate: TranslateService, |
| 53 | + protected router: Router, |
| 54 | + protected searchService: SearchService, |
| 55 | + protected requestService: RequestService, |
| 56 | + ) { } |
| 57 | + |
| 58 | + ngOnInit() { |
| 59 | + this.claimEnabled$ = this.getActionEnabled('claimaction'); |
| 60 | + this.claimedTaskActionsEnabled$ = this.getActionEnabled('claimedtask'); |
| 61 | + this.getSelectedList().subscribe(console.log); |
| 62 | + } |
| 63 | + |
| 64 | + ngOnDestroy() { |
| 65 | + if (hasValue(this.subs)) { |
| 66 | + this.subs.forEach(sub => sub.unsubscribe()); |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + claimAllSelectedTask() { |
| 71 | + this.subs.push( |
| 72 | + this.getSelectedList().pipe( |
| 73 | + take(1), |
| 74 | + map(list => list.map(item => |
| 75 | + this.poolTaskDataService.getPoolTaskEndpointById(item.indexableObject.id) |
| 76 | + ) |
| 77 | + ), |
| 78 | + switchMap(endPoints => combineLatest(...endPoints)), |
| 79 | + map(tasksHref => tasksHref.filter(data => hasValue(data)) |
| 80 | + .map(href => this.claimItemByHref(href)) |
| 81 | + ), |
| 82 | + switchMap(claims => combineLatest(...claims)) |
| 83 | + ).subscribe(() => { |
| 84 | + this.handlePageReload(); |
| 85 | + }) |
| 86 | + ); |
| 87 | + } |
| 88 | + |
| 89 | + getSelectedList(): Observable<PoolTaskSearchResult[] | ClaimedTaskSearchResult[]> { |
| 90 | + return this.selectableListService.getSelectableList(this.listId).pipe( |
| 91 | + filter(data => !!data), |
| 92 | + distinctUntilChanged(), |
| 93 | + map(task => task.selection as (PoolTaskSearchResult[] | ClaimedTaskSearchResult[])), |
| 94 | + ); |
| 95 | + } |
| 96 | + |
| 97 | + getActionEnabled(actionType: string): Observable<boolean> { |
| 98 | + return this.getSelectedList().pipe( |
| 99 | + map(list => list.map( |
| 100 | + item => (item._embedded.indexableObject.action || item._embedded.indexableObject.type) as any as string |
| 101 | + ).some( |
| 102 | + action => action === actionType |
| 103 | + ) |
| 104 | + ), |
| 105 | + ); |
| 106 | + } |
| 107 | + |
| 108 | + claimItemByHref(href: string): Observable<ProcessTaskResponse> { |
| 109 | + const id = href.substring(href.lastIndexOf('/') + 1, href.length); |
| 110 | + return this.getSelectedList().pipe( |
| 111 | + take(1), |
| 112 | + map(list => list.find(item => item.indexableObject.id.toString() === id)), |
| 113 | + switchMap(item => this.claimedTaskService.claimTask(item.indexableObject.id, href)), |
| 114 | + map((response) => { |
| 115 | + if (response.hasSucceeded) { |
| 116 | + this.successfullItems += 1; |
| 117 | + } else { |
| 118 | + this.errorItems += 1; |
| 119 | + } |
| 120 | + |
| 121 | + return response; |
| 122 | + }) |
| 123 | + ); |
| 124 | + } |
| 125 | + |
| 126 | + |
| 127 | + approveItem(id: string, options): Observable<ProcessTaskResponse> { |
| 128 | + return this.claimedTaskService.submitTask(id, options).pipe( |
| 129 | + take(1), |
| 130 | + map((response) => { |
| 131 | + if (response.hasSucceeded) { |
| 132 | + this.successfullItems += 1; |
| 133 | + } else { |
| 134 | + this.errorItems += 1; |
| 135 | + } |
| 136 | + |
| 137 | + return response; |
| 138 | + }) |
| 139 | + ); |
| 140 | + } |
| 141 | + |
| 142 | + notifyOperationStatus(succeeded: boolean, itemNumber: number) { |
| 143 | + if (succeeded) { |
| 144 | + this.notificationsService.success(null, |
| 145 | + this.translate.get('submission.workflow.tasks.bulk.item.success', {itemNumber}), |
| 146 | + new NotificationOptions(5000, false) |
| 147 | + ); |
| 148 | + } else { |
| 149 | + this.notificationsService.error(null, |
| 150 | + this.translate.get('submission.workflow.tasks.bulk.item.error', {itemNumber}), |
| 151 | + new NotificationOptions(20000, true)); |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + reload(): void { |
| 156 | + this.router.navigated = false; |
| 157 | + const url = decodeURIComponent(this.router.url); |
| 158 | + // override the route reuse strategy |
| 159 | + this.router.routeReuseStrategy.shouldReuseRoute = () => { |
| 160 | + return false; |
| 161 | + }; |
| 162 | + // This assures that the search cache is empty before reloading mydspace. |
| 163 | + // See https://github.com/DSpace/dspace-angular/pull/468 |
| 164 | + this.searchService.getEndpoint().pipe( |
| 165 | + take(1), |
| 166 | + tap((cachedHref: string) => this.requestService.removeByHrefSubstring(cachedHref)) |
| 167 | + ).subscribe(() => this.router.navigateByUrl(url)); |
| 168 | + } |
| 169 | + |
| 170 | + handlePageReload(): void { |
| 171 | + if ( this.successfullItems > 0) { |
| 172 | + this.notifyOperationStatus(true, this.successfullItems); |
| 173 | + } |
| 174 | + if (this.errorItems > 0) { |
| 175 | + this.notifyOperationStatus(false, this.errorItems); |
| 176 | + } |
| 177 | + this.successfullItems = 0; |
| 178 | + this.errorItems = 0; |
| 179 | + this.selectableListService.deselectAll(this.listId); |
| 180 | + this.reload(); |
| 181 | + } |
| 182 | + |
| 183 | + submitAllSelectedTask() { |
| 184 | + this.subs.push( |
| 185 | + this.getSelectedList().pipe( |
| 186 | + take(1), |
| 187 | + map(list => list.map(item => this.approveItem(item.indexableObject.id, { |
| 188 | + [this.approveOption]: 'true' |
| 189 | + })) |
| 190 | + ), |
| 191 | + switchMap(submissions => combineLatest(...submissions)) |
| 192 | + ).subscribe(() => { |
| 193 | + this.handlePageReload(); |
| 194 | + }) |
| 195 | + ); |
| 196 | + } |
| 197 | +} |
0 commit comments