mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-12 12:33:07 +00:00
83707: Implement feedback
This commit is contained in:
@@ -11,6 +11,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="font-weight-bold">{{'collection.source.controls.harvest.last' | translate}}</span>
|
<span class="font-weight-bold">{{'collection.source.controls.harvest.last' | translate}}</span>
|
||||||
|
<span>{{contentSource?.message ? contentSource?.message : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="font-weight-bold">{{'collection.source.controls.harvest.message' | translate}}</span>
|
||||||
<span>{{contentSource?.lastHarvested ? contentSource?.lastHarvested : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
<span>{{contentSource?.lastHarvested ? contentSource?.lastHarvested : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import { getTestScheduler } from 'jasmine-marbles';
|
|||||||
import { TestScheduler } from 'rxjs/testing';
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { VarDirective } from '../../../../shared/utils/var.directive';
|
import { VarDirective } from '../../../../shared/utils/var.directive';
|
||||||
|
import { ContentSourceSetSerializer } from '../../../../core/shared/content-source-set-serializer';
|
||||||
|
|
||||||
describe('CollectionSourceControlsComponent', () => {
|
describe('CollectionSourceControlsComponent', () => {
|
||||||
let comp: CollectionSourceControlsComponent;
|
let comp: CollectionSourceControlsComponent;
|
||||||
@@ -133,7 +134,7 @@ describe('CollectionSourceControlsComponent', () => {
|
|||||||
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
||||||
{name: '-g', value: null},
|
{name: '-g', value: null},
|
||||||
{name: '-a', value: contentSource.oaiSource},
|
{name: '-a', value: contentSource.oaiSource},
|
||||||
{name: '-i', value: contentSource.oaiSetId},
|
{name: '-i', value: new ContentSourceSetSerializer().Serialize(contentSource.oaiSetId)},
|
||||||
], []);
|
], []);
|
||||||
|
|
||||||
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
||||||
@@ -148,7 +149,19 @@ describe('CollectionSourceControlsComponent', () => {
|
|||||||
|
|
||||||
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
||||||
{name: '-r', value: null},
|
{name: '-r', value: null},
|
||||||
{name: '-e', value: 'dspacedemo+admin@gmail.com'},
|
{name: '-c', value: collection.uuid},
|
||||||
|
], []);
|
||||||
|
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
||||||
|
expect(notificationsService.success).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('resetAndReimport', () => {
|
||||||
|
it('should invoke a script that will start the harvest', () => {
|
||||||
|
comp.resetAndReimport();
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect(scriptDataService.invoke).toHaveBeenCalledWith('harvest', [
|
||||||
|
{name: '-o', value: null},
|
||||||
{name: '-c', value: collection.uuid},
|
{name: '-c', value: collection.uuid},
|
||||||
], []);
|
], []);
|
||||||
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
expect(processDataService.findById).toHaveBeenCalledWith(process.processId, false);
|
||||||
|
@@ -21,6 +21,7 @@ import { Process } from '../../../../process-page/processes/process.model';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
|
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
|
||||||
|
import { ContentSourceSetSerializer } from '../../../../core/shared/content-source-set-serializer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that contains the controls to run, reset and test the harvest
|
* Component that contains the controls to run, reset and test the harvest
|
||||||
@@ -77,7 +78,7 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
|||||||
this.subs.push(this.scriptDataService.invoke('harvest', [
|
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||||
{name: '-g', value: null},
|
{name: '-g', value: null},
|
||||||
{name: '-a', value: contentSource.oaiSource},
|
{name: '-a', value: contentSource.oaiSource},
|
||||||
{name: '-i', value: contentSource.oaiSetId},
|
{name: '-i', value: new ContentSourceSetSerializer().Serialize(contentSource.oaiSetId)},
|
||||||
], []).pipe(
|
], []).pipe(
|
||||||
getFirstCompletedRemoteData(),
|
getFirstCompletedRemoteData(),
|
||||||
tap((rd) => {
|
tap((rd) => {
|
||||||
@@ -124,14 +125,15 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
|||||||
importNow() {
|
importNow() {
|
||||||
this.subs.push(this.scriptDataService.invoke('harvest', [
|
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||||
{name: '-r', value: null},
|
{name: '-r', value: null},
|
||||||
{name: '-e', value: 'dspacedemo+admin@gmail.com'},
|
|
||||||
{name: '-c', value: this.collection.uuid},
|
{name: '-c', value: this.collection.uuid},
|
||||||
], [])
|
], [])
|
||||||
.pipe(
|
.pipe(
|
||||||
getFirstCompletedRemoteData(),
|
getFirstCompletedRemoteData(),
|
||||||
tap((rd) => {
|
tap((rd) => {
|
||||||
if (rd.hasFailed) {
|
if (rd.hasFailed) {
|
||||||
this.notificationsService.error(this.translateService.get('collection.source.controls.test.submit.error'));
|
this.notificationsService.error(this.translateService.get('collection.source.controls.import.submit.error'));
|
||||||
|
} else {
|
||||||
|
this.notificationsService.success(this.translateService.get('collection.source.controls.import.submit.success'));
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
||||||
@@ -164,7 +166,43 @@ export class CollectionSourceControlsComponent implements OnDestroy {
|
|||||||
* Reset and reimport the current collection
|
* Reset and reimport the current collection
|
||||||
*/
|
*/
|
||||||
resetAndReimport() {
|
resetAndReimport() {
|
||||||
// TODO implement when a single option is present
|
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||||
|
{name: '-o', value: null},
|
||||||
|
{name: '-c', value: this.collection.uuid},
|
||||||
|
], [])
|
||||||
|
.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
tap((rd) => {
|
||||||
|
if (rd.hasFailed) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.reset.submit.error'));
|
||||||
|
} else {
|
||||||
|
this.notificationsService.success(this.translateService.get('collection.source.controls.reset.submit.success'));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
||||||
|
switchMap((rd) => this.processDataService.findById(rd.payload.processId, false)),
|
||||||
|
getAllCompletedRemoteData(),
|
||||||
|
filter((rd) => !rd.isStale && (rd.hasSucceeded || rd.hasFailed)),
|
||||||
|
map((rd) => rd.payload),
|
||||||
|
hasValueOperator(),
|
||||||
|
).subscribe((process) => {
|
||||||
|
if (process.processStatus.toString() !== ProcessStatus[ProcessStatus.COMPLETED].toString() &&
|
||||||
|
process.processStatus.toString() !== ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
// Ping the current process state every 5s
|
||||||
|
setTimeout(() => {
|
||||||
|
this.requestService.setStaleByHrefSubstring(process._links.self.href);
|
||||||
|
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.reset.failed'));
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.COMPLETED].toString()) {
|
||||||
|
this.notificationsService.success(this.translateService.get('collection.source.controls.reset.completed'));
|
||||||
|
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
26
src/app/core/shared/content-source-set-serializer.spec.ts
Normal file
26
src/app/core/shared/content-source-set-serializer.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { ContentSourceSetSerializer } from './content-source-set-serializer';
|
||||||
|
|
||||||
|
describe('ContentSourceSetSerializer', () => {
|
||||||
|
let serializer: ContentSourceSetSerializer;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
serializer = new ContentSourceSetSerializer();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Serialize', () => {
|
||||||
|
it('should return all when the value is empty', () => {
|
||||||
|
expect(serializer.Serialize('')).toEqual('all');
|
||||||
|
});
|
||||||
|
it('should return the value when it is not empty', () => {
|
||||||
|
expect(serializer.Serialize('test-value')).toEqual('test-value');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Deserialize', () => {
|
||||||
|
it('should return an empty value when the value is \'all\'', () => {
|
||||||
|
expect(serializer.Deserialize('all')).toEqual('');
|
||||||
|
});
|
||||||
|
it('should return the value when it is not \'all\'', () => {
|
||||||
|
expect(serializer.Deserialize('test-value')).toEqual('test-value');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
31
src/app/core/shared/content-source-set-serializer.ts
Normal file
31
src/app/core/shared/content-source-set-serializer.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { isEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializer to create convert the 'all' value supported by the server to an empty string and vice versa.
|
||||||
|
*/
|
||||||
|
export class ContentSourceSetSerializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to serialize a setId
|
||||||
|
* @param {string} setId
|
||||||
|
* @returns {string} the provided set ID, unless when an empty set ID is provided. In that case, 'all' will be returned.
|
||||||
|
*/
|
||||||
|
Serialize(setId: string): any {
|
||||||
|
if (isEmpty(setId)) {
|
||||||
|
return 'all';
|
||||||
|
}
|
||||||
|
return setId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to deserialize a setId
|
||||||
|
* @param {string} setId
|
||||||
|
* @returns {string} the provided set ID. When 'all' is provided, an empty set ID will be returned.
|
||||||
|
*/
|
||||||
|
Deserialize(setId: string): string {
|
||||||
|
if (setId === 'all') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return setId;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
import { autoserializeAs, deserializeAs, deserialize } from 'cerialize';
|
import { autoserializeAs, deserializeAs, deserialize, serializeAs } from 'cerialize';
|
||||||
import { HALLink } from './hal-link.model';
|
import { HALLink } from './hal-link.model';
|
||||||
import { MetadataConfig } from './metadata-config.model';
|
import { MetadataConfig } from './metadata-config.model';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
@@ -6,6 +6,8 @@ import { typedObject } from '../cache/builders/build-decorators';
|
|||||||
import { CONTENT_SOURCE } from './content-source.resource-type';
|
import { CONTENT_SOURCE } from './content-source.resource-type';
|
||||||
import { excludeFromEquals } from '../utilities/equals.decorators';
|
import { excludeFromEquals } from '../utilities/equals.decorators';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
|
import { IDToUUIDSerializer } from '../cache/id-to-uuid-serializer';
|
||||||
|
import { ContentSourceSetSerializer } from './content-source-set-serializer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of content harvesting used
|
* The type of content harvesting used
|
||||||
@@ -49,7 +51,8 @@ export class ContentSource extends CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* OAI Specific set ID
|
* OAI Specific set ID
|
||||||
*/
|
*/
|
||||||
@autoserializeAs('oai_set_id')
|
@deserializeAs(new ContentSourceSetSerializer(), 'oai_set_id')
|
||||||
|
@serializeAs(new ContentSourceSetSerializer(), 'oai_set_id')
|
||||||
oaiSetId: string;
|
oaiSetId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,15 +73,30 @@ export class ContentSource extends CacheableObject {
|
|||||||
*/
|
*/
|
||||||
metadataConfigs: MetadataConfig[];
|
metadataConfigs: MetadataConfig[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current harvest status
|
||||||
|
*/
|
||||||
@autoserializeAs('harvest_status')
|
@autoserializeAs('harvest_status')
|
||||||
harvestStatus: string;
|
harvestStatus: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last's harvest start time
|
||||||
|
*/
|
||||||
@autoserializeAs('harvest_start_time')
|
@autoserializeAs('harvest_start_time')
|
||||||
harvestStartTime: string;
|
harvestStartTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the collection was last harvested
|
||||||
|
*/
|
||||||
@autoserializeAs('last_harvested')
|
@autoserializeAs('last_harvested')
|
||||||
lastHarvested: string;
|
lastHarvested: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current harvest message
|
||||||
|
*/
|
||||||
|
@autoserializeAs('harvest_message')
|
||||||
|
message: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink}s for this ContentSource
|
* The {@link HALLink}s for this ContentSource
|
||||||
*/
|
*/
|
||||||
|
@@ -891,10 +891,15 @@
|
|||||||
"collection.source.controls.import.submit": "Import now",
|
"collection.source.controls.import.submit": "Import now",
|
||||||
"collection.source.controls.import.failed": "An error occurred during the import",
|
"collection.source.controls.import.failed": "An error occurred during the import",
|
||||||
"collection.source.controls.import.completed": "The import completed",
|
"collection.source.controls.import.completed": "The import completed",
|
||||||
|
"collection.source.controls.reset.submit.success": "The reset and reimport has been successfully initiated",
|
||||||
|
"collection.source.controls.reset.submit.error": "Something went wrong with initiating the reset and reimport",
|
||||||
|
"collection.source.controls.reset.failed": "An error occurred during the reset and reimport",
|
||||||
|
"collection.source.controls.reset.completed": "The reset and reimport completed",
|
||||||
"collection.source.controls.reset.submit": "Reset and reimport",
|
"collection.source.controls.reset.submit": "Reset and reimport",
|
||||||
"collection.source.controls.harvest.status": "Harvest status:",
|
"collection.source.controls.harvest.status": "Harvest status:",
|
||||||
"collection.source.controls.harvest.start": "Harvest start time:",
|
"collection.source.controls.harvest.start": "Harvest start time:",
|
||||||
"collection.source.controls.harvest.last": "Last time harvested:",
|
"collection.source.controls.harvest.last": "Last time harvested:",
|
||||||
|
"collection.source.controls.harvest.message": "Harvest info:",
|
||||||
"collection.source.controls.harvest.no-information": "N/A",
|
"collection.source.controls.harvest.no-information": "N/A",
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user