diff --git a/docs/process-services-cloud/components/form-cloud.component.md b/docs/process-services-cloud/components/form-cloud.component.md index 8736b93555..4167d2b05f 100644 --- a/docs/process-services-cloud/components/form-cloud.component.md +++ b/docs/process-services-cloud/components/form-cloud.component.md @@ -78,6 +78,7 @@ The template defined inside `empty-form` will be shown when no form definition i | appName | `string` | | App id to fetch corresponding form and values. | | data | [`TaskVariableCloud`](../../../lib/process-services-cloud/src/lib/form/models/task-variable-cloud.model.ts)`[]` | | Custom form values map to be used with the rendered form. | | disableCompleteButton | `boolean` | false | If true then the `Complete` outcome button is shown but it will be disabled. | +| disableSaveButton | `boolean` | false | If true then the `Save` outcome button is shown but it will be disabled. | | disableStartProcessButton | `boolean` | false | If true then the `Start Process` outcome button is shown but it will be disabled. | | fieldValidators | [`FormFieldValidator`](../../../lib/core/form/components/widgets/core/form-field-validator.ts)`[]` | \[] | Contains a list of form field validator instances. | | form | [`FormCloud`](../../../lib/process-services-cloud/src/lib/form/models/form-cloud.model.ts) | | Underlying [form model](../../../lib/core/form/components/widgets/core/form.model.ts) instance. | diff --git a/docs/process-services/components/form.component.md b/docs/process-services/components/form.component.md index 281684db21..1df904b9a6 100644 --- a/docs/process-services/components/form.component.md +++ b/docs/process-services/components/form.component.md @@ -56,6 +56,7 @@ Any content in the body of `` will be shown when no form definition is | ---- | ---- | ------------- | ----------- | | data | [`FormValues`](../../../lib/core/form/components/widgets/core/form-values.ts) | | Custom form values map to be used with the rendered form. | | disableCompleteButton | `boolean` | false | If true then the `Complete` outcome button is shown but it will be disabled. | +| disableSaveButton | `boolean` | false | If true then the `Save` outcome button is shown but it will be disabled. | | disableStartProcessButton | `boolean` | false | If true then the `Start Process` outcome button is shown but it will be disabled. | | fieldValidators | [`FormFieldValidator`](../../../lib/core/form/components/widgets/core/form-field-validator.ts)`[]` | \[] | Contains a list of form field validator instances. | | form | [`FormModel`](../../../lib/core/form/components/widgets/core/form.model.ts) | | Underlying [form model](../../../lib/core/form/components/widgets/core/form.model.ts) instance. | diff --git a/lib/core/form/components/form-base.component.ts b/lib/core/form/components/form-base.component.ts index 76b87d761c..31bd072352 100644 --- a/lib/core/form/components/form-base.component.ts +++ b/lib/core/form/components/form-base.component.ts @@ -48,6 +48,10 @@ export abstract class FormBaseComponent { @Input() disableCompleteButton: boolean = false; + /** If true then the `Save` outcome button is shown but it will be disabled. */ + @Input() + disableSaveButton: boolean = false; + /** If true then the `Start Process` outcome button is shown but it will be disabled. */ @Input() disableStartProcessButton: boolean = false; @@ -116,9 +120,8 @@ export abstract class FormBaseComponent { } if (outcome) { - // Make 'Save' button always available if (outcome.name === FormOutcomeModel.SAVE_ACTION) { - return true; + return this.disableSaveButton ? false : this.form.isValid; } if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) { return this.disableCompleteButton ? false : this.form.isValid; diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts index a7e5edb31a..cf4b36a26b 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts @@ -689,25 +689,48 @@ describe('FormCloudComponent', () => { }); it('should disable complete outcome button when disableCompleteButton is true', () => { - const formModel = new FormCloud(); + const formModel = new FormCloud(cloudFormMock); formComponent.form = formModel; formComponent.disableCompleteButton = true; expect(formModel.isValid).toBeTruthy(); + expect(formComponent.form.hasOutcomes()).toBe(true); const completeOutcome = formComponent.form.outcomes.find((outcome) => outcome.name === FormOutcomeModel.COMPLETE_ACTION); expect(formComponent.isOutcomeButtonEnabled(completeOutcome)).toBeFalsy(); + + formComponent.disableCompleteButton = false; + expect(formComponent.isOutcomeButtonEnabled(completeOutcome)).toBeTruthy(); + }); + + it('should disable save outcome button when disableSaveButton is true', () => { + const formModel = new FormCloud(cloudFormMock); + formComponent.form = formModel; + formComponent.disableSaveButton = true; + + expect(formModel.isValid).toBeTruthy(); + expect(formComponent.form.hasOutcomes()).toBe(true); + const saveOutcome = formComponent.form.outcomes.find((outcome) => outcome.name === FormOutcomeModel.SAVE_ACTION); + + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeFalsy(); + + formComponent.disableSaveButton = false; + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeTruthy(); }); it('should disable start process outcome button when disableStartProcessButton is true', () => { - const formModel = new FormCloud(); + const formModel = new FormCloud(cloudFormMock); formComponent.form = formModel; formComponent.disableStartProcessButton = true; expect(formModel.isValid).toBeTruthy(); + expect(formComponent.form.hasOutcomes()).toBe(true); const startProcessOutcome = formComponent.form.outcomes.find((outcome) => outcome.name === FormOutcomeModel.START_PROCESS_ACTION); expect(formComponent.isOutcomeButtonEnabled(startProcessOutcome)).toBeFalsy(); + + formComponent.disableStartProcessButton = false; + expect(formComponent.isOutcomeButtonEnabled(startProcessOutcome)).toBeTruthy(); }); it('should raise [executeOutcome] event for formService', (done) => { diff --git a/lib/process-services/form/form.component.spec.ts b/lib/process-services/form/form.component.spec.ts index a9bdd4f0ff..b815b8819d 100644 --- a/lib/process-services/form/form.component.spec.ts +++ b/lib/process-services/form/form.component.spec.ts @@ -586,7 +586,7 @@ describe('FormComponent', () => { expect(formService.completeTaskForm).not.toHaveBeenCalled(); }); - it('should complete form form and raise corresponding event', () => { + it('should complete form and raise corresponding event', () => { spyOn(formService, 'completeTaskForm').and.callFake(() => { return new Observable((observer) => { observer.next(); @@ -709,7 +709,7 @@ describe('FormComponent', () => { expect(formComponent.data).toBe(metadata); }); - it('should disable outcome buttons for readonly form', () => { + it('should disable custom outcome buttons for readonly form', () => { const formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; @@ -727,31 +727,6 @@ describe('FormComponent', () => { expect(formComponent.isOutcomeButtonEnabled(null)).toBeFalsy(); }); - it('should always enable save outcome for writeable form', () => { - const formModel = new FormModel(); - - const field = new FormFieldModel(formModel, { - type: 'text', - value: null, - required: true - }); - - const containerModel = new ContainerModel(field); - formModel.fields.push(containerModel); - formComponent.form = formModel; - formModel.onFormFieldChanged(field); - - expect(formModel.isValid).toBeFalsy(); - - const outcome = new FormOutcomeModel(new FormModel(), { - id: FormComponent.SAVE_OUTCOME_ID, - name: FormOutcomeModel.SAVE_ACTION - }); - - formComponent.readOnly = true; - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeTruthy(); - }); - it('should disable outcome buttons for invalid form', () => { const formModel = new FormModel(); const field = new FormFieldModel(formModel, { @@ -780,19 +755,139 @@ describe('FormComponent', () => { formComponent.form = formModel; formComponent.disableCompleteButton = true; + const field = new FormFieldModel(formModel, { + type: 'text', + value: 'text', + required: true + }); + + const containerModel = new ContainerModel(field); + formModel.fields.push(containerModel); + formComponent.form = formModel; + formModel.onFormFieldChanged(field); + + expect(formModel.isValid).toBeTruthy(); + + const completeOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.COMPLETE_OUTCOME_ID, + name: FormOutcomeModel.COMPLETE_ACTION + }); + expect(formModel.isValid).toBeTruthy(); - const completeOutcome = formComponent.form.outcomes.find((outcome) => outcome.name === FormOutcomeModel.COMPLETE_ACTION); expect(formComponent.isOutcomeButtonEnabled(completeOutcome)).toBeFalsy(); }); + it('should disable save outcome button when form is valid and readOnly', () => { + const formModel = new FormModel(); + + const field = new FormFieldModel(formModel, { + type: 'text', + value: 'text', + required: true + }); + + const containerModel = new ContainerModel(field); + formModel.fields.push(containerModel); + formComponent.form = formModel; + formModel.onFormFieldChanged(field); + + expect(formModel.isValid).toBeTruthy(); + + const saveOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.SAVE_OUTCOME_ID, + name: FormOutcomeModel.SAVE_ACTION + }); + + formComponent.form.readOnly = true; + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeFalsy(); + }); + + it('should enable save outcome button when form is valid and not readOnly', () => { + const formModel = new FormModel(); + + const field = new FormFieldModel(formModel, { + type: 'text', + value: 'text', + required: true + }); + + const containerModel = new ContainerModel(field); + formModel.fields.push(containerModel); + formComponent.form = formModel; + formModel.onFormFieldChanged(field); + + expect(formModel.isValid).toBeTruthy(); + + const saveOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.SAVE_OUTCOME_ID, + name: FormOutcomeModel.SAVE_ACTION + }); + + formComponent.form.readOnly = false; + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeTruthy(); + }); + + it('should disable save outcome button when disableSaveButton is true', () => { + const formModel = new FormModel(); + formComponent.form = formModel; + formComponent.disableSaveButton = true; + + const saveOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.SAVE_OUTCOME_ID, + name: FormOutcomeModel.SAVE_ACTION + }); + + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeFalsy(); + }); + + it('should disable save outcome button when the form is invalid', () => { + const formModel = new FormModel(); + formComponent.form = formModel; + + const field = new FormFieldModel(formModel, { + type: 'text', + value: null, + required: true + }); + + const containerModel = new ContainerModel(field); + formModel.fields.push(containerModel); + formComponent.form = formModel; + formModel.onFormFieldChanged(field); + + expect(formModel.isValid).toBeFalsy(); + + const saveOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.SAVE_OUTCOME_ID, + name: FormOutcomeModel.SAVE_ACTION + }); + + expect(formComponent.isOutcomeButtonEnabled(saveOutcome)).toBeFalsy(); + }); + it('should disable start process outcome button when disableStartProcessButton is true', () => { const formModel = new FormModel(); formComponent.form = formModel; formComponent.disableStartProcessButton = true; + const field = new FormFieldModel(formModel, { + type: 'text', + value: 'text', + required: true + }); + + const containerModel = new ContainerModel(field); + formModel.fields.push(containerModel); + formComponent.form = formModel; + formModel.onFormFieldChanged(field); + expect(formModel.isValid).toBeTruthy(); - const startProcessOutcome = formComponent.form.outcomes.find((outcome) => outcome.name === FormOutcomeModel.START_PROCESS_ACTION); + + const startProcessOutcome = new FormOutcomeModel(new FormModel(), { + id: FormComponent.START_PROCESS_OUTCOME_ID, + name: FormOutcomeModel.START_PROCESS_ACTION + }); expect(formComponent.isOutcomeButtonEnabled(startProcessOutcome)).toBeFalsy(); });