mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[CST-4878] Finished working on embargo add part of form and unit testing
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
import { autoserialize } from 'cerialize';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model class for an Access Condition
|
||||||
|
*/
|
||||||
|
export class AccessesConditionOption {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name for this Access Condition
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The groupName for this Access Condition
|
||||||
|
*/
|
||||||
|
groupName: string;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this Access Condition has a start date
|
||||||
|
*/
|
||||||
|
hasStartDate: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this Access Condition has an end date
|
||||||
|
*/
|
||||||
|
hasEndDate: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum value of the start date
|
||||||
|
*/
|
||||||
|
endDateLimit?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum value of the end date
|
||||||
|
*/
|
||||||
|
startDateLimit?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum value of the start date
|
||||||
|
*/
|
||||||
|
maxStartDate?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum value of the end date
|
||||||
|
*/
|
||||||
|
maxEndDate?: string;
|
||||||
|
}
|
27
src/app/core/config/models/config-submission-access.model.ts
Normal file
27
src/app/core/config/models/config-submission-access.model.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { autoserialize, inheritSerialization, deserialize } from 'cerialize';
|
||||||
|
import { typedObject, link } from '../../cache/builders/build-decorators';
|
||||||
|
import { ConfigObject } from './config.model';
|
||||||
|
import { AccessesConditionOption } from './config-accesses-conditions-options.model';
|
||||||
|
import { SUBMISSION_ACCESSES_TYPE } from './config-type';
|
||||||
|
import { HALLink } from '../../shared/hal-link.model';
|
||||||
|
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(ConfigObject)
|
||||||
|
export class SubmissionAccessModel extends ConfigObject {
|
||||||
|
static type = SUBMISSION_ACCESSES_TYPE;
|
||||||
|
/**
|
||||||
|
* A list of available bitstream access conditions
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
accessConditionOptions: AccessesConditionOption[];
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
discoverable: boolean;
|
||||||
|
|
||||||
|
@deserialize
|
||||||
|
_links: {
|
||||||
|
self: HALLink
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
import { inheritSerialization } from 'cerialize';
|
||||||
|
import { typedObject } from '../../cache/builders/build-decorators';
|
||||||
|
import { SUBMISSION_ACCESSES_TYPE } from './config-type';
|
||||||
|
import { SubmissionAccessModel } from './config-submission-access.model';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(SubmissionAccessModel)
|
||||||
|
export class SubmissionAccessesModel extends SubmissionAccessModel {
|
||||||
|
static type = SUBMISSION_ACCESSES_TYPE;
|
||||||
|
}
|
@@ -15,3 +15,5 @@ export const SUBMISSION_SECTION_TYPE = new ResourceType('submissionsection');
|
|||||||
export const SUBMISSION_UPLOADS_TYPE = new ResourceType('submissionuploads');
|
export const SUBMISSION_UPLOADS_TYPE = new ResourceType('submissionuploads');
|
||||||
|
|
||||||
export const SUBMISSION_UPLOAD_TYPE = new ResourceType('submissionupload');
|
export const SUBMISSION_UPLOAD_TYPE = new ResourceType('submissionupload');
|
||||||
|
|
||||||
|
export const SUBMISSION_ACCESSES_TYPE = new ResourceType('submissionaccessoption');
|
||||||
|
44
src/app/core/config/submission-accesses-config.service.ts
Normal file
44
src/app/core/config/submission-accesses-config.service.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ConfigService } from './config.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
|
import { SUBMISSION_ACCESSES_TYPE } from './models/config-type';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||||
|
import { ConfigObject } from './models/config.model';
|
||||||
|
import { SubmissionAccessesModel } from './models/config-submission-accesses.model';
|
||||||
|
import { RemoteData } from '../data/remote-data';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||||
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods to retrieve, from REST server, bitstream access conditions configurations applicable during the submission process.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
@dataService(SUBMISSION_ACCESSES_TYPE)
|
||||||
|
export class SubmissionAccessesConfigService extends ConfigService {
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected comparator: DefaultChangeAnalyzer<SubmissionAccessesModel>
|
||||||
|
) {
|
||||||
|
super(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator, 'submissionaccessoptions');
|
||||||
|
}
|
||||||
|
|
||||||
|
findByHref(href: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow): Observable<RemoteData<SubmissionAccessesModel>> {
|
||||||
|
return super.findByHref(href, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow as FollowLinkConfig<ConfigObject>[]) as Observable<RemoteData<SubmissionAccessesModel>>;
|
||||||
|
}
|
||||||
|
}
|
@@ -163,6 +163,7 @@ import { RootDataService } from './data/root-data.service';
|
|||||||
import { Root } from './data/root.model';
|
import { Root } from './data/root.model';
|
||||||
import { SearchConfig } from './shared/search/search-filters/search-config.model';
|
import { SearchConfig } from './shared/search/search-filters/search-config.model';
|
||||||
import { SequenceService } from './shared/sequence.service';
|
import { SequenceService } from './shared/sequence.service';
|
||||||
|
import { SubmissionAccessesModel } from 'src/app/core/config/models/config-submission-accesses.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -343,7 +344,8 @@ export const models =
|
|||||||
Registration,
|
Registration,
|
||||||
UsageReport,
|
UsageReport,
|
||||||
Root,
|
Root,
|
||||||
SearchConfig
|
SearchConfig,
|
||||||
|
SubmissionAccessesModel
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
37
src/app/core/submission/models/submission-accesses.model.ts
Normal file
37
src/app/core/submission/models/submission-accesses.model.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { typedObject } from '../../cache/builders/build-decorators';
|
||||||
|
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
import { HALResource } from '../../shared/hal-resource.model';
|
||||||
|
import { SUBMISSION_ACCESSES } from 'src/app/core/submission/models/submission-accesses.resource-type';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(HALResource)
|
||||||
|
export class SubmissionAccesses extends HALResource {
|
||||||
|
|
||||||
|
static type = SUBMISSION_ACCESSES;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object type
|
||||||
|
*/
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
discoverable: boolean;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
accessConditions: AccessConditions[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AccessConditions {
|
||||||
|
name: string;
|
||||||
|
startDate?: Date;
|
||||||
|
hasStartDate?: boolean;
|
||||||
|
maxStartDate?: string;
|
||||||
|
hasEndDate?: boolean;
|
||||||
|
maxEndDate?: string;
|
||||||
|
endDate?: Date;
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource type for License
|
||||||
|
*
|
||||||
|
* Needs to be in a separate file to prevent circular
|
||||||
|
* dependencies in webpack.
|
||||||
|
*/
|
||||||
|
export const SUBMISSION_ACCESSES = new ResourceType('submissionaccesses');
|
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* An interface to represent the submission's creative commons license section data.
|
||||||
|
*/
|
||||||
|
export interface WorkspaceitemSectionAccessesObject {
|
||||||
|
id: string;
|
||||||
|
discoverable: boolean;
|
||||||
|
accessConditions: [
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
startDate?: Date;
|
||||||
|
hasStartDate?: boolean;
|
||||||
|
maxStartDate?: string;
|
||||||
|
hasEndDate?: boolean;
|
||||||
|
maxEndDate?: string;
|
||||||
|
endDate?: Date;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { WorkspaceitemSectionAccessesObject } from './workspaceitem-section-accesses.model';
|
||||||
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
||||||
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
||||||
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
||||||
@@ -19,4 +20,5 @@ export type WorkspaceitemSectionDataType
|
|||||||
| WorkspaceitemSectionFormObject
|
| WorkspaceitemSectionFormObject
|
||||||
| WorkspaceitemSectionLicenseObject
|
| WorkspaceitemSectionLicenseObject
|
||||||
| WorkspaceitemSectionCcLicenseObject
|
| WorkspaceitemSectionCcLicenseObject
|
||||||
|
| WorkspaceitemSectionAccessesObject
|
||||||
| string;
|
| string;
|
||||||
|
44
src/app/shared/mocks/section-accesses-config.service.mock.ts
Normal file
44
src/app/shared/mocks/section-accesses-config.service.mock.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { SubmissionFormsConfigService } from '../../core/config/submission-forms-config.service';
|
||||||
|
import { SubmissionFormsModel } from 'src/app/core/config/models/config-submission-forms.model';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from 'src/app/shared/remote-data.utils';
|
||||||
|
|
||||||
|
const configRes = Object.assign(new SubmissionFormsModel(), {
|
||||||
|
'id': 'AccessConditionDefaultConfiguration',
|
||||||
|
'canChangeDiscoverable': true,
|
||||||
|
'accessConditionOptions': [
|
||||||
|
{
|
||||||
|
'name': 'openaccess',
|
||||||
|
'hasStartDate': false,
|
||||||
|
'hasEndDate': false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'lease',
|
||||||
|
'hasStartDate': false,
|
||||||
|
'hasEndDate': true,
|
||||||
|
'maxEndDate': '2022-06-20T12:17:44.420+00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'embargo',
|
||||||
|
'hasStartDate': true,
|
||||||
|
'hasEndDate': false,
|
||||||
|
'maxStartDate': '2024-12-20T12:17:44.420+00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'administrator',
|
||||||
|
'hasStartDate': false,
|
||||||
|
'hasEndDate': false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'type': 'submissionaccessoption',
|
||||||
|
'_links': {
|
||||||
|
'self': {
|
||||||
|
'href': 'http://localhost:8080/server/api/config/submissionaccessoptions/AccessConditionDefaultConfiguration'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export function getSubmissionAccessesConfigService(): SubmissionFormsConfigService {
|
||||||
|
return jasmine.createSpyObj('SubmissionAccessesConfigService', {
|
||||||
|
findByHref: createSuccessfulRemoteDataObject$(configRes),
|
||||||
|
});
|
||||||
|
}
|
13
src/app/shared/mocks/section-accesses.service.mock.ts
Normal file
13
src/app/shared/mocks/section-accesses.service.mock.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { SubmissionFormsModel } from 'src/app/core/config/models/config-submission-forms.model';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
|
const dataRes = Object.assign(new SubmissionFormsModel(), {
|
||||||
|
'id': 'AccessConditionDefaultConfiguration',
|
||||||
|
'accessConditions': [],
|
||||||
|
});
|
||||||
|
|
||||||
|
export function getSectionAccessesService() {
|
||||||
|
return jasmine.createSpyObj('SectionAccessesService', {
|
||||||
|
getAccessesData: observableOf(dataRes),
|
||||||
|
});
|
||||||
|
}
|
@@ -1654,7 +1654,7 @@ export const mockFileFormData = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessConditionGroup:{
|
accessConditionGroup: {
|
||||||
name: [
|
name: [
|
||||||
{
|
{
|
||||||
value: 'lease',
|
value: 'lease',
|
||||||
@@ -1723,3 +1723,94 @@ export const mockFileFormData = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const mockAccessesFormData = {
|
||||||
|
discoverable: true,
|
||||||
|
accessCondition: [
|
||||||
|
{
|
||||||
|
accessConditionGroup: {
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
value: 'openaccess',
|
||||||
|
language: null,
|
||||||
|
authority: null,
|
||||||
|
display: 'openaccess',
|
||||||
|
confidence: -1,
|
||||||
|
place: 0,
|
||||||
|
otherInformation: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessConditionGroup: {
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
value: 'lease',
|
||||||
|
language: null,
|
||||||
|
authority: null,
|
||||||
|
display: 'lease',
|
||||||
|
confidence: -1,
|
||||||
|
place: 0,
|
||||||
|
otherInformation: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
endDate: [
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
year: 2019,
|
||||||
|
month: 1,
|
||||||
|
day: 16
|
||||||
|
},
|
||||||
|
language: null,
|
||||||
|
authority: null,
|
||||||
|
display: {
|
||||||
|
year: 2019,
|
||||||
|
month: 1,
|
||||||
|
day: 16
|
||||||
|
},
|
||||||
|
confidence: -1,
|
||||||
|
place: 0,
|
||||||
|
otherInformation: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessConditionGroup: {
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
value: 'embargo',
|
||||||
|
language: null,
|
||||||
|
authority: null,
|
||||||
|
display: 'lease',
|
||||||
|
confidence: -1,
|
||||||
|
place: 0,
|
||||||
|
otherInformation: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
startDate: [
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
year: 2019,
|
||||||
|
month: 1,
|
||||||
|
day: 16
|
||||||
|
},
|
||||||
|
language: null,
|
||||||
|
authority: null,
|
||||||
|
display: {
|
||||||
|
year: 2019,
|
||||||
|
month: 1,
|
||||||
|
day: 16
|
||||||
|
},
|
||||||
|
confidence: -1,
|
||||||
|
place: 0,
|
||||||
|
otherInformation: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
106
src/app/shared/testing/form-event.stub.ts
Normal file
106
src/app/shared/testing/form-event.stub.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { FormControl, FormGroup, AbstractControl } from '@angular/forms';
|
||||||
|
import { DynamicCheckboxModel, DynamicSelectModel } from '@ng-dynamic-forms/core';
|
||||||
|
|
||||||
|
export const accessConditionChangeEvent = {
|
||||||
|
$event: {
|
||||||
|
bubbles: true,
|
||||||
|
cancelBubble: false,
|
||||||
|
cancelable: false,
|
||||||
|
composed: false,
|
||||||
|
currentTarget: null,
|
||||||
|
defaultPrevented: false,
|
||||||
|
eventPhase: 0,
|
||||||
|
isTrusted: true,
|
||||||
|
path: ['input#accessCondition-0-endDate.form-control.ng-touched.ng-dirty.ng-valid', 'div.input-group.ng-touched.ng-valid.ng-pristine', 'ds-dynamic-date-picker-inline.ng-star-inserted, div, div, div, div.ng-touched.ng-valid.ng-pristine, ds-dynamic-form-control-container.col-6.ng-star-inserted, div#accessCondition-0-accessConditionGroup.form-row.ng-star-inserted.ng-touched.ng-valid.ng-pristine, ds-dynamic-form-group.ng-star-inserted, div, div, div, div.pl-1.pr-1.ng-touched.ng-valid.ng-pristine, ds-dynamic-form-control-container.form-group.flex-fill.access-condition-group.ng-star-inserted.ng-to…, div.cdk-drag.cdk-drag-handle.form-row.cdk-drag-disabled.ng-star-inserted.ng-touched.ng-valid.ng-pris…, div#cdk-drop-list-5.cdk-drop-list, div#accessCondition.ng-star-inserted.ng-touched.ng-valid.ng-pristine, ds-dynamic-form-array.ng-star-inserted, div, div, div, div.form-group.ng-touched.ng-valid.ng-pristine, ds-dynamic-form-control-container.ng-star-inserted, ds-dynamic-form.ng-touched.ng-valid.ng-pristine, form.form-horizontal.ng-touched.ng-valid.ng-pristine, div.container-fluid, ds-form.ng-star-inserted, ds-section-accesses.ng-star-inserted, div#sectionContent_AccessConditionDefaultConfiguration.ng-star-inserted, div.card-body, div#AccessConditionDefaultConfiguration.collapse.show.ng-star-inserted, div.card.ng-star-inserted, ngb-accordion.accordion, div#section_AccessConditionDefaultConfiguration.section-focus, ds-submission-section-container.ng-star-inserted, div.submission-form-content, div.container-fluid, ds-submission-form, div.submission-submit-container, ds-submission-edit.ng-star-inserted, ds-themed-submission-edit.ng-star-inserted, div.ng-tns-c392-0, main.main-content.ng-tns-c392-0, div.inner-wrapper.ng-tns-c392-0.ng-trigger.ng-trigger-slideSidebarPadding, div.outer-wrapper.ng-tns-c392-0.ng-star-inserted, ds-root.ng-tns-c392-0.ng-star-inserted, ds-themed-root, ds-app, body, html.wf-droidsans-n4-active.wf-active, document, Window'],
|
||||||
|
returnValue: true,
|
||||||
|
srcElement: 'input#accessCondition-0-endDate.form-control.ng-touched.ng-dirty.ng-valid',
|
||||||
|
target: 'input#accessCondition-0-endDate.form-control.ng-touched.ng-dirty.ng-valid',
|
||||||
|
timeStamp: 143042.8999999999,
|
||||||
|
type: 'change',
|
||||||
|
},
|
||||||
|
context: null,
|
||||||
|
control: new FormControl({
|
||||||
|
errors: null,
|
||||||
|
pristine: false,
|
||||||
|
status: 'VALID',
|
||||||
|
statusChanges: { _isScalar: false, observers: [], closed: false, isStopped: false, hasError: false },
|
||||||
|
touched: true,
|
||||||
|
value: { year: 2021, month: 12, day: 30 },
|
||||||
|
valueChanges: { _isScalar: false, observers: [], closed: false, isStopped: false, hasError: false },
|
||||||
|
_updateOn: 'change',
|
||||||
|
}),
|
||||||
|
group: new FormGroup({}),
|
||||||
|
model: new DynamicSelectModel({
|
||||||
|
additional: null,
|
||||||
|
asyncValidators: null,
|
||||||
|
controlTooltip: null,
|
||||||
|
errorMessages: { required: 'submission.sections.upload.form.date-required-until' },
|
||||||
|
hidden: false,
|
||||||
|
hint: null,
|
||||||
|
id: 'endDate',
|
||||||
|
label: 'submission.sections.upload.form.until-label',
|
||||||
|
labelTooltip: null,
|
||||||
|
name: 'endDate',
|
||||||
|
placeholder: 'Until',
|
||||||
|
prefix: null,
|
||||||
|
relations: [],
|
||||||
|
required: true,
|
||||||
|
suffix: null,
|
||||||
|
tabIndex: null,
|
||||||
|
updateOn: null,
|
||||||
|
validators: { required: null },
|
||||||
|
}),
|
||||||
|
type: 'change'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const checkboxChangeEvent = {
|
||||||
|
$event: {
|
||||||
|
bubbles: true,
|
||||||
|
cancelBubble: false,
|
||||||
|
cancelable: false,
|
||||||
|
composed: false,
|
||||||
|
currentTarget: null,
|
||||||
|
defaultPrevented: false,
|
||||||
|
eventPhase: 0,
|
||||||
|
isTrusted: true,
|
||||||
|
path: ['input#discoverable.form-check-input.ng-valid.ng-touched.ng-pristine', 'label.form-check-label', 'div.form-check.ng-touched.ng-valid.ng-pristine', 'dynamic-ng-bootstrap-checkbox.ng-star-inserted', 'div', 'div', 'div', 'div.form-group.ng-touched.ng-valid.ng-pristine', 'ds-dynamic-form-control-container.ng-star-inserted', 'ds-dynamic-form.ng-touched.ng-valid.ng-pristine', 'form.form-horizontal.ng-touched.ng-valid.ng-pristine', 'div.container-fluid', 'ds-form.ng-star-inserted', 'ds-section-accesses.ng-star-inserted', 'div#sectionContent_AccessConditionDefaultConfiguration.ng-star-inserted', 'div.card-body', 'div#AccessConditionDefaultConfiguration.collapse.show.ng-star-inserted', 'div.card.ng-star-inserted', 'ngb-accordion.accordion', 'div#section_AccessConditionDefaultConfiguration.section-focus', 'ds-submission-section-container.ng-star-inserted', 'div.submission-form-content', 'div.container-fluid', 'ds-submission-form', 'div.submission-submit-container', 'ds-submission-edit.ng-star-inserted', 'ds-themed-submission-edit.ng-star-inserted', 'div.ng-tns-c392-0', 'main.main-content.ng-tns-c392-0', 'div.inner-wrapper.ng-tns-c392-0.ng-trigger.ng-trigger-slideSidebarPadding', 'div.outer-wrapper.ng-tns-c392-0.ng-star-inserted', 'ds-root.ng-tns-c392-0.ng-star-inserted', 'ds-themed-root', 'ds-app', 'body', 'html.wf-droidsans-n4-active.wf-active', 'document', 'Window'],
|
||||||
|
returnValue: true,
|
||||||
|
srcElement: 'input#discoverable.form-check-input.ng-valid.ng-touched.ng-pristine',
|
||||||
|
target: 'input#discoverable.form-check-input.ng-valid.ng-touched.ng-pristine',
|
||||||
|
timeStamp: 143042.8999999999,
|
||||||
|
type: 'change',
|
||||||
|
},
|
||||||
|
context: null,
|
||||||
|
control: new FormControl({
|
||||||
|
errors: null,
|
||||||
|
pristine: false,
|
||||||
|
status: 'VALID',
|
||||||
|
statusChanges: { _isScalar: false, observers: [], closed: false, isStopped: false, hasError: false },
|
||||||
|
touched: true,
|
||||||
|
value: { year: 2021, month: 12, day: 30 },
|
||||||
|
valueChanges: { _isScalar: false, observers: [], closed: false, isStopped: false, hasError: false },
|
||||||
|
_updateOn: 'change',
|
||||||
|
}),
|
||||||
|
group: new FormGroup({}),
|
||||||
|
model: new DynamicCheckboxModel({
|
||||||
|
additional: null,
|
||||||
|
asyncValidators: null,
|
||||||
|
controlTooltip: null,
|
||||||
|
errorMessages: null,
|
||||||
|
hidden: false,
|
||||||
|
hint: null,
|
||||||
|
id: 'discoverable',
|
||||||
|
indeterminate: false,
|
||||||
|
label: 'Discoverable',
|
||||||
|
labelPosition: null,
|
||||||
|
labelTooltip: null,
|
||||||
|
name: 'discoverable',
|
||||||
|
relations: [],
|
||||||
|
required: false,
|
||||||
|
tabIndex: null,
|
||||||
|
updateOn: null,
|
||||||
|
validators: { required: null },
|
||||||
|
}),
|
||||||
|
type: 'change'
|
||||||
|
};
|
@@ -6,6 +6,7 @@ import { debounceTime, filter, switchMap } from 'rxjs/operators';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
|
import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
|
||||||
|
import { WorkspaceitemSectionAccessesObject } from '../../core/submission/models/workspaceitem-section-accesses.model';
|
||||||
import { hasValue, isEmpty, isNotEmptyOperator, isNotNull } from '../../shared/empty.util';
|
import { hasValue, isEmpty, isNotEmptyOperator, isNotNull } from '../../shared/empty.util';
|
||||||
import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
|
import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
|
||||||
import { SubmissionService } from '../submission.service';
|
import { SubmissionService } from '../submission.service';
|
||||||
@@ -97,13 +98,13 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
|||||||
* @param {SubmissionJsonPatchOperationsService} submissionJsonPatchOperationsService
|
* @param {SubmissionJsonPatchOperationsService} submissionJsonPatchOperationsService
|
||||||
*/
|
*/
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef,
|
constructor(private changeDetectorRef: ChangeDetectorRef,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private itemDataService: ItemDataService,
|
private itemDataService: ItemDataService,
|
||||||
private submissionService: SubmissionService,
|
private submissionService: SubmissionService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private submissionJsonPatchOperationsService: SubmissionJsonPatchOperationsService) {
|
private submissionJsonPatchOperationsService: SubmissionJsonPatchOperationsService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,6 +128,8 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
|
|||||||
this.collectionId = (submissionObjectRD.payload.collection as Collection).id;
|
this.collectionId = (submissionObjectRD.payload.collection as Collection).id;
|
||||||
this.selfUrl = submissionObjectRD.payload._links.self.href;
|
this.selfUrl = submissionObjectRD.payload._links.self.href;
|
||||||
this.sections = submissionObjectRD.payload.sections;
|
this.sections = submissionObjectRD.payload.sections;
|
||||||
|
|
||||||
|
|
||||||
this.itemLink$.next(submissionObjectRD.payload._links.item.href);
|
this.itemLink$.next(submissionObjectRD.payload._links.item.href);
|
||||||
this.item = submissionObjectRD.payload.item;
|
this.item = submissionObjectRD.payload.item;
|
||||||
this.submissionDefinition = (submissionObjectRD.payload.submissionDefinition as SubmissionDefinitionsModel);
|
this.submissionDefinition = (submissionObjectRD.payload.submissionDefinition as SubmissionDefinitionsModel);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
||||||
|
|
||||||
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
||||||
import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, map, switchMap, tap } from 'rxjs/operators';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
|
import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
@@ -131,6 +131,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
if ((changes.collectionId && this.collectionId) && (changes.submissionId && this.submissionId)) {
|
if ((changes.collectionId && this.collectionId) && (changes.submissionId && this.submissionId)) {
|
||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
|
|
||||||
|
|
||||||
// retrieve submission's section list
|
// retrieve submission's section list
|
||||||
this.submissionSections = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
this.submissionSections = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||||
filter(() => this.isActive),
|
filter(() => this.isActive),
|
||||||
@@ -143,7 +144,9 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
return observableOf([]);
|
return observableOf([]);
|
||||||
}
|
}
|
||||||
}));
|
}),
|
||||||
|
tap((res) => { console.log(res); }));
|
||||||
|
|
||||||
this.uploadEnabled$ = this.sectionsService.isSectionTypeAvailable(this.submissionId, SectionsType.Upload);
|
this.uploadEnabled$ = this.sectionsService.isSectionTypeAvailable(this.submissionId, SectionsType.Upload);
|
||||||
|
|
||||||
// check if is submission loading
|
// check if is submission loading
|
||||||
@@ -230,6 +233,8 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
protected getSectionsList(): Observable<any> {
|
protected getSectionsList(): Observable<any> {
|
||||||
return this.submissionService.getSubmissionSections(this.submissionId).pipe(
|
return this.submissionService.getSubmissionSections(this.submissionId).pipe(
|
||||||
filter((sections: SectionDataObject[]) => isNotEmpty(sections)),
|
filter((sections: SectionDataObject[]) => isNotEmpty(sections)),
|
||||||
map((sections: SectionDataObject[]) => sections));
|
map((sections: SectionDataObject[]) => sections
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -125,8 +125,8 @@ export class SubmissionObjectEffects {
|
|||||||
this.submissionService.getSubmissionObjectLinkName(),
|
this.submissionService.getSubmissionObjectLinkName(),
|
||||||
action.payload.submissionId,
|
action.payload.submissionId,
|
||||||
'sections').pipe(
|
'sections').pipe(
|
||||||
map((response: SubmissionObject[]) => new SaveSubmissionFormSuccessAction(action.payload.submissionId, response, action.payload.isManual)),
|
map((response: SubmissionObject[]) => new SaveSubmissionFormSuccessAction(action.payload.submissionId, response, action.payload.isManual)),
|
||||||
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,8 +139,8 @@ export class SubmissionObjectEffects {
|
|||||||
this.submissionService.getSubmissionObjectLinkName(),
|
this.submissionService.getSubmissionObjectLinkName(),
|
||||||
action.payload.submissionId,
|
action.payload.submissionId,
|
||||||
'sections').pipe(
|
'sections').pipe(
|
||||||
map((response: SubmissionObject[]) => new SaveForLaterSubmissionFormSuccessAction(action.payload.submissionId, response)),
|
map((response: SubmissionObject[]) => new SaveForLaterSubmissionFormSuccessAction(action.payload.submissionId, response)),
|
||||||
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,8 +179,8 @@ export class SubmissionObjectEffects {
|
|||||||
action.payload.submissionId,
|
action.payload.submissionId,
|
||||||
'sections',
|
'sections',
|
||||||
action.payload.sectionId).pipe(
|
action.payload.sectionId).pipe(
|
||||||
map((response: SubmissionObject[]) => new SaveSubmissionSectionFormSuccessAction(action.payload.submissionId, response)),
|
map((response: SubmissionObject[]) => new SaveSubmissionSectionFormSuccessAction(action.payload.submissionId, response)),
|
||||||
catchError(() => observableOf(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId))));
|
catchError(() => observableOf(new SaveSubmissionSectionFormErrorAction(action.payload.submissionId))));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,16 +202,16 @@ export class SubmissionObjectEffects {
|
|||||||
this.submissionService.getSubmissionObjectLinkName(),
|
this.submissionService.getSubmissionObjectLinkName(),
|
||||||
action.payload.submissionId,
|
action.payload.submissionId,
|
||||||
'sections').pipe(
|
'sections').pipe(
|
||||||
map((response: SubmissionObject[]) => {
|
map((response: SubmissionObject[]) => {
|
||||||
if (this.canDeposit(response)) {
|
if (this.canDeposit(response)) {
|
||||||
return new DepositSubmissionAction(action.payload.submissionId);
|
return new DepositSubmissionAction(action.payload.submissionId);
|
||||||
} else {
|
} else {
|
||||||
this.notificationsService.warning(null, this.translate.get('submission.sections.general.sections_not_valid'));
|
this.notificationsService.warning(null, this.translate.get('submission.sections.general.sections_not_valid'));
|
||||||
return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId],
|
return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId],
|
||||||
response, action.payload.submissionId, currentState.forms);
|
response, action.payload.submissionId, currentState.forms);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId))));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,13 +310,13 @@ export class SubmissionObjectEffects {
|
|||||||
tap(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.discard_error_notice'))));
|
tap(() => this.notificationsService.error(null, this.translate.get('submission.sections.general.discard_error_notice'))));
|
||||||
|
|
||||||
constructor(private actions$: Actions,
|
constructor(private actions$: Actions,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private operationsService: SubmissionJsonPatchOperationsService,
|
private operationsService: SubmissionJsonPatchOperationsService,
|
||||||
private sectionService: SectionsService,
|
private sectionService: SectionsService,
|
||||||
private store$: Store<any>,
|
private store$: Store<any>,
|
||||||
private submissionService: SubmissionService,
|
private submissionService: SubmissionService,
|
||||||
private submissionObjectService: SubmissionObjectDataService,
|
private submissionObjectService: SubmissionObjectDataService,
|
||||||
private translate: TranslateService) {
|
private translate: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
<p>section-accesses works!</p>
|
<ds-form *ngIf="!!formModel" #formRef="formComponent" [formId]="formId" [formModel]="formModel" [displaySubmit]="false" [displayCancel]="false"
|
||||||
|
(submitForm)="onSubmit()" (dfChange)="onChange($event)"></ds-form>
|
@@ -1,25 +1,144 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { FormService } from './../../../shared/form/form.service';
|
||||||
|
import { ComponentFixture, TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
import { SubmissionSectionAccessesComponent } from './section-accesses.component';
|
import { SubmissionSectionAccessesComponent } from './section-accesses.component';
|
||||||
|
import { SectionsService } from 'src/app/submission/sections/sections.service';
|
||||||
|
import { SectionsServiceStub } from 'src/app/shared/testing/sections-service.stub';
|
||||||
|
|
||||||
|
import { FormBuilderService } from 'src/app/shared/form/builder/form-builder.service';
|
||||||
|
import { getMockFormBuilderService } from 'src/app/shared/mocks/form-builder-service.mock';
|
||||||
|
import { SubmissionAccessesConfigService } from 'src/app/core/config/submission-accesses-config.service';
|
||||||
|
import { getSubmissionAccessesConfigService } from 'src/app/shared/mocks/section-accesses-config.service.mock';
|
||||||
|
import { SectionAccessesService } from 'src/app/submission/sections/accesses/section-accesses.service';
|
||||||
|
import { SectionFormOperationsService } from 'src/app/submission/sections/form/section-form-operations.service';
|
||||||
|
import { JsonPatchOperationsBuilder } from 'src/app/core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { SubmissionJsonPatchOperationsService } from 'src/app/core/submission/submission-json-patch-operations.service';
|
||||||
|
import { getSectionAccessesService } from 'src/app/shared/mocks/section-accesses.service.mock';
|
||||||
|
import { getMockFormOperationsService } from 'src/app/shared/mocks/form-operations-service.mock';
|
||||||
|
import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock';
|
||||||
|
import { SubmissionJsonPatchOperationsServiceStub } from 'src/app/shared/testing/submission-json-patch-operations-service.stub';
|
||||||
|
import { BrowserModule, By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { Observable, of as observableOf, observable } from 'rxjs';
|
||||||
|
import { select, Store } from '@ngrx/store';
|
||||||
|
import { FormComponent } from 'src/app/shared/form/form.component';
|
||||||
|
import { DynamicFormControlModel, DynamicCheckboxModel, DynamicFormArrayGroupModel, DynamicSelectModel, DynamicDatePickerModel, DynamicFormArrayModel } from '@ng-dynamic-forms/core';
|
||||||
|
import { AppState } from 'src/app/app.reducer';
|
||||||
|
import { getMockFormService } from 'src/app/shared/mocks/form-service.mock';
|
||||||
|
import { mockAccessesFormData } from 'src/app/shared/mocks/submission.mock';
|
||||||
|
import { accessConditionChangeEvent, checkboxChangeEvent } from 'src/app/shared/testing/form-event.stub';
|
||||||
|
|
||||||
describe('SubmissionSectionAccessesComponent', () => {
|
describe('SubmissionSectionAccessesComponent', () => {
|
||||||
let component: SubmissionSectionAccessesComponent;
|
let component: SubmissionSectionAccessesComponent;
|
||||||
let fixture: ComponentFixture<SubmissionSectionAccessesComponent>;
|
let fixture: ComponentFixture<SubmissionSectionAccessesComponent>;
|
||||||
|
|
||||||
|
const sectionsServiceStub = new SectionsServiceStub();
|
||||||
|
// const pathCombiner = new JsonPatchOperationPathCombiner('sections', sectionId, 'files', fileIndex);
|
||||||
|
|
||||||
|
const builderService: FormBuilderService = getMockFormBuilderService();
|
||||||
|
const submissionAccessesConfigService = getSubmissionAccessesConfigService();
|
||||||
|
const sectionAccessesService = getSectionAccessesService();
|
||||||
|
const sectionFormOperationsService = getMockFormOperationsService();
|
||||||
|
const operationsBuilder = jasmine.createSpyObj('operationsBuilder', {
|
||||||
|
add: undefined,
|
||||||
|
remove: undefined,
|
||||||
|
replace: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
let formService: any;
|
||||||
|
|
||||||
|
const storeStub = jasmine.createSpyObj('store', ['dispatch']);
|
||||||
|
|
||||||
|
const sectionData = {
|
||||||
|
header: 'submit.progressbar.accessCondition',
|
||||||
|
config: 'http://localhost:8080/server/api/config/submissionaccessoptions/AccessConditionDefaultConfiguration',
|
||||||
|
mandatory: true,
|
||||||
|
sectionType: 'accessCondition',
|
||||||
|
collapsed: false,
|
||||||
|
enabled: true,
|
||||||
|
data: {
|
||||||
|
discoverable: true,
|
||||||
|
accessConditions: []
|
||||||
|
},
|
||||||
|
errorsToShow: [],
|
||||||
|
serverValidationErrors: [],
|
||||||
|
isLoading: false,
|
||||||
|
isValid: true
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [SubmissionSectionAccessesComponent]
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
TranslateModule.forRoot()
|
||||||
|
],
|
||||||
|
declarations: [SubmissionSectionAccessesComponent, FormComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: SectionsService, useValue: sectionsServiceStub },
|
||||||
|
{ provide: FormBuilderService, useValue: builderService },
|
||||||
|
{ provide: SubmissionAccessesConfigService, useValue: submissionAccessesConfigService },
|
||||||
|
{ provide: SectionAccessesService, useValue: sectionAccessesService },
|
||||||
|
{ provide: SectionFormOperationsService, useValue: sectionFormOperationsService },
|
||||||
|
{ provide: JsonPatchOperationsBuilder, useValue: operationsBuilder },
|
||||||
|
{ provide: TranslateService, useValue: getMockTranslateService() },
|
||||||
|
{ provide: FormService, useValue: getMockFormService() },
|
||||||
|
{ provide: Store, useValue: storeStub },
|
||||||
|
{ provide: SubmissionJsonPatchOperationsService, useValue: SubmissionJsonPatchOperationsServiceStub },
|
||||||
|
{ provide: 'sectionDataProvider', useValue: sectionData },
|
||||||
|
{ provide: 'submissionIdProvider', useValue: '1508' },
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(inject([Store], (store: Store<AppState>) => {
|
||||||
fixture = TestBed.createComponent(SubmissionSectionAccessesComponent);
|
fixture = TestBed.createComponent(SubmissionSectionAccessesComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
formService = TestBed.inject(FormService);
|
||||||
|
formService.validateAllFormFields.and.callFake(() => null);
|
||||||
|
formService.isValid.and.returnValue(observableOf(true));
|
||||||
|
formService.getFormData.and.returnValue(observableOf(mockAccessesFormData));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
}));
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should have created formModel', () => {
|
||||||
|
expect(component.formModel).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have formModel length should be 2', () => {
|
||||||
|
expect(component.formModel.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formModel should have 1 model type checkbox and 1 model type array', () => {
|
||||||
|
expect(component.formModel[0] instanceof DynamicCheckboxModel).toBeTrue();
|
||||||
|
expect(component.formModel[1] instanceof DynamicFormArrayModel).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formModel type array should have formgroup with 1 input and 2 datepickers', () => {
|
||||||
|
const formModel: any = component.formModel[1];
|
||||||
|
const formGroup = formModel.groupFactory()[0].group;
|
||||||
|
expect(formGroup[0] instanceof DynamicSelectModel).toBeTrue();
|
||||||
|
expect(formGroup[1] instanceof DynamicDatePickerModel).toBeTrue();
|
||||||
|
expect(formGroup[2] instanceof DynamicDatePickerModel).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when checkbox changed it should call operationsBuilder replace function', () => {
|
||||||
|
component.onChange(checkboxChangeEvent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(operationsBuilder.replace).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when dropdown select changed it should call operationsBuilder add function', () => {
|
||||||
|
component.onChange(accessConditionChangeEvent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(operationsBuilder.add).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,20 +1,404 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { SectionAccessesService } from './section-accesses.service';
|
||||||
|
import { Component, OnInit, ChangeDetectorRef, Inject, ViewChild } from '@angular/core';
|
||||||
import { renderSectionFor } from 'src/app/submission/sections/sections-decorator';
|
import { renderSectionFor } from 'src/app/submission/sections/sections-decorator';
|
||||||
import { SectionsType } from 'src/app/submission/sections/sections-type';
|
import { SectionsType } from 'src/app/submission/sections/sections-type';
|
||||||
|
import { SubmissionService } from 'src/app/submission/submission.service';
|
||||||
|
import { SectionDataObject } from 'src/app/submission/sections/models/section-data.model';
|
||||||
|
import { SectionsService } from 'src/app/submission/sections/sections.service';
|
||||||
|
import { SectionModelComponent } from 'src/app/submission/sections/models/section.model';
|
||||||
|
import { Observable, of, Subscription, combineLatest as observableCombineLatest, BehaviorSubject, combineLatest } from 'rxjs';
|
||||||
|
import { DynamicFormControlModel, MATCH_ENABLED, OR_OPERATOR, DynamicSelectModel, DynamicDatePickerModel, DynamicFormGroupModel, DynamicFormArrayModel, DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER, DynamicCheckboxModel, DynamicFormControlEvent } from '@ng-dynamic-forms/core';
|
||||||
|
import { FormBuilderService } from 'src/app/shared/form/builder/form-builder.service';
|
||||||
|
import { findIndex, isEqual } from 'lodash';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ACCESS_CONDITION_GROUP_CONFIG,
|
||||||
|
ACCESS_CONDITION_GROUP_LAYOUT,
|
||||||
|
ACCESS_CONDITIONS_FORM_ARRAY_CONFIG,
|
||||||
|
ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT,
|
||||||
|
FORM_ACCESS_CONDITION_END_DATE_CONFIG,
|
||||||
|
FORM_ACCESS_CONDITION_END_DATE_LAYOUT,
|
||||||
|
FORM_ACCESS_CONDITION_START_DATE_CONFIG,
|
||||||
|
FORM_ACCESS_CONDITION_START_DATE_LAYOUT,
|
||||||
|
FORM_ACCESS_CONDITION_TYPE_CONFIG,
|
||||||
|
FORM_ACCESS_CONDITION_TYPE_LAYOUT,
|
||||||
|
ACCESS_FORM_CHECKBOX_LAYOUT
|
||||||
|
} from './section-accesses.model';
|
||||||
|
import { isNotEmpty, isNotUndefined, isUndefined, hasValue, isNotNull } from 'src/app/shared/empty.util';
|
||||||
|
import { WorkspaceitemSectionAccessesObject } from '../../../core/submission/models/workspaceitem-section-accesses.model';
|
||||||
|
import { SubmissionAccessesConfigService } from 'src/app/core/config/submission-accesses-config.service';
|
||||||
|
import { getFirstSucceededRemoteData } from 'src/app/core/shared/operators';
|
||||||
|
import { map, take, filter, mergeMap } from 'rxjs/operators';
|
||||||
|
import { FormComponent } from 'src/app/shared/form/form.component';
|
||||||
|
import { FormService } from 'src/app/shared/form/form.service';
|
||||||
|
import { JsonPatchOperationPathCombiner } from 'src/app/core/json-patch/builder/json-patch-operation-path-combiner';
|
||||||
|
import { SectionFormOperationsService } from 'src/app/submission/sections/form/section-form-operations.service';
|
||||||
|
import { JsonPatchOperationsBuilder } from 'src/app/core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { AccessesConditionOption } from 'src/app/core/config/models/config-accesses-conditions-options.model';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { FormFieldPreviousValueObject } from 'src/app/shared/form/builder/models/form-field-previous-value-object';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
import { SubmissionObject } from 'src/app/core/submission/models/submission-object.model';
|
||||||
|
import { SubmissionJsonPatchOperationsService } from 'src/app/core/submission/submission-json-patch-operations.service';
|
||||||
|
import { dateToISOFormat } from 'src/app/shared/date.util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-section-accesses',
|
selector: 'ds-section-accesses',
|
||||||
templateUrl: './section-accesses.component.html',
|
templateUrl: './section-accesses.component.html',
|
||||||
styleUrls: ['./section-accesses.component.scss']
|
styleUrls: ['./section-accesses.component.scss']
|
||||||
})
|
})
|
||||||
@renderSectionFor(SectionsType.Accesses)
|
@renderSectionFor(SectionsType.AccessesCondition)
|
||||||
export class SubmissionSectionAccessesComponent implements OnInit {
|
export class SubmissionSectionAccessesComponent extends SectionModelComponent {
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty
|
/**
|
||||||
constructor() { }
|
* The FormComponent reference
|
||||||
|
*/
|
||||||
|
@ViewChild('formRef') public formRef: FormComponent;
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty
|
/**
|
||||||
ngOnInit(): void {
|
* List of available access conditions that could be set to files
|
||||||
|
*/
|
||||||
|
public availableAccessConditionOptions: AccessesConditionOption[]; // List of accessConditions that an user can select
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accesses metadata data
|
||||||
|
* @type {WorkspaceitemSectionAccessesObject}
|
||||||
|
*/
|
||||||
|
public accessesData: WorkspaceitemSectionAccessesObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection name this submission belonging to
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public collectionName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the upload required
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
public required$ = new BehaviorSubject<boolean>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[JsonPatchOperationPathCombiner]] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map representing all field prevous values
|
||||||
|
* @type {Map}
|
||||||
|
*/
|
||||||
|
protected previousValue: Map<string, number[]> = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map representing all field on their way to be removed
|
||||||
|
* @type {Map}
|
||||||
|
*/
|
||||||
|
protected fieldsOnTheirWayToBeRemoved: Map<string, number[]> = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model
|
||||||
|
* @type {DynamicFormControlModel[]}
|
||||||
|
*/
|
||||||
|
formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {SectionsService} sectionService
|
||||||
|
* @param {SectionDataObject} injectedSectionData
|
||||||
|
* @param {FormService} formService
|
||||||
|
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||||
|
* @param {SectionFormOperationsService} formOperationsService
|
||||||
|
* @param {FormBuilderService} formBuilderService
|
||||||
|
* @param {SubmissionAccessesConfigService} accessesConfigService
|
||||||
|
* @param {SectionAccessesService} accessesService
|
||||||
|
* @param {SubmissionJsonPatchOperationsService} operationsService
|
||||||
|
* @param {string} injectedSubmissionId
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
protected sectionService: SectionsService,
|
||||||
|
private formBuilderService: FormBuilderService,
|
||||||
|
private accessesConfigService: SubmissionAccessesConfigService,
|
||||||
|
private accessesService: SectionAccessesService,
|
||||||
|
protected formOperationsService: SectionFormOperationsService,
|
||||||
|
protected operationsBuilder: JsonPatchOperationsBuilder,
|
||||||
|
private formService: FormService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
private operationsService: SubmissionJsonPatchOperationsService,
|
||||||
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
|
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||||
|
super(undefined, injectedSectionData, injectedSubmissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables and retrieve collection default access conditions
|
||||||
|
*/
|
||||||
|
protected onSectionInit(): void {
|
||||||
|
|
||||||
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
||||||
|
this.formId = this.formService.getUniqueId(this.sectionData.id);
|
||||||
|
const config$ = this.accessesConfigService.findByHref(this.sectionData.config, true, false).pipe(
|
||||||
|
getFirstSucceededRemoteData(),
|
||||||
|
map((config) => config.payload),
|
||||||
|
);
|
||||||
|
|
||||||
|
const accessData$ = this.accessesService.getAccessesData(this.submissionId, this.sectionData.id);
|
||||||
|
|
||||||
|
combineLatest(config$, accessData$).subscribe(([config, accessData]) => {
|
||||||
|
this.availableAccessConditionOptions = isNotEmpty(config.accessConditionOptions) ? config.accessConditionOptions : [];
|
||||||
|
this.accessesData = accessData;
|
||||||
|
this.formModel = this.buildFileEditForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
|
protected getSectionStatus(): Observable<boolean> {
|
||||||
|
console.log('Method not implemented.');
|
||||||
|
return of(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize form model
|
||||||
|
*/
|
||||||
|
protected buildFileEditForm() {
|
||||||
|
|
||||||
|
const formModel: DynamicFormControlModel[] = [];
|
||||||
|
formModel.push(
|
||||||
|
new DynamicCheckboxModel({
|
||||||
|
id: 'discoverable',
|
||||||
|
label: this.translate.instant('submission.sections.accesses.form.discoverable-label'),
|
||||||
|
name: 'discoverable',
|
||||||
|
value: this.accessesData.discoverable
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const accessConditionTypeModelConfig = Object.assign({}, FORM_ACCESS_CONDITION_TYPE_CONFIG);
|
||||||
|
const accessConditionsArrayConfig = Object.assign({}, ACCESS_CONDITIONS_FORM_ARRAY_CONFIG);
|
||||||
|
const accessConditionTypeOptions = [];
|
||||||
|
|
||||||
|
for (const accessCondition of this.availableAccessConditionOptions) {
|
||||||
|
accessConditionTypeOptions.push(
|
||||||
|
{
|
||||||
|
label: accessCondition.name,
|
||||||
|
value: accessCondition.name
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
accessConditionTypeModelConfig.options = accessConditionTypeOptions;
|
||||||
|
|
||||||
|
// Dynamically assign of relation in config. For startdate, endDate, groups.
|
||||||
|
const hasStart = [];
|
||||||
|
const hasEnd = [];
|
||||||
|
const hasGroups = [];
|
||||||
|
this.availableAccessConditionOptions.forEach((condition) => {
|
||||||
|
const showStart: boolean = condition.hasStartDate === true;
|
||||||
|
const showEnd: boolean = condition.hasEndDate === true;
|
||||||
|
const showGroups: boolean = showStart || showEnd;
|
||||||
|
if (showStart) {
|
||||||
|
hasStart.push({ id: 'name', value: condition.name });
|
||||||
|
}
|
||||||
|
if (showEnd) {
|
||||||
|
hasEnd.push({ id: 'name', value: condition.name });
|
||||||
|
}
|
||||||
|
if (showGroups) {
|
||||||
|
hasGroups.push({ id: 'name', value: condition.name });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const confStart = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasStart }] };
|
||||||
|
const confEnd = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasEnd }] };
|
||||||
|
|
||||||
|
accessConditionsArrayConfig.groupFactory = () => {
|
||||||
|
const type = new DynamicSelectModel(accessConditionTypeModelConfig, FORM_ACCESS_CONDITION_TYPE_LAYOUT);
|
||||||
|
const startDateConfig = Object.assign({}, FORM_ACCESS_CONDITION_START_DATE_CONFIG, confStart);
|
||||||
|
const endDateConfig = Object.assign({}, FORM_ACCESS_CONDITION_END_DATE_CONFIG, confEnd);
|
||||||
|
|
||||||
|
const startDate = new DynamicDatePickerModel(startDateConfig, FORM_ACCESS_CONDITION_START_DATE_LAYOUT);
|
||||||
|
const endDate = new DynamicDatePickerModel(endDateConfig, FORM_ACCESS_CONDITION_END_DATE_LAYOUT);
|
||||||
|
const accessConditionGroupConfig = Object.assign({}, ACCESS_CONDITION_GROUP_CONFIG);
|
||||||
|
accessConditionGroupConfig.group = [type];
|
||||||
|
if (hasStart.length > 0) { accessConditionGroupConfig.group.push(startDate); }
|
||||||
|
if (hasEnd.length > 0) { accessConditionGroupConfig.group.push(endDate); }
|
||||||
|
return [new DynamicFormGroupModel(accessConditionGroupConfig, ACCESS_CONDITION_GROUP_LAYOUT)];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number of access conditions blocks in form
|
||||||
|
accessConditionsArrayConfig.initialCount = isNotEmpty(this.accessesData.accessConditions) ? this.accessesData.accessConditions.length : 1;
|
||||||
|
formModel.push(
|
||||||
|
new DynamicFormArrayModel(accessConditionsArrayConfig, ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.initModelData(formModel);
|
||||||
|
return formModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize form model values
|
||||||
|
*
|
||||||
|
* @param formModel
|
||||||
|
* The form model
|
||||||
|
*/
|
||||||
|
public initModelData(formModel: DynamicFormControlModel[]) {
|
||||||
|
this.accessesData.accessConditions.forEach((accessCondition, index) => {
|
||||||
|
Array.of('name', 'startDate', 'endDate')
|
||||||
|
.filter((key) => accessCondition.hasOwnProperty(key) && isNotEmpty(accessCondition[key]))
|
||||||
|
.forEach((key) => {
|
||||||
|
const metadataModel: any = this.formBuilderService.findById(key, formModel, index);
|
||||||
|
if (metadataModel) {
|
||||||
|
if (metadataModel.type === DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER) {
|
||||||
|
const date = new Date(accessCondition[key]);
|
||||||
|
metadataModel.value = {
|
||||||
|
year: date.getUTCFullYear(),
|
||||||
|
month: date.getUTCMonth() + 1,
|
||||||
|
day: date.getUTCDate()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
metadataModel.value = accessCondition[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
// this.formService.validateAllFormFields(this.formRef.formGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when a form dfChange event is fired.
|
||||||
|
* Dispatch form operations based on changes.
|
||||||
|
*/
|
||||||
|
onChange(event: DynamicFormControlEvent) {
|
||||||
|
if (event.model.type === 'CHECKBOX') {
|
||||||
|
const path = this.formOperationsService.getFieldPathSegmentedFromChangeEvent(event);
|
||||||
|
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||||
|
this.operationsBuilder.replace(this.pathCombiner.getPath(path), value.value, true);
|
||||||
|
} else {
|
||||||
|
// validate form
|
||||||
|
this.formService.validateAllFormFields(this.formRef.formGroup);
|
||||||
|
this.formService.isValid(this.formId).pipe(
|
||||||
|
take(1),
|
||||||
|
filter((isValid) => isValid),
|
||||||
|
mergeMap(() => this.formService.getFormData(this.formId)),
|
||||||
|
take(1),
|
||||||
|
mergeMap((formData: any) => {
|
||||||
|
console.log(formData);
|
||||||
|
const accessConditionsToSave = [];
|
||||||
|
formData.accessCondition
|
||||||
|
.map((accessConditions) => accessConditions.accessConditionGroup)
|
||||||
|
.filter((accessCondition) => isNotEmpty(accessCondition))
|
||||||
|
.forEach((accessCondition) => {
|
||||||
|
let accessConditionOpt;
|
||||||
|
|
||||||
|
this.availableAccessConditionOptions
|
||||||
|
.filter((element) => isNotNull(accessCondition.name) && element.name === accessCondition.name[0].value)
|
||||||
|
.forEach((element) => accessConditionOpt = element);
|
||||||
|
|
||||||
|
if (accessConditionOpt) {
|
||||||
|
const currentAccessCondition = Object.assign({}, accessCondition);
|
||||||
|
currentAccessCondition.name = this.retrieveValueFromField(accessCondition.name);
|
||||||
|
|
||||||
|
/* When start and end date fields are deactivated, their values may be still present in formData,
|
||||||
|
therefore it is necessary to delete them if they're not allowed by the current access condition option. */
|
||||||
|
if (!accessConditionOpt.hasStartDate) {
|
||||||
|
delete currentAccessCondition.startDate;
|
||||||
|
} else if (accessCondition.startDate) {
|
||||||
|
const startDate = this.retrieveValueFromField(accessCondition.startDate);
|
||||||
|
currentAccessCondition.startDate = dateToISOFormat(startDate);
|
||||||
|
}
|
||||||
|
if (!accessConditionOpt.hasEndDate) {
|
||||||
|
delete currentAccessCondition.endDate;
|
||||||
|
} else if (accessCondition.endDate) {
|
||||||
|
const endDate = this.retrieveValueFromField(accessCondition.endDate);
|
||||||
|
currentAccessCondition.endDate = dateToISOFormat(endDate);
|
||||||
|
}
|
||||||
|
accessConditionsToSave.push(currentAccessCondition);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.operationsBuilder.add(this.pathCombiner.getPath('accessConditions'), accessConditionsToSave, true);
|
||||||
|
|
||||||
|
return this.formService.getFormData(this.formId);
|
||||||
|
|
||||||
|
})
|
||||||
|
).subscribe((result: SubmissionObject[]) => {
|
||||||
|
console.log(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected retrieveValueFromField(field: any) {
|
||||||
|
const temp = Array.isArray(field) ? field[0] : field;
|
||||||
|
return (temp) ? temp.value : undefined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check if the specified form field has already a value stored
|
||||||
|
*
|
||||||
|
* @param fieldId
|
||||||
|
* the section data retrieved from the serverù
|
||||||
|
* @param index
|
||||||
|
* the section data retrieved from the server
|
||||||
|
*/
|
||||||
|
hasStoredValue(fieldId, index): boolean {
|
||||||
|
if (isNotEmpty(this.sectionData.data)) {
|
||||||
|
return this.sectionData.data.hasOwnProperty(fieldId) &&
|
||||||
|
isNotEmpty(this.sectionData.data[fieldId][index]) &&
|
||||||
|
!this.isFieldToRemove(fieldId, index);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasRelatedCustomError(medatata): boolean {
|
||||||
|
const index = findIndex(this.sectionData.errorsToShow, { path: this.pathCombiner.getPath(medatata).path });
|
||||||
|
if (index !== -1) {
|
||||||
|
const error = this.sectionData.errorsToShow[index];
|
||||||
|
const validator = error.message.replace('error.validation.', '');
|
||||||
|
return !environment.form.validatorMap.hasOwnProperty(validator);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the specified field is on the way to be removed
|
||||||
|
*
|
||||||
|
* @param fieldId
|
||||||
|
* the section data retrieved from the serverù
|
||||||
|
* @param index
|
||||||
|
* the section data retrieved from the server
|
||||||
|
*/
|
||||||
|
isFieldToRemove(fieldId, index) {
|
||||||
|
return this.fieldsOnTheirWayToBeRemoved.has(fieldId) && this.fieldsOnTheirWayToBeRemoved.get(fieldId).includes(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
|
onSectionDestroy() {
|
||||||
|
this.subs
|
||||||
|
.filter((subscription) => hasValue(subscription))
|
||||||
|
.forEach((subscription) => subscription.unsubscribe());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
117
src/app/submission/sections/accesses/section-accesses.model.ts
Normal file
117
src/app/submission/sections/accesses/section-accesses.model.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import {
|
||||||
|
DynamicDatePickerModelConfig,
|
||||||
|
DynamicFormArrayModelConfig,
|
||||||
|
DynamicFormControlLayout,
|
||||||
|
DynamicFormGroupModelConfig,
|
||||||
|
DynamicSelectModelConfig,
|
||||||
|
MATCH_ENABLED,
|
||||||
|
OR_OPERATOR,
|
||||||
|
} from '@ng-dynamic-forms/core';
|
||||||
|
|
||||||
|
|
||||||
|
export const ACCESS_FORM_CHECKBOX_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
element: {
|
||||||
|
host: 'form-group flex-fill access-condition-group',
|
||||||
|
id: 'discoverable',
|
||||||
|
// disabled: false,
|
||||||
|
label: 'submission.sections.accesses.form.discoverable-label',
|
||||||
|
name: 'discoverable',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const ACCESS_CONDITION_GROUP_CONFIG: DynamicFormGroupModelConfig = {
|
||||||
|
id: 'accessConditionGroup',
|
||||||
|
group: []
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ACCESS_CONDITION_GROUP_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
element: {
|
||||||
|
host: 'form-group flex-fill access-condition-group',
|
||||||
|
container: 'pl-1 pr-1',
|
||||||
|
control: 'form-row '
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ACCESS_CONDITIONS_FORM_ARRAY_CONFIG: DynamicFormArrayModelConfig = {
|
||||||
|
id: 'accessCondition',
|
||||||
|
groupFactory: null,
|
||||||
|
};
|
||||||
|
export const ACCESS_CONDITIONS_FORM_ARRAY_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
grid: {
|
||||||
|
group: 'form-row',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FORM_ACCESS_CONDITION_TYPE_CONFIG: DynamicSelectModelConfig<any> = {
|
||||||
|
id: 'name',
|
||||||
|
label: 'submission.sections.upload.form.access-condition-label',
|
||||||
|
options: []
|
||||||
|
};
|
||||||
|
export const FORM_ACCESS_CONDITION_TYPE_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
element: {
|
||||||
|
host: 'col-12',
|
||||||
|
label: 'col-form-label name-label'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FORM_ACCESS_CONDITION_START_DATE_CONFIG: DynamicDatePickerModelConfig = {
|
||||||
|
id: 'startDate',
|
||||||
|
label: 'submission.sections.upload.form.from-label',
|
||||||
|
placeholder: 'submission.sections.upload.form.from-placeholder',
|
||||||
|
inline: false,
|
||||||
|
toggleIcon: 'far fa-calendar-alt',
|
||||||
|
relations: [
|
||||||
|
{
|
||||||
|
match: MATCH_ENABLED,
|
||||||
|
operator: OR_OPERATOR,
|
||||||
|
when: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
validators: {
|
||||||
|
required: null
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
required: 'submission.sections.upload.form.date-required-from'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const FORM_ACCESS_CONDITION_START_DATE_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
element: {
|
||||||
|
label: 'col-form-label'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
host: 'col-6'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FORM_ACCESS_CONDITION_END_DATE_CONFIG: DynamicDatePickerModelConfig = {
|
||||||
|
id: 'endDate',
|
||||||
|
label: 'submission.sections.upload.form.until-label',
|
||||||
|
placeholder: 'submission.sections.upload.form.until-placeholder',
|
||||||
|
inline: false,
|
||||||
|
toggleIcon: 'far fa-calendar-alt',
|
||||||
|
relations: [
|
||||||
|
{
|
||||||
|
match: MATCH_ENABLED,
|
||||||
|
operator: OR_OPERATOR,
|
||||||
|
when: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
validators: {
|
||||||
|
required: null
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
required: 'submission.sections.upload.form.date-required-until'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const FORM_ACCESS_CONDITION_END_DATE_LAYOUT: DynamicFormControlLayout = {
|
||||||
|
element: {
|
||||||
|
label: 'col-form-label'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
host: 'col-6'
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { SubmissionState } from '../../submission.reducers';
|
||||||
|
import { isUndefined } from 'util';
|
||||||
|
import { submissionSectionFromIdSelector, submissionSectionDataFromIdSelector } from 'src/app/submission/selectors';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that provides methods to handle submission's bitstream state.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class SectionAccessesService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize service variables
|
||||||
|
*
|
||||||
|
* @param {Store<SubmissionState>} store
|
||||||
|
*/
|
||||||
|
constructor(private store: Store<SubmissionState>) { }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return bitstream's metadata
|
||||||
|
*
|
||||||
|
* @param submissionId
|
||||||
|
* The submission id
|
||||||
|
* @param sectionId
|
||||||
|
* The section id
|
||||||
|
* @param fileUUID
|
||||||
|
* The bitstream UUID
|
||||||
|
* @returns {Observable}
|
||||||
|
* Emits bitstream's metadata
|
||||||
|
*/
|
||||||
|
public getAccessesData(submissionId: string, sectionId: string): Observable<any> {
|
||||||
|
|
||||||
|
return this.store.select(submissionSectionDataFromIdSelector(submissionId, sectionId)).pipe(
|
||||||
|
filter((state) => !isUndefined(state)),
|
||||||
|
distinctUntilChanged());
|
||||||
|
}
|
||||||
|
}
|
@@ -1,52 +1,36 @@
|
|||||||
<div dsSection #sectionRef="sectionRef"
|
<div dsSection #sectionRef="sectionRef" [attr.id]="'section_' + sectionData.id" [ngClass]="{ 'section-focus' : sectionRef.isSectionActive() }"
|
||||||
[attr.id]="'section_' + sectionData.id"
|
[mandatory]="sectionData.mandatory" [submissionId]="submissionId" [sectionType]="sectionData.sectionType" [sectionId]="sectionData.id">
|
||||||
[ngClass]="{ 'section-focus' : sectionRef.isSectionActive() }"
|
<!-- *ngIf="(sectionRef.isEnabled() | async)" -->
|
||||||
[mandatory]="sectionData.mandatory"
|
<ngb-accordion #acc="ngbAccordion" (panelChange)="sectionRef.sectionChange($event)" activeIds="{{ sectionData.id }}" [destroyOnHide]="false">
|
||||||
[submissionId]="submissionId"
|
|
||||||
[sectionType]="sectionData.sectionType"
|
|
||||||
[sectionId]="sectionData.id">
|
|
||||||
<ngb-accordion #acc="ngbAccordion"
|
|
||||||
*ngIf="(sectionRef.isEnabled() | async)"
|
|
||||||
(panelChange)="sectionRef.sectionChange($event)"
|
|
||||||
activeIds="{{ sectionData.id }}"
|
|
||||||
[destroyOnHide]="false">
|
|
||||||
<ngb-panel id="{{ sectionData.id }}">
|
<ngb-panel id="{{ sectionData.id }}">
|
||||||
<ng-template ngbPanelTitle>
|
<ng-template ngbPanelTitle>
|
||||||
<span class="float-left section-title" tabindex="0">{{ 'submission.sections.'+sectionData.header | translate }}</span>
|
<span class="float-left section-title" tabindex="0">{{ 'submission.sections.'+sectionData.header | translate }}</span>
|
||||||
<div class="d-inline-block float-right">
|
<div class="d-inline-block float-right">
|
||||||
<i *ngIf="!(sectionRef.isValid() | async) && !(sectionRef.hasErrors())" class="fas fa-exclamation-circle text-warning mr-3"
|
<i *ngIf="!(sectionRef.isValid() | async) && !(sectionRef.hasErrors())" class="fas fa-exclamation-circle text-warning mr-3"
|
||||||
title="{{'submission.sections.status.warnings.title' | translate}}" role="img" [attr.aria-label]="'submission.sections.status.warnings.aria' | translate"></i>
|
title="{{'submission.sections.status.warnings.title' | translate}}" role="img" [attr.aria-label]="'submission.sections.status.warnings.aria' | translate"></i>
|
||||||
<i *ngIf="(sectionRef.hasErrors())" class="fas fa-exclamation-circle text-danger mr-3"
|
<i *ngIf="(sectionRef.hasErrors())" class="fas fa-exclamation-circle text-danger mr-3" title="{{'submission.sections.status.errors.title' | translate}}"
|
||||||
title="{{'submission.sections.status.errors.title' | translate}}" role="img" [attr.aria-label]="'submission.sections.status.errors.aria' | translate"></i>
|
role="img" [attr.aria-label]="'submission.sections.status.errors.aria' | translate"></i>
|
||||||
<i *ngIf="(sectionRef.isValid() | async) && !(sectionRef.hasErrors())" class="fas fa-check-circle text-success mr-3"
|
<i *ngIf="(sectionRef.isValid() | async) && !(sectionRef.hasErrors())" class="fas fa-check-circle text-success mr-3" title="{{'submission.sections.status.valid.title' | translate}}"
|
||||||
title="{{'submission.sections.status.valid.title' | translate}}" role="img" [attr.aria-label]="'submission.sections.status.valid.aria' | translate"></i>
|
role="img" [attr.aria-label]="'submission.sections.status.valid.aria' | translate"></i>
|
||||||
<a class="close"
|
<a class="close" tabindex="0" role="button" [attr.aria-label]="(sectionRef.isOpen() ? 'submission.sections.toggle.aria.close' : 'submission.sections.toggle.aria.open') | translate: {sectionHeader: ('submission.sections.'+sectionData.header | translate)}"
|
||||||
tabindex="0"
|
[title]="(sectionRef.isOpen() ? 'submission.sections.toggle.close' : 'submission.sections.toggle.open') | translate">
|
||||||
role="button"
|
|
||||||
[attr.aria-label]="(sectionRef.isOpen() ? 'submission.sections.toggle.aria.close' : 'submission.sections.toggle.aria.open') | translate: {sectionHeader: ('submission.sections.'+sectionData.header | translate)}"
|
|
||||||
[title]="(sectionRef.isOpen() ? 'submission.sections.toggle.close' : 'submission.sections.toggle.open') | translate">
|
|
||||||
<span *ngIf="sectionRef.isOpen()" class="fas fa-chevron-up fa-fw"></span>
|
<span *ngIf="sectionRef.isOpen()" class="fas fa-chevron-up fa-fw"></span>
|
||||||
<span *ngIf="!sectionRef.isOpen()" class="fas fa-chevron-down fa-fw"></span>
|
<span *ngIf="!sectionRef.isOpen()" class="fas fa-chevron-down fa-fw"></span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="close mr-3" *ngIf="!sectionRef.isMandatory()"
|
<a href="#" class="close mr-3" *ngIf="!sectionRef.isMandatory()" (click)="removeSection($event)">
|
||||||
(click)="removeSection($event)">
|
|
||||||
<i class="fas fa-trash-o" aria-hidden="true" tabindex="0"></i>
|
<i class="fas fa-trash-o" aria-hidden="true" tabindex="0"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<div id="sectionGenericError_{{sectionData.id}}" *ngIf="sectionRef.hasGenericErrors()">
|
<div id="sectionGenericError_{{sectionData.id}}" *ngIf="sectionRef.hasGenericErrors()">
|
||||||
<ds-alert *ngFor="let error of sectionRef.getErrors(); let i = index"
|
<ds-alert *ngFor="let error of sectionRef.getErrors(); let i = index" [content]="error" [dismissible]="true" [type]="AlertTypeEnum.Error"
|
||||||
[content]="error"
|
(close)="sectionRef.removeError(i)"></ds-alert>
|
||||||
[dismissible]="true"
|
|
||||||
[type]="AlertTypeEnum.Error"
|
|
||||||
(close)="sectionRef.removeError(i)"></ds-alert>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="sectionContent_{{sectionData.id}}"
|
<div id="sectionContent_{{sectionData.id}}" (click)="sectionRef.setFocus($event)">
|
||||||
(click)="sectionRef.setFocus($event)">
|
|
||||||
<ng-container *ngComponentOutlet="getSectionContent(); injector: objectInjector;"></ng-container>
|
<ng-container *ngComponentOutlet="getSectionContent(); injector: objectInjector;"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
</ngb-accordion>
|
</ngb-accordion>
|
||||||
</div>
|
</div>
|
@@ -64,9 +64,9 @@ export class SubmissionSectionContainerComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.objectInjector = Injector.create({
|
this.objectInjector = Injector.create({
|
||||||
providers: [
|
providers: [
|
||||||
{provide: 'collectionIdProvider', useFactory: () => (this.collectionId), deps: []},
|
{ provide: 'collectionIdProvider', useFactory: () => (this.collectionId), deps: [] },
|
||||||
{provide: 'sectionDataProvider', useFactory: () => (this.sectionData), deps: []},
|
{ provide: 'sectionDataProvider', useFactory: () => (this.sectionData), deps: [] },
|
||||||
{provide: 'submissionIdProvider', useFactory: () => (this.submissionId), deps: []},
|
{ provide: 'submissionIdProvider', useFactory: () => (this.submissionId), deps: [] },
|
||||||
],
|
],
|
||||||
parent: this.injector
|
parent: this.injector
|
||||||
});
|
});
|
||||||
|
@@ -59,8 +59,8 @@ export abstract class SectionModelComponent implements OnDestroy, OnInit, Sectio
|
|||||||
* @param {string} injectedSubmissionId
|
* @param {string} injectedSubmissionId
|
||||||
*/
|
*/
|
||||||
public constructor(@Inject('collectionIdProvider') public injectedCollectionId: string,
|
public constructor(@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||||
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||||
this.collectionId = injectedCollectionId;
|
this.collectionId = injectedCollectionId;
|
||||||
this.sectionData = injectedSectionData;
|
this.sectionData = injectedSectionData;
|
||||||
this.submissionId = injectedSubmissionId;
|
this.submissionId = injectedSubmissionId;
|
||||||
|
@@ -5,5 +5,5 @@ export enum SectionsType {
|
|||||||
License = 'license',
|
License = 'license',
|
||||||
CcLicense = 'cclicense',
|
CcLicense = 'cclicense',
|
||||||
collection = 'collection',
|
collection = 'collection',
|
||||||
Accesses = 'accesses',
|
AccessesCondition = 'accessCondition',
|
||||||
}
|
}
|
||||||
|
@@ -174,10 +174,10 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit {
|
|||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.uploadService
|
this.uploadService
|
||||||
.getFileData(this.submissionId, this.sectionId, this.fileId).pipe(
|
.getFileData(this.submissionId, this.sectionId, this.fileId).pipe(
|
||||||
filter((bitstream) => isNotUndefined(bitstream)))
|
filter((bitstream) => isNotUndefined(bitstream)))
|
||||||
.subscribe((bitstream) => {
|
.subscribe((bitstream) => {
|
||||||
this.fileData = bitstream;
|
this.fileData = bitstream;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -251,12 +251,12 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit {
|
|||||||
|
|
||||||
protected loadFormMetadata() {
|
protected loadFormMetadata() {
|
||||||
this.configMetadataForm.rows.forEach((row) => {
|
this.configMetadataForm.rows.forEach((row) => {
|
||||||
row.fields.forEach((field) => {
|
row.fields.forEach((field) => {
|
||||||
field.selectableMetadata.forEach((metadatum) => {
|
field.selectableMetadata.forEach((metadatum) => {
|
||||||
this.formMetadata.push(metadatum.metadata);
|
this.formMetadata.push(metadatum.metadata);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,27 +45,28 @@ export function submissionUploadedFilesFromIdSelector(submissionId: string, sect
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function submissionUploadedFileFromUuidSelector(submissionId: string, sectionId: string, uuid: string): MemoizedSelector<SubmissionState, any> {
|
export function submissionUploadedFileFromUuidSelector(submissionId: string, sectionId: string, uuid: string): MemoizedSelector<SubmissionState, any> {
|
||||||
const filesSelector = submissionSectionDataFromIdSelector(submissionId, sectionId);
|
const filesSelector = submissionSectionDataFromIdSelector(submissionId, sectionId);
|
||||||
return keySelector<SubmissionState, any>(filesSelector, 'files', uuid);
|
return keySelector<SubmissionState, any>(filesSelector, 'files', uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function submissionSectionFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
export function submissionSectionFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
||||||
const submissionIdSelector = submissionObjectFromIdSelector(submissionId);
|
const submissionIdSelector = submissionObjectFromIdSelector(submissionId);
|
||||||
return keySelector<SubmissionState, SubmissionObjectEntry>(submissionIdSelector, 'sections', sectionId);
|
return keySelector<SubmissionState, SubmissionObjectEntry>(submissionIdSelector, 'sections', sectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function submissionSectionDataFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
export function submissionSectionDataFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
||||||
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
||||||
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'data');
|
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'data');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function submissionSectionErrorsFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
export function submissionSectionErrorsFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
||||||
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
||||||
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'errorsToShow');
|
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'errorsToShow');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function submissionSectionServerErrorsFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
export function submissionSectionServerErrorsFromIdSelector(submissionId: string, sectionId: string): MemoizedSelector<SubmissionState, any> {
|
||||||
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
const submissionIdSelector = submissionSectionFromIdSelector(submissionId, sectionId);
|
||||||
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'serverValidationErrors');
|
return subStateSelector<SubmissionState, SubmissionSectionObject>(submissionIdSelector, 'serverValidationErrors');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,6 +37,9 @@ import { ResearchEntitiesModule } from '../entity-groups/research-entities/resea
|
|||||||
import { ThemedSubmissionEditComponent } from './edit/themed-submission-edit.component';
|
import { ThemedSubmissionEditComponent } from './edit/themed-submission-edit.component';
|
||||||
import { ThemedSubmissionSubmitComponent } from './submit/themed-submission-submit.component';
|
import { ThemedSubmissionSubmitComponent } from './submit/themed-submission-submit.component';
|
||||||
import { ThemedSubmissionImportExternalComponent } from './import-external/themed-submission-import-external.component';
|
import { ThemedSubmissionImportExternalComponent } from './import-external/themed-submission-import-external.component';
|
||||||
|
import { SubmissionSectionAccessesComponent } from 'src/app/submission/sections/accesses/section-accesses.component';
|
||||||
|
import { SubmissionAccessesConfigService } from 'src/app/core/config/submission-accesses-config.service';
|
||||||
|
import { SectionAccessesService } from 'src/app/submission/sections/accesses/section-accesses.service';
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
SubmissionSectionUploadAccessConditionsComponent,
|
SubmissionSectionUploadAccessConditionsComponent,
|
||||||
@@ -62,7 +65,8 @@ const DECLARATIONS = [
|
|||||||
ThemedSubmissionImportExternalComponent,
|
ThemedSubmissionImportExternalComponent,
|
||||||
SubmissionImportExternalSearchbarComponent,
|
SubmissionImportExternalSearchbarComponent,
|
||||||
SubmissionImportExternalPreviewComponent,
|
SubmissionImportExternalPreviewComponent,
|
||||||
SubmissionImportExternalCollectionComponent
|
SubmissionImportExternalCollectionComponent,
|
||||||
|
SubmissionSectionAccessesComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -80,7 +84,9 @@ const DECLARATIONS = [
|
|||||||
providers: [
|
providers: [
|
||||||
SectionUploadService,
|
SectionUploadService,
|
||||||
SectionsService,
|
SectionsService,
|
||||||
SubmissionUploadsConfigService
|
SubmissionUploadsConfigService,
|
||||||
|
SubmissionAccessesConfigService,
|
||||||
|
SectionAccessesService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -3889,7 +3889,8 @@
|
|||||||
|
|
||||||
"submission.sections.upload.upload-successful": "Upload successful",
|
"submission.sections.upload.upload-successful": "Upload successful",
|
||||||
|
|
||||||
|
"submission.sections.accesses.form.discoverable-label": "Discoverable",
|
||||||
|
|
||||||
|
|
||||||
"submission.submit.breadcrumbs": "New submission",
|
"submission.submit.breadcrumbs": "New submission",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user