From da30b5bbb9c1d64c78011e5c7e8f5c362785b353 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Wed, 30 Oct 2024 12:45:49 +0000 Subject: [PATCH 1/9] Change files in order to try and trigger sonar checks in pipeline --- .../AdminWebsite/Contracts/Requests/BookHearingRequest.cs | 2 +- .../AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs | 1 + .../AdminWebsite/Contracts/Requests/BookingSearchRequest.cs | 2 +- .../Contracts/Requests/CancelMultiDayHearingRequest.cs | 2 +- .../Contracts/Requests/EditMultiDayHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Services/UserAccountService.cs | 4 ++-- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs index 339ad812e..ca2289c33 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs @@ -5,7 +5,7 @@ namespace AdminWebsite.Contracts.Requests public class BookHearingRequest { public BookingDetailsRequest BookingDetails { get; set; } - public bool IsMultiDay { get; set; } + public bool IsMultiDay { get; set; } // Test public MultiHearingRequest MultiHearingDetails { get; set; } public string OtherInformationDetails { get; set; } } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs index 5927bd8d0..1a5df486c 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs @@ -7,6 +7,7 @@ namespace AdminWebsite.Contracts.Requests; public class BookingDetailsRequest { + // Test public DateTime ScheduledDateTime { get; set; } public int ScheduledDuration { get; set; } public string HearingVenueCode { get; set; } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs index 0571239dc..23b669ad1 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs @@ -45,7 +45,7 @@ public BookingSearchRequest() [JsonProperty("noJudge")] [Required] - public bool Nojudge { get; set; } + public bool Nojudge { get; set; } // Test [JsonProperty("noAllocated")] [Required] diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs index c26d1aed0..51b1a071f 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs @@ -5,7 +5,7 @@ public class CancelMultiDayHearingRequest /// /// When true, applies updates to future days of the multi day hearing as well /// - public bool UpdateFutureDays { get; set; } + public bool UpdateFutureDays { get; set; } // Test /// /// The reason for cancelling the video hearing diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs index a1c89d4a8..13c327656 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs @@ -16,7 +16,7 @@ public EditMultiDayHearingRequest() /// /// Duration of the hearing /// - public int ScheduledDuration { get; set; } + public int ScheduledDuration { get; set; } // Test /// /// The name of the hearing venue diff --git a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs index 9f5dfb415..080f29bc4 100644 --- a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs @@ -19,7 +19,7 @@ public EditHearingRequest() /// /// The date and time for a hearing /// - public DateTime ScheduledDateTime { get; set; } + public DateTime ScheduledDateTime { get; set; } // Test /// /// The duration of a hearing (number of minutes) diff --git a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs index 6f2d54594..034ba3703 100644 --- a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs @@ -5,7 +5,7 @@ namespace AdminWebsite.Models { public class MultiHearingRequest { - public DateTime StartDate { get; set; } + public DateTime StartDate { get; set; } // Test public DateTime EndDate { get; set; } public IList HearingDates { get; set; } diff --git a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs index 838797d3b..088d162d2 100644 --- a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs +++ b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs @@ -95,7 +95,7 @@ public UserAccountService( public async Task GetUserRoleAsync(string userName) { var user = await _userApiClient.GetUserByAdUserNameAsync(userName); - Enum.TryParse(user.UserRole, out var userRoleResult); + Enum.TryParse(user.UserRole, out var userRoleResult); // Test return new UserRole { UserRoleType = userRoleResult, CaseTypes = user.CaseType }; } @@ -222,7 +222,7 @@ private async Task CheckUsernameExistsInAdAsync(string username) try { var person = await _userApiClient.GetUserByAdUserNameAsync(username); - Enum.TryParse(person.UserRole, out var userRoleResult); + Enum.TryParse(person.UserRole, out var userRoleResult); // Test if (userRoleResult == UserRoleType.Judge || userRoleResult == UserRoleType.VhOfficer) { var e = new UserServiceException From 2631fd18eb26585c4b8b02cc34619c74d49e4915 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Wed, 30 Oct 2024 14:03:30 +0000 Subject: [PATCH 2/9] Revert "Change files in order to try and trigger sonar checks in pipeline" This reverts commit da30b5bbb9c1d64c78011e5c7e8f5c362785b353. --- .../AdminWebsite/Contracts/Requests/BookHearingRequest.cs | 2 +- .../AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs | 1 - .../AdminWebsite/Contracts/Requests/BookingSearchRequest.cs | 2 +- .../Contracts/Requests/CancelMultiDayHearingRequest.cs | 2 +- .../Contracts/Requests/EditMultiDayHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs | 2 +- AdminWebsite/AdminWebsite/Services/UserAccountService.cs | 4 ++-- 8 files changed, 8 insertions(+), 9 deletions(-) diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs index ca2289c33..339ad812e 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs @@ -5,7 +5,7 @@ namespace AdminWebsite.Contracts.Requests public class BookHearingRequest { public BookingDetailsRequest BookingDetails { get; set; } - public bool IsMultiDay { get; set; } // Test + public bool IsMultiDay { get; set; } public MultiHearingRequest MultiHearingDetails { get; set; } public string OtherInformationDetails { get; set; } } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs index 1a5df486c..5927bd8d0 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs @@ -7,7 +7,6 @@ namespace AdminWebsite.Contracts.Requests; public class BookingDetailsRequest { - // Test public DateTime ScheduledDateTime { get; set; } public int ScheduledDuration { get; set; } public string HearingVenueCode { get; set; } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs index 23b669ad1..0571239dc 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs @@ -45,7 +45,7 @@ public BookingSearchRequest() [JsonProperty("noJudge")] [Required] - public bool Nojudge { get; set; } // Test + public bool Nojudge { get; set; } [JsonProperty("noAllocated")] [Required] diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs index 51b1a071f..c26d1aed0 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs @@ -5,7 +5,7 @@ public class CancelMultiDayHearingRequest /// /// When true, applies updates to future days of the multi day hearing as well /// - public bool UpdateFutureDays { get; set; } // Test + public bool UpdateFutureDays { get; set; } /// /// The reason for cancelling the video hearing diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs index 13c327656..a1c89d4a8 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs @@ -16,7 +16,7 @@ public EditMultiDayHearingRequest() /// /// Duration of the hearing /// - public int ScheduledDuration { get; set; } // Test + public int ScheduledDuration { get; set; } /// /// The name of the hearing venue diff --git a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs index 080f29bc4..9f5dfb415 100644 --- a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs @@ -19,7 +19,7 @@ public EditHearingRequest() /// /// The date and time for a hearing /// - public DateTime ScheduledDateTime { get; set; } // Test + public DateTime ScheduledDateTime { get; set; } /// /// The duration of a hearing (number of minutes) diff --git a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs index 034ba3703..6f2d54594 100644 --- a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs @@ -5,7 +5,7 @@ namespace AdminWebsite.Models { public class MultiHearingRequest { - public DateTime StartDate { get; set; } // Test + public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public IList HearingDates { get; set; } diff --git a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs index 088d162d2..838797d3b 100644 --- a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs +++ b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs @@ -95,7 +95,7 @@ public UserAccountService( public async Task GetUserRoleAsync(string userName) { var user = await _userApiClient.GetUserByAdUserNameAsync(userName); - Enum.TryParse(user.UserRole, out var userRoleResult); // Test + Enum.TryParse(user.UserRole, out var userRoleResult); return new UserRole { UserRoleType = userRoleResult, CaseTypes = user.CaseType }; } @@ -222,7 +222,7 @@ private async Task CheckUsernameExistsInAdAsync(string username) try { var person = await _userApiClient.GetUserByAdUserNameAsync(username); - Enum.TryParse(person.UserRole, out var userRoleResult); // Test + Enum.TryParse(person.UserRole, out var userRoleResult); if (userRoleResult == UserRoleType.Judge || userRoleResult == UserRoleType.VhOfficer) { var e = new UserServiceException From 86bd154bd81f915ce3f0f7249ca28cfebd0ab1c1 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Wed, 30 Oct 2024 16:50:31 +0000 Subject: [PATCH 3/9] Fix reliability issues --- .../ClientApp/acessability_lint.js | 38 ++++++++++--------- .../app/security/reform-login.component.ts | 7 +++- .../models/allocate-hearing.model.ts | 4 +- .../Contracts/Requests/BookHearingRequest.cs | 4 ++ .../Requests/BookingDetailsRequest.cs | 12 ++++++ .../Requests/BookingSearchRequest.cs | 2 + .../Requests/CancelMultiDayHearingRequest.cs | 3 ++ .../Requests/EditMultiDayHearingRequest.cs | 4 ++ .../AdminWebsite/Models/EditHearingRequest.cs | 4 ++ .../Models/MultiHearingRequest.cs | 7 ++++ 10 files changed, 63 insertions(+), 22 deletions(-) diff --git a/AdminWebsite/AdminWebsite/ClientApp/acessability_lint.js b/AdminWebsite/AdminWebsite/ClientApp/acessability_lint.js index 8c67d4bbb..4c098c52a 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/acessability_lint.js +++ b/AdminWebsite/AdminWebsite/ClientApp/acessability_lint.js @@ -32,26 +32,28 @@ async function runPa11y(filename) { } const run = () => { - return new Promise(async (resolve, reject) => { - try { - const result = []; - const files = await getHtmlFiles(); - output(`detected ${files.length} html files to parse`); - for (let index = 0; index < files.length; index += 1) { - const lintErrors = await runPa11y(files[index]); - if (lintErrors.issues.length > 0) { - result.push({ - file: lintErrors.pageUrl, - issues: lintErrors.issues - }); + return new Promise((resolve, reject) => { + (async () => { + try { + const result = []; + const files = await getHtmlFiles(); + output(`detected ${files.length} html files to parse`); + for (let index = 0; index < files.length; index += 1) { + const lintErrors = await runPa11y(files[index]); + if (lintErrors.issues.length > 0) { + result.push({ + file: lintErrors.pageUrl, + issues: lintErrors.issues + }); + } + const doneDegree = Math.round((index / files.length) * 100); + output(`${doneDegree}% done, completed ${files[index]}`); } - const doneDegree = Math.round((index / files.length) * 100); - output(`${doneDegree}% done, completed ${files[index]}`); + resolve(result); + } catch (err) { + reject(err); } - resolve(result); - } catch (err) { - reject(err); - } + })(); }); }; diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/security/reform-login.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/security/reform-login.component.ts index e46f0dad6..17278c065 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/security/reform-login.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/security/reform-login.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { IdpProviders, SecurityService } from './services/security.service'; import { PageUrls } from '../shared/page-url.constants'; @@ -6,9 +6,12 @@ import { PageUrls } from '../shared/page-url.constants'; selector: 'app-reform-login', templateUrl: './login.component.html' }) -export class ReformLoginComponent { +export class ReformLoginComponent implements OnInit { constructor(private readonly router: Router, private readonly securityService: SecurityService) { this.securityService.currentIdpConfigId = IdpProviders.reform; + } + + ngOnInit(): void { this.router.navigate([`/${PageUrls.Login}`]); } } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/models/allocate-hearing.model.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/models/allocate-hearing.model.ts index 9e3bebf4b..9866e346e 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/models/allocate-hearing.model.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/models/allocate-hearing.model.ts @@ -84,8 +84,8 @@ export class AllocateHearingModel { } get hasPendingChanges(): boolean { - const original = this.originalState.map(h => { id: h.hearing_id, cso: h.allocated_cso }).sort(); - const current = this.hearings.map(h => { id: h.hearingId, cso: h.allocatedOfficerUsername }).sort(); + const original = this.originalState.map(h => { id: h.hearing_id, cso: h.allocated_cso }).sort((a, b) => a - b); + const current = this.hearings.map(h => { id: h.hearingId, cso: h.allocatedOfficerUsername }).sort((a, b) => a - b); const stringMatch = JSON.stringify(original) === JSON.stringify(current); return !stringMatch; diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs index 339ad812e..8719ce112 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookHearingRequest.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using AdminWebsite.Models; namespace AdminWebsite.Contracts.Requests @@ -5,7 +6,10 @@ namespace AdminWebsite.Contracts.Requests public class BookHearingRequest { public BookingDetailsRequest BookingDetails { get; set; } + + [JsonRequired] public bool IsMultiDay { get; set; } + public MultiHearingRequest MultiHearingDetails { get; set; } public string OtherInformationDetails { get; set; } } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs index 5927bd8d0..968ed8690 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingDetailsRequest.cs @@ -1,14 +1,19 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Text.Json.Serialization; using AdminWebsite.Contracts.Enums; namespace AdminWebsite.Contracts.Requests; public class BookingDetailsRequest { + [JsonRequired] public DateTime ScheduledDateTime { get; set; } + + [JsonRequired] public int ScheduledDuration { get; set; } + public string HearingVenueCode { get; set; } public string CaseTypeName { get; set; } public string CaseTypeServiceId { get; set; } @@ -18,10 +23,17 @@ public class BookingDetailsRequest public string HearingRoomName { get; set; } public string OtherInformation { get; set; } public string CreatedBy { get; set; } + + [JsonRequired] public bool AudioRecordingRequired { get; set; } + [DefaultValue(false)] + [JsonRequired] public bool IsMultiDayHearing { get; set; } + + [JsonRequired] public VideoSupplier ConferenceSupplier { get; set; } + public List Endpoints { get; set; } public List LinkedParticipants { get; set; } } \ No newline at end of file diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs index 0571239dc..87ba89e2c 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/BookingSearchRequest.cs @@ -45,10 +45,12 @@ public BookingSearchRequest() [JsonProperty("noJudge")] [Required] + [JsonRequired] public bool Nojudge { get; set; } [JsonProperty("noAllocated")] [Required] + [JsonRequired] public bool NoAllocated { get; set; } } } diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs index c26d1aed0..434255f50 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/CancelMultiDayHearingRequest.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Serialization; + namespace AdminWebsite.Contracts.Requests { public class CancelMultiDayHearingRequest @@ -5,6 +7,7 @@ public class CancelMultiDayHearingRequest /// /// When true, applies updates to future days of the multi day hearing as well /// + [JsonRequired] public bool UpdateFutureDays { get; set; } /// diff --git a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs index a1c89d4a8..d3b87034f 100644 --- a/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Contracts/Requests/EditMultiDayHearingRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; using AdminWebsite.Models; namespace AdminWebsite.Contracts.Requests @@ -16,6 +17,7 @@ public EditMultiDayHearingRequest() /// /// Duration of the hearing /// + [JsonRequired] public int ScheduledDuration { get; set; } /// @@ -46,6 +48,7 @@ public EditMultiDayHearingRequest() /// /// Gets or sets the audio recording required flag, value true is indicated that recording is required, otherwise false /// + [JsonRequired] public bool AudioRecordingRequired { get; set; } /// @@ -71,6 +74,7 @@ public EditMultiDayHearingRequest() /// /// When true, applies updates to future days of the multi day hearing as well /// + [JsonRequired] public bool UpdateFutureDays { get; set; } } } diff --git a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs index 9f5dfb415..c640195cd 100644 --- a/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/EditHearingRequest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using AdminWebsite.Contracts.Requests; namespace AdminWebsite.Models @@ -19,11 +20,13 @@ public EditHearingRequest() /// /// The date and time for a hearing /// + [JsonRequired] public DateTime ScheduledDateTime { get; set; } /// /// The duration of a hearing (number of minutes) /// + [JsonRequired] public int ScheduledDuration { get; set; } /// @@ -64,6 +67,7 @@ public EditHearingRequest() /// /// Gets or sets audio recording required flag /// + [JsonRequired] public bool AudioRecordingRequired { get; set; } /// diff --git a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs index 6f2d54594..f0199457a 100644 --- a/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs +++ b/AdminWebsite/AdminWebsite/Models/MultiHearingRequest.cs @@ -1,16 +1,23 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; namespace AdminWebsite.Models { public class MultiHearingRequest { + [JsonRequired] public DateTime StartDate { get; set; } + + [JsonRequired] public DateTime EndDate { get; set; } public IList HearingDates { get; set; } + [JsonRequired] public bool IsIndividualDates { get; set; } + + [JsonRequired] public int ScheduledDuration { get; set; } } } From 9e2abd662957e4143d4100717329a295017df34c Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 12:22:19 +0000 Subject: [PATCH 4/9] Maintainability fixes - quick wins --- .../Controllers/BookingListControllerTest.cs | 2 +- .../HearingsController/PostHearingTests.cs | 11 +- .../Services/HearingServiceTests.cs | 2 +- AdminWebsite/AdminWebsite/AdminWebsite.csproj | 1 + .../HearingInputSanitizerAttribute.cs | 11 +- .../AdminWebsite/ClientApp/package-lock.json | 288 +++++++++++------- .../AdminWebsite/ClientApp/package.json | 2 +- .../create-hearing.component.ts | 2 +- .../booking/endpoints/endpoints.component.ts | 12 +- .../hearing-schedule.component.ts | 151 ++++----- .../other-information.component.ts | 2 +- .../change-password.component.ts | 8 +- .../unallocated-hearings.component.ts | 10 +- .../src/app/services/justice-users.service.ts | 2 +- .../participant-edit-service.service.ts | 2 +- .../src/app/shared/window-scrolling.ts | 2 +- .../Configuration/FeatureToggles.cs | 2 +- .../Controllers/BookingListController.cs | 2 +- .../Controllers/HearingsController.cs | 19 +- .../Controllers/WorkAllocationController.cs | 6 +- AdminWebsite/AdminWebsite/Dockerfile | 7 +- .../HearingChangesMapper.cs | 8 +- .../ParticipantIdMapper.cs | 8 +- .../Mappers/HearingDetailsResponseMapper.cs | 4 +- .../profile.arm.json | 113 ------- .../Services/ApplicationLogger.cs | 5 +- .../Services/UserAccountService.cs | 10 +- 27 files changed, 338 insertions(+), 354 deletions(-) delete mode 100644 AdminWebsite/AdminWebsite/Properties/ServiceDependencies/vh-admin-web-demo - Web Deploy/profile.arm.json diff --git a/AdminWebsite/AdminWebsite.UnitTests/Controllers/BookingListControllerTest.cs b/AdminWebsite/AdminWebsite.UnitTests/Controllers/BookingListControllerTest.cs index 1fbd9278c..8c28003a1 100644 --- a/AdminWebsite/AdminWebsite.UnitTests/Controllers/BookingListControllerTest.cs +++ b/AdminWebsite/AdminWebsite.UnitTests/Controllers/BookingListControllerTest.cs @@ -452,7 +452,7 @@ public async Task Should_return_booking_list_when_admin_search_by_multiple_crite okResult.StatusCode.Should().Be(200); } - private List GetCaseTypesList() + private static List GetCaseTypesList() { return new List { diff --git a/AdminWebsite/AdminWebsite.UnitTests/Controllers/HearingsController/PostHearingTests.cs b/AdminWebsite/AdminWebsite.UnitTests/Controllers/HearingsController/PostHearingTests.cs index 42dfd063d..287fa1f43 100644 --- a/AdminWebsite/AdminWebsite.UnitTests/Controllers/HearingsController/PostHearingTests.cs +++ b/AdminWebsite/AdminWebsite.UnitTests/Controllers/HearingsController/PostHearingTests.cs @@ -1,21 +1,16 @@ using AdminWebsite.Models; -using AdminWebsite.Security; using AdminWebsite.Services; using AdminWebsite.UnitTests.Helper; -using FizzWare.NBuilder; using Microsoft.AspNetCore.Mvc; using System.Linq; using System.Net; using System.Threading.Tasks; -using AdminWebsite.Configuration; -using AdminWebsite.Contracts.Enums; using AdminWebsite.Contracts.Requests; using BookingsApi.Client; using Autofac.Extras.Moq; using BookingsApi.Contract.V1.Requests; +using BookingsApi.Contract.V2.Requests; using VideoApi.Contract.Responses; -using EndpointRequest = AdminWebsite.Contracts.Requests.EndpointRequest; -using LinkedParticipantRequest = AdminWebsite.Contracts.Requests.LinkedParticipantRequest; using ParticipantRequest = AdminWebsite.Contracts.Requests.ParticipantRequest; using V1 = BookingsApi.Contract.V1; @@ -69,7 +64,7 @@ public void Should_throw_BookingsApiException() BookingDetails = hearing }; - _mocker.Mock().Setup(x => x.BookNewHearingAsync(It.IsAny())) + _mocker.Mock().Setup(x => x.BookNewHearingWithCodeAsync(It.IsAny())) .Throws(ClientException.ForBookingsAPI(HttpStatusCode.InternalServerError)); var response = _controller.Post(bookingRequest); @@ -90,7 +85,7 @@ public void Should_throw_Exception() BookingDetails = hearing }; - _mocker.Mock().Setup(x => x.BookNewHearingAsync(It.IsAny())) + _mocker.Mock().Setup(x => x.BookNewHearingWithCodeAsync(It.IsAny())) .Throws(new Exception("Some internal error")); var response = _controller.Post(bookingRequest); diff --git a/AdminWebsite/AdminWebsite.UnitTests/Services/HearingServiceTests.cs b/AdminWebsite/AdminWebsite.UnitTests/Services/HearingServiceTests.cs index 8ea6db4b9..b70709cfd 100644 --- a/AdminWebsite/AdminWebsite.UnitTests/Services/HearingServiceTests.cs +++ b/AdminWebsite/AdminWebsite.UnitTests/Services/HearingServiceTests.cs @@ -116,7 +116,7 @@ public async Task Should_process_participants() && x.LinkedParticipants == linkedParticipants)), Times.Once); } - private HearingDetailsResponse InitHearing() + private static HearingDetailsResponse InitHearing() { var cases = new List { new CaseResponse { Name = "Test", Number = "123456" } }; var rep = Builder.CreateNew() diff --git a/AdminWebsite/AdminWebsite/AdminWebsite.csproj b/AdminWebsite/AdminWebsite/AdminWebsite.csproj index aa093685d..5d0b0a5b1 100644 --- a/AdminWebsite/AdminWebsite/AdminWebsite.csproj +++ b/AdminWebsite/AdminWebsite/AdminWebsite.csproj @@ -87,6 +87,7 @@ + diff --git a/AdminWebsite/AdminWebsite/Attributes/HearingInputSanitizerAttribute.cs b/AdminWebsite/AdminWebsite/Attributes/HearingInputSanitizerAttribute.cs index addf9858c..63d2c5824 100644 --- a/AdminWebsite/AdminWebsite/Attributes/HearingInputSanitizerAttribute.cs +++ b/AdminWebsite/AdminWebsite/Attributes/HearingInputSanitizerAttribute.cs @@ -7,13 +7,13 @@ namespace AdminWebsite.Attributes { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public class HearingInputSanitizerAttribute : ActionFilterAttribute + public partial class HearingInputSanitizerAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { - if (context.ActionArguments != null && context.ActionArguments.ContainsKey("request")) + if (context.ActionArguments.TryGetValue("request", out var argument)) { - switch (context.ActionArguments["request"]) + switch (argument) { case BookNewHearingRequest newHearingRequest: newHearingRequest.HearingRoomName = Sanitize(newHearingRequest.HearingRoomName); @@ -74,9 +74,12 @@ private static string Sanitize(string input) return input; } - var regex = new Regex(@"<(.*?)>", RegexOptions.Compiled); + var regex = InputRegex(); return regex.Replace(input, string.Empty); } + + [GeneratedRegex(@"<(.*?)>", RegexOptions.Compiled)] + private static partial Regex InputRegex(); } } \ No newline at end of file diff --git a/AdminWebsite/AdminWebsite/ClientApp/package-lock.json b/AdminWebsite/AdminWebsite/ClientApp/package-lock.json index 4f202ffb1..7d50f2652 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/package-lock.json +++ b/AdminWebsite/AdminWebsite/ClientApp/package-lock.json @@ -74,7 +74,7 @@ "nswag": "^13.19.0", "pa11y": "^6.2.3", "prettier": "^2.8.8", - "puppeteer": "^22.8.1", + "puppeteer": "^23.6.0", "run-script-os": "^1.1.6", "sass": "^1.32.12", "typescript": "^5.4.4", @@ -4725,19 +4725,20 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", - "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", + "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.4.0", - "semver": "7.6.0", - "tar-fs": "3.0.5", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "debug": "^4.3.6", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" @@ -4746,6 +4747,19 @@ "node": ">=18" } }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.14.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz", @@ -5045,7 +5059,8 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", @@ -6508,6 +6523,7 @@ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.1" }, @@ -6609,10 +6625,11 @@ } }, "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "dev": true + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/babel-loader": { "version": "9.1.3", @@ -6734,49 +6751,54 @@ "dev": true }, "node_modules/bare-events": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", - "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", + "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", "dev": true, + "license": "Apache-2.0", "optional": true }, "node_modules/bare-fs": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.0.tgz", - "integrity": "sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", "dev": true, + "license": "Apache-2.0", "optional": true, "dependencies": { "bare-events": "^2.0.0", "bare-path": "^2.0.0", - "bare-stream": "^1.0.0" + "bare-stream": "^2.0.0" } }, "node_modules/bare-os": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.3.0.tgz", - "integrity": "sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", "dev": true, + "license": "Apache-2.0", "optional": true }, "node_modules/bare-path": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.2.tgz", - "integrity": "sha512-o7KSt4prEphWUHa3QUwCxUI00R86VdjiuxmJK0iNVDHYPGo+HsDaVCnqCmPbf/MiW1ok8F4p3m8RTHlWk8K2ig==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", "dev": true, + "license": "Apache-2.0", "optional": true, "dependencies": { "bare-os": "^2.1.0" } }, "node_modules/bare-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-1.0.0.tgz", - "integrity": "sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.2.tgz", + "integrity": "sha512-EFZHSIBkDgSHIwj2l2QZfP4U5OcD4xFAOwhSb/vlr9PIqyGJGvB/nfClJbcnh3EY4jtPE4zsb5ztae96bVF79A==", "dev": true, + "license": "Apache-2.0", "optional": true, "dependencies": { - "streamx": "^2.16.1" + "streamx": "^2.20.0" } }, "node_modules/base64-js": { @@ -6812,6 +6834,7 @@ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -7224,14 +7247,15 @@ } }, "node_modules/chromium-bidi": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.19.tgz", - "integrity": "sha512-UA6zL77b7RYCjJkZBsZ0wlvCTD+jTjllZ8f6wdO4buevXgTZYjV+XLB9CiEa2OuuTGGTLnI7eN9I60YxuALGQg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.8.0.tgz", + "integrity": "sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug==", "dev": true, + "license": "Apache-2.0", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "10.0.0", - "zod": "3.22.4" + "zod": "3.23.8" }, "peerDependencies": { "devtools-protocol": "*" @@ -7914,6 +7938,7 @@ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 14" } @@ -7979,11 +8004,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -8072,6 +8098,7 @@ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dev": true, + "license": "MIT", "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", @@ -8125,10 +8152,11 @@ "dev": true }, "node_modules/devtools-protocol": { - "version": "0.0.1273771", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1273771.tgz", - "integrity": "sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==", - "dev": true + "version": "0.0.1354347", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1354347.tgz", + "integrity": "sha512-BlmkSqV0V84E2WnEnoPnwyix57rQxAM5SKJjf4TbYOCGLAWtz8CDH8RIaGOjPgPCXo2Mce3kxSY497OySidY3Q==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/di": { "version": "0.0.1", @@ -8728,6 +8756,7 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -8749,6 +8778,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -9524,7 +9554,8 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -10020,6 +10051,7 @@ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dev": true, + "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", @@ -10703,6 +10735,7 @@ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -10715,7 +10748,8 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { "version": "2.1.0", @@ -11555,7 +11589,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsesc": { "version": "2.5.2", @@ -12641,7 +12676,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mkdirp": { "version": "0.5.6", @@ -12679,9 +12715,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -12788,6 +12825,7 @@ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -13984,19 +14022,34 @@ "dev": true }, "node_modules/pac-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", - "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.2" + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" }, "engines": { "node": ">= 14" @@ -14007,6 +14060,7 @@ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, + "license": "MIT", "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" @@ -14629,6 +14683,7 @@ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", @@ -14648,6 +14703,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -14685,35 +14741,40 @@ } }, "node_modules/puppeteer": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.8.1.tgz", - "integrity": "sha512-CFgPSKV+iydjO/8/hJVj251Hqp2PLcIa70j6H7sYqkwM8YJ+D3CA74Ufuj+yKtvDIntQPB/nLw4EHrHPcHOPjw==", + "version": "23.6.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.6.1.tgz", + "integrity": "sha512-8+ALGQgwXd3P/tGcuSsxTPGDaOQIjcDIm04I5hpWZv/PiN5q8bQNHRUyfYrifT+flnM9aTWCP7tLEzuB6SlIgA==", "dev": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.2.3", - "cosmiconfig": "9.0.0", - "devtools-protocol": "0.0.1273771", - "puppeteer-core": "22.8.1" + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.8.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1354347", + "puppeteer-core": "23.6.1", + "typed-query-selector": "^2.12.0" }, "bin": { - "puppeteer": "lib/esm/puppeteer/node/cli.js" + "puppeteer": "lib/cjs/puppeteer/node/cli.js" }, "engines": { "node": ">=18" } }, "node_modules/puppeteer-core": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.8.1.tgz", - "integrity": "sha512-m1F6ZSTw1xrJ6xD4B+HonkSNVQmMrRMaqca/ivRcZYJ6jqzOnfEh3QgO9HpNPj6heiAZ2+4IPAU3jdZaTIDnSA==", + "version": "23.6.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.6.1.tgz", + "integrity": "sha512-DoNLAzQfGklPauEn33N4h9cM9GubJSINEn+AUMwAXwW159Y9JLk5y34Jsbv4c7kG8P0puOYWV9leu2siMZ/QpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.2.3", - "chromium-bidi": "0.5.19", - "debug": "4.3.4", - "devtools-protocol": "0.0.1273771", - "ws": "8.17.0" + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.8.0", + "debug": "^4.3.7", + "devtools-protocol": "0.0.1354347", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" }, "engines": { "node": ">=18" @@ -14766,7 +14827,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", @@ -15465,12 +15527,6 @@ "node": ">=4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -15708,6 +15764,7 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -15796,10 +15853,11 @@ } }, "node_modules/socks": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, + "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -15810,14 +15868,15 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" @@ -16028,13 +16087,15 @@ } }, "node_modules/streamx": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", - "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", "dev": true, + "license": "MIT", "dependencies": { - "fast-fifo": "^1.1.0", - "queue-tick": "^1.0.1" + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" @@ -16256,10 +16317,11 @@ } }, "node_modules/tar-fs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", - "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" @@ -16274,6 +16336,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, + "license": "MIT", "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -16490,6 +16553,13 @@ "node": "*" } }, + "node_modules/text-decoder": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.1.tgz", + "integrity": "sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -16888,6 +16958,13 @@ "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", "dev": true }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "dev": true, + "license": "MIT" + }, "node_modules/typescript": { "version": "5.4.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", @@ -17087,7 +17164,8 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -18133,10 +18211,11 @@ "dev": true }, "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -18299,10 +18378,11 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/AdminWebsite/AdminWebsite/ClientApp/package.json b/AdminWebsite/AdminWebsite/ClientApp/package.json index a5c2a9a83..5d7205005 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/package.json +++ b/AdminWebsite/AdminWebsite/ClientApp/package.json @@ -87,7 +87,7 @@ "nswag": "^13.19.0", "pa11y": "^6.2.3", "prettier": "^2.8.8", - "puppeteer": "^22.8.1", + "puppeteer": "^23.6.0", "run-script-os": "^1.1.6", "sass": "^1.32.12", "typescript": "^5.4.4", diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.ts index 1882028c1..e86461003 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.ts @@ -75,7 +75,7 @@ export class CreateHearingComponent extends BookingBaseComponent implements OnIn if (this.isExistingHearingOrParticipantsAdded()) { this.form.get('supplier').disable(); } - } else if (this.form && this.form.contains('supplier')) { + } else if (this.form?.contains('supplier')) { this.form.removeControl('supplier'); this.hearing.supplier = this.retrieveDefaultSupplier(); } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts index 149634ee1..761ecda96 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts @@ -79,14 +79,12 @@ export class EndpointsComponent extends BookingBaseComponent implements OnInit, if (this.editMode || !canEditOtherInformation) { this.logger.debug(`${this.loggerPrefix} In edit mode. Returning to summary.`); this.router.navigate([PageUrls.Summary]); + } else if (this.specialMeasureEnabled) { + this.logger.debug(`${this.loggerPrefix} Proceeding to screening.`); + this.router.navigate([PageUrls.Screening]); } else { - if (this.specialMeasureEnabled) { - this.logger.debug(`${this.loggerPrefix} Proceeding to screening.`); - this.router.navigate([PageUrls.Screening]); - } else { - this.logger.debug(`${this.loggerPrefix} Proceeding to other information.`); - this.router.navigate([PageUrls.OtherInformation]); - } + this.logger.debug(`${this.loggerPrefix} Proceeding to other information.`); + this.router.navigate([PageUrls.OtherInformation]); } } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts index 796dc6bc9..b6b96fca1 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts @@ -49,6 +49,14 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On hearingsInGroupToEdit: HearingModel[]; newDatesFormArray: FormArray; + multiDaysRange: boolean; + hearingDateParsed: string; + startTimeHour: string; + startTimeMinute: string; + endHearingDateParsed: string; + durationHour: string; + durationMinute: string; + private readonly destroyed$ = new Subject(); multiDayBookingEnhancementsEnabled: boolean; @@ -94,107 +102,112 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On } private initForm() { - let hearingDateParsed = null; - let startTimeHour = null; - let startTimeMinute = null; - let durationHour = null; - let durationMinute = null; - let room = ''; + this.initialiseHearingDetails(); + this.setUpDurationControls(); + this.buildFormGroup(); + this.subscribeToFormChanges(); + } + + private initialiseHearingDetails() { this.multiDaysHearing = null; - let endHearingDateParsed = null; + this.selectedCourtName = this.hearing.court_name; + this.selectedCourtCode = this.hearing.court_code; - let multiDaysRange = true; + this.logger.debug(`${this.loggerPrefix} Populating form with existing hearing details`, { + hearing: this.hearing?.hearing_id + }); - if (this.hearing) { - this.logger.debug(`${this.loggerPrefix} Populating form with existing hearing details`, { - hearing: this.hearing?.hearing_id - }); - if (this.hearing.hearing_venue_id === undefined) { - this.hearing.hearing_venue_id = -1; - } + if (!this.hearing) { + return; + } - if (this.hearing.scheduled_date_time) { - const date = new Date(this.hearing.scheduled_date_time); - hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); - startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); - } + this.hearing.hearing_venue_id = this.hearing.hearing_venue_id ?? -1; - if (this.hearing.end_hearing_date_time) { - const date = new Date(this.hearing.end_hearing_date_time); - endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - } + if (this.hearing.scheduled_date_time) { + this.setHearingDateTimeDetails(this.hearing.scheduled_date_time); + } - if (this.hearing.hearing_dates.length > 0) { - this.hearingDates = this.hearing.hearing_dates.map(x => new Date(x)); - multiDaysRange = false; - } + if (this.hearing.end_hearing_date_time) { + this.setEndHearingDate(this.hearing.end_hearing_date_time); + } - if (this.hearing.scheduled_duration) { - const duration = new Date(); - duration.setHours(0, 0, 0, 0); - duration.setMinutes(this.hearing.scheduled_duration); - durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); - durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); - } + if (this.hearing.hearing_dates.length > 0) { + this.hearingDates = this.hearing.hearing_dates.map(x => new Date(x)); + this.multiDaysRange = false; + } - if (this.hearing.scheduled_date_time && this.hearing.scheduled_duration && this.hearing.hearing_venue_id) { - this.hasSaved = true; - } + if (this.hearing.scheduled_duration) { + this.setDurationDetails(this.hearing.scheduled_duration); + } - if (this.hearing.court_room) { - room = this.hearing.court_room; - } + this.hasSaved = Boolean(this.hearing.scheduled_date_time && this.hearing.scheduled_duration && this.hearing.hearing_venue_id); - this.multiDaysHearing = this.hearing.isMultiDayEdit; + this.multiDaysHearing = this.hearing.isMultiDayEdit; - if (this.hearing.isMultiDayEdit && this.hearing.multiDayHearingLastDayScheduledDateTime) { - const date = new Date(this.hearing.multiDayHearingLastDayScheduledDateTime); - endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - } + if (this.hearing.isMultiDayEdit && this.hearing.multiDayHearingLastDayScheduledDateTime) { + this.setEndHearingDate(this.hearing.multiDayHearingLastDayScheduledDateTime); } + } - if (!this.showDurationControls) { - this.durationHourControl = new FormControl(durationHour); - this.durationMinuteControl = new FormControl(durationMinute); - } else { - this.durationHourControl = new FormControl(durationHour, [Validators.required, Validators.min(0), Validators.max(23)]); - this.durationMinuteControl = new FormControl(durationMinute, [Validators.required, Validators.min(0), Validators.max(59)]); - } + private setHearingDateTimeDetails(dateTime: Date) { + const date = new Date(dateTime); + this.hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); + this.startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); + this.startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); + } - this.selectedCourtName = this.hearing.court_name; - this.selectedCourtCode = this.hearing.court_code; + private setEndHearingDate(dateTime: Date) { + const date = new Date(dateTime); + this.endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); + } - this.newDatesFormArray = this.formBuilder.array([]); + private setDurationDetails(durationMinutes: number) { + const duration = new Date(); + duration.setHours(0, 0, 0, 0); + duration.setMinutes(durationMinutes); + this.durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); + this.durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); + } + private setUpDurationControls() { + const durationValidators = this.showDurationControls ? [Validators.required, Validators.min(0), Validators.max(23)] : []; + + this.durationHourControl = new FormControl(this.durationHour, durationValidators); + this.durationMinuteControl = new FormControl(this.durationMinute, durationValidators); + } + + private buildFormGroup() { + this.newDatesFormArray = this.formBuilder.array([]); this.form = this.formBuilder.group({ - hearingDate: [hearingDateParsed, [Validators.required, pastDateValidator()]], - hearingStartTimeHour: [startTimeHour, [Validators.required, Validators.min(0), Validators.max(23)]], - hearingStartTimeMinute: [startTimeMinute, [Validators.required, Validators.min(0), Validators.max(59)]], + hearingDate: [this.hearingDateParsed, [Validators.required, pastDateValidator()]], + hearingStartTimeHour: [this.startTimeHour, [Validators.required, Validators.min(0), Validators.max(23)]], + hearingStartTimeMinute: [this.startTimeMinute, [Validators.required, Validators.min(0), Validators.max(59)]], hearingDurationHour: this.durationHourControl, hearingDurationMinute: this.durationMinuteControl, courtAddress: [this.hearing.hearing_venue_id, [Validators.required, Validators.min(1)]], - courtRoom: [room, [Validators.pattern(Constants.TextInputPatternDisplayName), Validators.maxLength(255)]], + courtRoom: [ + this.hearing.court_room || '', + [Validators.pattern(Constants.TextInputPatternDisplayName), Validators.maxLength(255)] + ], multiDays: [this.multiDaysHearing], - endHearingDate: [endHearingDateParsed], - multiDaysRange: [multiDaysRange], + endHearingDate: [this.endHearingDateParsed], + multiDaysRange: [this.multiDaysRange], newDates: this.newDatesFormArray }); if (this.hearing?.isMultiDayEdit) { this.setUpNewDateControls(); } + } + private subscribeToFormChanges() { ['multiDays', 'multiDaysRange'].forEach(k => { - this.form.get(k).valueChanges.subscribe(() => { - this.multiDaysChanged(); - }); + this.form.get(k).valueChanges.subscribe(() => this.multiDaysChanged()); }); this.courtAddressControl.valueChanges.subscribe(val => { - const id = val; - if (id !== null) { - const venue = this.availableCourts.find(c => c.id === id); + const venue = this.availableCourts.find(c => c.id === val); + if (venue) { this.selectedCourtName = venue.name; this.selectedCourtCode = venue.code; } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.ts index 6ca76c0f8..061b38506 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.ts @@ -85,7 +85,7 @@ export class OtherInformationComponent extends BookingBaseComponent implements O return true; } - return this.hearing && this.hearing.audio_recording_required !== null && this.hearing.audio_recording_required !== undefined + return this.hearing?.audio_recording_required !== null && this.hearing?.audio_recording_required !== undefined ? this.hearing.audio_recording_required : true; } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/change-password/change-password.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/change-password/change-password.component.ts index f1aa8c04e..3e0c277f1 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/change-password/change-password.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/change-password/change-password.component.ts @@ -62,20 +62,20 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { this.saveSuccess = false; this.logger.debug(`${this.loggerPrefix} Attempting to reset password for user.`, { username: this.userName.value }); - this.$subcription = this.userDataService.updateUser(this.userName.value).subscribe( - () => { + this.$subcription = this.userDataService.updateUser(this.userName.value).subscribe({ + next: () => { // tslint:disable-next-line: quotemark this.popupMessage = "User's password has been changed"; this.showUpdateSuccess = true; this.logger.info(`${this.loggerPrefix} User password has been reset.`, { username: this.userName.value }); this.saveSuccess = true; }, - error => { + error: error => { this.popupMessage = 'User does not exist - please try again'; this.showUpdateSuccess = true; this.logger.error(`${this.loggerPrefix} User does not exist.`, error, { username: this.userName.value }); } - ); + }); } else { this.failedSubmission = true; } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/dashboard/unallocated-hearings/unallocated-hearings.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/dashboard/unallocated-hearings/unallocated-hearings.component.ts index a9f97713b..06a0ef0e4 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/dashboard/unallocated-hearings/unallocated-hearings.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/dashboard/unallocated-hearings/unallocated-hearings.component.ts @@ -40,13 +40,15 @@ export class UnallocatedHearingsComponent implements OnInit { } ngOnInit(): void { - this.client.getUnallocatedHearings().subscribe( - result => { + this.client.getUnallocatedHearings().subscribe({ + next: result => { this.unallocatedHearings = result; this.setRouterParameters(); }, - error => this.logger.error(`${this.loggerPrefix} Could not get unallocated hearings`, error) - ); + error: error => { + this.logger.error(`${this.loggerPrefix} Could not get unallocated hearings`, error); + } + }); } private setRouterParameters() { const format = (dt: Date) => dt.toISOString().split('T')[0]; diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/justice-users.service.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/justice-users.service.ts index 7ee59aa34..99fd6dee5 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/justice-users.service.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/justice-users.service.ts @@ -95,7 +95,7 @@ export class JusticeUsersService { return this.apiClient.getUserList(cleanQuery(term)).pipe( catchError(error => { this.logger.error(`${this.loggerPrefix} There was an unexpected error getting justice users`, new Error(error)); - return throwError(error); + return throwError(() => error); }) ); } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/participant-edit-service.service.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/participant-edit-service.service.ts index 48829f3c0..7c887ca01 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/participant-edit-service.service.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/participant-edit-service.service.ts @@ -26,7 +26,7 @@ export class ParticipantEditService { } catch (error) { this.logger.error(`Failed to find person ${contactEmail}. ${error.response}`, error); if (BookHearingException.isBookHearingException(error)) { - throw error as BookHearingException; + throw error; } return null; } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/window-scrolling.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/window-scrolling.ts index bd89e54da..c214a9ce6 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/window-scrolling.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/window-scrolling.ts @@ -6,7 +6,7 @@ export class WindowScrolling { constructor(@Inject(DOCUMENT) private readonly document: Document) {} getPosition(): number { - return window.pageYOffset; + return window.scrollY; } getWindowHeight(): number { diff --git a/AdminWebsite/AdminWebsite/Configuration/FeatureToggles.cs b/AdminWebsite/AdminWebsite/Configuration/FeatureToggles.cs index 670c4f039..3b4644a45 100644 --- a/AdminWebsite/AdminWebsite/Configuration/FeatureToggles.cs +++ b/AdminWebsite/AdminWebsite/Configuration/FeatureToggles.cs @@ -13,7 +13,7 @@ public interface IFeatureToggles public class FeatureToggles : IFeatureToggles { - private readonly ILdClient _ldClient; + private readonly LdClient _ldClient; private readonly Context _context; private const string LdUser = "vh-admin-web"; private const string Dom1EnabledToggleKey = "dom1"; diff --git a/AdminWebsite/AdminWebsite/Controllers/BookingListController.cs b/AdminWebsite/AdminWebsite/Controllers/BookingListController.cs index 6c1be340a..bfc33ed55 100644 --- a/AdminWebsite/AdminWebsite/Controllers/BookingListController.cs +++ b/AdminWebsite/AdminWebsite/Controllers/BookingListController.cs @@ -106,7 +106,7 @@ private async Task> GetCaseTypesId(IEnumerable caseTypes) { var typeIds = new List(); var types = await _bookingsApiClient.GetCaseTypesAsync(includeDeleted:true); - if (types != null && types.Any()) + if (types != null && types.Count != 0) foreach (var item in caseTypes) { var caseType = types.FirstOrDefault(s => s.Name == item); diff --git a/AdminWebsite/AdminWebsite/Controllers/HearingsController.cs b/AdminWebsite/AdminWebsite/Controllers/HearingsController.cs index d71711853..62c59ce88 100644 --- a/AdminWebsite/AdminWebsite/Controllers/HearingsController.cs +++ b/AdminWebsite/AdminWebsite/Controllers/HearingsController.cs @@ -85,7 +85,7 @@ public async Task> Post([FromBody] BookHear newBookingRequest.IsMultiDayHearing = request.IsMultiDay; try { - if (newBookingRequest.Endpoints != null && newBookingRequest.Endpoints.Any()) + if (newBookingRequest.Endpoints != null && newBookingRequest.Endpoints.Count != 0) { var endpointsWithDa = newBookingRequest.Endpoints .Where(x => !string.IsNullOrWhiteSpace(x.DefenceAdvocateContactEmail)) @@ -174,7 +174,7 @@ public async Task CloneHearing(Guid hearingId, MultiHearingReques var hearingDates = GetDatesForClonedHearings(hearingRequest); - if (!hearingDates.Any()) + if (hearingDates.Count == 0) { _logger.LogWarning("No working dates provided to clone to"); return BadRequest(); @@ -547,7 +547,7 @@ private async Task UpdateParticipantsAndEndpointsV2(Guid hearingId, List(request.NewParticipants)); @@ -590,7 +590,7 @@ private static List GetRemovedParticipantIds(List .Select(x => x.Id).ToList(); } - private static IEnumerable GetRemovedParticipants(List participants, HearingDetailsResponse originalHearing) + private static List GetRemovedParticipants(List participants, HearingDetailsResponse originalHearing) { return originalHearing.Participants.Where(p => participants.TrueForAll(rp => rp.Id != p.Id)) .Select(x => x).ToList(); @@ -640,7 +640,7 @@ private async Task UpdateJudiciaryParticipants(Guid hearingId, List jp.HearingRoleCode != JudiciaryParticipantHearingRoleCode.Judge) .ToList(); - if (johsToAdd.Any()) + if (johsToAdd.Count != 0) { await _bookingsApiClient.AddJudiciaryParticipantsToHearingAsync(hearingId, johsToAdd); } @@ -712,12 +712,12 @@ private static UpdateJudiciaryParticipantsRequest MapUpdateJudiciaryParticipants InterpreterLanguageCode = jp.InterpreterLanguageCode }; }).ToList(); - if (newJohRequest.Any()) + if (newJohRequest.Count != 0) { var johsToAdd = newJohRequest .ToList(); - if (johsToAdd.Any()) + if (johsToAdd.Count != 0) { var newParticipants = johsToAdd .Select(x => new BookingsApi.Contract.V1.Requests.JudiciaryParticipantRequest @@ -940,7 +940,7 @@ public async Task GetHearingConferenceStatus(Guid hearingId) var errorMessage = $"Failed to get the booking created status, possibly the conference was not created - hearingId: {hearingId}"; try { - _logger.LogDebug("Hearing {1} is booked. Polling for the status in BookingsApi", hearingId); + _logger.LogDebug("Hearing {HearingId} is booked. Polling for the status in BookingsApi", hearingId); var response = await GetHearing(hearingId); var participantsNeedVhAccounts = ParticipantsNeedVhAccounts(response.Participants); var accountsStillNeedCreating = participantsNeedVhAccounts.Any(x => x.ContactEmail == x.Username); @@ -1043,14 +1043,13 @@ public async Task CancelBooking(Guid hearingId, string reason) [ProducesResponseType((int) HttpStatusCode.BadRequest)] public async Task UpdateFailedBookingStatus(Guid hearingId) { - var errorMessage = $"Failed to update the failed status for a hearing - hearingId: {hearingId}"; try { await _bookingsApiClient.FailBookingAsync(hearingId); } catch (VideoApiException e) { - _logger.LogError(e, errorMessage); + _logger.LogError(e, "Failed to update the failed status for a hearing - hearingId: {HearingId}", hearingId); if (e.StatusCode == (int) HttpStatusCode.NotFound) return NotFound(); if (e.StatusCode == (int) HttpStatusCode.BadRequest) return BadRequest(e.Response); } diff --git a/AdminWebsite/AdminWebsite/Controllers/WorkAllocationController.cs b/AdminWebsite/AdminWebsite/Controllers/WorkAllocationController.cs index 818f6f1f4..77060c49a 100644 --- a/AdminWebsite/AdminWebsite/Controllers/WorkAllocationController.cs +++ b/AdminWebsite/AdminWebsite/Controllers/WorkAllocationController.cs @@ -39,7 +39,7 @@ public async Task GetUnallocatedHearings() { var unallocatedHearings = await _bookingsApiClient.GetUnallocatedHearingsAsync(); - if (unallocatedHearings == null || !unallocatedHearings.Any()) + if (unallocatedHearings == null || unallocatedHearings.Count == 0) return Ok(UnallocatedHearingsForVhoMapper.MapFrom(new List(), DateTime.Today)); return Ok(UnallocatedHearingsForVhoMapper.MapFrom(unallocatedHearings.ToList(), DateTime.Today)); @@ -59,7 +59,7 @@ public async Task GetAllocationHearings( cso: searchRequest.Cso, isUnallocated: searchRequest.IsUnallocated); - if (hearings == null || !hearings.Any()) + if (hearings == null || hearings.Count == 0) return Ok(new List()); return Ok(hearings.Select(AllocationHearingsResponseMapper.Map)); @@ -79,7 +79,7 @@ public async Task AllocateHearingsToCso(UpdateHearingAllocationTo { var hearings = await _bookingsApiClient.AllocateHearingsToCsoAsync(request); - if (hearings == null || !hearings.Any()) + if (hearings == null || hearings.Count == 0) return Ok(new List()); return Ok(hearings.Select(AllocationHearingsResponseMapper.Map).ToList()); diff --git a/AdminWebsite/AdminWebsite/Dockerfile b/AdminWebsite/AdminWebsite/Dockerfile index 9bc4c9a41..64efaede3 100644 --- a/AdminWebsite/AdminWebsite/Dockerfile +++ b/AdminWebsite/AdminWebsite/Dockerfile @@ -8,8 +8,11 @@ FROM node:18.13-alpine AS client ARG skip_client_build=false WORKDIR /app COPY AdminWebsite/ClientApp . -RUN [[ ${skip_client_build} = true ]] && echo "Skipping npm install" || npm install -RUN [[ ${skip_client_build} = true ]] && mkdir dist || npm run-script build-prod +RUN if [ "$skip_client_build" = "true" ]; then \ + echo "Skipping npm install" && mkdir dist; \ + else \ + npm install && npm run-script build-prod; \ + fi FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src diff --git a/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/HearingChangesMapper.cs b/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/HearingChangesMapper.cs index 8547cc22a..4609d27f3 100644 --- a/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/HearingChangesMapper.cs +++ b/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/HearingChangesMapper.cs @@ -153,7 +153,7 @@ private static LinkedParticipantChanges MapLinkedParticipantChanges( return linkedParticipantChanges; } - private static IEnumerable GetRemovedParticipants(List participants, HearingDetailsResponse originalHearing) + private static List GetRemovedParticipants(List participants, HearingDetailsResponse originalHearing) { return originalHearing.Participants .Where(p => participants.TrueForAll(rp => rp.Id != p.Id)) @@ -186,7 +186,7 @@ private static List MapEndpointChanges(HearingDetailsResponseV2 return endpointChanges; } - private static IEnumerable GetRemovedEndpoints(List endpoints, HearingDetailsResponse originalHearing) + private static List GetRemovedEndpoints(List endpoints, HearingDetailsResponse originalHearing) { return originalHearing.Endpoints .Where(p => endpoints.TrueForAll(rp => rp.Id != p.Id)) @@ -194,14 +194,14 @@ private static IEnumerable GetRemovedEndpoints(List GetNewJudiciaryParticipants(HearingDetailsResponseV2 hearing, EditMultiDayHearingRequest request) + private static List GetNewJudiciaryParticipants(HearingDetailsResponseV2 hearing, EditMultiDayHearingRequest request) { return request.JudiciaryParticipants .Where(rjp => !hearing.JudiciaryParticipants.Exists(jp => jp.PersonalCode == rjp.PersonalCode)) .ToList(); } - private static IEnumerable GetRemovedJudiciaryParticipants( + private static List GetRemovedJudiciaryParticipants( List judiciaryParticipants, HearingDetailsResponse originalHearing) { diff --git a/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/ParticipantIdMapper.cs b/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/ParticipantIdMapper.cs index 7d12f3dca..9246069ac 100644 --- a/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/ParticipantIdMapper.cs +++ b/AdminWebsite/AdminWebsite/Mappers/EditMultiDayHearing/ParticipantIdMapper.cs @@ -43,8 +43,8 @@ public static void AssignParticipantIdsForFutureDayHearing( private static void CreateParticipantMappings( HearingDetailsResponse multiDayHearingFutureDay, List participants, - IDictionary participantIdMappings, - IDictionary participantsNewToEditedHearingButExistOnFutureDayHearing) + Dictionary participantIdMappings, + Dictionary participantsNewToEditedHearingButExistOnFutureDayHearing) { foreach (var participant in participants) { @@ -67,8 +67,8 @@ private static void CreateParticipantMappings( private static void MapParticipantId( EditParticipantRequest participant, - IReadOnlyDictionary participantIdMappings, - IReadOnlyDictionary participantsNewToEditedHearingButExistOnFutureDayHearing) + Dictionary participantIdMappings, + Dictionary participantsNewToEditedHearingButExistOnFutureDayHearing) { if (participant.Id.HasValue) { diff --git a/AdminWebsite/AdminWebsite/Mappers/HearingDetailsResponseMapper.cs b/AdminWebsite/AdminWebsite/Mappers/HearingDetailsResponseMapper.cs index 8178f6797..f37225345 100644 --- a/AdminWebsite/AdminWebsite/Mappers/HearingDetailsResponseMapper.cs +++ b/AdminWebsite/AdminWebsite/Mappers/HearingDetailsResponseMapper.cs @@ -50,13 +50,13 @@ public static HearingDetailsResponse Map(this V2.HearingDetailsResponseV2 hearin public static HearingDetailsResponse Map(this V2.HearingDetailsResponseV2 hearingDetails, ICollection hearingsInGroup) { var response = hearingDetails.Map(); - if (hearingsInGroup == null || !hearingsInGroup.Any()) return response; + if (hearingsInGroup == null || hearingsInGroup.Count == 0) return response; var activeHearings = hearingsInGroup .Where(h => h.Status != BookingStatusV2.Cancelled && h.Status != BookingStatusV2.Failed) .ToList(); - if (activeHearings.Any()) + if (activeHearings.Count != 0) { response.MultiDayHearingLastDayScheduledDateTime = activeHearings.ScheduledDateTimeOfLastHearing(); } diff --git a/AdminWebsite/AdminWebsite/Properties/ServiceDependencies/vh-admin-web-demo - Web Deploy/profile.arm.json b/AdminWebsite/AdminWebsite/Properties/ServiceDependencies/vh-admin-web-demo - Web Deploy/profile.arm.json deleted file mode 100644 index 3870aee9b..000000000 --- a/AdminWebsite/AdminWebsite/Properties/ServiceDependencies/vh-admin-web-demo - Web Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "compute.appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "vh-admin-web-demo", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "ukwest", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "vh-admin-web-demo", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/AdminWebsite/AdminWebsite/Services/ApplicationLogger.cs b/AdminWebsite/AdminWebsite/Services/ApplicationLogger.cs index 45fa3677c..238daae36 100644 --- a/AdminWebsite/AdminWebsite/Services/ApplicationLogger.cs +++ b/AdminWebsite/AdminWebsite/Services/ApplicationLogger.cs @@ -70,10 +70,7 @@ public static void TraceWithObject(string traceCategory, string eventTitle, stri public static void TraceException(string traceCategory, string eventTitle, Exception exception, IPrincipal user, IDictionary properties) { - if (exception == null) - { - throw new ArgumentNullException(nameof(exception)); - } + ArgumentNullException.ThrowIfNull(exception); var exceptionTelemetry = new ExceptionTelemetry(exception); diff --git a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs index 838797d3b..7152b1053 100644 --- a/AdminWebsite/AdminWebsite/Services/UserAccountService.cs +++ b/AdminWebsite/AdminWebsite/Services/UserAccountService.cs @@ -95,7 +95,10 @@ public UserAccountService( public async Task GetUserRoleAsync(string userName) { var user = await _userApiClient.GetUserByAdUserNameAsync(userName); - Enum.TryParse(user.UserRole, out var userRoleResult); + if (!Enum.TryParse(user.UserRole, out var userRoleResult)) + { + throw new InvalidOperationException($"Invalid user role: {user.UserRole}"); + } return new UserRole { UserRoleType = userRoleResult, CaseTypes = user.CaseType }; } @@ -222,7 +225,10 @@ private async Task CheckUsernameExistsInAdAsync(string username) try { var person = await _userApiClient.GetUserByAdUserNameAsync(username); - Enum.TryParse(person.UserRole, out var userRoleResult); + if (!Enum.TryParse(person.UserRole, out var userRoleResult)) + { + throw new InvalidOperationException($"Invalid user role: {person.UserRole}"); + } if (userRoleResult == UserRoleType.Judge || userRoleResult == UserRoleType.VhOfficer) { var e = new UserServiceException From 3c5dfabd2eb8b200f625e3c10185b2e72152f968 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 16:41:29 +0000 Subject: [PATCH 5/9] Remaining maintainability fixes --- .../add-participant.component.spec.ts | 9 +- .../add-participant.component.ts | 17 ++-- .../assign-judge.component.spec.ts | 1 + .../booking-base/booking-base.component.ts | 8 +- .../create-hearing.component.spec.ts | 9 +- .../endpoints/endpoints.component.spec.ts | 3 +- .../booking/endpoints/endpoints.component.ts | 6 +- .../hearing-schedule.component.spec.ts | 9 +- .../other-information.component.spec.ts | 3 +- .../search-email.component.spec.ts | 9 +- .../search-email/search-email.component.ts | 12 +-- .../booking/summary/summary.component.spec.ts | 1 + .../app/booking/summary/summary.component.ts | 6 +- .../services/video-hearings.service.spec.ts | 8 +- .../app/services/video-hearings.service.ts | 24 +++--- .../case-types-menu.component.spec.ts | 4 +- .../justice-users-menu.component.spec.ts | 4 +- .../src/app/shared/menus/menu-base.ts | 11 ++- .../venues-menu/venues-menu.component.spec.ts | 4 +- .../src/app/shared/feature-flag.directive.ts | 16 ++-- .../allocate-hearings.component.html | 6 +- .../allocate-hearings.component.spec.ts | 16 ++-- .../allocate-hearings.component.ts | 86 ++++++++++++------- .../edit-work-hours.component.spec.ts | 3 +- .../vho-search/vho-search.component.spec.ts | 20 +++++ .../vho-search/vho-search.component.ts | 16 ++-- ...s-non-availability-table.component.spec.ts | 3 +- ...-hours-non-availability-table.component.ts | 2 +- .../vho-work-hours-table.component.spec.ts | 3 +- .../vho-work-hours-table.component.ts | 2 +- 30 files changed, 193 insertions(+), 128 deletions(-) diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.spec.ts index a42169c44..f502778e2 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.spec.ts @@ -261,6 +261,7 @@ videoHearingsServiceSpy = jasmine.createSpyObj([ 'getParticipantRoles', 'getCurrentRequest', 'setBookingHasChanged', + 'unsetBookingHasChanged', 'updateHearingRequest', 'cancelRequest', 'isConferenceClosed', @@ -975,18 +976,18 @@ describe('AddParticipantComponent', () => { }); describe('subcribeForSeachEmailEvents', () => { - it('should return errorAlternativeEmail & errorJohAccountNotFound as false if called with notFoundEmailEvent as false', () => { + it('should return errorAlternativeEmail & errorJohAccountNotFound as false if called with emailFoundEvent', () => { component.errorAlternativeEmail = true; component.errorJohAccountNotFound = true; component.subscribeForSearchEmailEvents(); - component.searchEmail.notFoundEmailEvent.next(false); + component.searchEmail.emailFoundEvent.next(); expect(component.errorAlternativeEmail).toBeFalsy(); expect(component.errorJohAccountNotFound).toBeFalsy(); }); it('should have called Not Found Participant if Not Found Email Event has been called', () => { spyOn(component, 'notFoundParticipant'); component.subscribeForSearchEmailEvents(); - component.searchEmail.notFoundEmailEvent.next(true); + component.searchEmail.emailNotFoundEvent.next(); expect(component.notFoundParticipant).toHaveBeenCalledTimes(1); }); }); @@ -1026,6 +1027,7 @@ describe('AddParticipantComponent edit mode', () => { 'getCurrentRequest', 'getParticipantRoles', 'setBookingHasChanged', + 'unsetBookingHasChanged', 'updateHearingRequest', 'cancelRequest', 'isConferenceClosed', @@ -1452,6 +1454,7 @@ describe('AddParticipantComponent edit mode no participants added', () => { 'getParticipantRoles', 'getCurrentRequest', 'setBookingHasChanged', + 'unsetBookingHasChanged', 'updateHearingRequest', 'cancelRequest', 'isConferenceClosed', diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.ts index 93bf40203..e29db5286 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/add-participant/add-participant.component.ts @@ -165,13 +165,12 @@ export class AddParticipantComponent extends AddParticipantBaseDirective impleme } subscribeForSearchEmailEvents() { - this.searchEmail.notFoundEmailEvent$.subscribe(notFound => { - if (notFound) { - this.notFoundParticipant(); - } else { - this.errorAlternativeEmail = false; - this.errorJohAccountNotFound = false; - } + this.searchEmail.emailFoundEvent$.subscribe(() => { + this.errorAlternativeEmail = false; + this.errorJohAccountNotFound = false; + }); + this.searchEmail.emailNotFoundEvent$.subscribe(() => { + this.notFoundParticipant(); }); } @@ -472,7 +471,7 @@ export class AddParticipantComponent extends AddParticipantBaseDirective impleme this.removeLinkedParticipant(this.selectedParticipantEmail); this.hearing = { ...this.hearing }; this.videoHearingService.updateHearingRequest(this.hearing); - this.videoHearingService.setBookingHasChanged(true); + this.videoHearingService.setBookingHasChanged(); } mapParticipant(newParticipant: ParticipantModel) { @@ -792,7 +791,7 @@ export class AddParticipantComponent extends AddParticipantBaseDirective impleme this.removeLinkedParticipant(this.selectedParticipantEmail); this.hearing = { ...this.hearing }; this.videoHearingService.updateHearingRequest(this.hearing); - this.videoHearingService.setBookingHasChanged(true); + this.videoHearingService.setBookingHasChanged(); } private addLinkedParticipant(newParticipant: ParticipantModel): void { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/assign-judge/assign-judge.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/assign-judge/assign-judge.component.spec.ts index 9ec145eb0..c5b45e7a0 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/assign-judge/assign-judge.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/assign-judge/assign-judge.component.spec.ts @@ -93,6 +93,7 @@ describe('AssignJudgeComponent', () => { 'updateHearingRequest', 'cancelRequest', 'setBookingHasChanged', + 'unsetBookingHasChanged', 'canAddUser', 'canAddJudge' ]); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts index 8a8df4d1e..12f357d56 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts @@ -32,9 +32,11 @@ export abstract class BookingBaseComponentDirective implements OnInit { this.logger.debug(`${this.loggerPrefix} On step ${this.componentName}`, { step: this.componentName, editMode: this.editMode }); this.buttonAction = this.editMode ? 'Save' : 'Next'; - this.form.valueChanges.subscribe(() => { - this.videoHearingService.setBookingHasChanged(this.form.dirty); - }); + if (this.form.dirty) { + this.videoHearingService.setBookingHasChanged(); + } else { + this.videoHearingService.unsetBookingHasChanged(); + } } navigateToSummary() { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.spec.ts index 2a9304b40..8fcf54f45 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/create-hearing/create-hearing.component.spec.ts @@ -69,7 +69,8 @@ describe('CreateHearingComponent with multiple case types', () => { 'getHearingTypes', 'getCurrentRequest', 'updateHearingRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); routerSpy = jasmine.createSpyObj('Router', ['navigate']); @@ -212,7 +213,8 @@ describe('CreateHearingComponent with single case type', () => { 'getCurrentRequest', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); routerSpy = jasmine.createSpyObj('Router', ['navigate']); bookingServiceSpy = jasmine.createSpyObj('BookingSErvice', ['isEditMode', 'resetEditMode', 'removeEditMode']); @@ -278,7 +280,8 @@ describe('CreateHearingComponent with existing request in session', () => { 'getCurrentRequest', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); routerSpy = jasmine.createSpyObj('Router', ['navigate']); bookingServiceSpy = jasmine.createSpyObj('BookingSErvice', ['isEditMode', 'resetEditMode', 'removeEditMode']); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.spec.ts index 698b83a9b..89a9c0e83 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.spec.ts @@ -81,7 +81,8 @@ describe('EndpointsComponent', () => { 'isHearingAboutToStart', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); videoHearingsServiceSpy.getCurrentRequest.and.returnValue(newHearing); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts index 761ecda96..dfd6a63e1 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/endpoints/endpoints.component.ts @@ -151,7 +151,7 @@ export class EndpointsComponent extends BookingBaseComponent implements OnInit, // If no such endpoint exists, push the new endpoint to the videoEndpoints array if (!existingEndpoint) { this.videoEndpoints.push($event); - this.videoHearingService.setBookingHasChanged(true); + this.videoHearingService.setBookingHasChanged(); } this.upsertEndpointsToBooking(); } @@ -164,14 +164,14 @@ export class EndpointsComponent extends BookingBaseComponent implements OnInit, if (index !== -1) { this.videoEndpoints[index] = $event.updated; this.videoEndpointToEdit = null; - this.videoHearingService.setBookingHasChanged(true); + this.videoHearingService.setBookingHasChanged(); } this.upsertEndpointsToBooking(); } onEndpointSelectedForDeletion(existingEndpoint: VideoAccessPointDto) { this.videoEndpoints = this.videoEndpoints.filter(endpoint => endpoint.displayName !== existingEndpoint.displayName); - this.videoHearingService.setBookingHasChanged(true); + this.videoHearingService.setBookingHasChanged(); this.upsertEndpointsToBooking(); } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.spec.ts index e99ac820d..92d2c7821 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.spec.ts @@ -87,7 +87,8 @@ describe('HearingScheduleComponent first visit', () => { 'getCurrentRequest', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); videoHearingsServiceSpy.getCurrentRequest.and.returnValue(newHearing); @@ -416,7 +417,8 @@ describe('HearingScheduleComponent returning to page', () => { 'getCurrentRequest', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); videoHearingsServiceSpy.getCurrentRequest.and.returnValue(existingRequest); @@ -580,7 +582,8 @@ describe('HearingScheduleComponent multi days hearing', () => { 'getCurrentRequest', 'updateHearingRequest', 'cancelRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); videoHearingsServiceSpy.getCurrentRequest.and.returnValue(existingRequest); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.spec.ts index dd8787ae6..65a12f6e9 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/other-information/other-information.component.spec.ts @@ -65,7 +65,8 @@ describe('OtherInformationComponent', () => { 'getCurrentRequest', 'cancelRequest', 'updateHearingRequest', - 'setBookingHasChanged' + 'setBookingHasChanged', + 'unsetBookingHasChanged' ]); beforeEach(waitForAsync(() => { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.spec.ts index 2b53d06f7..7145d65d4 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.spec.ts @@ -344,11 +344,11 @@ describe('SearchEmailComponent', () => { expect(component.notFoundParticipant).toBeFalsy(); }); it('should set notFoundParticipant to true', () => { - spyOn(component.notFoundEmailEvent, 'next'); + spyOn(component.emailNotFoundEvent, 'next'); component.noDataFound(); expect(component.isShowResult).toBeFalsy(); expect(component.notFoundParticipant).toBeTruthy(); - expect(component.notFoundEmailEvent.next).toHaveBeenCalled(); + expect(component.emailNotFoundEvent.next).toHaveBeenCalled(); }); it('should set notFoundParticipant to false if less that 3 letters input', () => { component.lessThanThreeLetters(); @@ -370,10 +370,9 @@ describe('SearchEmailComponent', () => { it('should set correct errors when too few characters', fakeAsync(() => { component.isShowResult = true; component.notFoundParticipant = true; - component.notFoundEmailEvent.next(true); + component.emailNotFoundEvent.next(); - const subscription = component.notFoundEmailEvent.subscribe(emailEvent => { - expect(emailEvent).toBe(false); + const subscription = component.emailFoundEvent.subscribe(() => { expect(component.isShowResult).toBe(false); expect(component.notFoundParticipant).toBe(false); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.ts index 301566cef..74324a729 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/search-email/search-email.component.ts @@ -29,8 +29,10 @@ export class SearchEmailComponent implements OnInit, OnDestroy { invalidPattern: string; isErrorEmailAssignedToJudge = false; isJoh = false; - notFoundEmailEvent = new Subject(); - notFoundEmailEvent$ = this.notFoundEmailEvent.asObservable(); + emailFoundEvent = new Subject(); + emailFoundEvent$ = this.emailFoundEvent.asObservable(); + emailNotFoundEvent = new Subject(); + emailNotFoundEvent$ = this.emailNotFoundEvent.asObservable(); private readonly cannotAddNewUsersRoles = [this.constants.Judge]; @Input() disabled = true; @@ -107,19 +109,19 @@ export class SearchEmailComponent implements OnInit, OnDestroy { this.isShowResult = true; this.isValidEmail = true; this.notFoundParticipant = false; - this.notFoundEmailEvent.next(false); + this.emailFoundEvent.next(); } noDataFound() { this.isShowResult = false; this.notFoundParticipant = !this.isErrorEmailAssignedToJudge; - this.notFoundEmailEvent.next(true); + this.emailNotFoundEvent.next(); } lessThanThreeLetters() { this.isShowResult = false; this.notFoundParticipant = false; - this.notFoundEmailEvent.next(false); + this.emailFoundEvent.next(); } selectItemClick(result: ParticipantModel) { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.spec.ts index 369e6ed88..08fb80aa1 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.spec.ts @@ -115,6 +115,7 @@ const videoHearingsServiceSpy: jasmine.SpyObj = jasmine.cr 'cancelRequest', 'updateHearing', 'setBookingHasChanged', + 'unsetBookingHasChanged', 'cloneMultiHearings', 'isConferenceClosed', 'isHearingAboutToStart', diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.ts index 280121e3f..b6ec257ca 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/summary/summary.component.ts @@ -215,7 +215,7 @@ export class SummaryComponent implements OnInit, OnDestroy { } this.hearingService.updateHearingRequest(this.hearing); - this.hearingService.setBookingHasChanged(true); + this.hearingService.setBookingHasChanged(); this.bookingService.removeParticipantEmail(); } @@ -424,7 +424,7 @@ export class SummaryComponent implements OnInit, OnDestroy { const noJudgePrior = this.hearing.status === BookingStatus.BookedWithoutJudge || this.hearing.status === BookingStatus.ConfirmedWithoutJudge; this.showWaitSaving = false; - this.hearingService.setBookingHasChanged(false); + this.hearingService.unsetBookingHasChanged(); this.logger.info(`${this.loggerPrefix} Updated booking. Navigating to booking details.`, { hearingId: hearingDetailsResponse.id }); @@ -539,7 +539,7 @@ export class SummaryComponent implements OnInit, OnDestroy { this.removeLinkedParticipant(this.selectedParticipantEmail); this.hearing = { ...this.hearing }; this.hearingService.updateHearingRequest(this.hearing); - this.hearingService.setBookingHasChanged(true); + this.hearingService.setBookingHasChanged(); this.bookingService.removeParticipantEmail(); } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.spec.ts index d62ef6f37..4aad66272 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.spec.ts @@ -76,9 +76,9 @@ describe('Video hearing service', () => { }); it('should not have changes if we set it to false', () => { - service.setBookingHasChanged(true); + service.setBookingHasChanged(); expect(service.hasUnsavedChanges()).toBe(true); - service.setBookingHasChanged(false); + service.unsetBookingHasChanged(); expect(service.hasUnsavedChanges()).toBe(false); }); @@ -689,9 +689,9 @@ describe('Video hearing service', () => { }); it('should not have changes if we set it to false', () => { - service.setVhoNonAvailabiltiesHaveChanged(true); + service.setVhoNonAvailabiltiesHaveChanged(); expect(service.hasUnsavedVhoNonAvailabilityChanges()).toBe(true); - service.setVhoNonAvailabiltiesHaveChanged(false); + service.unsetVhoNonAvailabiltiesHaveChanged(); expect(service.hasUnsavedVhoNonAvailabilityChanges()).toBe(false); }); }); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.ts index 596c490e7..2b99361e9 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/video-hearings.service.ts @@ -96,20 +96,20 @@ export class VideoHearingsService { return !!request; } - setBookingHasChanged(isChanged: boolean) { - if (isChanged) { - sessionStorage.setItem(this.bookingHasChangesKey, 'true'); - } else { - sessionStorage.removeItem(this.bookingHasChangesKey); - } + setBookingHasChanged() { + sessionStorage.setItem(this.bookingHasChangesKey, 'true'); } - setVhoNonAvailabiltiesHaveChanged(isChanged: boolean) { - if (isChanged) { - sessionStorage.setItem(this.vhoNonAvailabiltiesHaveChangesKey, 'true'); - } else { - sessionStorage.removeItem(this.vhoNonAvailabiltiesHaveChangesKey); - } + unsetBookingHasChanged() { + sessionStorage.removeItem(this.bookingHasChangesKey); + } + + setVhoNonAvailabiltiesHaveChanged() { + sessionStorage.setItem(this.vhoNonAvailabiltiesHaveChangesKey, 'true'); + } + + unsetVhoNonAvailabiltiesHaveChanged() { + sessionStorage.removeItem(this.vhoNonAvailabiltiesHaveChangesKey); } cancelVhoNonAvailabiltiesRequest() { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/case-types-menu/case-types-menu.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/case-types-menu/case-types-menu.component.spec.ts index f875a3f67..333bda07b 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/case-types-menu/case-types-menu.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/case-types-menu/case-types-menu.component.spec.ts @@ -50,11 +50,11 @@ describe('CaseTypesMenuComponent', () => { describe('enable', () => { it('should call base enable function, to enable this component', () => { - component.enabled(true); + component.enabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(true); }); it('should call base enable function, to disable this component', () => { - component.enabled(false); + component.disabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(false); }); }); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/justice-users-menu/justice-users-menu.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/justice-users-menu/justice-users-menu.component.spec.ts index 81b51fcbc..6d3a88ef6 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/justice-users-menu/justice-users-menu.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/justice-users-menu/justice-users-menu.component.spec.ts @@ -53,11 +53,11 @@ describe('JusticeUsersMenuComponent', () => { describe('enable', () => { it('should call base enable function, to enable this component', () => { - component.enabled(true); + component.enabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(true); }); it('should call base enable function, to disable this component', () => { - component.enabled(false); + component.disabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(false); }); }); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/menu-base.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/menu-base.ts index 73842842b..e64782f38 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/menu-base.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/menu-base.ts @@ -22,12 +22,11 @@ export abstract class MenuBase implements OnInit { abstract formConfiguration: any; @Output() selectedEmitter = new EventEmitter(); - enabled(value: boolean) { - if (value !== false) { - this.form.controls[this.formGroupName].enable(); - } else { - this.form.controls[this.formGroupName].disable(); - } + enabled() { + this.form.controls[this.formGroupName].enable(); + } + disabled() { + this.form.controls[this.formGroupName].disable(); } abstract loadItems(): void; diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/venues-menu/venues-menu.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/venues-menu/venues-menu.component.spec.ts index ad66e9d01..c07a160b9 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/venues-menu/venues-menu.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/shared/menus/venues-menu/venues-menu.component.spec.ts @@ -48,11 +48,11 @@ describe('VenuesMenuComponent', () => { describe('enable', () => { it('should call base enable function, to enable this component', () => { - component.enabled(true); + component.enabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(true); }); it('should call base enable function, to disable this component', () => { - component.enabled(false); + component.disabled(); expect(component.form.controls[component.formGroupName].enabled).toEqual(false); }); }); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/src/app/shared/feature-flag.directive.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/src/app/shared/feature-flag.directive.ts index c2a02c052..ebab27af3 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/src/app/shared/feature-flag.directive.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/src/app/shared/feature-flag.directive.ts @@ -18,12 +18,16 @@ export class FeatureFlagDirective { @Input() set appFeatureFlag(flagKey: keyof typeof FeatureFlags) { this.subscription?.unsubscribe(); - this.subscription = this.launchDarklyService.getFlag(flagKey).subscribe(flagValue => { - if (flagValue) { - this.viewContainer.createEmbeddedView(this.templateRef); - } else { - this.viewContainer.clear(); - } + this.subscription = this.launchDarklyService.getFlag(flagKey).subscribe({ + next: flagValue => (flagValue ? this.showContent() : this.hideContent()) }); } + + private showContent(): void { + this.viewContainer.createEmbeddedView(this.templateRef); + } + + private hideContent(): void { + this.viewContainer.clear(); + } } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.html b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.html index e8c51fc0c..298b53460 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.html +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.html @@ -144,7 +144,7 @@ type="checkbox" [checked]="allocationHearingViewModel.areAllChecked" aria-label="Select all hearings" - (change)="toggleAll(!allocationHearingViewModel.areAllChecked)" + (change)="toggleAll()" /> Hearing date @@ -167,8 +167,8 @@ type="checkbox" [checked]="hearing.checked" aria-label="Select hearing" - (click)="selectHearing(!hearing.checked, hearing.hearingId)" - (keydown)="selectHearing(!hearing.checked, hearing.hearingId)" + (click)="toggleSelectHearing(hearing)" + (keydown)="toggleSelectHearing(hearing)" /> {{ hearing.scheduledDateTime.toLocaleDateString('en-GB') }} diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.spec.ts index e7c71abd1..92624ff1a 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.spec.ts @@ -336,7 +336,7 @@ describe('AllocateHearingsComponent', () => { const username = 'test@cso.com'; // act - component.selectHearing(true, hearingId); + component.selectHearing(hearingId); // mimic cso selection component.onJusticeUserForAllocationSelected({ entityId: csoId, data: username, label: '' }); @@ -365,7 +365,7 @@ describe('AllocateHearingsComponent', () => { // act // first allocate all hearings - component.toggleAll(true); + component.selectAll(); fixture.detectChanges(); const postUpdateHearing = component.allocationHearingViewModel.hearings.find(x => x.hearingId === hearingId); @@ -375,14 +375,14 @@ describe('AllocateHearingsComponent', () => { expect(matchingElements.every(x => (x.nativeElement).innerText === username)).toBeTruthy(); // then uncheck one - component.selectHearing(false, hearingId); + component.deselectHearing(hearingId); fixture.detectChanges(); const postRevertedHearing = component.allocationHearingViewModel.hearings.find(x => x.hearingId === hearingId); expect(postRevertedHearing.allocatedOfficerUsername).toBe(originalUsername); // then toggle all off - component.toggleAll(false); + component.deselectAll(); fixture.detectChanges(); expect(component.allocationHearingViewModel.originalState).toEqual(testData); const revertedMatchingElements = fixture.debugElement.queryAll(By.css('[id^=cso_]')); @@ -411,7 +411,7 @@ describe('AllocateHearingsComponent', () => { allocateServiceSpy.allocateCsoToHearings.and.returnValue(of([updatedAllocation])); // act - component.selectHearing(true, hearingId); + component.selectHearing(hearingId); // mimic cso selection component.onJusticeUserForAllocationSelected({ entityId: csoId, label: '' }); @@ -449,7 +449,7 @@ describe('AllocateHearingsComponent', () => { const spy = spyOn(component, 'clearHearingUpdatedMessage'); // act - component.selectHearing(true, hearingId); + component.selectHearing(hearingId); component.onJusticeUserForAllocationSelected({ entityId: csoId, label: '' }); component.confirmAllocation(); tick(); @@ -487,7 +487,7 @@ describe('AllocateHearingsComponent', () => { const csoId = newGuid(); // act - component.selectHearing(true, hearingId); + component.selectHearing(hearingId); component.cancelAllocation(); @@ -502,7 +502,7 @@ describe('AllocateHearingsComponent', () => { const hearingId = testData[0].hearing_id; // act - component.selectHearing(true, hearingId); + component.selectHearing(hearingId); // mimic cso selection clear component.onJusticeUserForAllocationSelected(); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.ts index 495a25103..ee9228d88 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/allocate-hearings/allocate-hearings.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { AllocateHearingsService } from '../services/allocate-hearings.service'; import { AllocationHearingsResponse, JusticeUserResponse } from '../../services/clients/api-client'; import { faCircleExclamation, faHourglassStart, faTriangleExclamation, faClock } from '@fortawesome/free-solid-svg-icons'; -import { AllocateHearingModel } from './models/allocate-hearing.model'; +import { AllocateHearingItemModel, AllocateHearingModel } from './models/allocate-hearing.model'; import { Transform } from '@fortawesome/fontawesome-svg-core'; import { Constants } from 'src/app/common/constants'; import { DatePipe } from '@angular/common'; @@ -84,7 +84,11 @@ export class AllocateHearingsComponent implements OnInit { }); this.form.get('isUnallocated').valueChanges.subscribe(val => { - this.onIsAllocatedCheckboxChanged(val); + if (val) { + this.onIsAllocatedCheckboxChecked(); + } else { + this.onIsAllocatedCheckboxUnchecked(); + } }); this.selectedJusticeUserIds = this.bookingPersistService.selectedUsers; @@ -176,13 +180,13 @@ export class AllocateHearingsComponent implements OnInit { } } - onIsAllocatedCheckboxChanged(checked: boolean) { - if (checked) { - this.selectFilterCso.clear(); - this.selectFilterCso.disable(); - } else { - this.selectFilterCso.enable(); - } + onIsAllocatedCheckboxChecked() { + this.selectFilterCso.clear(); + this.selectFilterCso.disable(); + } + + onIsAllocatedCheckboxUnchecked() { + this.selectFilterCso.enable(); } onJusticeUserForAllocationSelected(selectedItem?: SelectOption) { @@ -193,7 +197,7 @@ export class AllocateHearingsComponent implements OnInit { } else { // without a selected CSO, unset selection this.clearMessage(); - this.toggleAll(false); + this.deselectAll(); } } @@ -223,7 +227,7 @@ export class AllocateHearingsComponent implements OnInit { } cancelAllocation() { - this.toggleAll(false); + this.deselectAll(); this.selectAllocateCso.clear(); this.clearMessage(); this.allocationHearingViewModel.uncheckAllHearingsAndRevert(); @@ -241,20 +245,28 @@ export class AllocateHearingsComponent implements OnInit { }); } - toggleAll(checkAll: boolean) { - if (checkAll) { - this.allocationHearingViewModel.checkAllHearings(); - const selectedCso = this.selectAllocateCso?.selected as SelectOption; - if (selectedCso) { - const csoId = selectedCso.entityId; - const csoUsername = selectedCso.data; - this.attemptToAssignCsoToSelectedHearings(csoId, csoUsername); - } + toggleAll() { + if (this.allocationHearingViewModel.areAllChecked) { + this.deselectAll(); } else { - this.allocationHearingViewModel.uncheckAllHearingsAndRevert(); + this.selectAll(); + } + } + + selectAll() { + this.allocationHearingViewModel.checkAllHearings(); + const selectedCso = this.selectAllocateCso?.selected as SelectOption; + if (selectedCso) { + const csoId = selectedCso.entityId; + const csoUsername = selectedCso.data; + this.attemptToAssignCsoToSelectedHearings(csoId, csoUsername); } } + deselectAll() { + this.allocationHearingViewModel.uncheckAllHearingsAndRevert(); + } + private updateTableWithAllocatedCso(updatedHearings: AllocationHearingsResponse[]) { this.allocationHearingViewModel.updateHearings(updatedHearings); this.allocationHearingViewModel.uncheckAllHearingsAndRevert(); @@ -262,23 +274,31 @@ export class AllocateHearingsComponent implements OnInit { this.updateMessageAndDisplay(Constants.AllocateHearings.ConfirmationMessage); } - selectHearing(checked: boolean, hearing_id: string) { - if (checked) { - this.clearHearingUpdatedMessage(); - this.allocationHearingViewModel.checkHearing(hearing_id); + toggleSelectHearing(hearing: AllocateHearingItemModel) { + if (hearing.checked) { + this.deselectHearing(hearing.hearingId); + } else { + this.selectHearing(hearing.hearingId); + } + } + + selectHearing(hearing_id: string) { + this.clearHearingUpdatedMessage(); + this.allocationHearingViewModel.checkHearing(hearing_id); - const selectedCso = this.selectAllocateCso?.selected as SelectOption; - if (selectedCso) { - const csoId = selectedCso.entityId; - const csoUsername = selectedCso.data; + const selectedCso = this.selectAllocateCso?.selected as SelectOption; + if (selectedCso) { + const csoId = selectedCso.entityId; + const csoUsername = selectedCso.data; - this.attemptToAssignCsoToSelectedHearings(csoId, csoUsername); - } - } else { - this.allocationHearingViewModel.uncheckHearingAndRevert(hearing_id); + this.attemptToAssignCsoToSelectedHearings(csoId, csoUsername); } } + deselectHearing(hearing_id: string) { + this.allocationHearingViewModel.uncheckHearingAndRevert(hearing_id); + } + getConcurrentCountText(count: number): string { return `User has ${count} concurrent ${count > 1 ? 'hearings' : 'hearing'} allocated`; } diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/edit-work-hours.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/edit-work-hours.component.spec.ts index f0b722eba..b81b62f2e 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/edit-work-hours.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/edit-work-hours.component.spec.ts @@ -31,7 +31,8 @@ describe('EditWorkHoursComponent', () => { beforeEach(async () => { videoServiceSpy = jasmine.createSpyObj('VideoHearingsService', [ 'cancelVhoNonAvailabiltiesRequest', - 'setVhoNonAvailabiltiesHaveChanged' + 'setVhoNonAvailabiltiesHaveChanged', + 'unsetVhoNonAvailabiltiesHaveChanged' ]); bHClientSpy = jasmine.createSpyObj('BHClient', ['uploadWorkHours', 'uploadNonWorkingHours', 'updateNonAvailabilityWorkHours']); bHClientSpy.uploadWorkHours.and.returnValue(of(new UploadWorkHoursResponse({ failed_usernames: [] }))); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.spec.ts index 985bd3fb7..ec5ca8839 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.spec.ts @@ -250,4 +250,24 @@ describe('VhoSearchComponent', () => { expect(component.dataChange.emit).toHaveBeenCalledTimes(0); }); }); + + describe('dataChangedBroadcast events received', () => { + beforeEach(() => { + spyOn(component, 'cancelEditing'); + spyOn(component, 'handleContinue'); + component.ngOnInit(); + }); + + it('should call cancelEditing when dataChangedBroadcast emits true', () => { + component.dataChangedBroadcast.next(true); + expect(component.cancelEditing).toHaveBeenCalled(); + expect(component.handleContinue).not.toHaveBeenCalled(); + }); + + it('should call handleContinue when dataChangedBroadcast emits false', () => { + component.dataChangedBroadcast.next(false); + expect(component.handleContinue).toHaveBeenCalled(); + expect(component.cancelEditing).not.toHaveBeenCalled(); + }); + }); }); diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.ts index 5a5408e54..046be0c5d 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-search/vho-search.component.ts @@ -46,18 +46,22 @@ export class VhoSearchComponent implements OnInit { username: ['', Validators.required], hoursType: ['', Validators.required] }); - this.dataChangedBroadcast.subscribe(x => { - if (!x) { - this.handleContinue(); - } else { - this.cancelEditing(); - } + this.dataChangedBroadcast.subscribe({ + next: (x: boolean) => (x ? this.handleDataChanged() : this.handleDataUnchanged()) }); this.service.fetchNonWorkHours$.subscribe(async refresh => { await this.search(refresh); }); } + handleDataChanged() { + this.cancelEditing(); + } + + handleDataUnchanged() { + this.handleContinue(); + } + async search(refresh: boolean = false): Promise { if (this.form.valid) { const hoursType: HoursType = this.form.controls['hoursType'].value; diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.spec.ts index 9fd1814d6..48ef9f6d4 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.spec.ts @@ -20,7 +20,8 @@ describe('VhoNonAvailabilityWorkHoursTableComponent', () => { let loggerSpy: jasmine.SpyObj; const videoServiceSpy = jasmine.createSpyObj('VideoHearingsService', [ 'cancelVhoNonAvailabiltiesRequest', - 'setVhoNonAvailabiltiesHaveChanged' + 'setVhoNonAvailabiltiesHaveChanged', + 'unsetVhoNonAvailabiltiesHaveChanged' ]); beforeEach(async () => { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.ts index 674006803..eb43f0978 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-non-availability-table/vho-work-hours-non-availability-table.component.ts @@ -179,7 +179,7 @@ export class VhoWorkHoursNonAvailabilityTableComponent implements OnInit, CanDea } registerUnsavedChanges() { - this.videoHearingsService.setVhoNonAvailabiltiesHaveChanged(true); + this.videoHearingsService.setVhoNonAvailabiltiesHaveChanged(); } validateNonWorkHour(nonWorkHour: EditVhoNonAvailabilityWorkHoursModel) { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.spec.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.spec.ts index d13a58202..944d8c53b 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.spec.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.spec.ts @@ -11,7 +11,8 @@ describe('VhoWorkHoursTableComponent', () => { let fixture: ComponentFixture; const videoServiceSpy = jasmine.createSpyObj('VideoHearingsService', [ 'cancelVhoNonAvailabiltiesRequest', - 'setVhoNonAvailabiltiesHaveChanged' + 'setVhoNonAvailabiltiesHaveChanged', + 'unsetVhoNonAvailabiltiesHaveChanged' ]); beforeEach(async () => { diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.ts index 20c391ee7..864d4c7c3 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/work-allocation/edit-work-hours/vho-work-hours-table/vho-work-hours-table.component.ts @@ -165,7 +165,7 @@ export class VhoWorkHoursTableComponent implements CanDeactiveComponent { } registerUnsavedChanges() { - this.videoHearingsService.setVhoNonAvailabiltiesHaveChanged(true); + this.videoHearingsService.setVhoNonAvailabiltiesHaveChanged(); } get checkVhoHasWorkHours(): boolean { From 3501623b89103f7094a66c2995ce23765b7a70c9 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 18:15:57 +0000 Subject: [PATCH 6/9] Schedule fixes --- .../hearing-schedule.component.ts | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts index b6b96fca1..90ab31802 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts @@ -49,13 +49,14 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On hearingsInGroupToEdit: HearingModel[]; newDatesFormArray: FormArray; - multiDaysRange: boolean; - hearingDateParsed: string; - startTimeHour: string; - startTimeMinute: string; - endHearingDateParsed: string; - durationHour: string; - durationMinute: string; + hearingDateParsed: string = null; + startTimeHour: string = null; + startTimeMinute: string = null; + durationHour: string = null; + durationMinute: string = null; + room = ''; + endHearingDateParsed: string = null; + multiDaysRange = true; private readonly destroyed$ = new Subject(); multiDayBookingEnhancementsEnabled: boolean; @@ -102,33 +103,38 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On } private initForm() { + this.multiDaysHearing = null; + this.initialiseHearingDetails(); this.setUpDurationControls(); this.buildFormGroup(); + if (this.hearing?.isMultiDayEdit) { + this.setUpNewDateControls(); + } this.subscribeToFormChanges(); } private initialiseHearingDetails() { - this.multiDaysHearing = null; - this.selectedCourtName = this.hearing.court_name; - this.selectedCourtCode = this.hearing.court_code; - + if (!this.hearing) { + return; + } this.logger.debug(`${this.loggerPrefix} Populating form with existing hearing details`, { hearing: this.hearing?.hearing_id }); - - if (!this.hearing) { - return; + if (this.hearing.hearing_venue_id === undefined) { + this.hearing.hearing_venue_id = -1; } - this.hearing.hearing_venue_id = this.hearing.hearing_venue_id ?? -1; - if (this.hearing.scheduled_date_time) { - this.setHearingDateTimeDetails(this.hearing.scheduled_date_time); + const date = new Date(this.hearing.scheduled_date_time); + this.hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); + this.startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); + this.startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); } if (this.hearing.end_hearing_date_time) { - this.setEndHearingDate(this.hearing.end_hearing_date_time); + const date = new Date(this.hearing.end_hearing_date_time); + this.endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); } if (this.hearing.hearing_dates.length > 0) { @@ -137,47 +143,45 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On } if (this.hearing.scheduled_duration) { - this.setDurationDetails(this.hearing.scheduled_duration); + const duration = new Date(); + duration.setHours(0, 0, 0, 0); + duration.setMinutes(this.hearing.scheduled_duration); + this.durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); + this.durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); + } + + if (this.hearing.scheduled_date_time && this.hearing.scheduled_duration && this.hearing.hearing_venue_id) { + this.hasSaved = true; } - this.hasSaved = Boolean(this.hearing.scheduled_date_time && this.hearing.scheduled_duration && this.hearing.hearing_venue_id); + if (this.hearing.court_room) { + this.room = this.hearing.court_room; + } this.multiDaysHearing = this.hearing.isMultiDayEdit; if (this.hearing.isMultiDayEdit && this.hearing.multiDayHearingLastDayScheduledDateTime) { - this.setEndHearingDate(this.hearing.multiDayHearingLastDayScheduledDateTime); + const date = new Date(this.hearing.multiDayHearingLastDayScheduledDateTime); + this.endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); } - } - - private setHearingDateTimeDetails(dateTime: Date) { - const date = new Date(dateTime); - this.hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - this.startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); - this.startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); - } - private setEndHearingDate(dateTime: Date) { - const date = new Date(dateTime); - this.endHearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - } - - private setDurationDetails(durationMinutes: number) { - const duration = new Date(); - duration.setHours(0, 0, 0, 0); - duration.setMinutes(durationMinutes); - this.durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); - this.durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); + this.selectedCourtName = this.hearing.court_name; + this.selectedCourtCode = this.hearing.court_code; } private setUpDurationControls() { - const durationValidators = this.showDurationControls ? [Validators.required, Validators.min(0), Validators.max(23)] : []; - - this.durationHourControl = new FormControl(this.durationHour, durationValidators); - this.durationMinuteControl = new FormControl(this.durationMinute, durationValidators); + if (!this.showDurationControls) { + this.durationHourControl = new FormControl(this.durationHour); + this.durationMinuteControl = new FormControl(this.durationMinute); + } else { + this.durationHourControl = new FormControl(this.durationHour, [Validators.required, Validators.min(0), Validators.max(23)]); + this.durationMinuteControl = new FormControl(this.durationMinute, [Validators.required, Validators.min(0), Validators.max(59)]); + } } private buildFormGroup() { this.newDatesFormArray = this.formBuilder.array([]); + this.form = this.formBuilder.group({ hearingDate: [this.hearingDateParsed, [Validators.required, pastDateValidator()]], hearingStartTimeHour: [this.startTimeHour, [Validators.required, Validators.min(0), Validators.max(23)]], @@ -185,29 +189,25 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On hearingDurationHour: this.durationHourControl, hearingDurationMinute: this.durationMinuteControl, courtAddress: [this.hearing.hearing_venue_id, [Validators.required, Validators.min(1)]], - courtRoom: [ - this.hearing.court_room || '', - [Validators.pattern(Constants.TextInputPatternDisplayName), Validators.maxLength(255)] - ], + courtRoom: [this.room, [Validators.pattern(Constants.TextInputPatternDisplayName), Validators.maxLength(255)]], multiDays: [this.multiDaysHearing], endHearingDate: [this.endHearingDateParsed], multiDaysRange: [this.multiDaysRange], newDates: this.newDatesFormArray }); - - if (this.hearing?.isMultiDayEdit) { - this.setUpNewDateControls(); - } } private subscribeToFormChanges() { ['multiDays', 'multiDaysRange'].forEach(k => { - this.form.get(k).valueChanges.subscribe(() => this.multiDaysChanged()); + this.form.get(k).valueChanges.subscribe(() => { + this.multiDaysChanged(); + }); }); this.courtAddressControl.valueChanges.subscribe(val => { - const venue = this.availableCourts.find(c => c.id === val); - if (venue) { + const id = val; + if (id !== null) { + const venue = this.availableCourts.find(c => c.id === id); this.selectedCourtName = venue.name; this.selectedCourtCode = venue.code; } From 2ad97779d9ca154314f95f2efe6049a53b319f2e Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 18:59:36 +0000 Subject: [PATCH 7/9] Booking list fixes --- .../ClientApp/src/app/services/bookings-list.service.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/bookings-list.service.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/bookings-list.service.ts index 18c342500..5d90f3df4 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/services/bookings-list.service.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/services/bookings-list.service.ts @@ -33,6 +33,12 @@ export class BookingsListService { noJudge?: boolean, noAllocated?: boolean ): Observable { + if (noJudge == null || undefined) { + noJudge = false; + } + if (noAllocated == null || undefined) { + noAllocated = false; + } const searchRequest = { cursor, limit, From aa9609420d20d12c74b17876c643ee3d7250ee38 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 19:15:10 +0000 Subject: [PATCH 8/9] Move into subscribe --- .../booking/booking-base/booking-base.component.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts index 12f357d56..e5188a216 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/booking-base/booking-base.component.ts @@ -32,11 +32,13 @@ export abstract class BookingBaseComponentDirective implements OnInit { this.logger.debug(`${this.loggerPrefix} On step ${this.componentName}`, { step: this.componentName, editMode: this.editMode }); this.buttonAction = this.editMode ? 'Save' : 'Next'; - if (this.form.dirty) { - this.videoHearingService.setBookingHasChanged(); - } else { - this.videoHearingService.unsetBookingHasChanged(); - } + this.form.valueChanges.subscribe(() => { + if (this.form.dirty) { + this.videoHearingService.setBookingHasChanged(); + } else { + this.videoHearingService.unsetBookingHasChanged(); + } + }); } navigateToSummary() { From 6315dcdaab0ca38bfda2ae4807cd03d54624863a Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 31 Oct 2024 19:35:44 +0000 Subject: [PATCH 9/9] Reduce complexity --- .../hearing-schedule.component.ts | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts index 90ab31802..3141ea5a5 100644 --- a/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts +++ b/AdminWebsite/AdminWebsite/ClientApp/src/app/booking/hearing-schedule/hearing-schedule.component.ts @@ -125,12 +125,7 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On this.hearing.hearing_venue_id = -1; } - if (this.hearing.scheduled_date_time) { - const date = new Date(this.hearing.scheduled_date_time); - this.hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); - this.startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); - this.startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); - } + this.setStartTime(); if (this.hearing.end_hearing_date_time) { const date = new Date(this.hearing.end_hearing_date_time); @@ -142,13 +137,7 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On this.multiDaysRange = false; } - if (this.hearing.scheduled_duration) { - const duration = new Date(); - duration.setHours(0, 0, 0, 0); - duration.setMinutes(this.hearing.scheduled_duration); - this.durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); - this.durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); - } + this.setDuration(); if (this.hearing.scheduled_date_time && this.hearing.scheduled_duration && this.hearing.hearing_venue_id) { this.hasSaved = true; @@ -169,6 +158,27 @@ export class HearingScheduleComponent extends BookingBaseComponent implements On this.selectedCourtCode = this.hearing.court_code; } + private setStartTime() { + if (!this.hearing.scheduled_date_time) { + return; + } + const date = new Date(this.hearing.scheduled_date_time); + this.hearingDateParsed = this.datePipe.transform(date, 'yyyy-MM-dd'); + this.startTimeHour = (date.getHours() < 10 ? '0' : '') + date.getHours(); + this.startTimeMinute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); + } + + private setDuration() { + if (!this.hearing.scheduled_duration) { + return; + } + const duration = new Date(); + duration.setHours(0, 0, 0, 0); + duration.setMinutes(this.hearing.scheduled_duration); + this.durationHour = (duration.getHours() < 10 ? '0' : '') + duration.getHours(); + this.durationMinute = (duration.getMinutes() < 10 ? '0' : '') + duration.getMinutes(); + } + private setUpDurationControls() { if (!this.showDurationControls) { this.durationHourControl = new FormControl(this.durationHour);