Final commit detect duplicate

This commit is contained in:
Giuseppe
2018-10-03 10:33:54 +02:00
parent 25bb5fddf6
commit 6f4b9fc818
16 changed files with 461 additions and 506 deletions

View File

@@ -299,11 +299,11 @@
"submit.progressbar.describe.stepone": "Describe", "submit.progressbar.describe.stepone": "Describe",
"submit.progressbar.describe.steptwo": "Describe", "submit.progressbar.describe.steptwo": "Describe",
"submit.progressbar.describe.stepcustom": "Describe", "submit.progressbar.describe.stepcustom": "Describe",
"submit.progressbar.describe.deduplication": "Potential duplicates",
"submit.progressbar.describe.recycle": "Recycle", "submit.progressbar.describe.recycle": "Recycle",
"submit.progressbar.upload": "Upload files", "submit.progressbar.upload": "Upload files",
"submit.progressbar.license": "Deposit license", "submit.progressbar.license": "Deposit license",
"submit.progressbar.cclicense": "Creative commons license", "submit.progressbar.cclicense": "Creative commons license",
"submit.progressbar.detect-duplicate": "Potential duplicates",
"upload": { "upload": {
"info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or <strong>upload additional files just dragging&dropping them everywhere in the page</strong>", "info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or <strong>upload additional files just dragging&dropping them everywhere in the page</strong>",
@@ -321,20 +321,26 @@
"group-label": "Group" "group-label": "Group"
} }
}, },
"deduplication": { "detect-duplicate": {
"duplicated": "It's a duplicate", "duplicate-detected": "Potential duplicate detected",
"not_duplicated": "It's not a duplicate", "duplicate": "It's a duplicate",
"duplicated_ctrl": "Mark the record to merge", "not-duplicate": "It's not a duplicate",
"duplicated_help": "Click here if this is a duplicate of your item", "confirm-duplicate": "Confirm (It's a duplicate)",
"not_duplicated_help": "Click here if this is not a duplicate of your item", "confirm-not-duplicate": "Confirm (It's not a duplicate)",
"note_help": "Please enter your reason for the duplication into the box below.", "duplicate-ctrl": "Mark the record to merge",
"note_placeholder": "Describe the reason of duplication", "duplicate-help": "Click here if this is a duplicate of your item",
"clear_decision": "Undo", "not-duplicate-help": "Click here if this is not a duplicate of your item",
"clear_decision_help": "Click for clear the decision about this pontential duplicate", "note-help": "Please enter your reason for the duplication into the box below.",
"your_decision": "Your choice:", "note-placeholder": "Describe the reason of duplication",
"submitter_decision": "Submitter choice:", "clear-decision": "Undo",
"clear-decision-help": "Click for clear the decision about this pontential duplicate",
"decision-success-notice": "Choice registered successfully",
"no-decision": "No decision yet",
"submitter-decision": "Submitter decision:",
"submitter-note": "Submitter note:",
"disclaimer": "The system has identified some potential duplicates. Please carefully review the list and flag each occurency with the appropriate choice or discard this submission.", "disclaimer": "The system has identified some potential duplicates. Please carefully review the list and flag each occurency with the appropriate choice or discard this submission.",
"disclaimer_ctrl": "The system has identified some potential duplicates. Please carefully review the list and the submitter comments and perform the appropriate action." "disclaimer-ctrl": "The system has identified some potential duplicates. Please carefully review the list and the submitter comments and perform the appropriate action.",
"disclaimer-no-match": "All your feedback on potential duplicates have been registered correctly."
}, },
"recycle": { "recycle": {
"disclaimer": "The following existent information are not valid within the selected collection. Please copy them to the appropriate metadata if applicable. Use the discard button to remove these information when done." "disclaimer": "The following existent information are not valid within the selected collection. Please copy them to the appropriate metadata if applicable. Use the discard button to remove these information when done."

View File

@@ -1,14 +1,12 @@
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; import { Item } from '../../shared/item.model';
import { WorkspaceitemSectionUploadFileObject } from './workspaceitem-section-upload-file.model';
import { FormFieldChangedObject } from '../../../shared/form/builder/models/form-field-unexpected-object.model';
import { DSpaceObject } from '../../shared/dspace-object.model'; export interface WorkspaceitemSectionDetectDuplicateObject {
matches: {
export interface WorkspaceitemSectionDeduplicationObject { [itemId: string]: DetectDuplicateMatch;
matches: DeduplicationSchema[]; };
} }
export interface DeduplicationSchema { export interface DetectDuplicateMatch {
submitterDecision?: string; // [reject|verify] submitterDecision?: string; // [reject|verify]
submitterNote?: string; submitterNote?: string;
submitterTime?: string; // (readonly) submitterTime?: string; // (readonly)
@@ -17,5 +15,7 @@ export interface DeduplicationSchema {
workflowNote?: string; workflowNote?: string;
workflowTime?: string; // (readonly) workflowTime?: string; // (readonly)
matchObject?: DSpaceObject; // item, workspaceItem, workflowItem adminDecision?: string;
matchObject?: Item;
} }

View File

@@ -4,7 +4,7 @@ import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload
import { isNotEmpty, isNotNull } from '../../../shared/empty.util'; import { isNotEmpty, isNotNull } from '../../../shared/empty.util';
import { FormFieldLanguageValueObject } from '../../../shared/form/builder/models/form-field-language-value.model'; import { FormFieldLanguageValueObject } from '../../../shared/form/builder/models/form-field-language-value.model';
import { WorkspaceitemSectionRecycleObject } from './workspaceitem-section-recycle.model'; import { WorkspaceitemSectionRecycleObject } from './workspaceitem-section-recycle.model';
import { WorkspaceitemSectionDeduplicationObject } from './workspaceitem-section-deduplication.model'; import { WorkspaceitemSectionDetectDuplicateObject } from './workspaceitem-section-deduplication.model';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
export class WorkspaceitemSectionsObject { export class WorkspaceitemSectionsObject {
@@ -61,5 +61,5 @@ export type WorkspaceitemSectionDataType
| WorkspaceitemSectionFormObject | WorkspaceitemSectionFormObject
| WorkspaceitemSectionLicenseObject | WorkspaceitemSectionLicenseObject
| WorkspaceitemSectionRecycleObject | WorkspaceitemSectionRecycleObject
| WorkspaceitemSectionDeduplicationObject | WorkspaceitemSectionDetectDuplicateObject
| string; | string;

View File

@@ -52,12 +52,9 @@ export const SubmissionObjectActionTypes = {
DISCARD_SUBMISSION: type('dspace/submission/DISCARD_SUBMISSION'), DISCARD_SUBMISSION: type('dspace/submission/DISCARD_SUBMISSION'),
DISCARD_SUBMISSION_SUCCESS: type('dspace/submission/DISCARD_SUBMISSION_SUCCESS'), DISCARD_SUBMISSION_SUCCESS: type('dspace/submission/DISCARD_SUBMISSION_SUCCESS'),
DISCARD_SUBMISSION_ERROR: type('dspace/submission/DISCARD_SUBMISSION_ERROR'), DISCARD_SUBMISSION_ERROR: type('dspace/submission/DISCARD_SUBMISSION_ERROR'),
SET_WORKSPACE_DUPLICATION: type('/sections/deduplication/SET_WORKSPACE_DUPLICATION'), SET_DUPLICATE_DECISION: type('dspace/submission/SET_DUPLICATE_DECISION'),
SET_WORKSPACE_DUPLICATION_SUCCESS: type('/sections/deduplication/SET_WORKSPACE_DUPLICATION_SUCCESS'), SET_DUPLICATE_DECISION_SUCCESS: type('dspace/submission/SET_DUPLICATE_DECISION_SUCCESS'),
SET_WORKSPACE_DUPLICATION_ERROR: type('/sections/deduplication/SET_WORKSPACE_DUPLICATION_ERROR'), SET_DUPLICATE_DECISION_ERROR: type('dspace/submission/SET_DUPLICATE_DECISION_ERROR'),
SET_WORKFLOW_DUPLICATION: type('/sections/deduplication/SET_WORKFLOW_DUPLICATION'),
SET_WORKFLOW_DUPLICATION_SUCCESS: type('/sections/deduplication/SET_WORKFLOW_DUPLICATION_SUCCESS'),
SET_WORKFLOW_DUPLICATION_ERROR: type('/sections/deduplication/SET_WORKFLOW_DUPLICATION_ERROR'),
// Upload file types // Upload file types
NEW_FILE: type('dspace/submission/NEW_FILE'), NEW_FILE: type('dspace/submission/NEW_FILE'),
@@ -763,129 +760,63 @@ export class DeleteUploadedFileAction implements Action {
} }
} }
export class SetWorkspaceDuplicatedAction implements Action { export class SetDuplicateDecisionAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION; type = SubmissionObjectActionTypes.SET_DUPLICATE_DECISION;
payload: { payload: {
index: number; submissionId: string;
decision: string; sectionId: string;
note?: string
}; };
/** /**
* Create a new SetWorkspaceDuplicatedAction * Create a new SetDuplicateDecisionAction
* *
* @param index * @param submissionId
* the index in matches array * the submission's ID
* @param decision * @param sectionId
* the submitter's decision ('verify'|'reject'|null) * the section's ID
* @param note
* the submitter's note, for 'verify' decision only
*/ */
constructor(payload: any) { constructor(submissionId: string, sectionId: string) {
this.payload = payload; this.payload = { submissionId, sectionId };
} }
} }
export class SetWorkspaceDuplicatedSuccessAction implements Action { export class SetDuplicateDecisionSuccessAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION_SUCCESS; type = SubmissionObjectActionTypes.SET_DUPLICATE_DECISION_SUCCESS;
payload: { payload: {
index: number; submissionId: string;
decision: string; sectionId: string;
note?: string submissionObject: SubmissionObject[];
}; };
/** /**
* Create a new SetWorkspaceDuplicatedSuccessAction * Create a new SetDuplicateDecisionSuccessAction
* *
* @param index * @param submissionId
* the index in matches array * the submission's ID
* @param decision * @param sectionId
* the submitter's decision ('verify'|'reject'|null) * the section's ID
* @param note * @param submissionObjects
* the submitter's note, for 'verify' decision only * the submission's Object
*/ */
constructor(payload: any) { constructor(submissionId: string, sectionId: string, submissionObject: SubmissionObject[]) {
this.payload = payload; this.payload = { submissionId, sectionId, submissionObject };
} }
} }
export class SetWorkspaceDuplicatedErrorAction implements Action { export class SetDuplicateDecisionErrorAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION_ERROR; type = SubmissionObjectActionTypes.SET_DUPLICATE_DECISION_ERROR;
payload: { payload: {
index: number; submissionId: string;
}; };
/** /**
* Create a new SetWorkspaceDuplicatedErrorAction * Create a new SetDuplicateDecisionErrorAction
* *
* @param index * @param submissionId
* the index in matches array * the submission's ID
*/ */
constructor(index: number) { constructor(submissionId: string) {
this.payload = { index }; this.payload = { submissionId };
}
}
export class SetWorkflowDuplicatedAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION;
payload: {
index: number;
decision: string;
note?: string
};
/**
* Create a new SetWorkflowDuplicatedAction
*
* @param index
* the index in matches array
* @param decision
* the controller's decision ('verify'|'reject'|null)
* @param note
* the controller's note, for 'verify' decision only
*/
constructor(payload: any) {
this.payload = payload;
}
}
export class SetWorkflowDuplicatedSuccessAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION_SUCCESS;
payload: {
index: number;
decision: string;
note?: string
};
/**
* Create a new SetWorkflowDuplicatedSuccessAction
*
* @param index
* the index in matches array
* @param decision
* the controller's decision ('verify'|'reject'|null)
* @param note
* the controller's note, for 'verify' decision only
*/
constructor(payload: any) {
this.payload = payload;
}
}
export class SetWorkflowDuplicatedErrorAction implements Action {
type = SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION_ERROR;
payload: {
index: number;
};
/**
* Create a new SetWorkflowDuplicatedErrorAction
*
* @param index
* the index in matches array
*/
constructor(index: number) {
this.payload = { index };
} }
} }
@@ -928,9 +859,6 @@ export type SubmissionObjectAction = DisableSectionAction
| SaveSubmissionSectionFormSuccessAction | SaveSubmissionSectionFormSuccessAction
| SaveSubmissionSectionFormErrorAction | SaveSubmissionSectionFormErrorAction
| SetActiveSectionAction | SetActiveSectionAction
| SetWorkspaceDuplicatedAction | SetDuplicateDecisionAction
| SetWorkspaceDuplicatedSuccessAction | SetDuplicateDecisionSuccessAction
| SetWorkspaceDuplicatedErrorAction | SetDuplicateDecisionErrorAction;
| SetWorkflowDuplicatedAction
| SetWorkflowDuplicatedSuccessAction
| SetWorkflowDuplicatedErrorAction;

View File

@@ -22,12 +22,7 @@ import {
SaveSubmissionSectionFormAction, SaveSubmissionSectionFormAction,
SaveSubmissionSectionFormErrorAction, SaveSubmissionSectionFormErrorAction,
SaveSubmissionSectionFormSuccessAction, SaveSubmissionSectionFormSuccessAction,
SetWorkflowDuplicatedAction, SetDuplicateDecisionAction, SetDuplicateDecisionErrorAction, SetDuplicateDecisionSuccessAction,
SetWorkflowDuplicatedErrorAction,
SetWorkflowDuplicatedSuccessAction,
SetWorkspaceDuplicatedAction,
SetWorkspaceDuplicatedErrorAction,
SetWorkspaceDuplicatedSuccessAction,
SubmissionObjectActionTypes, SubmissionObjectActionTypes,
UpdateSectionDataAction UpdateSectionDataAction
} from './submission-objects.actions'; } from './submission-objects.actions';
@@ -43,11 +38,13 @@ import { Workflowitem } from '../../core/submission/models/workflowitem.model';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { SubmissionObject } from '../../core/submission/models/submission-object.model'; import { SubmissionObject } from '../../core/submission/models/submission-object.model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DeduplicationService } from '../sections/deduplication/deduplication.service'; import { DetectDuplicateService } from '../sections/detect-duplicate/detect-duplicate.service';
import { SubmissionState } from '../submission.reducers'; import { SubmissionState } from '../submission.reducers';
import { SubmissionObjectEntry } from './submission-objects.reducer'; import { SubmissionObjectEntry } from './submission-objects.reducer';
import { SubmissionSectionModel } from '../../core/shared/config/config-submission-section.model'; import { SubmissionSectionModel } from '../../core/shared/config/config-submission-section.model';
import parseSectionErrors from '../utils/parseSectionErrors'; import parseSectionErrors from '../utils/parseSectionErrors';
import { SectionsType } from '../sections/sections-type';
import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
@Injectable() @Injectable()
export class SubmissionObjectEffects { export class SubmissionObjectEffects {
@@ -60,7 +57,7 @@ export class SubmissionObjectEffects {
definition.sections.forEach((sectionDefinition: SubmissionSectionModel, index: number) => { definition.sections.forEach((sectionDefinition: SubmissionSectionModel, index: number) => {
const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1); const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1);
const config = sectionDefinition._links.config || ''; const config = sectionDefinition._links.config || '';
const enabled = sectionDefinition.mandatory || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId)); const enabled = (sectionDefinition.mandatory && sectionDefinition.sectionType !== SectionsType.DetectDuplicate) || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId));
const sectionData = (isNotUndefined(action.payload.sections) && isNotUndefined(action.payload.sections[sectionId])) ? action.payload.sections[sectionId] : Object.create(null); const sectionData = (isNotUndefined(action.payload.sections) && isNotUndefined(action.payload.sections[sectionId])) ? action.payload.sections[sectionId] : Object.create(null);
const sectionErrors = null; const sectionErrors = null;
mappedActions.push( mappedActions.push(
@@ -127,9 +124,7 @@ export class SubmissionObjectEffects {
.map(([action, currentState]: [SaveSubmissionFormSuccessAction | SaveSubmissionSectionFormSuccessAction, any]) => { .map(([action, currentState]: [SaveSubmissionFormSuccessAction | SaveSubmissionSectionFormSuccessAction, any]) => {
return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId], action.payload.submissionObject, action.payload.submissionId); return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId], action.payload.submissionObject, action.payload.submissionId);
}) })
.mergeMap((actions) => { .mergeMap((actions) => Observable.from(actions));
return Observable.from(actions);
});
@Effect() saveSection$ = this.actions$ @Effect() saveSection$ = this.actions$
.ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_SECTION_FORM) .ofType(SubmissionObjectActionTypes.SAVE_SUBMISSION_SECTION_FORM)
@@ -143,6 +138,31 @@ export class SubmissionObjectEffects {
.catch(() => Observable.of(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId))); .catch(() => Observable.of(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId)));
}); });
@Effect() saveDuplicateDecision$ = this.actions$
.ofType(SubmissionObjectActionTypes.SET_DUPLICATE_DECISION)
.switchMap((action: SetDuplicateDecisionAction) => {
return this.operationsService.jsonPatchByResourceID(
this.submissionService.getSubmissionObjectLinkName(),
action.payload.submissionId,
'sections',
action.payload.sectionId)
.map((response: SubmissionObject[]) => new SetDuplicateDecisionSuccessAction(action.payload.submissionId, action.payload.sectionId, response))
.catch(() => Observable.of(new SetDuplicateDecisionErrorAction(action.payload.submissionId)));
});
@Effect({dispatch: false}) setDuplicateDecisionSuccess$ = this.actions$
.ofType(SubmissionObjectActionTypes.SET_DUPLICATE_DECISION_SUCCESS)
.do(() => this.notificationsService.success(null, this.translate.get('submission.sections.detect-duplicate.decision-success-notice')));
/* @Effect() setDuplicateDecisionSuccess$ = this.actions$
.ofType(SubmissionObjectActionTypes.SET_DUPLICATE_DECISION_SUCCESS)
.withLatestFrom(this.store$)
.map(([action, currentState]: [SetDuplicateDecisionSuccessAction, any]) => {
this.notificationsService.success(null, this.translate.get('submission.sections.detect-duplicate.decision-success-notice'));
return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId], action.payload.submissionObject, action.payload.submissionId, false);
})
.mergeMap((actions) => Observable.from(actions));*/
@Effect() saveAndDepositSection$ = this.actions$ @Effect() saveAndDepositSection$ = this.actions$
.ofType(SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION) .ofType(SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION)
.withLatestFrom(this.store$) .withLatestFrom(this.store$)
@@ -202,79 +222,13 @@ export class SubmissionObjectEffects {
.ofType(SubmissionObjectActionTypes.DISCARD_SUBMISSION_ERROR) .ofType(SubmissionObjectActionTypes.DISCARD_SUBMISSION_ERROR)
.do(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.discard_error_notice'))); .do(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.discard_error_notice')));
@Effect()
public wsDuplication: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION)
.map((action: SetWorkspaceDuplicatedAction) => {
// return this.deduplicationService.setWorkspaceDuplicated(action.payload)
// .first()
// .map((response) => {
console.log('Effect of SET_WORKSPACE_DUPLICATION');
// TODO JSON PATCH
// const pathCombiner = new JsonPatchOperationPathCombiner('sections', 'deduplication');
// const path = ''; // `metadata/${metadataKey}`; // TODO
// this.operationsBuilder.add(pathCombiner.getPath(path), action.payload, true);
return new SetWorkspaceDuplicatedSuccessAction(action.payload);
})
.catch((error) => Observable.of(new SetWorkspaceDuplicatedErrorAction(error)));
@Effect({dispatch: false})
public wsDuplicationSuccess: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION_SUCCESS)
// TODO
.do((action: SetWorkspaceDuplicatedAction) => {
console.log('Effect of SET_WORKSPACE_DUPLICATION_SUCCESS');
this.deduplicationService.setWorkspaceDuplicationSuccess(action.payload);
});
@Effect({dispatch: false})
public wsDuplicationError: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION_ERROR)
.do((action: SetWorkspaceDuplicatedAction) => {
console.log('Effect of SET_WORKSPACE_DUPLICATION_ERROR');
this.deduplicationService.setWorkspaceDuplicationError(action.payload);
});
@Effect()
public wfDuplication: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION)
.map((action: SetWorkflowDuplicatedAction) => {
// return this.deduplicationService.setWorkflowDuplicated(action.payload)
// .first()
// .map((response) => {
console.log('Effect of SET_WORKFLOW_DUPLICATION');
// TODO JSON PATCH
// const pathCombiner = new JsonPatchOperationPathCombiner('sections', 'deduplication');
// const path = ''; // `metadata/${metadataKey}`; // TODO
// this.operationsBuilder.add(pathCombiner.getPath(path), action.payload, true);
return new SetWorkflowDuplicatedSuccessAction(action.payload);
})
.catch((error) => Observable.of(new SetWorkflowDuplicatedErrorAction(error)));
@Effect({dispatch: false})
public wfDuplicationSuccess: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION_SUCCESS)
// TODO
.do((action: SetWorkflowDuplicatedAction) => {
console.log('Effect of SET_WORKFLOW_DUPLICATION_SUCCESS');
this.deduplicationService.setWorkflowDuplicationSuccess(action.payload);
});
@Effect({dispatch: false})
public wfDuplicationError: Observable<Action> = this.actions$
.ofType(SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION_ERROR)
.do((action: SetWorkflowDuplicatedAction) => {
console.log('Effect of SET_WORKFLOW_DUPLICATION_ERROR');
this.deduplicationService.setWorkflowDuplicationError(action.payload);
});
constructor(private actions$: Actions, constructor(private actions$: Actions,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private operationsService: JsonPatchOperationsService<SubmitDataResponseDefinitionObject>, private operationsService: JsonPatchOperationsService<SubmitDataResponseDefinitionObject>,
private sectionService: SectionsService, private sectionService: SectionsService,
private store$: Store<any>, private store$: Store<any>,
private submissionService: SubmissionService, private submissionService: SubmissionService,
private deduplicationService: DeduplicationService, private deduplicationService: DetectDuplicateService,
private translate: TranslateService) { private translate: TranslateService) {
} }
@@ -293,11 +247,13 @@ export class SubmissionObjectEffects {
return canDeposit; return canDeposit;
} }
protected parseSaveResponse(currentState: SubmissionObjectEntry, response: SubmissionObject[], submissionId: string) { protected parseSaveResponse(currentState: SubmissionObjectEntry, response: SubmissionObject[], submissionId: string, notify: boolean = true) {
const mappedActions = []; const mappedActions = [];
if (isNotEmpty(response)) { if (isNotEmpty(response)) {
this.notificationsService.success(null, this.translate.get('submission.sections.general.save_success_notice')); if (notify) {
this.notificationsService.success(null, this.translate.get('submission.sections.general.save_success_notice'));
}
// to avoid dispatching an action for every error, create an array of errors per section // to avoid dispatching an action for every error, create an array of errors per section
response.forEach((item: Workspaceitem | Workflowitem) => { response.forEach((item: Workspaceitem | Workflowitem) => {
@@ -307,19 +263,20 @@ export class SubmissionObjectEffects {
if (errors && !isEmpty(errors)) { if (errors && !isEmpty(errors)) {
errorsList = parseSectionErrors(errors); errorsList = parseSectionErrors(errors);
this.notificationsService.warning(null, this.translate.get('submission.sections.general.sections_not_valid')); if (notify) {
this.notificationsService.warning(null, this.translate.get('submission.sections.general.sections_not_valid'));
}
} }
const sections = (item.sections && isNotEmpty(item.sections)) ? item.sections : {}; const sections: WorkspaceitemSectionsObject = (item.sections && isNotEmpty(item.sections)) ? item.sections : {};
const sectionsKeys: string[] = union(Object.keys(sections), Object.keys(errorsList)); const sectionsKeys: string[] = union(Object.keys(sections), Object.keys(errorsList));
sectionsKeys sectionsKeys
.forEach((sectionId) => { .forEach((sectionId) => {
const sectionErrors = errorsList[sectionId] || []; const sectionErrors = errorsList[sectionId] || [];
const sectionData = sections[sectionId] || {}; const sectionData = sections[sectionId] || {};
if (!currentState.sections[sectionId].enabled) { if (notify && !currentState.sections[sectionId].enabled) {
this.submissionService.notifyNewSection(sectionId); this.submissionService.notifyNewSection(submissionId, sectionId, currentState.sections[sectionId].sectionType);
} }
mappedActions.push(new UpdateSectionDataAction(submissionId, sectionId, sectionData, sectionErrors)); mappedActions.push(new UpdateSectionDataAction(submissionId, sectionId, sectionData, sectionErrors));
}); });

View File

@@ -27,16 +27,18 @@ import {
SaveSubmissionFormErrorAction, SaveSubmissionFormErrorAction,
SaveSubmissionSectionFormSuccessAction, SaveSubmissionSectionFormSuccessAction,
SaveSubmissionSectionFormErrorAction, SaveSubmissionSectionFormErrorAction,
SetWorkspaceDuplicatedAction,
SetWorkflowDuplicatedAction,
InitSectionAction, InitSectionAction,
RemoveSectionErrorsAction, RemoveSectionErrorsAction,
SaveForLaterSubmissionFormAction, SaveForLaterSubmissionFormAction,
SaveAndDepositSubmissionAction, SaveForLaterSubmissionFormSuccessAction, SaveForLaterSubmissionFormErrorAction SaveAndDepositSubmissionAction,
SaveForLaterSubmissionFormSuccessAction,
SaveForLaterSubmissionFormErrorAction,
SetDuplicateDecisionAction, SetDuplicateDecisionSuccessAction, SetDuplicateDecisionErrorAction
} from './submission-objects.actions'; } from './submission-objects.actions';
import { WorkspaceitemSectionDataType } from '../../core/submission/models/workspaceitem-sections.model'; import { WorkspaceitemSectionDataType } from '../../core/submission/models/workspaceitem-sections.model';
import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model'; import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model';
import { SectionsType } from '../sections/sections-type'; import { SectionsType } from '../sections/sections-type';
import { WorkspaceitemSectionDetectDuplicateObject } from '../../core/submission/models/workspaceitem-section-deduplication.model';
export interface SectionVisibility { export interface SectionVisibility {
main: any; main: any;
@@ -74,6 +76,7 @@ export interface SubmissionObjectEntry {
sections?: SubmissionSectionEntry; sections?: SubmissionSectionEntry;
isLoading?: boolean; isLoading?: boolean;
savePending?: boolean; savePending?: boolean;
saveDecisionPending?: boolean;
depositPending?: boolean; depositPending?: boolean;
} }
@@ -192,15 +195,6 @@ export function submissionObjectReducer(state = initialState, action: Submission
return deleteFile(state, action as DeleteUploadedFileAction); return deleteFile(state, action as DeleteUploadedFileAction);
} }
// deduplication
case SubmissionObjectActionTypes.SET_WORKSPACE_DUPLICATION: {
return updateDeduplication(state, action as SetWorkspaceDuplicatedAction);
}
case SubmissionObjectActionTypes.SET_WORKFLOW_DUPLICATION: {
return updateDeduplication(state, action as SetWorkflowDuplicatedAction);
}
// errors actions // errors actions
case SubmissionObjectActionTypes.ADD_SECTION_ERROR: { case SubmissionObjectActionTypes.ADD_SECTION_ERROR: {
return addError(state, action as InertSectionErrorsAction); return addError(state, action as InertSectionErrorsAction);
@@ -214,6 +208,19 @@ export function submissionObjectReducer(state = initialState, action: Submission
return removeSectionErrors(state, action as RemoveSectionErrorsAction); return removeSectionErrors(state, action as RemoveSectionErrorsAction);
} }
// detect duplicate
case SubmissionObjectActionTypes.SET_DUPLICATE_DECISION: {
return startSaveDecision(state, action as SetDuplicateDecisionAction);
}
case SubmissionObjectActionTypes.SET_DUPLICATE_DECISION_SUCCESS: {
return setDuplicateMatches(state, action as SetDuplicateDecisionSuccessAction);
}
case SubmissionObjectActionTypes.SET_DUPLICATE_DECISION: {
return endSaveDecision(state, action as SetDuplicateDecisionErrorAction);
}
default: { default: {
return state; return state;
} }
@@ -319,6 +326,7 @@ function initSubmission(state: SubmissionObjectState, action: InitSubmissionForm
sections: Object.create(null), sections: Object.create(null),
isLoading: true, isLoading: true,
savePending: false, savePending: false,
saveDecisionPending: false,
depositPending: false, depositPending: false,
}; };
return newState; return newState;
@@ -740,7 +748,7 @@ function deleteFile(state: SubmissionObjectState, action: DeleteUploadedFileActi
[ action.payload.submissionId ]: Object.assign({}, state[action.payload.submissionId], { [ action.payload.submissionId ]: Object.assign({}, state[action.payload.submissionId], {
sections: Object.assign({}, state[action.payload.submissionId].sections, sections: Object.assign({}, state[action.payload.submissionId].sections,
Object.assign({}, { Object.assign({}, {
[ action.payload.sectionId ]: Object.assign({}, state[ action.payload.submissionId ].sections [ action.payload.sectionId ], { [ action.payload.sectionId ]: Object.assign({}, state[ action.payload.submissionId ].sections[ action.payload.sectionId ], {
data: Object.assign({}, state[ action.payload.submissionId ].sections[ action.payload.sectionId ].data, { data: Object.assign({}, state[ action.payload.submissionId ].sections[ action.payload.sectionId ].data, {
files: newData files: newData
}) })
@@ -754,25 +762,74 @@ function deleteFile(state: SubmissionObjectState, action: DeleteUploadedFileActi
return state; return state;
} }
// ------ Detect duplicate functions ------ //
/** /**
* Update a Workspace deduplication match. * Set decision flag to true
* *
* @param state * @param state
* the current state * the current state
* @param action * @param action
* a SetWorkspaceDuplicatedAction or SetWorkflowDuplicatedAction * an SetDuplicateDecisionAction
* @return SubmissionObjectState * @return SubmissionObjectState
* the new state, with the match parameter changed. * the new state, with the decision flag changed.
*/ */
function updateDeduplication(state: SubmissionObjectState, action: SetWorkspaceDuplicatedAction|SetWorkflowDuplicatedAction): SubmissionObjectState { function startSaveDecision(state: SubmissionObjectState, action: SetDuplicateDecisionAction): SubmissionObjectState {
const matches = Object.assign([], (state[(action.payload as any).submissionId].sections.deduplication.data as any).matches); if (hasValue(state[ action.payload.submissionId ])) {
const newMatch = (action.payload as any).data; return Object.assign({}, state, {
matches.forEach( (match, i) => { [ action.payload.submissionId ]: Object.assign({}, state[ action.payload.submissionId ], {
if (i === action.payload.index) { saveDecisionPending: true,
matches.splice(i, 1, Object.assign({}, match, newMatch)); })
return; });
} } else {
}); return state;
// const updatedMatches = Object.assign({}, matches, newMatch); }
return Object.assign({}, state, {[(action.payload as any).submissionId]: {sections: {deduplication: {data: {matches}}}}}); }
function setDuplicateMatches(state: SubmissionObjectState, action: SetDuplicateDecisionSuccessAction) {
const index: any = findKey(
action.payload.submissionObject,
{id: parseInt(action.payload.submissionId, 10)});
const sectionData = action.payload.submissionObject[index].sections[ action.payload.sectionId ] as WorkspaceitemSectionDetectDuplicateObject;
const newData = (sectionData && sectionData.matches) ? sectionData : Object.create({});
if (hasValue(state[ action.payload.submissionId ].sections[ action.payload.sectionId ])) {
return Object.assign({}, state, {
[ action.payload.submissionId ]: Object.assign({}, state[ action.payload.submissionId ], {
sections: Object.assign({}, state[ action.payload.submissionId ].sections,
Object.assign({}, {
[ action.payload.sectionId ]: Object.assign({}, state[ action.payload.submissionId ].sections [ action.payload.sectionId ], {
enabled: true,
data: newData
})
})
),
saveDecisionPending: false
})
});
} else {
return state;
}
}
/**
* Set decision flag to false
*
* @param state
* the current state
* @param action
* an SetDuplicateDecisionSuccessAction or SetDuplicateDecisionErrorAction
* @return SubmissionObjectState
* the new state, with the decision flag changed.
*/
function endSaveDecision(state: SubmissionObjectState, action: SetDuplicateDecisionSuccessAction | SetDuplicateDecisionErrorAction): SubmissionObjectState {
if (hasValue(state[ action.payload.submissionId ])) {
return Object.assign({}, state, {
[ action.payload.submissionId ]: Object.assign({}, state[ action.payload.submissionId ], {
saveDecisionPending: false,
})
});
} else {
return state;
}
} }

View File

@@ -1,51 +0,0 @@
import { Store } from '@ngrx/store';
import { SubmissionState } from '../../submission.reducers';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpHeaders } from '@angular/common/http';
import { HttpOptions } from '../../../core/dspace-rest-v2/dspace-rest-v2.service';
@Injectable()
export class DeduplicationService {
constructor(private store: Store<SubmissionState>) {
}
// setWorkspaceDuplicated(payload: any): Observable<any> {
// const options: HttpOptions = Object.create({});
// let headers = new HttpHeaders();
// headers = headers.append('Content-Type', 'application/json');
// options.headers = headers;
// // TODO REST CALL
// // return this.restService.postToEndpoint('workspace/deduplication', payload, null, options);
// return Observable.of(payload);
// }
setWorkspaceDuplicationSuccess(payload: any): void {
// TODO
}
setWorkspaceDuplicationError(payload: any): void {
// TODO
}
// setWorkflowDuplicated(payload: any): Observable<any> {
// const options: HttpOptions = Object.create({});
// let headers = new HttpHeaders();
// headers = headers.append('Content-Type', 'application/json');
// options.headers = headers;
// // TODO REST CALL
// // return this.restService.postToEndpoint('workflow/deduplication', payload, null, options);
// return Observable.of(payload);
// }
setWorkflowDuplicationSuccess(payload: any): void {
// TODO Update the redux store
}
setWorkflowDuplicationError(payload: any): void {
// TODO Update the redux store
}
}

View File

@@ -1,57 +1,50 @@
<!--<ds-item-list-preview--> <ds-item-list-preview
<!--[item]="item"--> [item]="item"
<!--[object]="object"--> [object]="object"
<!--&gt;</ds-item-list-preview>--> ></ds-item-list-preview>
<div *ngIf="isWorkFlow" class="mt-2">
<!--<button (click)="toggleSubmitterDecision()"--> <form>
<!--class="btn btn-link">--> <div class="form-group mb-2">
<!--<span *ngIf="isWorkFlow && !showSubmitterDecision"> <i class="fa fa-angle-double-down"></i> Show submitter decision</span>--> <label class="mb-1" for="submitterDecision"><strong> {{'submission.sections.detect-duplicate.submitter-decision' | translate}} </strong></label><br>
<!--<span *ngIf="isWorkFlow && showSubmitterDecision"> <i class="fa fa-angle-double-up"></i> Hide submitter decision</span>--> <span id="submitterDecision" class="badge badge-pill {{decisionLabelClass}}">
<!--</button>--> {{submitterDecision$ | async}}
</span>
<!--<div *ngIf="showSubmitterDecision">--> </div>
<div> <div class="form-group" *ngIf="submitterNote">
<label><strong> {{submitterDecisionLabel | async}} </strong> <label for="submitterNote"><strong>{{'submission.sections.detect-duplicate.submitter-note' | translate}}</strong></label>
<span [ngClass]="{'label': true, <textarea class="form-control" id="submitterNote" rows="3" readonly>{{submitterNote}}</textarea>
'label-warning': match.submitterDecision == 'verify', </div>
'label-success': match.submitterDecision == 'reject', </form>
'label-default': (match.submitterDecision == undefined || match.submitterDecision == null)}">
{{submitterDecisionTxt}}
</span>
</label>
</div> </div>
<!--<div>-->
<!--<label><strong> Explaination: </strong>-->
<!--<span class="label">-->
<!--I want to provide the fulltext of this article-->
<!--</span>-->
<!--</label>-->
<!--</div>-->
<div class="mb-3" *ngIf="!decidedYet"> <div class="mt-3 mb-2" *ngIf="!hasDecision">
<button type="button" <button type="button"
class="btn btn-warning" class="btn btn-warning"
ngbTooltip="{{'submission.sections.deduplication.duplicated_help' | translate}}" ngbTooltip="{{'submission.sections.detect-duplicate.duplicate-help' | translate}}"
[disabled]="(processingVerify | async) || (processingReject | async)"
(click)="openModal(modal)"> (click)="openModal(modal)">
<span> {{duplicatedBtnLabel | async}}</span> <span *ngIf="(processingVerify | async)"><i class='fa fa-circle-o-notch fa-spin'></i> {{'submission.workflow.tasks.generic.processing' | translate}}</span>
<span *ngIf="!(processingVerify | async)">{{duplicateBtnLabel$ | async}}</span>
</button> </button>
<button type="button" <button type="button"
class="btn btn-success" class="btn btn-success"
ngbTooltip="{{'submission.sections.deduplication.not_duplicated_help' | translate}}" ngbTooltip="{{'submission.sections.detect-duplicate.not-duplicate-help' | translate}}"
(click)="setAsNotDuplicated()"> [disabled]="(processingReject | async) || (processingVerify | async)"
(click)="setAsNotDuplicate()">
<span> {{'submission.sections.deduplication.not_duplicated' | translate}}</span> <span *ngIf="(processingReject | async)"><i class='fa fa-circle-o-notch fa-spin'></i> {{'submission.workflow.tasks.generic.processing' | translate}}</span>
<span *ngIf="!(processingReject | async)">{{notDuplicateBtnLabel$ | async}}</span>
</button> </button>
</div> </div>
<div class="mb-3" *ngIf="decidedYet"> <div class="mt-3 mb-2" *ngIf="hasDecision">
<button type="button" <button type="button"
class="btn btn-danger" class="btn btn-danger"
ngbTooltip="{{'submission.sections.deduplication.clear_decision_help' | translate}}" ngbTooltip="{{'submission.sections.detect-duplicate.clear-decision-help' | translate}}"
(click)="clearDecision()"> (click)="clearDecision()">
<span> {{'submission.sections.deduplication.clear_decision' | translate}}</span> <span> {{'submission.sections.detect-duplicate.clear-decision' | translate}}</span>
</button> </button>
</div> </div>
@@ -67,20 +60,19 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="alert alert-info" role="alert"> <div class="alert alert-info" role="alert">
{{'submission.sections.deduplication.note_help' | translate}} {{'submission.sections.detect-duplicate.note-help' | translate}}
</div> </div>
<form (ngSubmit)="setAsDuplicated();" [formGroup]="rejectForm" > <form (ngSubmit)="setAsDuplicate();" [formGroup]="rejectForm" >
<textarea <textarea class="w-100"
style="width: 100%" formControlName="reason"
formControlName="reason" rows="4"
rows="4" placeholder="{{'submission.sections.detect-duplicate.note-placeholder' | translate}}"></textarea>
placeholder="{{'submission.sections.deduplication.note_placeholder' | translate}}"></textarea> <button id="btn-chat"
<button class="btn btn-danger btn-lg btn-block mt-3"
id="btn-chat" [disabled]="!rejectForm.valid"
class="btn btn-danger btn-lg btn-block mt-3" type="submit">
[disabled]="!rejectForm.valid" <span *ngIf="(processingReject | async)"><i class='fa fa-circle-o-notch fa-spin'></i> {{'submission.workflow.tasks.generic.processing' | translate}}</span>
type="submit"> <span *ngIf="!(processingReject | async)">{{'submission.sections.detect-duplicate.duplicate' | translate}}</span>
<span>{{'submission.sections.deduplication.duplicated' | translate}}</span>
</button> </button>
</form> </form>
</div> </div>

View File

@@ -1,164 +1,146 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { DeduplicationSchema } from '../../../../core/submission/models/workspaceitem-section-deduplication.model'; import { DetectDuplicateMatch } from '../../../../core/submission/models/workspaceitem-section-deduplication.model';
import { SubmissionService } from '../../../submission.service'; import { SubmissionService } from '../../../submission.service';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { DetectDuplicateService } from '../detect-duplicate.service';
import { SubmissionState } from '../../../submission.reducers';
import { DeduplicationService } from '../deduplication.service';
import { JsonPatchOperationsBuilder } from '../../../../core/json-patch/builder/json-patch-operations-builder'; import { JsonPatchOperationsBuilder } from '../../../../core/json-patch/builder/json-patch-operations-builder';
import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { JsonPatchOperationPathCombiner } from '../../../../core/json-patch/builder/json-patch-operation-path-combiner';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { SubmissionScopeType } from '../../../../core/submission/submission-scope-type'; import { SubmissionScopeType } from '../../../../core/submission/submission-scope-type';
import { DuplicateDecisionValue } from '../models/duplicate-decision-value';
import { DuplicateDecision } from '../models/duplicate-decision.model';
import { DuplicateDecisionType } from '../models/duplicate-decision-type';
import { isNotEmpty } from '../../../../shared/empty.util';
import { SectionsService } from '../../sections.service';
@Component({ @Component({
selector: 'ds-deduplication-match', selector: 'ds-duplicate-match',
templateUrl: 'deduplication-match.component.html', templateUrl: 'duplicate-match.component.html',
}) })
export class DeduplicationMatchComponent implements OnInit { export class DuplicateMatchComponent implements OnInit {
@Input() @Input() sectionId: string;
sectionId: string; @Input() itemId: string;
@Input() @Input() match: DetectDuplicateMatch;
match: DeduplicationSchema; @Input() submissionId: string;
@Input() @Input() index: string;
submissionId: string;
@Input()
index: string;
object = {hitHighlights: []}; object = {hitHighlights: []};
item: Item; item: Item;
isWorkFlow = false; isWorkFlow = false;
showSubmitterDecision = false; showSubmitterDecision = false;
submitterDecisionTxt: string; decisionType: DuplicateDecisionType;
submitterDecision$: Observable<string>;
submitterNote: string;
decidedYet: boolean; hasDecision: boolean;
closeResult: string; // for modal closeResult: string; // for modal
rejectForm: FormGroup; rejectForm: FormGroup;
modalRef: NgbModalRef; modalRef: NgbModalRef;
pathCombiner: JsonPatchOperationPathCombiner; pathCombiner: JsonPatchOperationPathCombiner;
public processingVerify: Observable<boolean> = Observable.of(false);
public processingReject: Observable<boolean> = Observable.of(false);
decisionLabelClass: string;
duplicateBtnLabel$: Observable<string>;
notDuplicateBtnLabel$: Observable<string>;
duplicatedBtnLabel: Observable<string>; constructor(private detectDuplicateService: DetectDuplicateService,
submitterDecisionLabel: Observable<string>;
constructor(private deduplicationService: DeduplicationService,
private submissionService: SubmissionService,
private modalService: NgbModal,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private store: Store<SubmissionState>, private modalService: NgbModal,
protected operationsBuilder: JsonPatchOperationsBuilder, private operationsBuilder: JsonPatchOperationsBuilder,
private sectionService: SectionsService,
private submissionService: SubmissionService,
private translate: TranslateService) { private translate: TranslateService) {
} }
ngOnInit(): void { ngOnInit(): void {
if ((this.match.matchObject as any).item) {
// WSI & WFI
this.item = Object.assign(new Item(), (this.match.matchObject as any).item);
} else {
// Item
this.item = Object.assign(new Item(), this.match.matchObject);
}
this.isWorkFlow = this.submissionService.getSubmissionScope() === SubmissionScopeType.WorkflowItem; this.isWorkFlow = this.submissionService.getSubmissionScope() === SubmissionScopeType.WorkflowItem;
this.decisionType = this.isWorkFlow ? DuplicateDecisionType.WORKFLOW : DuplicateDecisionType.WORKSPACE;
this.item = Object.assign(new Item(), this.match.matchObject);
this.rejectForm = this.formBuilder.group({ this.rejectForm = this.formBuilder.group({
reason: ['', Validators.required] reason: ['', Validators.required]
}); });
this.decidedYet = this.isWorkFlow ? this.hasDecision = this.isWorkFlow ?
this.match.workflowDecision !== null ? true : false this.match.workflowDecision !== null
: this.match.submitterDecision !== null ? true : false; : this.match.submitterDecision !== null;
if (this.match.submitterDecision) { if (this.match.submitterDecision) {
if (this.match.submitterDecision === 'verify') { this.submitterDecision$ = (this.match.submitterDecision === DuplicateDecisionValue.Reject) ?
this.submitterDecisionTxt = 'It\'s a duplicate'; this.translate.get('submission.sections.detect-duplicate.not-duplicate') :
} else { this.translate.get('submission.sections.detect-duplicate.duplicate');
this.submitterDecisionTxt = 'It\'s not a duplicate'; this.decisionLabelClass = (this.match.submitterDecision === DuplicateDecisionValue.Reject) ? 'badge-success' : 'badge-warning';
} this.submitterNote = this.match.submitterNote;
} else { } else {
this.submitterDecisionTxt = 'Not decided'; this.submitterDecision$ = this.translate.get('submission.sections.detect-duplicate.no-decision');
this.decisionLabelClass = 'badge-light';
} }
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId, 'matches', this.index); this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionId);
this.duplicatedBtnLabel = this.isWorkFlow ? this.duplicateBtnLabel$ = this.isWorkFlow ?
this.translate.get('submission.sections.deduplication.duplicated_ctrl') ((this.match.submitterDecision === DuplicateDecisionValue.Verify) ?
: this.translate.get('submission.sections.deduplication.duplicated'); this.translate.get('submission.sections.detect-duplicate.confirm-duplicate') :
this.translate.get('submission.sections.detect-duplicate.duplicate-ctrl'))
: this.translate.get('submission.sections.detect-duplicate.duplicate');
this.submitterDecisionLabel = this.isWorkFlow ? this.notDuplicateBtnLabel$ = (this.isWorkFlow && this.match.submitterDecision === DuplicateDecisionValue.Reject) ?
this.translate.get('submission.sections.deduplication.submitter_decision') this.translate.get('submission.sections.detect-duplicate.confirm-not-duplicate') :
: this.translate.get('submission.sections.deduplication.your_decision'); this.translate.get('submission.sections.detect-duplicate.not-duplicate');
} }
setAsDuplicated() { setAsDuplicate() {
console.log('Setting item #' + this.item.uuid + ' as duplicated...'); this.processingVerify = Observable.of(true);
this.dispatchAction(true); const decision = new DuplicateDecision(
DuplicateDecisionValue.Verify,
this.decisionType,
this.rejectForm.get('reason').value);
this.dispatchAction(decision);
this.modalRef.dismiss(); this.modalRef.dismiss();
} }
setAsNotDuplicated() { setAsNotDuplicate() {
console.log('Setting item #' + this.item.uuid + ' as not duplicated...'); this.processingReject = Observable.of(true);
this.dispatchAction(false); const decision = new DuplicateDecision(
DuplicateDecisionValue.Reject,
this.decisionType);
this.dispatchAction(decision);
} }
clearDecision() { clearDecision() {
console.log('Clearing item #' + this.item.uuid + ' from previous decision...'); const decision = new DuplicateDecision(
DuplicateDecisionValue.Undo,
this.decisionType);
this.dispatchAction(decision);
} }
private dispatchAction(duplicated: boolean, clear?: boolean): void { private dispatchAction(decision: DuplicateDecision): void {
const pathDecision = Array.of('matches', this.itemId, this.isWorkFlow ? 'workflowDecision' : 'submitterDecision').join('/');
const payload = { const payload = {
submissionId: this.submissionId, value: isNotEmpty(decision.value) ? decision.value : null,
index: this.index, note: isNotEmpty(decision.note) ? decision.note : null
data: {} as DeduplicationSchema
}; };
// Call workflow action // dispatch patch operation only when section is active
const decision = clear ? null : duplicated ? 'verify' : 'reject'; this.sectionService.isSectionActive(this.submissionId, this.sectionId)
const pathDecision = this.isWorkFlow ? 'workflowDecision' : 'submitterDecision'; .filter((isActive: boolean) => isActive)
this.operationsBuilder.add(this.pathCombiner.getPath(pathDecision), decision, false, true); .take(1)
.subscribe(() => {
this.operationsBuilder.add(this.pathCombiner.getPath(pathDecision), payload, false, true);
this.detectDuplicateService.saveDuplicateDecision(this.submissionId, this.sectionId)
});
if (!clear && duplicated) {
const note = this.rejectForm.get('reason').value;
const pathNote = this.isWorkFlow ? 'workflowNote' : 'submitterNote';
this.operationsBuilder.add(this.pathCombiner.getPath(pathNote), note, false, true);
}
// const now = new Date();
// const time = now.getUTCFullYear() + '/' + now.getUTCMonth() + 1 + '/' + now.getDay();
// if (this.isWorkFlow) {
// // Call workflow action
// payload.data.workflowDecision = clear ? null : duplicated ? 'verify' : 'reject';
// // payload.data.workflowTime = time;
// if (!clear && duplicated) {
// const note = this.rejectForm.get('reason').value;
// payload.data.workflowNote = note;
// }
// // Dispatch WorkFLOW action
// // this.store.dispatch(new SetWorkflowDuplicatedAction(payload));
// const path = 'workflowDecision'
// this.operationsBuilder.add(this.pathCombiner.getPath(path), payload.data.workflowDecision, false, true);
//
// } else {
// // Call workspace action
// payload.data.submitterDecision = clear ? null : duplicated ? 'verify' : 'reject';
// // payload.data.submitterTime = time;
// if (!clear && duplicated) {
// const note = this.rejectForm.get('reason').value;
// payload.data.submitterNote = note;
// }
// // Dispatch workSPACE action
// this.store.dispatch(new SetWorkspaceDuplicatedAction(payload));
// }
}
toggleSubmitterDecision() {
this.showSubmitterDecision = !this.showSubmitterDecision;
} }
openModal(modal) { openModal(modal) {

View File

@@ -1,38 +1,32 @@
<ds-loading *ngIf="isLoading" message="Loading..."></ds-loading> <ds-loading *ngIf="isLoading" message="Loading..."></ds-loading>
<ng-container *ngIf="(sectionDataObs | async)?.matches.length == 0"> <ng-container *ngIf="(totalMatch$ | async) === 0">
<div class="row"> <ds-alert [type]="AlertTypeEnum.Info" [content]="('submission.sections.detect-duplicate.disclaimer-no-match' | translate)"></ds-alert>
<div class="col-md-12">
<h3 class="text-center"><span class="text-muted">No duplicated yet.</span></h3>
</div>
</div>
</ng-container> </ng-container>
<ng-container <ng-container *ngIf="(totalMatch$ | async) > 0">
*ngIf="(sectionDataObs | async)?.matches.length > 0"> <ds-alert [type]="AlertTypeEnum.Warning" [content]="(disclaimer | async)"></ds-alert>
<div class="alert alert-danger" role="alert">
{{ disclaimer | async }}
</div>
<ds-pagination <ds-pagination
[paginationOptions]="config" [paginationOptions]="config"
[collectionSize]="(sectionDataObs | async)?.matches.length" [collectionSize]="(totalMatch$ | async)"
[sortOptions]="sortConfig" [sortOptions]="sortConfig"
[hideGear]="true" [hideGear]="true"
[hidePagerWhenSinglePage]="false" [hidePagerWhenSinglePage]="false"
(pageChange)="setPage($event)"> (pageChange)="setPage($event)">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li *ngFor="let match of (sectionDataObs | async)?.matches <li *ngFor="let item of (sectionData$ | async)?.matches | dsObjNgFor
| paginate: {id: config.id, itemsPerPage: config.pageSize, currentPage: config.currentPage}; let i = index" | paginate: {id: config.id, itemsPerPage: config.pageSize, currentPage: config.currentPage}; let i = index; let l = last"
class="mt-4 mb-4"> class="mt-4 mb-4"
[class.border-bottom]="!l">
<ds-deduplication-match <ds-duplicate-match
*ngVar="(i + (config.currentPage-1)*config.pageSize) as totalIndex" *ngVar="(i + (config.currentPage-1)*config.pageSize) as totalIndex"
[sectionId]="sectionData.id" [sectionId]="sectionData.id"
[match]="match" [match]="item.value"
[submissionId]="submissionId" [submissionId]="submissionId"
[index]=totalIndex></ds-deduplication-match> [index]=totalIndex
[itemId]="item.key"></ds-duplicate-match>
</li> </li>
</ul> </ul>
</ds-pagination> </ds-pagination>

View File

@@ -1,40 +1,45 @@
import { SectionsType } from '../sections-type'; import { SectionsType } from '../sections-type';
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { SectionModelComponent } from '../models/section.model'; import { SectionModelComponent } from '../models/section.model';
import { renderSectionFor } from '../sections-decorator'; import { renderSectionFor } from '../sections-decorator';
import { SectionDataObject } from '../models/section-data.model'; import { SectionDataObject } from '../models/section-data.model';
import { SubmissionState } from '../../submission.reducers';
import { Store } from '@ngrx/store';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { submissionSectionDataFromIdSelector } from '../../selectors';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { isNotEmpty } from '../../../shared/empty.util';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { SubmissionService } from '../../submission.service'; import { SubmissionService } from '../../submission.service';
import { SubmissionScopeType } from '../../../core/submission/submission-scope-type'; import { SubmissionScopeType } from '../../../core/submission/submission-scope-type';
import { AlertType } from '../../../shared/alerts/aletrs-type';
import { DetectDuplicateService } from './detect-duplicate.service';
import { SectionsService } from '../sections.service';
import { Subscription } from 'rxjs/Subscription';
import { hasValue } from '../../../shared/empty.util';
@Component({ @Component({
selector: 'ds-deduplication-section', selector: 'ds-deduplication-section',
// styleUrls: ['./section-deduplication.component.scss'], // styleUrls: ['./section-deduplication.component.scss'],
templateUrl: './section-deduplication.component.html', templateUrl: './section-detect-duplicate.component.html',
changeDetection: ChangeDetectionStrategy.Default changeDetection: ChangeDetectionStrategy.Default
}) })
@renderSectionFor(SectionsType.Deduplication) @renderSectionFor(SectionsType.DetectDuplicate)
export class DeduplicationSectionComponent extends SectionModelComponent implements OnInit { export class DetectDuplicateSectionComponent extends SectionModelComponent implements OnDestroy, OnInit {
public AlertTypeEnum = AlertType;
public isLoading = true; public isLoading = true;
public sectionDataObs: Observable<any>; public sectionData$: Observable<any>;
public matches = []; public matches = {};
public totalMatch$: Observable<number>;
config: PaginationComponentOptions; config: PaginationComponentOptions;
sortConfig: SortOptions; sortConfig: SortOptions;
isWorkFlow = false; isWorkFlow = false;
disclaimer: Observable<string>; disclaimer: Observable<string>;
sub: Subscription;
constructor(protected store: Store<SubmissionState>, constructor(private detectDuplicateService: DetectDuplicateService,
private translate: TranslateService, private translate: TranslateService,
private sectionService: SectionsService,
private submissionService: SubmissionService, private submissionService: SubmissionService,
@Inject('collectionIdProvider') public injectedCollectionId: string, @Inject('collectionIdProvider') public injectedCollectionId: string,
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject, @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
@@ -48,26 +53,34 @@ export class DeduplicationSectionComponent extends SectionModelComponent impleme
this.config.pageSize = 2; this.config.pageSize = 2;
this.sortConfig = new SortOptions('dc.title', SortDirection.ASC); this.sortConfig = new SortOptions('dc.title', SortDirection.ASC);
this.sectionDataObs = this.store.select(submissionSectionDataFromIdSelector(this.submissionId, this.sectionData.id)) this.sectionData$ = this.detectDuplicateService.getDuplicateMatches(this.submissionId, this.sectionData.id);
.filter((sd) => isNotEmpty(sd))
.startWith({matches: []}) this.totalMatch$ = this.detectDuplicateService.getDuplicateTotalMatches(this.submissionId, this.sectionData.id);
.distinctUntilChanged()
.map((sd) => {
return sd;
});
this.isWorkFlow = this.submissionService.getSubmissionScope() === SubmissionScopeType.WorkflowItem; this.isWorkFlow = this.submissionService.getSubmissionScope() === SubmissionScopeType.WorkflowItem;
this.disclaimer = this.isWorkFlow ? this.disclaimer = this.isWorkFlow ?
this.translate.get('submission.sections.deduplication.disclaimer_ctrl') this.translate.get('submission.sections.detect-duplicate.disclaimer-ctrl')
: this.translate.get('submission.sections.deduplication.disclaimer'); : this.translate.get('submission.sections.detect-duplicate.disclaimer');
this.isLoading = false; this.isLoading = false;
this.sub = this.totalMatch$
.map((totalMatches: number) => totalMatches === 0)
.distinctUntilChanged()
.subscribe((status: boolean) => {
this.sectionService.setSectionStatus(this.submissionId, this.sectionData.id, status);
})
} }
setPage(page) { setPage(page) {
console.log('Select page #', page);
this.config.currentPage = page; this.config.currentPage = page;
} }
ngOnDestroy(): void {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
} }

View File

@@ -0,0 +1,33 @@
import { Store } from '@ngrx/store';
import { SubmissionState } from '../../submission.reducers';
import { Injectable } from '@angular/core';
import { SetDuplicateDecisionAction } from '../../objects/submission-objects.actions';
import { submissionSectionDataFromIdSelector } from '../../selectors';
import { WorkspaceitemSectionDetectDuplicateObject } from '../../../core/submission/models/workspaceitem-section-deduplication.model';
import { isEmpty } from '../../../shared/empty.util';
@Injectable()
export class DetectDuplicateService {
constructor(private store: Store<SubmissionState>) {
}
getDuplicateMatches(submissionId: string, sectionId: string) {
return this.store.select(submissionSectionDataFromIdSelector(submissionId, sectionId))
.map((sectionData: WorkspaceitemSectionDetectDuplicateObject) => {
return (isEmpty(sectionData)) ? {matches: {}} : sectionData
})
.startWith({matches: {}})
.distinctUntilChanged();
}
getDuplicateTotalMatches(submissionId: string, sectionId: string) {
return this.getDuplicateMatches(submissionId, sectionId)
.map((sectionData: WorkspaceitemSectionDetectDuplicateObject) => Object.keys(sectionData.matches).length)
.distinctUntilChanged();
}
saveDuplicateDecision(submissionId: string, sectionId: string): void {
this.store.dispatch(new SetDuplicateDecisionAction(submissionId, sectionId));
}
}

View File

@@ -134,7 +134,7 @@ export class SectionsDirective implements OnDestroy, OnInit {
public setFocus(event) { public setFocus(event) {
if (!this.active) { if (!this.active) {
this.store.dispatch(new SetActiveSectionAction(this.submissionId, this.sectionId)); this.submissionService.setActiveSection(this.submissionId, this.sectionId);
} }
} }

View File

@@ -9,7 +9,7 @@ import { hasValue, isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empt
import { import {
DisableSectionAction, DisableSectionAction,
EnableSectionAction, EnableSectionAction,
InertSectionErrorsAction, RemoveSectionErrorsAction, InertSectionErrorsAction, RemoveSectionErrorsAction, SectionStatusChangeAction,
UpdateSectionDataAction UpdateSectionDataAction
} from '../objects/submission-objects.actions'; } from '../objects/submission-objects.actions';
import { import {
@@ -24,12 +24,14 @@ import parseSectionErrorPaths, { SectionErrorPath } from '../utils/parseSectionE
import { FormAddError, FormClearErrorsAction, FormRemoveErrorAction } from '../../shared/form/form.actions'; import { FormAddError, FormClearErrorsAction, FormRemoveErrorAction } from '../../shared/form/form.actions';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { SubmissionService } from '../submission.service';
@Injectable() @Injectable()
export class SectionsService { export class SectionsService {
constructor(private notificationsService: NotificationsService, constructor(private notificationsService: NotificationsService,
private scrollToService: ScrollToService, private scrollToService: ScrollToService,
private submissionService: SubmissionService,
private store: Store<SubmissionState>, private store: Store<SubmissionState>,
private translate: TranslateService) { private translate: TranslateService) {
} }
@@ -86,6 +88,12 @@ export class SectionsService {
.distinctUntilChanged(); .distinctUntilChanged();
} }
public isSectionActive(submissionId, sectionId): Observable<boolean> {
return this.submissionService.getActiveSectionId(submissionId)
.map((activeSectionId: string) => sectionId === activeSectionId)
.distinctUntilChanged();
}
public isSectionEnabled(submissionId, sectionId): Observable<boolean> { public isSectionEnabled(submissionId, sectionId): Observable<boolean> {
return this.store.select(submissionSectionFromIdSelector(submissionId, sectionId)) return this.store.select(submissionSectionFromIdSelector(submissionId, sectionId))
.filter((sectionObj) => hasValue(sectionObj)) .filter((sectionObj) => hasValue(sectionObj))
@@ -150,4 +158,8 @@ export class SectionsService {
public setSectionError(submissionId: string, sectionId: string, error: SubmissionSectionError) { public setSectionError(submissionId: string, sectionId: string, error: SubmissionSectionError) {
this.store.dispatch(new InertSectionErrorsAction(submissionId, sectionId, error)); this.store.dispatch(new InertSectionErrorsAction(submissionId, sectionId, error));
} }
public setSectionStatus(submissionId: string, sectionId: string, status: boolean) {
this.store.dispatch(new SectionStatusChangeAction(submissionId, sectionId, status));
}
} }

View File

@@ -29,9 +29,9 @@ import { UploadSectionFileEditComponent } from './sections/upload/file/edit/file
import { UploadSectionFileViewComponent } from './sections/upload/file/view/file-view.component'; import { UploadSectionFileViewComponent } from './sections/upload/file/view/file-view.component';
import { AccessConditionsComponent } from './sections/upload/accessConditions/accessConditions.component'; import { AccessConditionsComponent } from './sections/upload/accessConditions/accessConditions.component';
import { RecycleSectionComponent } from './sections/recycle/section-recycle.component'; import { RecycleSectionComponent } from './sections/recycle/section-recycle.component';
import { DeduplicationSectionComponent } from './sections/deduplication/section-deduplication.component'; import { DetectDuplicateSectionComponent } from './sections/detect-duplicate/section-detect-duplicate.component';
import { DeduplicationMatchComponent } from './sections/deduplication/match/deduplication-match.component'; import { DuplicateMatchComponent } from './sections/detect-duplicate/duplicate-match/duplicate-match.component';
import { DeduplicationService } from './sections/deduplication/deduplication.service'; import { DetectDuplicateService } from './sections/detect-duplicate/detect-duplicate.service';
import { SubmissionSubmitComponent } from './submit/submission-submit.component'; import { SubmissionSubmitComponent } from './submit/submission-submit.component';
@NgModule({ @NgModule({
@@ -62,8 +62,8 @@ import { SubmissionSubmitComponent } from './submit/submission-submit.component'
UploadSectionFileEditComponent, UploadSectionFileEditComponent,
UploadSectionFileViewComponent, UploadSectionFileViewComponent,
RecycleSectionComponent, RecycleSectionComponent,
DeduplicationSectionComponent, DetectDuplicateSectionComponent,
DeduplicationMatchComponent, DuplicateMatchComponent,
], ],
entryComponents: [ entryComponents: [
DefaultSectionComponent, DefaultSectionComponent,
@@ -72,7 +72,7 @@ import { SubmissionSubmitComponent } from './submit/submission-submit.component'
LicenseSectionComponent, LicenseSectionComponent,
SectionContainerComponent, SectionContainerComponent,
RecycleSectionComponent, RecycleSectionComponent,
DeduplicationSectionComponent], DetectDuplicateSectionComponent],
exports: [ exports: [
SubmissionEditComponent, SubmissionEditComponent,
SubmissionFormComponent, SubmissionFormComponent,
@@ -83,7 +83,7 @@ import { SubmissionSubmitComponent } from './submit/submission-submit.component'
SectionsService, SectionsService,
SubmissionRestService, SubmissionRestService,
SubmissionUploadsConfigService, SubmissionUploadsConfigService,
DeduplicationService DetectDuplicateService
] ]
}) })
export class SubmissionModule { export class SubmissionModule {

View File

@@ -7,7 +7,7 @@ import { Store } from '@ngrx/store';
import { submissionSelector, SubmissionState } from './submission.reducers'; import { submissionSelector, SubmissionState } from './submission.reducers';
import { hasValue, isEmpty, isNotUndefined } from '../shared/empty.util'; import { hasValue, isEmpty, isNotUndefined } from '../shared/empty.util';
import { SaveSubmissionFormAction } from './objects/submission-objects.actions'; import { SaveSubmissionFormAction, SetActiveSectionAction } from './objects/submission-objects.actions';
import { import {
SubmissionObjectEntry, SubmissionObjectEntry,
SubmissionSectionEntry, SubmissionSectionEntry,
@@ -26,6 +26,8 @@ import { RouteService } from '../shared/services/route.service';
import { SectionsType } from './sections/sections-type'; import { SectionsType } from './sections/sections-type';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { NotificationsService } from '../shared/notifications/notifications.service'; import { NotificationsService } from '../shared/notifications/notifications.service';
import { ScrollToConfigOptions, ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
import { NotificationOptions } from '../shared/notifications/models/notification-options.model';
@Injectable() @Injectable()
export class SubmissionService { export class SubmissionService {
@@ -38,6 +40,7 @@ export class SubmissionService {
protected restService: SubmissionRestService, protected restService: SubmissionRestService,
protected router: Router, protected router: Router,
protected routeService: RouteService, protected routeService: RouteService,
protected scrollToService: ScrollToService,
protected store: Store<SubmissionState>, protected store: Store<SubmissionState>,
protected translate: TranslateService) { protected translate: TranslateService) {
} }
@@ -79,6 +82,7 @@ export class SubmissionService {
const availableSections: SectionDataObject[] = []; const availableSections: SectionDataObject[] = [];
Object.keys(sections) Object.keys(sections)
.filter((sectionId) => !this.isSectionHidden(sections[sectionId] as SubmissionSectionObject)) .filter((sectionId) => !this.isSectionHidden(sections[sectionId] as SubmissionSectionObject))
// .filter((sectionId) => sections[sectionId].sectionType !== SectionsType.DetectDuplicate || isNotEmpty(sections[sectionId].data))
.forEach((sectionId) => { .forEach((sectionId) => {
const sectionObject: SectionDataObject = Object.create({}); const sectionObject: SectionDataObject = Object.create({});
sectionObject.config = sections[sectionId].config; sectionObject.config = sections[sectionId].config;
@@ -105,6 +109,7 @@ export class SubmissionService {
Object.keys(sections) Object.keys(sections)
.filter((sectionId) => !this.isSectionHidden(sections[sectionId] as SubmissionSectionObject)) .filter((sectionId) => !this.isSectionHidden(sections[sectionId] as SubmissionSectionObject))
.filter((sectionId) => !sections[sectionId].enabled) .filter((sectionId) => !sections[sectionId].enabled)
.filter((sectionId) => sections[sectionId].sectionType !== SectionsType.DetectDuplicate)
.forEach((sectionId) => { .forEach((sectionId) => {
const sectionObject: SectionDataObject = Object.create({}); const sectionObject: SectionDataObject = Object.create({});
sectionObject.header = sections[sectionId].header; sectionObject.header = sections[sectionId].header;
@@ -196,6 +201,13 @@ export class SubmissionService {
.startWith(false); .startWith(false);
} }
getSubmissionDuplicateDecisionProcessingStatus(submissionId: string): Observable<boolean> {
return this.getSubmissionObject(submissionId)
.map((state: SubmissionObjectEntry) => state.saveDecisionPending)
.distinctUntilChanged()
.startWith(false);
}
redirectToMyDSpace() { redirectToMyDSpace() {
const previousUrl = this.routeService.getPreviousUrl(); const previousUrl = this.routeService.getPreviousUrl();
if (isEmpty(previousUrl)) { if (isEmpty(previousUrl)) {
@@ -205,12 +217,28 @@ export class SubmissionService {
} }
} }
notifyNewSection(sectionId: string, sectionType?: SectionsType) { notifyNewSection(submissionId: string, sectionId: string, sectionType?: SectionsType) {
this.translate.get('submission.sections.general.metadata-extracted-new-section', {sectionId})
.take(1) if (sectionType === SectionsType.DetectDuplicate) {
.subscribe((m) => { this.setActiveSection(submissionId, sectionId);
this.notificationsService.info(null, m, null, true); this.translate.get('submission.sections.detect-duplicate.duplicate-detected', {sectionId})
}); .take(1)
.subscribe((msg) => {
this.notificationsService.warning(null, msg, new NotificationOptions(0));
});
const config: ScrollToConfigOptions = {
target: sectionId,
offset: -70
};
this.scrollToService.scrollTo(config);
} else {
this.translate.get('submission.sections.general.metadata-extracted-new-section', {sectionId})
.take(1)
.subscribe((msg) => {
this.notificationsService.info(null, msg, null, true);
});
}
} }
retrieveSubmission(submissionId): Observable<SubmissionObject> { retrieveSubmission(submissionId): Observable<SubmissionObject> {
return this.restService.getDataById(this.getSubmissionObjectLinkName(), submissionId) return this.restService.getDataById(this.getSubmissionObjectLinkName(), submissionId)
@@ -219,6 +247,10 @@ export class SubmissionService {
.map((submissionObjects: SubmissionObject[]) => submissionObjects[0]); .map((submissionObjects: SubmissionObject[]) => submissionObjects[0]);
} }
setActiveSection(submissionId, sectionId) {
this.store.dispatch(new SetActiveSectionAction(submissionId, sectionId));
}
startAutoSave(submissionId) { startAutoSave(submissionId) {
this.stopAutoSave(); this.stopAutoSave();
console.log('AUTOSAVE ON!!!'); console.log('AUTOSAVE ON!!!');