diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 8878e6c0d8..c5ad206f90 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,8 @@ ## RELEASE NOTES +### Version 7.3.54-exui-4675 +**EXUI-4675** Able to bypass mandatory reasons which expand with radio buttons + ### Version 7.3.54 **EXUI-4636** Revert CME-220 and EXUI-2111 **EXUI-4637** Revert EXUI-2645 diff --git a/package.json b/package.json index 38447a3b4c..b4ec91175a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hmcts/ccd-case-ui-toolkit", - "version": "7.3.54", + "version": "7.3.54-exui-4675", "engines": { "node": ">=20.19.0" }, diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json index 6fdf4141f8..b6ea8c7033 100644 --- a/projects/ccd-case-ui-toolkit/package.json +++ b/projects/ccd-case-ui-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@hmcts/ccd-case-ui-toolkit", - "version": "7.3.54", + "version": "7.3.54-exui-4675", "engines": { "node": ">=20.19.0" }, diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-form/case-edit-form.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-form/case-edit-form.component.ts index 48b7829df2..eb8c101227 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-form/case-edit-form.component.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-form/case-edit-form.component.ts @@ -1,8 +1,9 @@ -import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output, QueryList, ViewChildren } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Subject, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; import { CaseField } from '../../../domain/definition/case-field.model'; +import { ConditionalShowFormDirective } from '../../../directives/conditional-show/conditional-show-form.directive'; import { FormValueService } from '../../../services/form/form-value.service'; @Component({ @@ -12,6 +13,9 @@ import { FormValueService } from '../../../services/form/form-value.service'; }) export class CaseEditFormComponent implements OnDestroy, AfterViewInit { + @ViewChildren(ConditionalShowFormDirective) + private readonly conditionalShowFormDirectives: QueryList; + @Input() public fields: CaseField[] = []; @Input() @@ -71,4 +75,9 @@ export class CaseEditFormComponent implements OnDestroy, AfterViewInit { const current = JSON.stringify(this.formValueService.sanitise(changes)); this.initial !== current ? this.valuesChanged.emit(true) : this.valuesChanged.emit(false); } + + // EXUI-4675 - needed for the race condition caused by the debounce in ConditionalShowFormDirective + public syncConditionalShowStates(): void { + this.conditionalShowFormDirectives?.forEach(directive => directive.evalAllShowHideConditions()); + } } \ No newline at end of file diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.spec.ts index f2e2c8e9a9..224d33db41 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.spec.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.spec.ts @@ -1691,6 +1691,40 @@ describe('CaseEditPageComponent - all other tests', () => { expect(comp.editForm.controls.data.get('caseNameHmctsInternal')).toBeNull(); expect(comp.editForm.controls.data.get('caseLinksFlag')).toBeNull(); }); + + it('should call syncConditionalShowStates on each CaseEditFormComponent instance before form validation', () => { + const syncSpy = jasmine.createSpy('syncConditionalShowStates'); + const mockFormComponent = { syncConditionalShowStates: syncSpy }; + const forEachSpy = jasmine.createSpy('forEach').and.callFake((fn: Function) => fn(mockFormComponent)); + (comp as any).caseEditFormComponents = { forEach: forEachSpy }; + + comp.eventTrigger = { + id: 'testEvent', + case_fields: [caseField1], + name: 'Test event trigger name', + can_save_draft: false, + event_token: 'test-token' + } as unknown as CaseEventTrigger; + + comp.submit(); + + expect(forEachSpy).toHaveBeenCalled(); + expect(syncSpy).toHaveBeenCalled(); + }); + + it('should not throw when caseEditFormComponents is an empty QueryList during submit', () => { + (comp as any).caseEditFormComponents = { forEach: jasmine.createSpy('forEach') }; + + comp.eventTrigger = { + id: 'testEvent', + case_fields: [caseField1], + name: 'Test event trigger name', + can_save_draft: false, + event_token: 'test-token' + } as unknown as CaseEventTrigger; + + expect(() => comp.submit()).not.toThrow(); + }); }); describe('previous the form', () => { diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.ts index 15469dba6a..9ce50c7192 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit-page/case-edit-page.component.ts @@ -1,4 +1,4 @@ -import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; import { AbstractControl, FormArray, FormGroup } from '@angular/forms'; import { MatLegacyDialog as MatDialog, MatLegacyDialogConfig as MatDialogConfig} from '@angular/material/legacy-dialog'; import { ActivatedRoute } from '@angular/router'; @@ -18,6 +18,7 @@ import { SaveOrDiscardDialogComponent } from '../../dialogs/save-or-discard-dial import { CallbackErrorsContext } from '../../error/domain/error-context'; import { initDialog } from '../../helpers'; import { CaseEditComponent } from '../case-edit/case-edit.component'; +import { CaseEditFormComponent } from '../case-edit-form/case-edit-form.component'; import { WizardPage } from '../domain/wizard-page.model'; import { Wizard } from '../domain/wizard.model'; import { PageValidationService } from '../services/page-validation.service'; @@ -66,6 +67,9 @@ export class CaseEditPageComponent implements OnInit, AfterViewChecked, OnDestro public saveDraftSub: Subscription; public caseFormValidationErrorsSub: Subscription; + @ViewChildren(CaseEditFormComponent) + private readonly caseEditFormComponents: QueryList; + private static scrollToTop(): void { window.scrollTo(0, 0); } @@ -395,6 +399,7 @@ export class CaseEditPageComponent implements OnInit, AfterViewChecked, OnDestro this.caseEditDataService.clearFormValidationErrors(); this.checkForStagesCompleted(); + this.caseEditFormComponents?.forEach(component => component.syncConditionalShowStates()); if (this.currentPageIsNotValid()) { // The generateErrorMessage method filters out the hidden fields. // The error message for LinkedCases journey will never get displayed because the diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/directives/conditional-show/conditional-show-form.directive.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/directives/conditional-show/conditional-show-form.directive.ts index 9ef6126d7f..9185be5e98 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/directives/conditional-show/conditional-show-form.directive.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/directives/conditional-show/conditional-show-form.directive.ts @@ -145,7 +145,7 @@ export class ConditionalShowFormDirective implements OnInit, AfterViewInit, OnDe } } - private evalAllShowHideConditions(): void { + public evalAllShowHideConditions(): void { this.getCurrentPagesReadOnlyAndFormFieldValues(); this.fieldsUtils.controlIterator(this.formGroup, this.handleFormArray, this.handleFormGroup, this.handleFormControl); }