Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/app/core/submission/submission-object-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
import { environment } from '../../../environments/environment';
import { RequestEntryState } from '../data/request-entry-state.model';
import { IdentifiableDataService } from '../data/base/identifiable-data.service';
import { Operation } from 'fast-json-patch';

/**
* A service to retrieve submission objects (WorkspaceItem/WorkflowItem)
Expand Down Expand Up @@ -70,4 +71,24 @@ export class SubmissionObjectDataService {
));
}
}

patch(object: SubmissionObject, operations: Operation[]): Observable<RemoteData<SubmissionObject>> {
switch (this.submissionService.getSubmissionScope()) {
case SubmissionScopeType.WorkspaceItem:
return this.workspaceitemDataService.patch(object, operations);
case SubmissionScopeType.WorkflowItem:
return this.workflowItemDataService.patch(object, operations);
default:
const now = new Date().getTime();
return observableOf(new RemoteData(
now,
environment.cache.msToLive.default,
now,
RequestEntryState.Error,
'The request couldn\'t be sent. Unable to determine the type of submission object',
undefined,
400
));
}
}
}
2 changes: 2 additions & 0 deletions src/app/core/submission/workflowitem-data.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { WorkflowItemDataService } from './workflowitem-data.service';
import { WorkflowItem } from './models/workflowitem.model';
import { CoreState } from '../core-state.model';
import { RequestEntry } from '../data/request-entry.model';
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';

describe('WorkflowItemDataService test', () => {
let scheduler: TestScheduler;
Expand Down Expand Up @@ -87,6 +88,7 @@ describe('WorkflowItemDataService test', () => {
objectCache,
halService,
notificationsService,
new DefaultChangeAnalyzer(),
);
}

Expand Down
35 changes: 34 additions & 1 deletion src/app/core/submission/workflowitem-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,48 @@ import { SearchData, SearchDataImpl } from '../data/base/search-data';
import { DeleteData, DeleteDataImpl } from '../data/base/delete-data';
import { PaginatedList } from '../data/paginated-list.model';
import { dataService } from '../data/base/data-service.decorator';
import { PatchData, PatchDataImpl } from '../data/base/patch-data';
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
import { RestRequestMethod } from '../data/rest-request-method';
import { Operation } from 'fast-json-patch';

/**
* Constructs an endpoint taking into account that the WorkflowItem's "uuid" has a prefix by removing that prefix from the ID
* @param endpoint Endpoint to append ID to
* @param resourceID WorkflowItem's "uuid" including the prefix to remove
*/
const constructWorkflowItemIdEndpoint = (endpoint, resourceID) => {
const regex = new RegExp(`^${WorkflowItem.type.value}-`);
return `${endpoint}/${resourceID.replace(regex, '')}`;
};

/**
* A service that provides methods to make REST requests with workflow items endpoint.
*/
@Injectable()
@dataService(WorkflowItem.type)
export class WorkflowItemDataService extends IdentifiableDataService<WorkflowItem> implements SearchData<WorkflowItem>, DeleteData<WorkflowItem> {
export class WorkflowItemDataService extends IdentifiableDataService<WorkflowItem> implements SearchData<WorkflowItem>, DeleteData<WorkflowItem>, PatchData<WorkflowItem> {
protected linkPath = 'workflowitems';
protected searchByItemLinkPath = 'item';
protected responseMsToLive = 10 * 1000;

private searchData: SearchDataImpl<WorkflowItem>;
private deleteData: DeleteDataImpl<WorkflowItem>;
private patchData: PatchDataImpl<WorkflowItem>;

constructor(
protected requestService: RequestService,
protected rdbService: RemoteDataBuildService,
protected objectCache: ObjectCacheService,
protected halService: HALEndpointService,
protected notificationsService: NotificationsService,
protected comparator: DefaultChangeAnalyzer<WorkflowItem>,
) {
super('workspaceitems', requestService, rdbService, objectCache, halService);

this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.comparator, this.responseMsToLive, constructWorkflowItemIdEndpoint);
}

/**
Expand Down Expand Up @@ -142,4 +159,20 @@ export class WorkflowItemDataService extends IdentifiableDataService<WorkflowIte
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
}

commitUpdates(method?: RestRequestMethod): void {
this.patchData.commitUpdates(method);
}

createPatchFromCache(object: WorkflowItem): Observable<Operation[]> {
return this.patchData.createPatchFromCache(object);
}

patch(object: WorkflowItem, operations: Operation[]): Observable<RemoteData<WorkflowItem>> {
return this.patchData.patch(object, operations);
}

update(object: WorkflowItem): Observable<RemoteData<WorkflowItem>> {
return this.patchData.update(object);
}
}
4 changes: 3 additions & 1 deletion src/app/core/submission/workspaceitem-data.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { RequestEntry } from '../data/request-entry.model';
import { CoreState } from '../core-state.model';
import { testSearchDataImplementation } from '../data/base/search-data.spec';
import { testDeleteDataImplementation } from '../data/base/delete-data.spec';
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';

describe('WorkspaceitemDataService test', () => {
let scheduler: TestScheduler;
Expand Down Expand Up @@ -89,11 +90,12 @@ describe('WorkspaceitemDataService test', () => {
objectCache,
halService,
notificationsService,
new DefaultChangeAnalyzer(),
);
}

describe('composition', () => {
const initService = () => new WorkspaceitemDataService(null, null, null, null, null);
const initService = () => new WorkspaceitemDataService(null, null, null, null, null, null);
testSearchDataImplementation(initService);
testDeleteDataImplementation(initService);
});
Expand Down
35 changes: 34 additions & 1 deletion src/app/core/submission/workspaceitem-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,46 @@ import { PaginatedList } from '../data/paginated-list.model';
import { DeleteData, DeleteDataImpl } from '../data/base/delete-data';
import { NoContent } from '../shared/NoContent.model';
import { dataService } from '../data/base/data-service.decorator';
import { PatchData, PatchDataImpl } from '../data/base/patch-data';
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
import { RestRequestMethod } from '../data/rest-request-method';
import { Operation } from 'fast-json-patch';

/**
* Constructs an endpoint taking into account that the WorkspaceItem's "uuid" has a prefix by removing that prefix from the ID
* @param endpoint Endpoint to append ID to
* @param resourceID WorkspaceItem's "uuid" including the prefix to remove
*/
const constructWorkspaceItemIdEndpoint = (endpoint, resourceID) => {
const regex = new RegExp(`^${WorkspaceItem.type.value}-`);
return `${endpoint}/${resourceID.replace(regex, '')}`;
};

/**
* A service that provides methods to make REST requests with workspaceitems endpoint.
*/
@Injectable()
@dataService(WorkspaceItem.type)
export class WorkspaceitemDataService extends IdentifiableDataService<WorkspaceItem> implements SearchData<WorkspaceItem>, DeleteData<WorkspaceItem> {
export class WorkspaceitemDataService extends IdentifiableDataService<WorkspaceItem> implements SearchData<WorkspaceItem>, DeleteData<WorkspaceItem>, PatchData<WorkspaceItem> {
protected searchByItemLinkPath = 'item';

private searchData: SearchDataImpl<WorkspaceItem>;
private deleteData: DeleteDataImpl<WorkspaceItem>;
private patchData: PatchDataImpl<WorkspaceItem>;

constructor(
protected requestService: RequestService,
protected rdbService: RemoteDataBuildService,
protected objectCache: ObjectCacheService,
protected halService: HALEndpointService,
protected notificationsService: NotificationsService,
protected comparator: DefaultChangeAnalyzer<WorkspaceItem>,
) {
super('workspaceitems', requestService, rdbService, objectCache, halService);

this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.comparator, this.responseMsToLive, constructWorkspaceItemIdEndpoint);
}

/**
Expand Down Expand Up @@ -115,4 +132,20 @@ export class WorkspaceitemDataService extends IdentifiableDataService<WorkspaceI
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
}

commitUpdates(method?: RestRequestMethod): void {
this.patchData.commitUpdates(method);
}

createPatchFromCache(object: WorkspaceItem): Observable<Operation[]> {
return this.patchData.createPatchFromCache(object);
}

patch(object: WorkspaceItem, operations: Operation[]): Observable<RemoteData<WorkspaceItem>> {
return this.patchData.patch(object, operations);
}

update(object: WorkspaceItem): Observable<RemoteData<WorkspaceItem>> {
return this.patchData.update(object);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
}
},
{ provide: NgZone, useValue: new NgZone({}) },
{ provide: APP_CONFIG, useValue: environment }
{ provide: APP_CONFIG, useValue: environment },
{ provide: 'sectionDataProvider', useValue: { id: 'mock-section-id' } },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents().then(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
QueryList,
SimpleChanges,
Expand Down Expand Up @@ -120,6 +121,7 @@ import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './ds-dynamic-form-cons
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
import { itemLinksToFollow } from '../../../utils/relation-query.utils';
import { SectionDataObject } from '../../../../submission/sections/models/section-data.model';

export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
switch (model.type) {
Expand Down Expand Up @@ -209,6 +211,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
@Input() hasErrorMessaging = false;
@Input() layout = null as DynamicFormLayout;
@Input() model: any;
@Input() arrayIndex: number;
relationshipValue$: Observable<ReorderableRelationship>;
isRelationship: boolean;
modalRef: NgbModalRef;
Expand Down Expand Up @@ -262,6 +265,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
public formBuilderService: FormBuilderService,
private submissionService: SubmissionService,
@Inject(APP_CONFIG) protected appConfig: AppConfig,
@Optional() @Inject('sectionDataProvider') public sectionData: SectionDataObject,
) {
super(ref, componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
this.fetchThumbnail = this.appConfig.browseBy.showThumbnails;
Expand Down Expand Up @@ -456,6 +460,13 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
} else if (typeof this.model.value.value === 'string') {
modalComp.query = this.model.value.value;
}

// If the existing value is not virtual, store properties on the modal required to perform a replace operation
if (hasValue(this.sectionData) && !this.model.value.isVirtual) {
modalComp.replaceValuePlace = this.arrayIndex || 0;
modalComp.replaceValueMetadataField = this.model.name;
modalComp.replaceValueSection = this.sectionData?.id;
}
}

modalComp.repeatable = this.model.repeatable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
[class.d-none]="_model.hidden"
[layout]="formLayout"
[model]="_model"
[arrayIndex]="idx"
[templates]="templates"
[ngClass]="[getClass('element', 'host', _model), getClass('grid', 'host', _model)]"
(dfBlur)="onBlur($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat
</button>
</div>
<div class="modal-body">
<ds-themed-loading *ngIf="!item || !collection"></ds-themed-loading>
<ng-container *ngIf="item && collection">
<ds-themed-loading *ngIf="!item || !collection || isSubmitting"></ds-themed-loading>
<ng-container *ngIf="item && collection && !isSubmitting">
<ul ngbNav #nav="ngbNav" class="nav-tabs">
<li ngbNavItem>
<a ngbNavLink>{{'submission.sections.describe.relationship-lookup.search-tab.tab-title.' + relationshipOptions.relationshipType | translate : { count: (totalInternal$ | async)} }}</a>
Expand Down Expand Up @@ -71,18 +71,18 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat
<small>{{ ('submission.sections.describe.relationship-lookup.selected' | translate: {size: (selection$ | async)?.length || 0}) }}</small>
<div class="d-flex float-right space-children-mr">
<div class="close-button">
<button type="button" [disabled]="isPending" class="btn btn-outline-secondary" (click)="close()">
<button type="button" [disabled]="isPending || isSubmitting" class="btn btn-outline-secondary" (click)="close()">
{{ ('submission.sections.describe.relationship-lookup.close' | translate) }}</button>
</div>
<ng-container *ngIf="isEditRelationship">
<button class="btn btn-danger discard"
[disabled]="(toAdd.length == 0 && toRemove.length == 0) || isPending"
[disabled]="(toAdd.length == 0 && toRemove.length == 0) || isPending || isSubmitting"
(click)="discardEv()">
<i class="fas fa-times"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.metadata.discard-button" | translate}}</span>
</button>
<button class="btn btn-primary submit"
[disabled]="(toAdd.length == 0 && toRemove.length == 0) || isPending"
[disabled]="(toAdd.length == 0 && toRemove.length == 0) || isPending || isSubmitting"
(click)="submitEv()">
<span *ngIf="isPending" class="spinner-border spinner-border-sm" role="status"
aria-hidden="true"></span>
Expand Down
Loading
Loading