diff --git a/test/unit/services/FormsService.test.js b/test/unit/services/FormsService.test.js index e00fb85a4..c821c64f4 100644 --- a/test/unit/services/FormsService.test.js +++ b/test/unit/services/FormsService.test.js @@ -40,7 +40,7 @@ describe('The FormsService', function () { type: 'rdmp' } }; - FormsService.getForm(brand, '', true, '', record).subscribe(form => { + FormsService.getForm(brand, '', true, '', record).then(form => { expect(form).to.have.property('name', formName); done(); }) @@ -55,7 +55,7 @@ describe('The FormsService', function () { type: 'rdmp' } }; - FormsService.getForm(brand, '', true, '', record).subscribe(form => { + FormsService.getForm(brand, '', true, '', record).then(form => { expect(form).to.have.property('name', formName); done(); }) @@ -64,7 +64,7 @@ describe('The FormsService', function () { it('should return the form', function (done) { let brand = BrandingService.getDefault(); let formName = 'default-1.0-draft'; - FormsService.getForm(brand, formName, true, 'rdmp', {}).subscribe(form => { + FormsService.getForm(brand, formName, true, 'rdmp', {}).then(form => { expect(form).to.have.property('name', formName); done(); }) @@ -73,7 +73,7 @@ describe('The FormsService', function () { it('should return the autogenerated form', function (done) { let brand = BrandingService.getDefault(); let formName = 'generated-view-only'; - FormsService.getForm(brand, formName, true, 'rdmp', {}).subscribe(form => { + FormsService.getForm(brand, formName, true, 'rdmp', {}).then(form => { expect(form).to.have.property('name', formName); done(); }) diff --git a/typescript/api/controllers/RecordController.ts b/typescript/api/controllers/RecordController.ts index 45b1d4c2b..ae787d36a 100644 --- a/typescript/api/controllers/RecordController.ts +++ b/typescript/api/controllers/RecordController.ts @@ -261,7 +261,7 @@ export module Controllers { if (!hasEditAccess) { return this.ajaxFail(req, res, null, {message: TranslationService.t('edit-error-no-permissions')}); } - form = await FormsService.getForm(brand, formParam, editMode, '', currentRec).toPromise(); + form = await FormsService.getForm(brand, formParam, editMode, '', currentRec); if (_.isEmpty(form)) { return this.ajaxFail(req, res, null, {message: `Error, getting form ${formParam} for OID: ${oid}`}); } @@ -271,7 +271,7 @@ export module Controllers { if (!hasViewAccess) { return this.ajaxFail(req, res, null, {message: TranslationService.t('view-error-no-permissions')}); } - form = await FormsService.getForm(brand, formParam, editMode, '', currentRec).toPromise(); + form = await FormsService.getForm(brand, formParam, editMode, '', currentRec); if (_.isEmpty(form)) { return this.ajaxFail(req, res, null, {message: `Error, getting form ${formParam} for OID: ${oid}`}); } diff --git a/typescript/api/controllers/webservice/RecordController.ts b/typescript/api/controllers/webservice/RecordController.ts index 1775d7778..65c66bad6 100644 --- a/typescript/api/controllers/webservice/RecordController.ts +++ b/typescript/api/controllers/webservice/RecordController.ts @@ -1085,7 +1085,7 @@ export module Controllers { let keys = _.keys(meta1); for(let key of keys) { - if(_.get(meta1,key,'') != _.get(meta2,key,'')) { + if(!_.isEqual(meta1?.[key],meta2?.[key])) { return false; } } diff --git a/typescript/api/services/FormsService.ts b/typescript/api/services/FormsService.ts index d47fdb751..dc1623c91 100644 --- a/typescript/api/services/FormsService.ts +++ b/typescript/api/services/FormsService.ts @@ -162,16 +162,16 @@ export module Services { }); } - public getForm(branding: BrandingModel, formParam: string, editMode: boolean, recordType: string, currentRec: any): Observable { + public async getForm(branding: BrandingModel, formParam: string, editMode: boolean, recordType: string, currentRec: any) { // allow client to set the form name to use const formName = _.isUndefined(formParam) || _.isEmpty(formParam) ? currentRec.metaMetadata.form : formParam; if(formName == 'generated-view-only') { - return this.generateFormFromSchema(branding, recordType, currentRec); + return await this.generateFormFromSchema(branding, recordType, currentRec); } else { - return this.getFormByName(formName, editMode); + return await this.getFormByName(formName, editMode).toPromise(); } } @@ -213,241 +213,219 @@ export module Services { return schema; } - public generateFormFromSchema(branding: BrandingModel, recordType: string, record: any): Observable { + public async generateFormFromSchema(branding: BrandingModel, recordType: string, record: any) { if(recordType == '') { recordType = _.get(record,'metaMetadata.type',''); if(recordType == '') { - return Observable.of(null); + return {}; } } - let starting = true; + let form: FormModel; + + let schema = this.inferSchemaFromMetadata(record); + + let fieldKeys = _.keys(schema.properties); + + let buttonsList = [ + { + class: 'AnchorOrButton', + roles: ['Admin', 'Librarians'], + viewOnly: true, + definition: { + label: '@view-record-audit-link', + value: '/@branding/@portal/record/viewAudit/@oid', + cssClasses: 'btn btn-large btn-info margin-15', + controlType: 'anchor' + }, + variableSubstitutionFields: ['value'] + }, + { + class: 'SaveButton', + viewOnly: true, + roles: ['Admin', 'Librarians'], + definition: { + name: 'confirmDelete', + label: 'Delete this record', + closeOnSave: true, + redirectLocation: '/@branding/@portal/dashboard/'+recordType, + cssClasses: 'btn-danger', + confirmationMessage: '@dataPublication-confirmDelete', + confirmationTitle: '@dataPublication-confirmDeleteTitle', + cancelButtonMessage: '@dataPublication-cancelButtonMessage', + confirmButtonMessage: '@dataPublication-confirmButtonMessage', + isDelete: true, + isSubmissionButton: true + }, + variableSubstitutionFields: ['redirectLocation'] + } + ]; + + let textFieldTemplate = { + class: 'TextField', + viewOnly: true, + definition: { + name: '', + label: '', + help: '', + type: 'text' + } + }; - return super.getObservable(RecordType.findOne({ - key: branding.id + "_" + recordType - })) - .flatMap(recordType => { + let groupComponentTemplate = { + class: 'Container', + compClass: 'GenericGroupComponent', + definition: { + name: '', + cssClasses: 'form-inline', + fields: [] + } + }; - return super.getObservable(WorkflowStep.findOne({ - recordType: recordType.id, - starting: starting - })); - }).flatMap(workflowStep => { + let groupTextFieldTemplate = { + class: 'TextField', + definition: { + name: '', + label: '', + type: 'text', + groupName: '', + groupClasses: 'width-30', + cssClasses : "width-80 form-control" + } + }; - if (workflowStep.starting == true) { - - let form: FormModel; - - let schema = this.inferSchemaFromMetadata(record); - - let fieldKeys = _.keys(schema.properties); - - let buttonsList = [ - { - class: 'AnchorOrButton', - roles: ['Admin', 'Librarians'], - viewOnly: true, - definition: { - label: '@view-record-audit-link', - value: '/@branding/@portal/record/viewAudit/@oid', - cssClasses: 'btn btn-large btn-info margin-15', - controlType: 'anchor' - }, - variableSubstitutionFields: ['value'] - }, - { - class: 'SaveButton', - viewOnly: true, - roles: ['Admin', 'Librarians'], - definition: { - name: 'confirmDelete', - label: 'Delete this record', - closeOnSave: true, - redirectLocation: '/@branding/@portal/dashboard/'+recordType, - cssClasses: 'btn-danger', - confirmationMessage: '@dataPublication-confirmDelete', - confirmationTitle: '@dataPublication-confirmDeleteTitle', - cancelButtonMessage: '@dataPublication-cancelButtonMessage', - confirmButtonMessage: '@dataPublication-confirmButtonMessage', - isDelete: true, - isSubmissionButton: true - }, - variableSubstitutionFields: ['redirectLocation'] - } - ]; - - let textFieldTemplate = { - class: 'TextField', - viewOnly: true, - definition: { - name: '', - label: '', - help: '', - type: 'text' - } - }; - - let groupComponentTemplate = { - class: 'Container', - compClass: 'GenericGroupComponent', - definition: { - name: '', - cssClasses: 'form-inline', - fields: [] - } - }; - - let groupTextFieldTemplate = { - class: 'TextField', - definition: { - name: '', - label: '', - type: 'text', - groupName: '', - groupClasses: 'width-30', - cssClasses : "width-80 form-control" - } - }; - - let repeatableGroupComponentTemplate = { - class: 'RepeatableContainer', - compClass: 'RepeatableGroupComponent', - definition: { - name: '', - label: '', - help: '', - forceClone: ['fields'], - fields: [] - } - }; - - let objectFieldHeadingTemplate = { - class: 'Container', - compClass: 'TextBlockComponent', - definition: { - value: '', - type: 'h3' - } - }; - - let mainTitleFieldName = 'title'; - - let fieldList = [ - { - class: 'Container', - compClass: 'TextBlockComponent', - viewOnly: true, - definition: { - name: mainTitleFieldName, - type: 'h1' - } - }, - { - class: 'Container', - compClass: 'GenericGroupComponent', - definition: { - cssClasses: "form-inline", - fields: buttonsList - } - } - ]; - - for(let fieldKey of fieldKeys) { - - let schemaProperty = schema.properties[fieldKey]; - - if(_.get(schemaProperty,'type','') == 'string') { - - let textField = _.cloneDeep(textFieldTemplate); - _.set(textField.definition,'name',fieldKey); - _.set(textField.definition,'label',fieldKey); - fieldList.push(textField); - - } if(_.get(schemaProperty,'type','') == 'array') { - - if(_.get(schemaProperty,'items.type','') == 'string') { - - let textField = _.cloneDeep(textFieldTemplate); - _.set(textField.definition,'name',fieldKey); - _.set(textField.definition,'label',fieldKey); - fieldList.push(textField); - - } else if(_.get(schemaProperty,'items.type','') == 'object') { - - let objectFieldKeys = _.keys(schemaProperty.items.properties); - let repeatableGroupField = _.cloneDeep(repeatableGroupComponentTemplate); - let groupField = _.cloneDeep(groupComponentTemplate); - let groupFieldList = []; - - for(let objectFieldKey of objectFieldKeys) { - let innerProperty = schemaProperty.items.properties[objectFieldKey]; - if(_.get(innerProperty,'type','') == 'string') { - let textField = _.cloneDeep(groupTextFieldTemplate); - _.set(textField.definition,'name',objectFieldKey); - _.set(textField.definition,'label',objectFieldKey); - _.set(textField.definition,'groupName','item'); - groupFieldList.push(textField); - } - } - - _.set(groupField.definition,'name','item'); - _.set(groupField.definition,'fields',groupFieldList); - _.set(repeatableGroupField.definition,'name',fieldKey); - _.set(repeatableGroupField.definition,'label',fieldKey); - _.set(repeatableGroupField.definition,'fields',[groupField]); - fieldList.push(repeatableGroupField); - } - - } else if(_.get(schemaProperty,'type','') == 'object') { - - let objectFieldKeys = _.keys(schemaProperty.properties); - let groupField = _.cloneDeep(groupComponentTemplate); - let groupFieldList = []; - - for(let objectFieldKey of objectFieldKeys) { - let innerProperty = schemaProperty.properties[objectFieldKey]; - if(_.get(innerProperty,'type','') == 'string') { - let textField = _.cloneDeep(groupTextFieldTemplate); - _.set(textField.definition,'name',objectFieldKey); - _.set(textField.definition,'label',objectFieldKey); - _.set(textField.definition,'groupName',fieldKey); - groupFieldList.push(textField); - } - } - - let objectFieldHeading = _.cloneDeep(objectFieldHeadingTemplate); - _.set(objectFieldHeading.definition, 'value', fieldKey); - fieldList.push(objectFieldHeading); - - _.set(groupField.definition,'name',fieldKey); - _.set(groupField.definition,'fields',groupFieldList); - fieldList.push(groupField); + let repeatableGroupComponentTemplate = { + class: 'RepeatableContainer', + compClass: 'RepeatableGroupComponent', + definition: { + name: '', + label: '', + help: '', + forceClone: ['fields'], + fields: [] + } + }; + + let objectFieldHeadingTemplate = { + class: 'Container', + compClass: 'TextBlockComponent', + definition: { + value: '', + type: 'h3' + } + }; + + let mainTitleFieldName = 'title'; + + let fieldList = [ + { + class: 'Container', + compClass: 'TextBlockComponent', + viewOnly: true, + definition: { + name: mainTitleFieldName, + type: 'h1' + } + }, + { + class: 'Container', + compClass: 'GenericGroupComponent', + definition: { + cssClasses: "form-inline", + fields: buttonsList + } + } + ]; + + for(let fieldKey of fieldKeys) { + + let schemaProperty = schema.properties[fieldKey]; + + if(_.get(schemaProperty,'type','') == 'string') { + + let textField = _.cloneDeep(textFieldTemplate); + _.set(textField.definition,'name',fieldKey); + _.set(textField.definition,'label',fieldKey); + fieldList.push(textField); + + } if(_.get(schemaProperty,'type','') == 'array') { + + if(_.get(schemaProperty,'items.type','') == 'string') { + + let textField = _.cloneDeep(textFieldTemplate); + _.set(textField.definition,'name',fieldKey); + _.set(textField.definition,'label',fieldKey); + fieldList.push(textField); + + } else if(_.get(schemaProperty,'items.type','') == 'object') { + + let objectFieldKeys = _.keys(schemaProperty.items.properties); + let repeatableGroupField = _.cloneDeep(repeatableGroupComponentTemplate); + let groupField = _.cloneDeep(groupComponentTemplate); + let groupFieldList = []; + + for(let objectFieldKey of objectFieldKeys) { + let innerProperty = schemaProperty.items.properties[objectFieldKey]; + if(_.get(innerProperty,'type','') == 'string') { + let textField = _.cloneDeep(groupTextFieldTemplate); + _.set(textField.definition,'name',objectFieldKey); + _.set(textField.definition,'label',objectFieldKey); + _.set(textField.definition,'groupName','item'); + groupFieldList.push(textField); } } - - let formObject = { - name: 'generated-view-only', - type: recordType, - skipValidationOnSave: false, - editCssClasses: 'row col-md-12', - viewCssClasses: 'row col-md-offset-1 col-md-10', - messages: {}, - attachmentFields: [], - fields: fieldList - }; - - form = formObject as any; - - return Observable.of(form); + + _.set(groupField.definition,'name','item'); + _.set(groupField.definition,'fields',groupFieldList); + _.set(repeatableGroupField.definition,'name',fieldKey); + _.set(repeatableGroupField.definition,'label',fieldKey); + _.set(repeatableGroupField.definition,'fields',[groupField]); + fieldList.push(repeatableGroupField); } - return Observable.of(null); + } else if(_.get(schemaProperty,'type','') == 'object') { + + let objectFieldKeys = _.keys(schemaProperty.properties); + let groupField = _.cloneDeep(groupComponentTemplate); + let groupFieldList = []; + + for(let objectFieldKey of objectFieldKeys) { + let innerProperty = schemaProperty.properties[objectFieldKey]; + if(_.get(innerProperty,'type','') == 'string') { + let textField = _.cloneDeep(groupTextFieldTemplate); + _.set(textField.definition,'name',objectFieldKey); + _.set(textField.definition,'label',objectFieldKey); + _.set(textField.definition,'groupName',fieldKey); + groupFieldList.push(textField); + } + } - }).filter(result => result !== null).last(); - } - + let objectFieldHeading = _.cloneDeep(objectFieldHeadingTemplate); + _.set(objectFieldHeading.definition, 'value', fieldKey); + fieldList.push(objectFieldHeading); + + _.set(groupField.definition,'name',fieldKey); + _.set(groupField.definition,'fields',groupFieldList); + fieldList.push(groupField); + } + } + + let formObject = { + name: 'generated-view-only', + type: recordType, + skipValidationOnSave: false, + editCssClasses: 'row col-md-12', + viewCssClasses: 'row col-md-offset-1 col-md-10', + messages: {}, + attachmentFields: [], + fields: fieldList + }; + + form = formObject as any; + return form; + } protected setFormEditMode(fields, editMode): void{ _.remove(fields, field => { diff --git a/typescript/api/services/RecordsService.ts b/typescript/api/services/RecordsService.ts index 8a82d4485..cdc815473 100644 --- a/typescript/api/services/RecordsService.ts +++ b/typescript/api/services/RecordsService.ts @@ -176,7 +176,7 @@ export module Services { let wfStep = await WorkflowStepsService.getFirst(recordType).toPromise(); let formName = _.get(wfStep,'config.form'); - let form = await FormsService.getForm(brand, formName, true, recordType.name, record).toPromise(); + let form = await FormsService.getForm(brand, formName, true, recordType.name, record); let metaMetadata = this.initRecordMetaMetadata(brand.id, user.username, recordType, wfStep, form, moment().format()); _.set(record,'metaMetadata',metaMetadata);