- {{case.caseName}}
{{case.caseReference | ccdCaseReference}}
|
@@ -24,7 +24,7 @@
{{reason.value | ccdLinkCasesReasonValue}}{{getCaseRefereneLink(case.caseReference)}}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.ts
index dceea7eb0a..21f2d3c7b1 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.ts
@@ -24,6 +24,6 @@ export class NoLinkedCasesComponent extends AbstractJourneyComponent implements
}
public onBack(): void {
- this.router.navigate(['cases', 'case-details', this.linkedCasesService.caseId], { fragment: 'Linked cases' });
+ this.router.navigate(['cases', 'case-details', this.linkedCasesService.caseJurisdictionID, this.linkedCasesService.caseDetails.case_type, this.linkedCasesService.caseId], { fragment: 'Linked cases' });
}
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
index 5ecc02d294..b35d7cee6e 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
@@ -72,7 +72,7 @@ export class ReadLinkedCasesFieldComponent implements OnInit, AfterViewInit {
}
public reloadCurrentRoute(): void {
- this.router.navigate(['cases', 'case-details', this.linkedCasesService.caseDetails.case_id], { fragment: 'Linked cases' });
+ this.router.navigate(['cases', 'case-details', this.linkedCasesService.caseJurisdictionID, this.linkedCasesService.caseDetails.case_type, this.linkedCasesService.caseDetails.case_id], { fragment: 'Linked cases' });
}
public getFailureLinkedToNotification(evt): void {
From 3bcba4c945e096c8818d8de0159905ae4f3ef5f1 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Mon, 14 Apr 2025 12:16:30 +0100
Subject: [PATCH 04/21] url change
---
.../case-viewer/services/event-trigger.resolver.ts | 1 -
.../components/task-assigned/task-assigned.component.html | 2 +-
.../qualifying-question-options.component.ts | 6 +++++-
.../query-confirmation/query-confirmation.component.html | 6 +++---
.../query-confirmation/query-confirmation.component.ts | 4 ++++
5 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
index 9d633c603f..ab9472dc3f 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
@@ -77,7 +77,6 @@ export class EventTriggerResolver implements Resolve {
this.errorNotifier.announceError(error);
caseTypeId = route.parent.paramMap.get('caseType');
this.router.navigate([`/cases/case-details/${jurisdiction}/${caseTypeId}/${cid}/tasks`]);
- this.router.navigate([`/cases/case-details/${cid}/tasks`]);
return throwError(error);
})
).toPromise();
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.html b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.html
index 028006dda1..ca862ce433 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.html
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.html
@@ -17,7 +17,7 @@ {{'Task assignment required' | rpxTranslate}}
{{'This task is assigned to' | rpxTranslate}} {{assignedUserName}}. {{'You must assign it to yourself to continue.' | rpxTranslate}}
-
+
{{'Return to tasks tab' | rpxTranslate}}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.ts
index 765a6115be..30abb970ba 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.ts
@@ -15,6 +15,8 @@ export class QualifyingQuestionOptionsComponent implements OnInit {
@Input() public qualifyingQuestions$: Observable;
public qualifyingQuestionsErrorMessage = QualifyingQuestionsErrorMessage;
public caseId: string;
+ public jurisdiction: string;
+ public caseType: string;
constructor(
private readonly route: ActivatedRoute,
@@ -24,6 +26,8 @@ export class QualifyingQuestionOptionsComponent implements OnInit {
public ngOnInit(): void {
this.caseId = this.route.snapshot.params.cid;
+ this.jurisdiction = this.route.snapshot.params.jurisdiction;
+ this.caseType = this.route.snapshot.params.caseType;
// Check if there's already a selected qualifying question from the service
const savedSelection = this.qualifyingQuestionService.getQualifyingQuestionSelection();
@@ -33,7 +37,7 @@ export class QualifyingQuestionOptionsComponent implements OnInit {
}
public click(): void {
- this.router.navigate(['cases', 'case-details', this.caseId], { fragment: 'Queries' });
+ this.router.navigate(['cases', 'case-details', this.jurisdiction, this.caseType, this.caseId], { fragment: 'Queries' });
}
public get displayError(): boolean {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.html b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.html
index 37e45d3eee..8d561458ea 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.html
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.html
@@ -12,7 +12,7 @@ {{'What happens next' | rpxTranslate}}
{{'When the response is available it will be added to the \'Queries\' section.' | rpxTranslate}}
{{'You can' | rpxTranslate}}
- {{'Go back to the case' | rpxTranslate}}
+ {{'Go back to the case' | rpxTranslate}}
@@ -23,8 +23,8 @@ {{'Query response submitted' | rpxTranslate}}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.ts
index d17a1a2386..57dbe969ce 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/query-confirmation/query-confirmation.component.ts
@@ -10,6 +10,8 @@ export class QueryConfirmationComponent implements OnInit {
@Input() public queryCreateContext: QueryCreateContext;
public caseId = '';
+ public jurisdiction = '';
+ public caseType = '';
public queryCreateContextEnum = QueryCreateContext;
constructor(private readonly route: ActivatedRoute) {
@@ -17,5 +19,7 @@ export class QueryConfirmationComponent implements OnInit {
public ngOnInit(): void {
this.caseId = this.route.snapshot.params.cid;
+ this.jurisdiction = this.route.snapshot.params.jurisdiction;
+ this.caseType = this.route.snapshot.params.caseType;
}
}
From 04aa6252322b43688499f71d2d9817ade362cd58 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 3 Jun 2025 15:41:02 +0100
Subject: [PATCH 05/21] fixed unit tests
---
.../case-edit/case-edit.component.spec.ts | 25 ++++
...ompletion-task-cancelled.component.spec.ts | 30 ++++-
...mpletion-task-reassigned.component.spec.ts | 2 +-
...nt-completion-task-reassigned.component.ts | 4 +-
...hallenged-access-success.component.spec.ts | 8 +-
.../case-event-trigger.component.spec.ts | 6 +-
.../case-full-access-view.component.spec.ts | 126 +++++++++++++-----
...w-specific-access-reject.component.spec.ts | 13 +-
.../multiple-tasks-exist.component.spec.ts | 8 +-
.../no-tasks-available.component.spec.ts | 8 +-
.../task-assigned.component.spec.ts | 2 +-
.../task-assigned/task-assigned.component.ts | 4 +-
.../task-unassigned.component.spec.ts | 8 +-
.../event-guard/event-start.guard.spec.ts | 12 +-
.../event-start/event-start.component.spec.ts | 2 +-
.../event-start-state-machine.service.spec.ts | 11 +-
.../event-start-state-machine.service.ts | 16 +--
.../before-you-start.component.spec.ts | 4 +-
.../no-linked-cases.component.spec.ts | 4 +-
...lifying-question-options.component.spec.ts | 8 +-
20 files changed, 223 insertions(+), 78 deletions(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.spec.ts
index 0d09f97890..0738945a91 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.spec.ts
@@ -1477,6 +1477,31 @@ describe('CaseEditComponent', () => {
component.isCaseFlagSubmission = true;
component.isLinkedCasesSubmission = true;
component.confirmation = {} as unknown as Confirmation;
+ component.caseDetails = {
+ case_type: {
+ id: 'case_view_1_type_id',
+ name: 'case view 1 type',
+ jurisdiction: {
+ id: 'case_view_1_jurisdiction_id',
+ name: 'case view 1 jurisdiction',
+ },
+ },
+ state: {
+ id: 'case_view_1_state_id',
+ name: 'case view 1 state',
+ },
+ channels: [],
+ tabs: [],
+ triggers: [],
+ events: [],
+ metadataFields: [],
+ basicFields: {
+ caseNameHmctsInternal: 'Dummy vs Dummy',
+ caseManagementLocation: {
+ baseLocation: 22
+ }
+ }
+ };
formValueService.sanitise.and.returnValue({ name: 'sweet' });
component.onEventCanBeCompleted({
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-cancelled/case-event-completion-task-cancelled.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-cancelled/case-event-completion-task-cancelled.component.spec.ts
index 4d22301080..236a930444 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-cancelled/case-event-completion-task-cancelled.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-cancelled/case-event-completion-task-cancelled.component.spec.ts
@@ -5,6 +5,7 @@ import { MockRpxTranslatePipe } from '../../../../../test/mock-rpx-translate.pip
import { CaseEditComponent } from '../../../case-edit';
import { EventCompletionStateMachineContext } from '../../../domain';
import { CaseEventCompletionTaskCancelledComponent } from './case-event-completion-task-cancelled.component';
+import { Task } from '../../../../../domain/work-allocation/Task';
@Component({
template: ''
@@ -18,6 +19,33 @@ describe('TaskCancelledComponent', () => {
let component: CaseEventCompletionTaskCancelledComponent;
let wrapper: WrapperComponent;
let fixture: ComponentFixture;
+ const taskDetails: Task = {
+ assignee: '1234-1234-1234-1234',
+ auto_assigned: false,
+ case_category: 'asylum',
+ case_id: '1620409659381330',
+ case_management_category: null,
+ case_name: 'Alan Jonson',
+ case_type_id: 'Appeal-864',
+ created_date: '2021-04-19T14:00:00.000+0000',
+ due_date: '2021-05-20T16:00:00.000+0000',
+ execution_type: null,
+ id: '0d22d838-b25a-11eb-a18c-f2d58a9b7bc6',
+ jurisdiction: 'Immigration and Asylum',
+ location: null,
+ location_name: null,
+ name: 'Task name',
+ permissions: null,
+ region: null,
+ security_classification: null,
+ task_state: null,
+ task_system: null,
+ task_title: 'Some lovely task name',
+ type: null,
+ warning_list: null,
+ warnings: true,
+ work_type_id: null
+ };
beforeEach(async () => {
TestBed.configureTestingModule({
@@ -34,7 +62,7 @@ describe('TaskCancelledComponent', () => {
wrapper = fixture.componentInstance;
component = fixture.componentInstance.appComponentRef;
const sessionStorageSpy = jasmine.createSpyObj('mockSessionStorageService', ['removeItem']);
- wrapper.context = {caseId: '123456789', sessionStorageService: sessionStorageSpy} as EventCompletionStateMachineContext;
+ wrapper.context = {caseId: '123456789', task: taskDetails, sessionStorageService: sessionStorageSpy} as EventCompletionStateMachineContext;
fixture.detectChanges();
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.spec.ts
index f56b33c918..6f2118e7c0 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.spec.ts
@@ -46,7 +46,7 @@ describe('TaskReassignedComponent', () => {
case_id: '1620409659381330',
case_management_category: null,
case_name: 'Alan Jonson',
- case_type_id: null,
+ case_type_id: 'Appeal-864',
created_date: '2021-04-19T14:00:00.000+0000',
due_date: '2021-05-20T16:00:00.000+0000',
execution_type: null,
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.ts
index 73f463ddd5..ed65591aab 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-event-completion/components/case-event-completion-task-reassigned/case-event-completion-task-reassigned.component.ts
@@ -37,8 +37,8 @@ export class CaseEventCompletionTaskReassignedComponent implements OnInit, OnDes
// Get case id and task from the parent component
this.caseId = this.context.caseId;
const task = this.context.reassignedTask;
- this.jurisdiction = this.context.task.jurisdiction;
- this.caseType = this.context.task.case_type_id;
+ this.jurisdiction = task.jurisdiction;
+ this.caseType = task.case_type_id;
// Current user is a caseworker?
this.caseworkerSubscription = this.caseworkerService.getCaseworkers(task.jurisdiction).subscribe(result => {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-challenged-access-success/case-challenged-access-success.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-challenged-access-success/case-challenged-access-success.component.spec.ts
index a03089d18e..4a78c1072f 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-challenged-access-success/case-challenged-access-success.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-challenged-access-success/case-challenged-access-success.component.spec.ts
@@ -8,10 +8,14 @@ describe('CaseChallengedAccessSuccessComponent', () => {
let component: CaseChallengedAccessSuccessComponent;
let fixture: ComponentFixture;
const caseId = '1234123412341234';
+ const jurisdictionId = 'TestJurisdiction';
+ const caseTypeId = 'TestCaseType';
const mockRoute = {
snapshot: {
params: {
- cid: caseId
+ cid: caseId,
+ jurisdiction: jurisdictionId,
+ caseType: caseTypeId
}
}
};
@@ -41,6 +45,6 @@ describe('CaseChallengedAccessSuccessComponent', () => {
it('should have the correct Case Reference in the \"View case file\" link URL', () => {
const viewCaseFileLinkElement = fixture.debugElement.nativeElement.querySelector('p.govuk-body a');
- expect(viewCaseFileLinkElement.getAttribute('href')).toContain(`/cases/case-details/${caseId}`);
+ expect(viewCaseFileLinkElement.getAttribute('href')).toContain(`/cases/case-details/${jurisdictionId}/${caseTypeId}/${caseId}`);
});
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
index 2fa7c8bbde..ab41d8ef02 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
@@ -136,7 +136,7 @@ describe('CaseEventTriggerComponent', () => {
let sessionStorageService: any;
let casesReferencePipe: any;
let activityPollingService: any;
- const finalUrl = '/cases/case-details/1707912713167104#Claim%20details';
+ const finalUrl = '/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104#Claim%20details';
beforeEach(waitForAsync(() => {
caseNotifier = createSpyObj('caseService', ['announceCase']);
@@ -254,7 +254,7 @@ describe('CaseEventTriggerComponent', () => {
it('should verify cancel navigate to the correct url', () => {
component.cancel();
- expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/1707912713167104'], { fragment: 'Claim details' });
+ expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104'], { fragment: 'Claim details' });
});
it('should bypass validation if the eventTrigger case fields contain a FlagLauncher field', (done) => {
@@ -371,7 +371,7 @@ describe('CaseEventTriggerComponent', () => {
routerWithModifiedUrl.url = 'linkCases';
component.caseDetails.case_id = '1111-2222-3333-4444';
component.cancel();
- expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/1707912713167104'], { fragment: 'Claim details' });
+ expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104'], { fragment: 'Claim details' });
});
it('should call unregisterStoredSpinner if there is a stored spinnter', () => {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
index 3bc3fc2848..74ce54b879 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
@@ -1272,11 +1272,21 @@ describe('CaseFullAccessViewComponent - prependedTabs', () => {
path: 'case-details',
children: [
{
- path: ':id',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
@@ -1309,7 +1319,7 @@ describe('CaseFullAccessViewComponent - prependedTabs', () => {
{
provide: Location,
useClass: class MockLocation {
- public path = (_: string) => 'cases/case-details/1234567890123456/tasks';
+ public path = (_: string) => 'cases/case-details/TEST/TestAddressBookCase/1234567890123456/tasks';
}
},
ErrorNotifierService,
@@ -1390,7 +1400,7 @@ describe('CaseFullAccessViewComponent - appendedTabs', () => {
convertHrefToRouterService.getHrefMarkdownLinkContent.and.returnValue(of('[Send a new direction](/case/IA/Asylum/1641014744613435/trigger/sendDirection)'));
mockLocation = createSpyObj('location', ['path', 'go', 'isCurrentPathEqualTo']);
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330#caseNotes');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1234567890123456');
TestBed
.configureTestingModule({
@@ -1409,11 +1419,21 @@ describe('CaseFullAccessViewComponent - appendedTabs', () => {
path: 'case-details',
children: [
{
- path: ':id',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
@@ -1623,16 +1643,26 @@ describe('CaseFullAccessViewComponent - ends with caseID', () => {
path: 'case-details',
children: [
{
- path: ':id',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
]
- },
+ }
]
}
]),
@@ -1663,7 +1693,7 @@ describe('CaseFullAccessViewComponent - ends with caseID', () => {
{
provide: Location,
useClass: class MockLocation {
- public path = (_: string) => 'cases/case-details/1234567890123456';
+ public path = (_: string) => 'cases/case-details/TEST/TestAddressBookCase/1234567890123456';
}
},
ErrorNotifierService,
@@ -1752,7 +1782,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
navigationNotifierService = new NavigationNotifierService();
spyOn(navigationNotifierService, 'announceNavigation').and.callThrough();
mockLocation = createSpyObj('location', ['path']);
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330#caseNotes');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330#caseNotes');
TestBed
.configureTestingModule({
imports: [
@@ -1770,11 +1800,21 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
path: 'case-details',
children: [
{
- path: ':id#overview',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id#overview',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
@@ -1898,7 +1938,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
});
it('should return blank array when prepended tabs are null', () => {
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330');
componentFixture.detectChanges();
caseViewerComponent.prependedTabs = null;
caseViewerComponent.organiseTabPosition();
@@ -1912,7 +1952,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
});
it('should navigate to roles and access tab', () => {
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/roles-and-access');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/roles-and-access');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
componentFixture.detectChanges();
expect(caseViewerComponent.tabGroup.selectedIndex).toEqual(1);
@@ -1922,7 +1962,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
spyOn(caseViewerComponent, 'organiseTabPosition').and.callThrough();
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/caseNotes');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/caseNotes');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -1946,7 +1986,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
// Using /caseNotes at the end of the URL ensures there won't be a matching tab found, so the selected tab should
// default to the first *in the CaseView object*, which is the "Overview" tab
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/caseNotes');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/caseNotes');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -1960,7 +2000,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
spyOn(caseViewerComponent, 'organiseTabPosition').and.callThrough();
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/roles-and-access');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/roles-and-access');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -1982,7 +2022,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
spyOn(caseViewerComponent, 'organiseTabPosition').and.callThrough();
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/dummy');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/dummy');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -1996,7 +2036,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
spyOn(caseViewerComponent, 'organiseTabPosition').and.callThrough();
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/dummy');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/dummy');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -2017,7 +2057,7 @@ describe('CaseFullAccessViewComponent - Overview with prepended Tabs', () => {
spyOn(caseViewerComponent, 'organiseTabPosition').and.callThrough();
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
const selectedIndexSetSpy = spyOnProperty(caseViewerComponent.tabGroup, 'selectedIndex', 'set').and.callThrough();
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330/tasks');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330/tasks');
caseViewerComponent.ngOnChanges({ prependedTabs: new SimpleChange(null, prependedTabsList, false) });
tick();
componentFixture.detectChanges();
@@ -2041,7 +2081,7 @@ describe('CaseFullAccessViewComponent - get default hrefMarkdownLinkContent', ()
convertHrefToRouterService = jasmine.createSpyObj('ConvertHrefToRouterService', ['getHrefMarkdownLinkContent', 'callAngularRouter']);
convertHrefToRouterService.getHrefMarkdownLinkContent.and.returnValue(of('Default'));
mockLocation = createSpyObj('location', ['path']);
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330#caseNotes');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330#caseNotes');
subscribeSpy = spyOn(subscriptionMock, 'unsubscribe');
alertService = createSpyObj('alertService', ['setPreserveAlerts', 'success', 'warning', 'clear']);
@@ -2065,11 +2105,21 @@ describe('CaseFullAccessViewComponent - get default hrefMarkdownLinkContent', ()
path: 'case-details',
children: [
{
- path: ':id#overview',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id#overview',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
@@ -2218,7 +2268,7 @@ describe('CaseFullAccessViewComponent - findPreSelectedActiveTab', () => {
beforeEach(async () => {
mockLocation = createSpyObj('location', ['path']);
- mockLocation.path.and.returnValue('/cases/case-details/1620409659381330');
+ mockLocation.path.and.returnValue('/cases/case-details/TEST/TestAddressBookCase/1620409659381330');
convertHrefToRouterService = jasmine.createSpyObj('ConvertHrefToRouterService', ['getHrefMarkdownLinkContent', 'callAngularRouter']);
convertHrefToRouterService.getHrefMarkdownLinkContent.and.returnValue(of('Default'));
@@ -2237,11 +2287,21 @@ describe('CaseFullAccessViewComponent - findPreSelectedActiveTab', () => {
path: 'case-details',
children: [
{
- path: ':id#overview',
+ path: ':jurisdiction',
children: [
{
- path: 'tasks',
- component: TasksContainerComponent
+ path: ':caseType',
+ children: [
+ {
+ path: ':id#overview',
+ children: [
+ {
+ path: 'tasks',
+ component: TasksContainerComponent
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-review-specific-access-reject/case-review-specific-access-reject.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-review-specific-access-reject/case-review-specific-access-reject.component.spec.ts
index 4ace550844..054aebdbda 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-review-specific-access-reject/case-review-specific-access-reject.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-review-specific-access-reject/case-review-specific-access-reject.component.spec.ts
@@ -9,11 +9,20 @@ describe('CaseReviewSpecificAccessRejectComponent', () => {
let component: CaseReviewSpecificAccessRejectComponent;
let fixture: ComponentFixture;
const caseId = '1234123412341234';
+ const caseTypeId = 'TestCaseType';
+ const caseJurisdictionId = 'TestJurisdiction';
+
const mockRoute = {
snapshot: {
data: {
case: {
- case_id: caseId
+ case_id: caseId,
+ case_type: {
+ id: caseTypeId,
+ jurisdiction: {
+ id: caseJurisdictionId
+ }
+ }
}
}
}
@@ -55,6 +64,6 @@ describe('CaseReviewSpecificAccessRejectComponent', () => {
const myTaskLinkElement = fixture.debugElement.nativeElement.querySelector('.govuk-button');
expect(myTaskLinkElement.getAttribute('href')).toEqual(`tasks/list`);
const viewCaseFileLinkElement = fixture.debugElement.nativeElement.querySelector('.cancel a');
- expect(viewCaseFileLinkElement.getAttribute('href')).toEqual(`cases/case-details/${caseId}`);
+ expect(viewCaseFileLinkElement.getAttribute('href')).toEqual(`cases/case-details/${caseJurisdictionId}/${caseTypeId}/${caseId}`);
});
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/multiple-tasks-exist/multiple-tasks-exist.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/multiple-tasks-exist/multiple-tasks-exist.component.spec.ts
index 1489f7f5f9..1433c788d1 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/multiple-tasks-exist/multiple-tasks-exist.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/multiple-tasks-exist/multiple-tasks-exist.component.spec.ts
@@ -16,7 +16,13 @@ describe('MultipleTasksExistComponent', () => {
snapshot: {
data: {
case: {
- case_id: '1620409659381330'
+ case_id: '1620409659381330',
+ case_type: {
+ id: 'TestCaseType',
+ jurisdiction: {
+ id: 'TestJurisdiction'
+ }
+ }
}
}
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/no-tasks-available/no-tasks-available.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/no-tasks-available/no-tasks-available.component.spec.ts
index 18538837fe..fe9692b477 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/no-tasks-available/no-tasks-available.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/no-tasks-available/no-tasks-available.component.spec.ts
@@ -13,7 +13,13 @@ describe('NoTasksAvalaibleComponent', () => {
snapshot: {
data: {
case: {
- case_id: '1620409659381330'
+ case_id: '1620409659381330',
+ case_type: {
+ id: 'TestCaseType',
+ jurisdiction: {
+ id: 'TestJurisdiction'
+ }
+ }
}
}
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.spec.ts
index adab83903d..8a4eade048 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.spec.ts
@@ -30,7 +30,7 @@ describe('TaskRequirementComponent', () => {
case_id: '1620409659381330',
case_management_category: null,
case_name: 'Alan Jonson',
- case_type_id: null,
+ case_type_id: 'TestCaseType',
created_date: '2021-04-19T14:00:00.000+0000',
due_date: '2021-05-20T16:00:00.000+0000',
execution_type: null,
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.ts
index 079f7f6275..1e88cf6309 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-assigned/task-assigned.component.ts
@@ -23,13 +23,13 @@ export class TaskAssignedComponent implements OnInit, OnDestroy {
private readonly judicialworkerService: JudicialworkerService,
private readonly caseworkerService: CaseworkerService) {
this.caseId = this.route.snapshot.data.case.case_id;
- this.jurisdiction = this.route.snapshot.data.case.case_type.jurisdiction.id;
- this.caseType = this.route.snapshot.data.case.case_type.id;
this.task = this.route.snapshot.queryParams as Task;
}
public ngOnInit(): void {
// Current user is a caseworker?
+ this.jurisdiction = this.task.jurisdiction;
+ this.caseType = this.task.case_type_id;
this.caseworkerSubscription = this.caseworkerService.getCaseworkers(this.task.jurisdiction).subscribe(result => {
if (result && result[0].service === this.task.jurisdiction && result[0].caseworkers) {
const caseworker = result[0].caseworkers.find(x => x.idamId === this.task.assignee);
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-unassigned/task-unassigned.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-unassigned/task-unassigned.component.spec.ts
index 2d3644a45b..43f3b940f3 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-unassigned/task-unassigned.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/components/task-unassigned/task-unassigned.component.spec.ts
@@ -13,7 +13,13 @@ describe('TaskUnassignedComponent', () => {
snapshot: {
data: {
case: {
- case_id: '1620409659381330'
+ case_id: '1620409659381330',
+ case_type: {
+ id: 'TestCaseType',
+ jurisdiction: {
+ id: 'TestJurisdiction'
+ }
+ }
}
}
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
index 8cf1bfc87f..4f384a8dfd 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
@@ -18,13 +18,15 @@ describe('EventStartGuard', () => {
id: '0d22d838-b25a-11eb-a18c-f2d58a9b7bc6',
task_title: 'Some lovely task name',
dueDate: '2021-05-20T16:00:00.000+0000',
- description: '[End the appeal](/cases/case-details/${[CASE_REFERENCE]}/trigger/endAppeal/endAppealendAppeal',
+ description: '[End the appeal](/cases/case-details/${[JURISDICTION]}/${[CASE_TYPE]}/${[CASE_REFERENCE]}/trigger/endAppeal/endAppealendAppeal',
location_name: 'Newcastle',
location_id: '366796',
case_id: '1620409659381330',
case_category: 'asylum',
case_name: 'Alan Jonson',
permissions: [],
+ jurisdiction: 'TestJurisdiction',
+ case_type_id: 'TestCaseType'
}
];
@@ -99,12 +101,12 @@ describe('EventStartGuard', () => {
it('canActivate should navigate to event-start if task is required for event', () => {
sessionStorageService.getItem.and.returnValue(JSON.stringify({ cid: 'caseId' }));
const route = createActivatedRouteSnapshot('1620409659381330', 'eventId');
- const payload: TaskPayload = { task_required_for_event: true } as TaskPayload;
+ const payload: TaskPayload = { task_required_for_event: true, tasks} as TaskPayload;
service.getTasksByCaseIdAndEventId.and.returnValue(of(payload));
const result$ = guard.canActivate(route);
result$.subscribe(result => {
expect(result).toEqual(false);
- expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/1620409659381330/event-start'], { queryParams: { caseId: '1620409659381330', eventId: 'eventId', taskId: undefined } });
+ expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/${payload.tasks[0].jurisdiction}/${payload.tasks[0].case_type_id}/1620409659381330/event-start`], { queryParams: { caseId: '1620409659381330', eventId: 'eventId', taskId: undefined } });
});
});
@@ -176,7 +178,7 @@ describe('EventStartGuard', () => {
const mockPayload: TaskPayload = {task_required_for_event: false, tasks};
sessionStorageService.getItem.and.returnValue(JSON.stringify(getExampleUserInfo()));
expect(guard.checkTaskInEventNotRequired(mockPayload, caseId, null, null, null)).toBe(false);
- expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/${caseId}/multiple-tasks-exist`]);
+ expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/${mockPayload.tasks[0].jurisdiction}/${mockPayload.tasks[0].case_type_id}/${caseId}/multiple-tasks-exist`]);
});
it('should return true and navigate to event trigger if navigated to via task next steps', () => {
@@ -241,7 +243,7 @@ describe('EventStartGuard - error', () => {
id: '0d22d838-b25a-11eb-a18c-f2d58a9b7bc6',
task_title: 'Some lovely task name',
dueDate: '2021-05-20T16:00:00.000+0000',
- description: '[End the appeal](/cases/case-details/${[CASE_REFERENCE]}/trigger/endAppeal/endAppealendAppeal',
+ description: '[End the appeal](/cases/case-details/${[JURISDICTION]}/${[CASE_TYPE]}/${[CASE_REFERENCE]}/trigger/endAppeal/endAppealendAppeal',
location_name: 'Newcastle',
location_id: '366796',
case_id: '1620409659381330',
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-start.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-start.component.spec.ts
index bb06f3b1d6..7c641b3af0 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-start.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-start.component.spec.ts
@@ -33,7 +33,7 @@ describe('EventStartComponent', () => {
case_id: '1620409659381330',
case_management_category: null,
case_name: 'Alan Jonson',
- case_type_id: null,
+ case_type_id: 'Appeal',
created_date: '2021-04-19T14:00:00.000+0000',
due_date: '2021-05-20T16:00:00.000+0000',
execution_type: null,
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.spec.ts
index d2ea4c7e81..972d276b00 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.spec.ts
@@ -31,7 +31,7 @@ describe('EventStartStateMachineService', () => {
case_id: '1620409659381330',
case_management_category: null,
case_name: 'Alan Jonson',
- case_type_id: null,
+ case_type_id: 'Appeal-864',
created_date: '2021-04-19T14:00:00.000+0000',
due_date: '2021-05-20T16:00:00.000+0000',
execution_type: null,
@@ -193,7 +193,7 @@ describe('EventStartStateMachineService', () => {
service.startStateMachine(stateMachine);
expect(stateMachine.currentState.id).toEqual(EventStartStates.FINAL);
expect(mockSessionStorageService.setItem).toHaveBeenCalled();
- expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.caseId}/trigger/${context.eventId}`],
+ expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.tasks[0].jurisdiction}/${context.tasks[0].case_type_id}/${context.caseId}/trigger/${context.eventId}`],
{ relativeTo: mockRoute });
});
@@ -209,7 +209,7 @@ describe('EventStartStateMachineService', () => {
service.startStateMachine(stateMachine);
expect(stateMachine.currentState.id).toEqual(EventStartStates.FINAL);
expect(mockSessionStorageService.setItem).toHaveBeenCalled();
- expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.caseId}/trigger/${context.eventId}`],
+ expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.tasks[0].jurisdiction}/${context.tasks[0].case_type_id}/${context.caseId}/trigger/${context.eventId}`],
{ relativeTo: mockRoute });
});
@@ -221,7 +221,7 @@ describe('EventStartStateMachineService', () => {
service.addTransitions();
service.startStateMachine(stateMachine);
expect(stateMachine.currentState.id).toEqual(EventStartStates.FINAL);
- expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.caseId}/task-unassigned`],
+ expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.tasks[0].jurisdiction}/${context.tasks[0].case_type_id}/${context.caseId}/task-unassigned`],
{ queryParams: {}, relativeTo: mockRoute });
});
@@ -233,10 +233,9 @@ describe('EventStartStateMachineService', () => {
service.addTransitions();
service.startStateMachine(stateMachine);
expect(stateMachine.currentState.id).toEqual(EventStartStates.FINAL);
- expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.caseId}/task-assigned`],
+ expect(mockRouter.navigate).toHaveBeenCalledWith([`/cases/case-details/${context.tasks[0].jurisdiction}/${context.tasks[0].case_type_id}/${context.caseId}/task-assigned`],
{ queryParams: context.tasks[0], relativeTo: context.route });
});
-
it('should action no task available', () => {
stateMachine = service.initialiseStateMachine(context);
service.createStates(stateMachine);
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.ts
index 6208e95762..f4099dceba 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/services/event-start-state-machine.service.ts
@@ -108,17 +108,11 @@ export class EventStartStateMachineService {
}
}
- private getJurisdictionNCaseType(context: EventStartStateMachineContext): any {
- const caseInfo = context.sessionStorageService.getItem('caseInfo');
- return caseInfo ? JSON.parse(caseInfo) : null;
- }
-
public entryActionForStateNoTask(state: State, context: EventStartStateMachineContext): void {
// Trigger final state to complete processing of state machine
state.trigger(EventStartStates.FINAL);
// Navigate to no tasks available error page
- const caseDetails = this.getJurisdictionNCaseType(context);
- context.router.navigate([`/cases/case-details/${caseDetails?.jurisdiction}/${caseDetails.caseType}/${context.caseId}/no-tasks-available`], { relativeTo: context.route });
+ context.router.navigate([`/cases/case-details/${context.tasks[0]?.jurisdiction}/${context.tasks[0]?.case_type_id}/${context.caseId}/no-tasks-available`], { relativeTo: context.route });
}
public entryActionForStateOneOrMoreTasks(state: State, context: EventStartStateMachineContext): void {
@@ -165,14 +159,13 @@ export class EventStartStateMachineService {
public entryActionForStateTaskUnAssigned(state: State, context: EventStartStateMachineContext): void {
let navigationURL = '';
let theQueryParams: Params = {};
- const caseDetails = this.getJurisdictionNCaseType(context);
if (context.tasks[0].assignee) {
// Task is assigned to some other user, navigate to task assigned error page
- navigationURL = `/cases/case-details/${caseDetails?.jurisdiction}/${caseDetails.caseType}/${context.caseId}/task-assigned`;
+ navigationURL = `/cases/case-details/${context.tasks[0]?.jurisdiction}/${context.tasks[0]?.case_type_id}/${context.caseId}/task-assigned`;
theQueryParams = context.tasks[0];
} else {
// Task is unassigned, navigate to task unassigned error page
- navigationURL = `/cases/case-details/${caseDetails?.jurisdiction}/${caseDetails.caseType}/${context.caseId}/task-unassigned`;
+ navigationURL = `/cases/case-details/${context.tasks[0]?.jurisdiction}/${context.tasks[0]?.case_type_id}/${context.caseId}/task-unassigned`;
}
// Trigger final state to complete processing of state machine
@@ -229,9 +222,8 @@ export class EventStartStateMachineService {
public entryActionForStateMultipleTasksAssignedToUser(state: State, context: EventStartStateMachineContext): void {
// Trigger final state to complete processing of state machine
state.trigger(EventStartStates.FINAL);
- const caseDetails = this.getJurisdictionNCaseType(context);
// Navigate to multiple tasks exist error page
- context.router.navigate([`/cases/case-details/${caseDetails?.jurisdiction}/${caseDetails.caseType}/${context.caseId}/multiple-tasks-exist`], { relativeTo: context.route });
+ context.router.navigate([`/cases/case-details/${context.tasks[0]?.jurisdiction}/${context.tasks[0]?.case_type_id}/${context.caseId}/multiple-tasks-exist`], { relativeTo: context.route });
}
public finalAction(state: State): void {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/before-you-start/before-you-start.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/before-you-start/before-you-start.component.spec.ts
index 5e90dd0561..0470bc13bc 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/before-you-start/before-you-start.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/before-you-start/before-you-start.component.spec.ts
@@ -20,7 +20,9 @@ describe('BeforeYouStartComponent', () => {
serverLinkedApiError: null,
hasContinuedFromStart: false,
casesToUnlink: [],
- initialCaseLinks: []
+ initialCaseLinks: [],
+ caseJurisdictionID: 'TEST_JURISDICTION',
+ caseDetails: { case_type: 'TEST_CASE_TYPE' },
};
const mockRouter = {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.spec.ts
index acc29ab0fc..298d3096ec 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/components/no-linked-cases/no-linked-cases.component.spec.ts
@@ -18,6 +18,8 @@ describe('NoLinkedCasesComponent', () => {
const linkedCasesService = {
caseId: '1682374819203471',
+ caseJurisdictionID: 'TEST_JURISDICTION',
+ caseDetails: { case_type: 'TEST_CASE_TYPE' },
getAllLinkedCaseInformation() {}
};
@@ -46,6 +48,6 @@ describe('NoLinkedCasesComponent', () => {
it('should back button navigate to linked cases tab', () => {
component.onBack();
- expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', caseId], { fragment: 'Linked cases' });
+ expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', 'TEST_JURISDICTION', 'TEST_CASE_TYPE', caseId], { fragment: 'Linked cases' });
});
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.spec.ts
index 15da28e323..22ba77db0e 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/query-management/components/qualifying-questions/qualifying-question-options/qualifying-question-options.component.spec.ts
@@ -17,10 +17,14 @@ describe('QualifyingQuestionOptionsComponent', () => {
navigate: jasmine.createSpy('navigate')
};
const caseId = '12345';
+ const jurisdictionId = 'TestJurisdiction';
+ const caseTypeId = 'TestCaseType';
const mockRoute = {
snapshot: {
params: {
- cid: caseId
+ cid: caseId,
+ jurisdiction: jurisdictionId,
+ caseType: caseTypeId
}
}
};
@@ -67,7 +71,7 @@ describe('QualifyingQuestionOptionsComponent', () => {
it('should have the link to case details queries tab', () => {
component.click();
- expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', '12345'], { fragment: 'Queries' });
+ expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', 'TestJurisdiction', 'TestCaseType', '12345'], { fragment: 'Queries' });
});
describe('displayError', () => {
From 195571ed511c80681b50d2e831748fc9b7b4c726 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 3 Jun 2025 16:02:54 +0100
Subject: [PATCH 06/21] fixed sonar issue
---
.../palette/linked-cases/read-linked-cases-field.component.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
index b35d7cee6e..b88afa017f 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/read-linked-cases-field.component.ts
@@ -56,7 +56,7 @@ export class ReadLinkedCasesFieldComponent implements OnInit, AfterViewInit {
}
public ngAfterViewInit(): void {
- this.linkedCasesService.caseFieldValue = this.caseField?.value || [];
+ this.linkedCasesService.caseFieldValue = this.caseField?.value ?? [];
let labelField = document.getElementsByClassName('govuk-heading-l');
if (labelField && labelField.length) {
labelField[0].replaceWith('');
From 5c17e0fa82d4ce15a943e1f8797c0690573f4192 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Fri, 6 Jun 2025 10:11:33 +0100
Subject: [PATCH 07/21] url change
---
.../components/case-editor/case-edit/case-edit.component.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.ts
index 942e42bd72..e252a32205 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-editor/case-edit/case-edit.component.ts
@@ -224,7 +224,7 @@ export class CaseEditComponent implements OnInit, OnDestroy {
}
public emitSubmitted(response: Record): void {
- this.submitted.emit({ caseId: response['id'], status: this.getStatus(response) });
+ this.submitted.emit({ caseId: response['id'], jurisdiction: response['jurisdiction'], caseType: response['case_type'], status: this.getStatus(response) });
}
public getNextPage({ wizard, currentPageId, eventTrigger, form }: CaseEditGetNextPage): WizardPage {
From 1da348a116ee83e5464ab3cb12d2c2331683fcb5 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 10 Jun 2025 14:37:36 +0100
Subject: [PATCH 08/21] url change
---
.../case-full-access-view.component.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
index 4806233a89..3c2c8f6632 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
@@ -360,7 +360,14 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
const id = (tab.element.nativeElement as HTMLElement).id;
// cases/case-details/:jurisdiction/:caseType/:caseId/hearings
// cases/case-details/:jurisdiction/:caseType/:caseId/roles-and-access
- this.router.navigate([id], { relativeTo: this.route });
+ this.router.navigate([
+ 'cases',
+ 'case-details',
+ this.caseDetails.case_type.jurisdiction.id,
+ this.caseDetails.case_type.id,
+ this.caseDetails.case_id,
+ id
+ ], { relativeTo: this.route.root });
} else {
// Routing here is based on tab label, not ideal
// cases/case-details/:jurisdiction/:caseType/:caseId#tabLabel
From 209c35280a76228e14a686e3a2fb23fa02d6b170 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Fri, 27 Jun 2025 15:16:05 +0100
Subject: [PATCH 09/21] version updated
---
RELEASE-NOTES.md | 3 +++
package.json | 2 +-
projects/ccd-case-ui-toolkit/package.json | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index fbd0e5c117..b582648487 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1,5 +1,8 @@
## RELEASE NOTES
+### Version 7.2.13-exui-2761-rc1
+**EXUI-2761** url change
+
### Version 7.2.13
**EXUI-2703** Add apply and cancel filter buttons at the top of the case filters
**EXUI-3050** SSCS - Duration of the hearing Value updating bug
diff --git a/package.json b/package.json
index c779ebb96f..7c6144fbd6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.13",
+ "version": "7.2.13-exui-2761-rc1",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json
index ac75e2580f..66ad4d37c4 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.2.13",
+ "version": "7.2.13-exui-2761-rc1",
"engines": {
"node": ">=18.19.0"
},
From 799d47c900ac12c576c605c1ce534a88c890791b Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 1 Jul 2025 15:53:45 +0100
Subject: [PATCH 10/21] fixed test
---
package.json | 2 +-
projects/ccd-case-ui-toolkit/package.json | 2 +-
.../event-start/event-guard/event-start.guard.spec.ts | 10 +++++++---
.../event-start/event-guard/event-start.guard.ts | 8 ++++----
4 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/package.json b/package.json
index 226f5b8a52..f137e18ab6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.13-exui-2761-rc2",
+ "version": "7.2.13-exui-2761-rc3",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json
index b18ce5a07f..cc44b90aee 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.2.13-exui-2761-rc2",
+ "version": "7.2.13-exui-2761-rc3",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
index 4f384a8dfd..b5dd84efcf 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.spec.ts
@@ -101,12 +101,14 @@ describe('EventStartGuard', () => {
it('canActivate should navigate to event-start if task is required for event', () => {
sessionStorageService.getItem.and.returnValue(JSON.stringify({ cid: 'caseId' }));
const route = createActivatedRouteSnapshot('1620409659381330', 'eventId');
- const payload: TaskPayload = { task_required_for_event: true, tasks} as TaskPayload;
+ guard.jurisdiction = 'jid';
+ guard.caseType = 'ctid';
+ const payload: TaskPayload = { task_required_for_event: true} as TaskPayload;
service.getTasksByCaseIdAndEventId.and.returnValue(of(payload));
const result$ = guard.canActivate(route);
result$.subscribe(result => {
expect(result).toEqual(false);
- expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/${payload.tasks[0].jurisdiction}/${payload.tasks[0].case_type_id}/1620409659381330/event-start`], { queryParams: { caseId: '1620409659381330', eventId: 'eventId', taskId: undefined } });
+ expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/jid/ctid/1620409659381330/event-start`], { queryParams: { caseId: '1620409659381330', eventId: 'eventId', taskId: undefined } });
});
});
@@ -175,10 +177,12 @@ describe('EventStartGuard', () => {
it('should return false with error navigation if there are more than 1 tasks assigned to the user', () => {
tasks[0].assignee = '1';
tasks.push(tasks[0]);
+ guard.jurisdiction = 'jid';
+ guard.caseType = 'ctid';
const mockPayload: TaskPayload = {task_required_for_event: false, tasks};
sessionStorageService.getItem.and.returnValue(JSON.stringify(getExampleUserInfo()));
expect(guard.checkTaskInEventNotRequired(mockPayload, caseId, null, null, null)).toBe(false);
- expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/${mockPayload.tasks[0].jurisdiction}/${mockPayload.tasks[0].case_type_id}/${caseId}/multiple-tasks-exist`]);
+ expect(router.navigate).toHaveBeenCalledWith([`/cases/case-details/jid/ctid/${caseId}/multiple-tasks-exist`]);
});
it('should return true and navigate to event trigger if navigated to via task next steps', () => {
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.ts
index 453dfe9699..abf8d29894 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/event-start/event-guard/event-start.guard.ts
@@ -12,8 +12,8 @@ import { removeTaskFromClientContext } from '../../case-editor/case-edit-utils/c
@Injectable()
export class EventStartGuard implements CanActivate {
- private jurisdiction: string;
- private caseType: string;
+ public jurisdiction: string;
+ public caseType: string;
private caseId: string;
constructor(private readonly workAllocationService: WorkAllocationService,
@@ -119,7 +119,7 @@ export class EventStartGuard implements CanActivate {
return true;
} else if (tasksAssignedToUser.length > 1 && !taskId) {
// if more than one task assigned to the user then give multiple tasks error
- this.router.navigate([`/cases/case-details/${payload.tasks[0].jurisdiction}/${payload.tasks[0].case_type_id}/${caseId}/multiple-tasks-exist`]);
+ this.router.navigate([`/cases/case-details/${this.jurisdiction}/${this.caseType}/${caseId}/multiple-tasks-exist`]);
return false;
} else {
let task: any;
@@ -150,7 +150,7 @@ export class EventStartGuard implements CanActivate {
if (this.router && this.router.url && this.router.url.includes('event-start')) {
return of(true);
}
- this.router.navigate([`/cases/case-details/${payload.tasks[0].jurisdiction}/${payload.tasks[0].case_type_id}/${caseId}/event-start`], { queryParams: { caseId, eventId, taskId } });
+ this.router.navigate([`/cases/case-details/${this.jurisdiction}/${this.caseType}/${caseId}/event-start`], { queryParams: { caseId, eventId, taskId } });
return of(false);
} else {
return of(this.checkTaskInEventNotRequired(payload, caseId, taskId, eventId, userId));
From d830f1dca6e4134faed75eca79a390f503d594fe Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 1 Jul 2025 15:59:07 +0100
Subject: [PATCH 11/21] cve
---
yarn-audit-known-issues | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/yarn-audit-known-issues b/yarn-audit-known-issues
index 68f9db8ad8..780225daac 100644
--- a/yarn-audit-known-issues
+++ b/yarn-audit-known-issues
@@ -7,7 +7,7 @@
{"value":"core-js","children":{"ID":"core-js (deprecation)","Issue":"core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.","Severity":"moderate","Vulnerable Versions":"1.2.7","Tree Versions":["1.2.7"],"Dependents":["fbjs@npm:0.8.18"]}}
{"value":"cross-spawn","children":{"ID":1104663,"Issue":"Regular Expression Denial of Service (ReDoS) in cross-spawn","URL":"https://github.com/advisories/GHSA-3xgq-45jj-v275","Severity":"high","Vulnerable Versions":"<6.0.6","Tree Versions":["5.1.0"],"Dependents":["execa@npm:0.7.0"]}}
{"value":"domexception","children":{"ID":"domexception (deprecation)","Issue":"Use your platform's native DOMException instead","Severity":"moderate","Vulnerable Versions":"4.0.0","Tree Versions":["4.0.0"],"Dependents":["jsdom@virtual:ce56289c4b7a2e9003d709997e253c1c80dcaee4c6fbe440cbe9ba5de5db8af3a7b7ad41bbdec5a5e3d40dc9c3c54bef92dd6885ff84cd436d636d5a1b380a61#npm:20.0.3"]}}
-{"value":"dompurify","children":{"ID":1102259,"Issue":"DOMPurify allows Cross-site Scripting (XSS)","URL":"https://github.com/advisories/GHSA-vhxf-7vqr-mrjg","Severity":"moderate","Vulnerable Versions":"<3.2.4","Tree Versions":["3.1.5"],"Dependents":["mermaid@npm:10.9.1"]}}
+{"value":"dompurify","children":{"ID":1105772,"Issue":"DOMPurify allows Cross-site Scripting (XSS)","URL":"https://github.com/advisories/GHSA-vhxf-7vqr-mrjg","Severity":"moderate","Vulnerable Versions":"<3.2.4","Tree Versions":["3.1.5"],"Dependents":["mermaid@npm:10.9.1"]}}
{"value":"express","children":{"ID":1096820,"Issue":"Express.js Open Redirect in malformed URLs","URL":"https://github.com/advisories/GHSA-rv95-896h-c2vc","Severity":"moderate","Vulnerable Versions":"<4.19.2","Tree Versions":["4.18.2"],"Dependents":["json-server@npm:0.15.1"]}}
{"value":"express","children":{"ID":1100530,"Issue":"express vulnerable to XSS via response.redirect()","URL":"https://github.com/advisories/GHSA-qw6h-vgh9-j6wx","Severity":"low","Vulnerable Versions":"<4.20.0","Tree Versions":["4.18.2"],"Dependents":["json-server@npm:0.15.1"]}}
{"value":"figgy-pudding","children":{"ID":"figgy-pudding (deprecation)","Issue":"This module is no longer supported.","Severity":"moderate","Vulnerable Versions":"3.5.2","Tree Versions":["3.5.2"],"Dependents":["npm-registry-fetch@npm:4.0.7"]}}
@@ -35,7 +35,7 @@
{"value":"path-to-regexp","children":{"ID":1105199,"Issue":"path-to-regexp contains a ReDoS","URL":"https://github.com/advisories/GHSA-rhx6-c78j-4q9w","Severity":"high","Vulnerable Versions":"<0.1.12","Tree Versions":["0.1.7"],"Dependents":["express@npm:4.18.2"]}}
{"value":"prismjs","children":{"ID":1089189,"Issue":"prismjs Regular Expression Denial of Service vulnerability","URL":"https://github.com/advisories/GHSA-hqhp-5p83-hx96","Severity":"moderate","Vulnerable Versions":"<1.25.0","Tree Versions":["1.24.1"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
{"value":"prismjs","children":{"ID":1090424,"Issue":"Cross-site Scripting in Prism","URL":"https://github.com/advisories/GHSA-3949-f494-cm99","Severity":"high","Vulnerable Versions":">=1.14.0 <1.27.0","Tree Versions":["1.24.1"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
-{"value":"prismjs","children":{"ID":1102459,"Issue":"PrismJS DOM Clobbering vulnerability","URL":"https://github.com/advisories/GHSA-x7hr-w5r2-h6wg","Severity":"moderate","Vulnerable Versions":"<1.30.0","Tree Versions":["1.24.1"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
+{"value":"prismjs","children":{"ID":1105770,"Issue":"PrismJS DOM Clobbering vulnerability","URL":"https://github.com/advisories/GHSA-x7hr-w5r2-h6wg","Severity":"moderate","Vulnerable Versions":"<1.30.0","Tree Versions":["1.24.1"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
{"value":"request","children":{"ID":1096727,"Issue":"Server-Side Request Forgery in Request","URL":"https://github.com/advisories/GHSA-p8p7-x288-28g6","Severity":"moderate","Vulnerable Versions":"<=2.88.2","Tree Versions":["2.88.2"],"Dependents":["json-server@npm:0.15.1"]}}
{"value":"resolve-url","children":{"ID":"resolve-url (deprecation)","Issue":"https://github.com/lydell/resolve-url#deprecated","Severity":"moderate","Vulnerable Versions":"0.2.1","Tree Versions":["0.2.1"],"Dependents":["source-map-resolve@npm:0.5.3"]}}
{"value":"rimraf","children":{"ID":"rimraf (deprecation)","Issue":"Rimraf versions prior to v4 are no longer supported","Severity":"moderate","Vulnerable Versions":"2.7.1","Tree Versions":["2.7.1"],"Dependents":["cacache@npm:12.0.4"]}}
From c15703581920c83dff6b685ad8999b69324a4a7e Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 1 Jul 2025 15:59:57 +0100
Subject: [PATCH 12/21] version updated
---
package.json | 2 +-
projects/ccd-case-ui-toolkit/package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index f137e18ab6..c2d6d73759 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.13-exui-2761-rc3",
+ "version": "7.2.13-exui-2761-rc4",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json
index cc44b90aee..8f79910cca 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.2.13-exui-2761-rc3",
+ "version": "7.2.13-exui-2761-rc4",
"engines": {
"node": ">=18.19.0"
},
From 5f3f4d104fb7619f75b78a07ef657e83dc35d098 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 10:46:53 +0100
Subject: [PATCH 13/21] fix back button url link
---
package.json | 2 +-
projects/ccd-case-ui-toolkit/package.json | 2 +-
.../case-event-trigger.component.spec.ts | 16 +++++++++++++++-
.../case-event-trigger.component.ts | 19 ++++++++++++++++++-
4 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/package.json b/package.json
index c2d6d73759..470460d90b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.13-exui-2761-rc4",
+ "version": "7.2.13-exui-2761-rc5",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json
index 8f79910cca..2e92c52c50 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.2.13-exui-2761-rc4",
+ "version": "7.2.13-exui-2761-rc5",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
index ab41d8ef02..f7b8c59bb9 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
@@ -136,7 +136,7 @@ describe('CaseEventTriggerComponent', () => {
let sessionStorageService: any;
let casesReferencePipe: any;
let activityPollingService: any;
- const finalUrl = '/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104#Claim%20details';
+ let finalUrl = '/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104#Claim%20details';
beforeEach(waitForAsync(() => {
caseNotifier = createSpyObj('caseService', ['announceCase']);
@@ -380,5 +380,19 @@ describe('CaseEventTriggerComponent', () => {
component.ngOnInit();
expect(loadingService.hasSharedSpinner).toBeTruthy();
expect(loadingService.unregisterSharedSpinner).toHaveBeenCalled();
+ })
+
+ it('cancel should navigate to url with fragment if previousUrl contains #', () => {
+ finalUrl = '/cases/case-details/1707912713167104#Claim%20details'
+ spyOn(component as any, 'getNavigationUrl').and.callThrough();
+ component.cancel();
+ expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104'], { fragment: 'Claim details' });
+ });
+
+it('getNavigationUrl should transform url if it matches /case-details/:id', () => {
+ component.caseDetails = CASE_DETAILS;
+ const url = '/case-details/1707912713167104';
+ const result = component['getNavigationUrl'](url);
+ expect(result).toBe('/case-details/TEST/TEST_CASE_TYPE/1707912713167104');
});
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index c0825d0d18..43d7b56e6f 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -123,9 +123,25 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
});
}
+ // replace the old link with the new one with jurisdiction and case type id
+ private getNavigationUrl(url: string): string {
+ const urlRegex = /\/case-details\/(\d+)/;
+ const match = url.match(urlRegex);
+ if (match && /^\d+$/.test(match[1]) && this.caseDetails?.case_type) {
+ const jurisdiction = this.caseDetails.case_type.jurisdiction.id;
+ const id = this.caseDetails.case_type.id;
+ return url.replace(
+ urlRegex,
+ `/case-details/${jurisdiction}/${id}/${match[1]}`
+ );
+ }
+ return url;
+ }
+
public cancel(): Promise {
- const previousUrl = this.routerCurrentNavigation?.previousNavigation?.finalUrl?.toString();
+ let previousUrl = this.routerCurrentNavigation?.previousNavigation?.finalUrl?.toString();
if (previousUrl) {
+ previousUrl = this.getNavigationUrl(previousUrl);
if (previousUrl.indexOf('#') > -1) {
const url = previousUrl.split('#')[0];
const fragment = previousUrl.split('#')[1].replace(/%20/g, ' ');
@@ -134,6 +150,7 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return this.router.navigate([previousUrl]);
}
} else {
+ this.parentUrl = this.getNavigationUrl(this.parentUrl);
return this.router.navigate([this.parentUrl]);
}
}
From c84713686be47bcedc8f5ee84c70821b0be3bd2b Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 14:20:27 +0100
Subject: [PATCH 14/21] fixed navigation
---
.../case-event-trigger.component.spec.ts | 2 +-
.../case-event-trigger.component.ts | 18 ++++++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
index f7b8c59bb9..758e8d1eaf 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
@@ -389,7 +389,7 @@ describe('CaseEventTriggerComponent', () => {
expect(router.navigate).toHaveBeenCalledWith(['/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104'], { fragment: 'Claim details' });
});
-it('getNavigationUrl should transform url if it matches /case-details/:id', () => {
+ it('getNavigationUrl should transform url if it matches /case-details/:id', () => {
component.caseDetails = CASE_DETAILS;
const url = '/case-details/1707912713167104';
const result = component['getNavigationUrl'](url);
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index 43d7b56e6f..a19a99c073 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -138,6 +138,22 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return url;
}
+ private getNavigationUrlWithTab(url: string): string {
+ const hasTidQuery = this.router.url.includes('?tid=');
+ const isNotCasesPath = !this.parentUrl.includes('/cases');
+ const match = this.parentUrl.match(/(\d+)(.*)$/);
+ const hasNoExtraPath = match && !match[2];
+
+ if (hasTidQuery && isNotCasesPath && hasNoExtraPath) {
+ // Only add '/cases' prefix if not already present
+ if (!this.parentUrl.startsWith('/cases')) {
+ return `/cases${this.parentUrl}/tasks`;
+ }
+ return `${this.parentUrl}/tasks`;
+ }
+ return url;
+ }
+
public cancel(): Promise {
let previousUrl = this.routerCurrentNavigation?.previousNavigation?.finalUrl?.toString();
if (previousUrl) {
@@ -151,6 +167,8 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
}
} else {
this.parentUrl = this.getNavigationUrl(this.parentUrl);
+ // If there is no tab name in the URL, we need to navigate to the tasks tab
+ this.parentUrl = this.getNavigationUrlWithTab(this.parentUrl);
return this.router.navigate([this.parentUrl]);
}
}
From eed2234535fd6b6480353ff8ed1e323a0ce4f98d Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 15:14:41 +0100
Subject: [PATCH 15/21] fixe unit test
---
.../case-event-trigger.component.spec.ts | 6 +++++
.../case-event-trigger.component.ts | 24 +++++++++----------
2 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
index 758e8d1eaf..eaaaa3886a 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
@@ -395,4 +395,10 @@ describe('CaseEventTriggerComponent', () => {
const result = component['getNavigationUrl'](url);
expect(result).toBe('/case-details/TEST/TEST_CASE_TYPE/1707912713167104');
});
+
+ it('getNavigationUrlWithTab should add /cases prefix and /tasks if needed', () => {
+ finalUrl = '/case-details/TEST/TEST_CASE_TYPE/1707912713167104';
+ const result = component['getNavigationUrlWithTab'](finalUrl);
+ expect(result).toBe('/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104/tasks');
+ });
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index a19a99c073..86c88c12fe 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -138,20 +138,18 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return url;
}
- private getNavigationUrlWithTab(url: string): string {
- const hasTidQuery = this.router.url.includes('?tid=');
- const isNotCasesPath = !this.parentUrl.includes('/cases');
- const match = this.parentUrl.match(/(\d+)(.*)$/);
+ private getNavigationUrlWithTab(urlLink: string): string {
+ const isNotCasesPath = !urlLink.startsWith('/cases');
+ const match = urlLink.match(/^.*?(\d+)([^\/]*)$/);
const hasNoExtraPath = match && !match[2];
-
- if (hasTidQuery && isNotCasesPath && hasNoExtraPath) {
+ if (isNotCasesPath && hasNoExtraPath) {
// Only add '/cases' prefix if not already present
- if (!this.parentUrl.startsWith('/cases')) {
- return `/cases${this.parentUrl}/tasks`;
+ if (!urlLink.startsWith('/cases')) {
+ return `/cases${urlLink}/tasks`;
}
- return `${this.parentUrl}/tasks`;
+ return `${urlLink}/tasks`;
}
- return url;
+ return urlLink;
}
public cancel(): Promise {
@@ -166,10 +164,10 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return this.router.navigate([previousUrl]);
}
} else {
- this.parentUrl = this.getNavigationUrl(this.parentUrl);
+ const url = this.getNavigationUrl(this.parentUrl);
// If there is no tab name in the URL, we need to navigate to the tasks tab
- this.parentUrl = this.getNavigationUrlWithTab(this.parentUrl);
- return this.router.navigate([this.parentUrl]);
+ const updatedUrl = this.getNavigationUrlWithTab(url);
+ return this.router.navigate([updatedUrl]);
}
}
From dc025e01269b1e87ee9815f905ce5add684426c0 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 15:24:46 +0100
Subject: [PATCH 16/21] updated regex for security failure
---
.../case-event-trigger/case-event-trigger.component.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index 86c88c12fe..e60c1448df 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -140,7 +140,8 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
private getNavigationUrlWithTab(urlLink: string): string {
const isNotCasesPath = !urlLink.startsWith('/cases');
- const match = urlLink.match(/^.*?(\d+)([^\/]*)$/);
+ // Use a safer regex to avoid super-linear runtime (ReDoS)
+ const match = urlLink.match(/(?:^|\/)(\d+)([^\/]*)$/);
const hasNoExtraPath = match && !match[2];
if (isNotCasesPath && hasNoExtraPath) {
// Only add '/cases' prefix if not already present
From 54edf394d5702580a10ae40f8e52efc25fa7c552 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 15:38:51 +0100
Subject: [PATCH 17/21] updatetest and revert the change
---
.../case-event-trigger/case-event-trigger.component.spec.ts | 6 ------
.../case-event-trigger/case-event-trigger.component.ts | 4 +---
2 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
index eaaaa3886a..758e8d1eaf 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.spec.ts
@@ -395,10 +395,4 @@ describe('CaseEventTriggerComponent', () => {
const result = component['getNavigationUrl'](url);
expect(result).toBe('/case-details/TEST/TEST_CASE_TYPE/1707912713167104');
});
-
- it('getNavigationUrlWithTab should add /cases prefix and /tasks if needed', () => {
- finalUrl = '/case-details/TEST/TEST_CASE_TYPE/1707912713167104';
- const result = component['getNavigationUrlWithTab'](finalUrl);
- expect(result).toBe('/cases/case-details/TEST/TEST_CASE_TYPE/1707912713167104/tasks');
- });
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index e60c1448df..854c871d96 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -165,9 +165,7 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return this.router.navigate([previousUrl]);
}
} else {
- const url = this.getNavigationUrl(this.parentUrl);
- // If there is no tab name in the URL, we need to navigate to the tasks tab
- const updatedUrl = this.getNavigationUrlWithTab(url);
+ const updatedUrl = this.getNavigationUrl(this.parentUrl);
return this.router.navigate([updatedUrl]);
}
}
From a0504d68fdbf04d2dccd635036e7173c49b35851 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Thu, 3 Jul 2025 15:52:24 +0100
Subject: [PATCH 18/21] revert the unwanted code
---
.../case-event-trigger.component.ts | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
index 854c871d96..a5ee525dca 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-event-trigger/case-event-trigger.component.ts
@@ -138,21 +138,6 @@ export class CaseEventTriggerComponent implements OnInit, OnDestroy {
return url;
}
- private getNavigationUrlWithTab(urlLink: string): string {
- const isNotCasesPath = !urlLink.startsWith('/cases');
- // Use a safer regex to avoid super-linear runtime (ReDoS)
- const match = urlLink.match(/(?:^|\/)(\d+)([^\/]*)$/);
- const hasNoExtraPath = match && !match[2];
- if (isNotCasesPath && hasNoExtraPath) {
- // Only add '/cases' prefix if not already present
- if (!urlLink.startsWith('/cases')) {
- return `/cases${urlLink}/tasks`;
- }
- return `${urlLink}/tasks`;
- }
- return urlLink;
- }
-
public cancel(): Promise {
let previousUrl = this.routerCurrentNavigation?.previousNavigation?.finalUrl?.toString();
if (previousUrl) {
From 4811486a2faf16bf46f0b94e891d75bd27db11a8 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Wed, 20 Aug 2025 16:42:09 +0100
Subject: [PATCH 19/21] cve
---
yarn-audit-known-issues | 1 +
1 file changed, 1 insertion(+)
diff --git a/yarn-audit-known-issues b/yarn-audit-known-issues
index eeb01c9307..b1e285317f 100644
--- a/yarn-audit-known-issues
+++ b/yarn-audit-known-issues
@@ -27,6 +27,7 @@
{"value":"marked","children":{"ID":1095051,"Issue":"Inefficient Regular Expression Complexity in marked","URL":"https://github.com/advisories/GHSA-rrrm-qjm4-v8hf","Severity":"high","Vulnerable Versions":"<4.0.10","Tree Versions":["0.7.0"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
{"value":"marked","children":{"ID":1095052,"Issue":"Inefficient Regular Expression Complexity in marked","URL":"https://github.com/advisories/GHSA-5v2h-r2cx-5xgj","Severity":"high","Vulnerable Versions":"<4.0.10","Tree Versions":["0.7.0"],"Dependents":["@hmcts/ccd-case-ui-toolkit@workspace:."]}}
{"value":"mermaid","children":{"ID":1100231,"Issue":"Prototype pollution vulnerability found in Mermaid's bundled version of DOMPurify","URL":"https://github.com/advisories/GHSA-m4gq-x24j-jpmf","Severity":"high","Vulnerable Versions":"<=10.9.2","Tree Versions":["10.9.1"],"Dependents":["ngx-markdown@virtual:6ff8c2a3aef81417d9f60600e3255d97c9c6c863d8733a87ed99d869392767523e0e28c07db1eb2a034bc9265813386132447698258584d621a7fd0e13d93585#npm:17.2.1"]}}
+{"value":"mermaid","children":{"ID":1106952,"Issue":"Mermaid improperly sanitizes sequence diagram labels leading to XSS","URL":"https://github.com/advisories/GHSA-7rqq-prvp-x9jh","Severity":"moderate","Vulnerable Versions":">=10.9.0-rc.1 <11.10.0","Tree Versions":["10.9.1"],"Dependents":["ngx-markdown@virtual:6ff8c2a3aef81417d9f60600e3255d97c9c6c863d8733a87ed99d869392767523e0e28c07db1eb2a034bc9265813386132447698258584d621a7fd0e13d93585#npm:17.2.1"]}}
{"value":"micromatch","children":{"ID":1098681,"Issue":"Regular Expression Denial of Service (ReDoS) in micromatch","URL":"https://github.com/advisories/GHSA-952p-6rrq-rcjv","Severity":"moderate","Vulnerable Versions":"<4.0.8","Tree Versions":["4.0.5"],"Dependents":["fast-glob@npm:3.3.2"]}}
{"value":"move-concurrently","children":{"ID":"move-concurrently (deprecation)","Issue":"This package is no longer supported.","Severity":"moderate","Vulnerable Versions":"1.0.1","Tree Versions":["1.0.1"],"Dependents":["cacache@npm:12.0.4"]}}
{"value":"nanoid","children":{"ID":1101163,"Issue":"Predictable results in nanoid generation when given non-integer values","URL":"https://github.com/advisories/GHSA-mwcw-c2x4-8c55","Severity":"moderate","Vulnerable Versions":"<3.3.8","Tree Versions":["2.1.11"],"Dependents":["json-server@npm:0.15.1"]}}
From cb24513a707784c52da35dacd5bc8758dfc67410 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Tue, 26 Aug 2025 12:27:20 +0100
Subject: [PATCH 20/21] version updated
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 27e6588edc..61171ec7f9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.38-exui-2761-rc1",
+ "version": "7.2.23-exui-2761-rc3",
"engines": {
"node": ">=18.19.0"
},
From bfaea77d61095aba41eb66ce82c91f563b679cc7 Mon Sep 17 00:00:00 2001
From: RiteshHMCTS
Date: Fri, 19 Sep 2025 16:14:28 +0100
Subject: [PATCH 21/21] fir for markdown link event
---
package.json | 2 +-
projects/ccd-case-ui-toolkit/package.json | 2 +-
.../case-full-access-view.component.spec.ts | 17 +-
.../case-full-access-view.component.ts | 15 ++
.../services/event-trigger.resolver.spec.ts | 173 ++++++++++++++++--
.../services/event-trigger.resolver.ts | 42 ++++-
6 files changed, 233 insertions(+), 18 deletions(-)
diff --git a/package.json b/package.json
index 09ee35aa89..a3fa101040 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
- "version": "7.2.43-exui-2761-rc1",
+ "version": "7.2.43-exui-2761-rc2",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json
index 90d53ff959..310401be9e 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.2.43-exui-2761-rc1",
+ "version": "7.2.43-exui-2761-rc2",
"engines": {
"node": ">=18.19.0"
},
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
index 74ce54b879..f61a4a26ff 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts
@@ -739,7 +739,7 @@ describe('CaseFullAccessViewComponent', () => {
fixture.detectChanges();
}));
-it('should set case view tab based on navigation end event', () => {
+ it('should set case view tab based on navigation end event', () => {
// Mock tabGroup._tabs with some dummy values for testing
component.tabGroup = { _tabs: [{ textLabel: 'Tab1' }, { textLabel: 'Tab2' }] } as any;
@@ -767,6 +767,21 @@ it('should set case view tab based on navigation end event', () => {
});
})
+ it('should call setCaseInfo', () => {
+ spyOn(component, 'setCaseInfo');
+ component.ngOnInit();
+ expect((component as any).setCaseInfo).toHaveBeenCalled();
+ });
+
+ it('should call setCaseInfo and update sessionStorage if caseId differs', () => {
+ sessionStorageMockService.getItem.and.returnValue(JSON.stringify({ caseId: 'old' }));
+ component.caseDetails.case_id = 'new';
+ component.caseDetails.case_type.jurisdiction.id = 'jid';
+ component.caseDetails.case_type.id = 'ctid';
+ component['setCaseInfo']();
+ expect(sessionStorageMockService.setItem).toHaveBeenCalled();
+ });
+
it('should call reset for linkedCaseService and caseFlagStateService oninit', () => {
const linkedCasesService = TestBed.inject(LinkedCasesService);
const caseFlagStateService = TestBed.inject(CaseFlagStateService);
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
index 3c2c8f6632..525e3fb257 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts
@@ -136,6 +136,8 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
this.checkRouteAndSetCaseViewTab();
+ this.setCaseInfo();
+
// Check for active Case Flags
this.activeCaseFlags = this.hasActiveCaseFlags();
this.linkedCasesService.resetLinkedCaseData();
@@ -150,6 +152,19 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
}
}
+ private setCaseInfo(): void {
+ const caseInfo = JSON.parse(this.sessionStorageService.getItem('caseInfo') || '{}');
+ console.log('Case Info from session storage: ', caseInfo);
+ if (caseInfo?.caseId !== this.caseDetails.case_id) {
+ const newCaseInfo = {
+ caseId: this.caseDetails.case_id,
+ jurisdiction: this.caseDetails.case_type.jurisdiction.id,
+ caseType: this.caseDetails.case_type.id
+ };
+ this.sessionStorageService.setItem('caseInfo', JSON.stringify(newCaseInfo));
+ }
+ }
+
public isPrintEnabled(): boolean {
return this.caseDetails.case_type.printEnabled;
}
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.spec.ts
index 9335320973..4b370ae32d 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.spec.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.spec.ts
@@ -4,7 +4,7 @@ import { AbstractAppConfig } from '../../../../app.config';
import { CaseEventTrigger, HttpError, Profile } from '../../../domain';
import { createAProfile } from '../../../domain/profile/profile.test.fixture';
import { createCaseEventTrigger } from '../../../fixture';
-import { ErrorNotifierService, HttpService, LoadingService, ProfileNotifier, ProfileService } from '../../../services';
+import { ErrorNotifierService, HttpService, LoadingService, ProfileNotifier, ProfileService, SessionStorageService } from '../../../services';
import { CaseResolver } from './case.resolver';
import { EventTriggerResolver } from './event-trigger.resolver';
@@ -32,6 +32,7 @@ describe('EventTriggerResolver', () => {
let alertService: any;
let orderService: any;
let loadingService: any;
+ let sessionStorageService: any;
let route: any;
@@ -79,6 +80,7 @@ describe('EventTriggerResolver', () => {
profileService = createSpyObj('profileService', ['get']);
profileNotifier = new ProfileNotifier();
errorNotifier = new ErrorNotifierService();
+ sessionStorageService = createSpyObj('sessionStorageService', ['getItem']);
router = createSpyObj('router', ['navigate']);
@@ -88,7 +90,7 @@ describe('EventTriggerResolver', () => {
httpService = createSpyObj('httpService', ['get']);
httpService.get.and.returnValue(of(MOCK_PROFILE));
- eventTriggerResolver = new EventTriggerResolver(casesService, alertService, profileService, profileNotifier, router, appConfig, errorNotifier, loadingService);
+ eventTriggerResolver = new EventTriggerResolver(casesService, alertService, profileService, profileNotifier, router, appConfig, errorNotifier, loadingService, sessionStorageService);
route = {
firstChild: {
@@ -110,8 +112,11 @@ describe('EventTriggerResolver', () => {
});
route.parent.paramMap.get.and.callFake(key => {
- // tslint:disable-next-line:switch-default
switch (key) {
+ case 'jurisdiction':
+ return 'PRIVATELAW';
+ case 'caseType':
+ return 'PRLAPPS';
case PARAM_CASE_ID:
return CASE_ID;
}
@@ -140,7 +145,7 @@ describe('EventTriggerResolver', () => {
expect(profileService.get).toHaveBeenCalledWith();
expect(casesService.getEventTrigger).toHaveBeenCalledWith(undefined, EVENT_TRIGGER_ID, CASE_ID, IGNORE_WARNING_VALUE);
expect(route.paramMap.get).toHaveBeenCalledWith(PARAM_EVENT_ID);
- expect(route.paramMap.get).toHaveBeenCalledTimes(1);
+ expect(route.paramMap.get).toHaveBeenCalledTimes(3);
expect(eventTriggerResolver['cachedEventTrigger']).toBe(EVENT_TRIGGER);
});
@@ -155,6 +160,16 @@ describe('EventTriggerResolver', () => {
paramMap: createSpyObj('paramMap', ['get']),
}
};
+ route.parent.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return 'PRIVATELAW';
+ case 'caseType':
+ return 'PRLAPPS';
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
casesService.getEventTrigger.and.returnValue(EVENT_TRIGGER_OBS);
expect(eventTriggerResolver['cachedEventTrigger']).toBeUndefined();
profileService.get.and.returnValue(PROFILE_OBS);
@@ -167,25 +182,35 @@ describe('EventTriggerResolver', () => {
expect(profileService.get).toHaveBeenCalledWith();
expect(casesService.getEventTrigger).toHaveBeenCalled();
expect(route.paramMap.get).toHaveBeenCalledWith(PARAM_EVENT_ID);
- expect(route.paramMap.get).toHaveBeenCalledTimes(1);
+ expect(route.paramMap.get).toHaveBeenCalledTimes(3);
expect(eventTriggerResolver['cachedEventTrigger']).toBe(EVENT_TRIGGER);
});
it('should return cached event trigger when route is not trigger/:eid if cache is not empty', () => {
route = {
firstChild: {
- url: ['someChild']
- },
- queryParamMap : createSpyObj('queryParamMap', ['get']),
+ url: ['someChild']
+ },
+ queryParamMap: createSpyObj('queryParamMap', ['get']),
paramMap: createSpyObj('paramMap', ['get']),
parent: {
- paramMap: createSpyObj('paramMap', ['get'])
+ paramMap: createSpyObj('paramMap', ['get'])
},
params: {
- eid: EVENT_TRIGGER_ID,
- cid: '42'
+ eid: EVENT_TRIGGER_ID,
+ cid: '42'
}
};
+ route.parent.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return 'PRIVATELAW';
+ case 'caseType':
+ return 'PRLAPPS';
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
casesService.getEventTrigger.and.returnValue(EVENT_TRIGGER_OBS);
eventTriggerResolver['cachedEventTrigger'] = EVENT_TRIGGER;
profileService.get.and.returnValue(PROFILE_OBS);
@@ -249,4 +274,130 @@ describe('EventTriggerResolver', () => {
expect(casesService.getEventTrigger).toHaveBeenCalled();
expect(eventTriggerResolver['cachedProfile']).toBe(PROFILE);
});
+
+it('should redirect and return null if jurisdiction or caseType are missing and caseInfo is incomplete', async () => {
+ route.parent.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return null;
+ case 'caseType':
+ return null;
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
+ route.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return null;
+ case 'caseType':
+ return null;
+ case PARAM_EVENT_ID:
+ return EVENT_TRIGGER_ID;
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
+ sessionStorageService.getItem.and.returnValue('{}');
+ eventTriggerResolver
+ .resolve(route)
+ .then(result => {
+ expect(result).toBeNull();
+ expect(alertService.error).toHaveBeenCalledWith({ phrase: 'Cannot determine jurisdiction and case type' });
+ expect(router.navigate).toHaveBeenCalledWith([router.url]);
+ });
+ });
+
+ it('should redirect to correct URL if jurisdiction or caseType are missing but caseInfo is present', async () => {
+ const caseInfo = {
+ jurisdiction: 'testJurisdiction',
+ caseType: 'testCaseType',
+ caseId: CASE_ID
+ };
+ route.parent.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return null;
+ case 'caseType':
+ return null;
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
+ route.paramMap.get.and.callFake(key => {
+ switch (key) {
+ case 'jurisdiction':
+ return null;
+ case 'caseType':
+ return null;
+ case PARAM_EVENT_ID:
+ return EVENT_TRIGGER_ID;
+ case PARAM_CASE_ID:
+ return CASE_ID;
+ }
+ });
+ route.queryParams = { foo: 'bar' };
+ sessionStorageService.getItem.and.returnValue(JSON.stringify(caseInfo));
+ eventTriggerResolver
+ .resolve(route)
+ .then(result => {
+ expect(result).toBeNull();
+ expect(router.navigate).toHaveBeenCalledWith([
+ '/cases/case-details',
+ caseInfo.jurisdiction,
+ caseInfo.caseType,
+ CASE_ID,
+ 'trigger',
+ EVENT_TRIGGER_ID
+ ], { queryParams: { foo: 'bar' } });
+ });
+ });
+
+ it('should reset cached event trigger', () => {
+ eventTriggerResolver['cachedEventTrigger'] = EVENT_TRIGGER;
+ eventTriggerResolver.resetCachedEventTrigger();
+ expect(eventTriggerResolver['cachedEventTrigger']).toBeNull();
+ });
+
+ it('should set ignoreWarning to false if not valid value', async () => {
+ route.queryParamMap.get.and.returnValue('invalid');
+ casesService.getEventTrigger.and.callFake((caseTypeId, eventTriggerId, cid, ignoreWarning) => {
+ expect(ignoreWarning).toBe('false');
+ return EVENT_TRIGGER_OBS;
+ });
+ profileService.get.and.returnValue(PROFILE_OBS);
+ await eventTriggerResolver.resolve(route);
+ });
+
+ it('should call profileNotifier.announceProfile with cachedProfile', async () => {
+ eventTriggerResolver['cachedProfile'] = PROFILE;
+ spyOn(profileNotifier, 'announceProfile');
+ casesService.getEventTrigger.and.returnValue(EVENT_TRIGGER_OBS);
+ await eventTriggerResolver.resolve(route);
+ expect(profileNotifier.announceProfile).toHaveBeenCalledWith(PROFILE);
+ });
+
+ it('should call profileNotifier.announceProfile after profileService.get', async () => {
+ eventTriggerResolver['cachedProfile'] = undefined;
+ spyOn(profileNotifier, 'announceProfile');
+ profileService.get.and.returnValue(of(PROFILE));
+ casesService.getEventTrigger.and.returnValue(EVENT_TRIGGER_OBS);
+ await eventTriggerResolver.resolve(route);
+ expect(profileNotifier.announceProfile).toHaveBeenCalledWith(PROFILE);
+ });
+
+ it('should handle error in getAndCacheEventTrigger and propagate error', async () => {
+ casesService.getEventTrigger.and.returnValue(throwError(ERROR));
+ profileService.get.and.returnValue(PROFILE_OBS);
+ spyOn(errorNotifier, 'announceError');
+ try {
+ await eventTriggerResolver.resolve(route);
+ fail('Should throw');
+ } catch (err) {
+ expect(alertService.setPreserveAlerts).toHaveBeenCalledWith(true);
+ expect(alertService.error).toHaveBeenCalledWith(ERROR.message);
+ expect(errorNotifier.announceError).toHaveBeenCalledWith(jasmine.objectContaining({ message: ERROR.message }));
+ expect(router.navigate).toHaveBeenCalled();
+ }
+ });
});
diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
index c6e894faf7..a6a83dbd18 100644
--- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
+++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/services/event-trigger.resolver.ts
@@ -10,7 +10,7 @@ import { ProfileService } from '../../../services/profile/profile.service';
import { CasesService } from '../../case-editor/services/cases.service';
import { AbstractAppConfig } from '../../../../app.config';
import { ErrorNotifierService } from '../../../services/error/error-notifier.service';
-import { LoadingService } from '../../../services';
+import { LoadingService, SessionStorageService } from '../../../services';
@Injectable()
export class EventTriggerResolver implements Resolve {
@@ -28,10 +28,44 @@ export class EventTriggerResolver implements Resolve {
private router: Router,
private appConfig: AbstractAppConfig,
private errorNotifier: ErrorNotifierService,
- private readonly loadingService: LoadingService
+ private readonly loadingService: LoadingService,
+ private readonly sessionStorageService: SessionStorageService,
) {}
public resolve(route: ActivatedRouteSnapshot): Promise {
+ const jurisdiction = route.parent?.paramMap.get('jurisdiction') || route.paramMap.get('jurisdiction');
+ const caseType = route.parent?.paramMap.get('caseType') || route.paramMap.get('caseType');
+ const eventTriggerId = route.paramMap.get(EventTriggerResolver.PARAM_EVENT_ID);
+ const cid = route.paramMap.get(EventTriggerResolver.PARAM_CASE_ID);
+ const query = route.queryParams;
+
+ // If jurisdiction or caseType are missing, redirect to correct URL
+ if (!jurisdiction || !caseType) {
+ const caseInfo = JSON.parse(this.sessionStorageService.getItem('caseInfo') || '{}');
+ const jurisdictionId = caseInfo?.jurisdiction;
+ const caseTypeId = caseInfo?.caseType;
+ const caseId = caseInfo?.caseId;
+ if (!jurisdictionId || !caseTypeId || !caseId || (caseId !== cid)) {
+ this.alertService.error({ phrase: 'Cannot determine jurisdiction and case type' });
+ this.router.navigate([this.router.url]);
+ return Promise.resolve(null);
+ }
+
+ this.router.navigate([
+ '/cases/case-details',
+ jurisdictionId,
+ caseTypeId,
+ cid,
+ 'trigger',
+ eventTriggerId
+ ], {
+ queryParams: {
+ ...query
+ }
+ });
+ return Promise.resolve(null);
+ }
+
if (this.isRootTriggerEventRoute(route)) {
return this.getAndCacheEventTrigger(route);
}
@@ -55,6 +89,7 @@ export class EventTriggerResolver implements Resolve {
// tslint:disable-next-line: prefer-const
let caseTypeId: string;
const jurisdiction = route.parent.paramMap.get('jurisdiction');
+ const caseType = route.parent.paramMap.get('caseType');
const eventTriggerId = route.paramMap.get(EventTriggerResolver.PARAM_EVENT_ID);
let ignoreWarning = route.queryParamMap.get(EventTriggerResolver.IGNORE_WARNING);
if (-1 === EventTriggerResolver.IGNORE_WARNING_VALUES.indexOf(ignoreWarning)) {
@@ -79,8 +114,7 @@ export class EventTriggerResolver implements Resolve {
this.alertService.setPreserveAlerts(true);
this.alertService.error(error.message);
this.errorNotifier.announceError(error);
- caseTypeId = route.parent.paramMap.get('caseType');
- this.router.navigate([`/cases/case-details/${jurisdiction}/${caseTypeId}/${cid}/tasks`]);
+ this.router.navigate([`/cases/case-details/${jurisdiction}/${caseType}/${cid}/tasks`]);
return throwError(error);
})
).toPromise();
|