diff --git a/applications/Unity.AutoUI/cypress/selectors/registry.json b/applications/Unity.AutoUI/cypress/selectors/registry.json index e5b7a6290a..f62d5784e3 100644 --- a/applications/Unity.AutoUI/cypress/selectors/registry.json +++ b/applications/Unity.AutoUI/cypress/selectors/registry.json @@ -1,7 +1,7 @@ { "schemaVersion": 2, "mode": "report-only", - "generatedAt": "2026-10-16T22:08:25.092Z", + "generatedAt": "2026-10-16T23:24:46.471Z", "summary": { "total": 364, "matched": 150, @@ -1790,10 +1790,10 @@ "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260917183045_AddTemplateTypes.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260928201123_LimitEmailTemplateNameLength.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261015221241_AddScheduledNotificationTemplateConstraint.Designer.cs", + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261016214750_AddApplicationFormListVisibility.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResultAttachments/AssessmentResultAttachments.js" + "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js" ] }, { @@ -1853,6 +1853,7 @@ "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260917183045_AddTemplateTypes.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260928201123_LimitEmailTemplateNameLength.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261015221241_AddScheduledNotificationTemplateConstraint.Designer.cs", + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261016214750_AddApplicationFormListVisibility.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/AssigneeSelection/AssigneeSelectionModal.cshtml" ] @@ -3258,10 +3259,10 @@ "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260917183045_AddTemplateTypes.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260928201123_LimitEmailTemplateNameLength.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261015221241_AddScheduledNotificationTemplateConstraint.Designer.cs", + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261016214750_AddApplicationFormListVisibility.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicantHistory/ReportsHistoryModalViewModel.cs", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantHistory/Default.js", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/CustomFields/Default.js" + "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantHistory/Default.js" ] }, { @@ -3541,9 +3542,9 @@ "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260917183045_AddTemplateTypes.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260928201123_LimitEmailTemplateNameLength.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261015221241_AddScheduledNotificationTemplateConstraint.Designer.cs", + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261016214750_AddApplicationFormListVisibility.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.js" + "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js" ] }, { @@ -3874,8 +3875,8 @@ "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260917183045_AddTemplateTypes.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260928201123_LimitEmailTemplateNameLength.Designer.cs", "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261015221241_AddScheduledNotificationTemplateConstraint.Designer.cs", - "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs", - "applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js" + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20261016214750_AddApplicationFormListVisibility.Designer.cs", + "applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs" ] }, { diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfiguration/ReportingConfigurationController.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfiguration/ReportingConfigurationController.cs index 7d8536a7b0..fe5d95eba4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfiguration/ReportingConfigurationController.cs +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfiguration/ReportingConfigurationController.cs @@ -6,6 +6,7 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using Unity.Reporting.Configuration; +using Unity.GrantManager.ApplicationForms; using Unity.Reporting.Permissions; using Volo.Abp.AspNetCore.Mvc; @@ -21,7 +22,10 @@ namespace Unity.Reporting.Web.Views.Shared.Components.ReportingConfiguration [ApiExplorerSettings(IgnoreApi = true)] [Route("ReportingConfiguration")] [Authorize(ReportingPermissions.Configuration.Default)] - public class ReportingConfigurationController(IReportMappingService reportMappingService) : AbpController + public class ReportingConfigurationController( + IReportMappingService reportMappingService, + IApplicationFormAppService applicationFormAppService, + IApplicationFormVersionAppService applicationFormVersionAppService) : AbpController { /// /// Handles AJAX requests to refresh the ReportingConfiguration view component with updated parameter values. @@ -34,7 +38,7 @@ public class ReportingConfigurationController(IReportMappingService reportMappin /// A ViewComponent result containing the updated configuration interface or default component on validation failure. [HttpGet] [Route("Refresh")] - public IActionResult Refresh(Guid formId, Guid? selectedVersionId = null, string? provider = null) + public async Task Refresh(Guid formId, Guid? selectedVersionId = null, string? provider = null) { if (!ModelState.IsValid) { @@ -42,6 +46,21 @@ public IActionResult Refresh(Guid formId, Guid? selectedVersionId = null, string return ViewComponent(typeof(ReportingConfigurationViewComponent)); } + var form = await applicationFormAppService.GetAsync(formId); + if (form.IsHiddenFromList) + { + return NotFound(); + } + if (selectedVersionId.HasValue + && (provider == null || provider == Providers.FormVersion || provider == Providers.Worksheet)) + { + var version = await applicationFormVersionAppService.GetAsync(selectedVersionId.Value); + if (version.ApplicationFormId != formId) + { + return NotFound(); + } + } + return ViewComponent(typeof(ReportingConfigurationViewComponent), new { formId, selectedVersionId, provider }); } diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfigurationViewStatus/ReportingConfigurationViewStatusController.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfigurationViewStatus/ReportingConfigurationViewStatusController.cs index 160601b5d2..76295b5db7 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfigurationViewStatus/ReportingConfigurationViewStatusController.cs +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Views/Shared/Components/ReportingConfigurationViewStatus/ReportingConfigurationViewStatusController.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Unity.Reporting.Configuration; +using Unity.GrantManager.ApplicationForms; using Volo.Abp.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -20,7 +21,10 @@ namespace Unity.Reporting.Web.Views.Shared.Components.ReportingConfigurationView /// The service for managing report mappings and view operations. [ApiExplorerSettings(IgnoreApi = true)] [Route("ApplicationForms/ReportingConfigurationViewStatus")] - public class ReportingConfigurationViewStatusController(IReportMappingService reportMappingService) : AbpController + public class ReportingConfigurationViewStatusController( + IReportMappingService reportMappingService, + IApplicationFormAppService applicationFormAppService, + IApplicationFormVersionAppService applicationFormVersionAppService) : AbpController { /// /// Handles AJAX requests to refresh the ReportingConfigurationViewStatus view component with updated status information. @@ -32,7 +36,7 @@ public class ReportingConfigurationViewStatusController(IReportMappingService re /// A ViewComponent result containing the updated status display or a default component on validation failure. [HttpGet] [Route("Refresh")] - public IActionResult Refresh(Guid versionId, string provider) + public async Task Refresh(Guid versionId, string provider) { if (!ModelState.IsValid) { @@ -40,6 +44,26 @@ public IActionResult Refresh(Guid versionId, string provider) return ViewComponent("ReportingConfigurationViewStatus"); } + Guid? formId = null; + if (provider == Providers.FormVersionConsolidated || provider == Providers.WorksheetConsolidated) + { + formId = versionId; + } + else if (provider == Providers.FormVersion || provider == Providers.Worksheet) + { + var version = await applicationFormVersionAppService.GetAsync(versionId); + formId = version.ApplicationFormId; + } + + if (formId.HasValue) + { + var form = await applicationFormAppService.GetAsync(formId.Value); + if (form.IsHiddenFromList) + { + return NotFound(); + } + } + return ViewComponent("ReportingConfigurationViewStatus", new { versionId, provider }); } diff --git a/applications/Unity.GrantManager/sonar-project.properties b/applications/Unity.GrantManager/sonar-project.properties index 4cb6670b8c..10ee7aac56 100644 --- a/applications/Unity.GrantManager/sonar-project.properties +++ b/applications/Unity.GrantManager/sonar-project.properties @@ -8,9 +8,11 @@ sonar.projectName=Unity sonar.projectVersion=${BUILD_VERSION} sonar.projectDescription=Grant management application for the Province of British Columbia -# Source code settings +# Source and test code settings. Module test projects are test code too. sonar.sources=src,modules -sonar.tests=test +sonar.tests=test,modules +# Test inclusions also exclude these paths from the main source scope. +sonar.test.inclusions=test/**,modules/**/test/** # Quality gate settings sonar.qualitygate.wait=true @@ -63,4 +65,4 @@ sonar.coverage.exclusions=**/* sonar.cpd.exclusions=**/*.aspx,**/*.aspx.designer.cs,**/*.cshtml,**/*.html,**/*.js,**/* # SCM settings -sonar.scm.provider=git \ No newline at end of file +sonar.scm.provider=git diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs index 07f08b9859..609c2b83a4 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs @@ -7,6 +7,7 @@ namespace Unity.GrantManager.ApplicationForms { public class ApplicationFormDto : EntityDto { + public bool IsHiddenFromList { get; set; } public Guid IntakeId { get; set; } public string? ApplicationFormName { get; set; } = string.Empty; public string? ApplicationFormDescription { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantManagerPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantManagerPermissionDefinitionProvider.cs index 53d584174d..4217039459 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantManagerPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantManagerPermissionDefinitionProvider.cs @@ -18,7 +18,8 @@ public override void Define(IPermissionDefinitionContext context) grantManagerPermissionsGroup.AddPermission(GrantManagerPermissions.Intakes.Default, L("Permission:GrantManagerManagement.Intakes.Default")); - grantManagerPermissionsGroup.AddPermission(GrantManagerPermissions.ApplicationForms.Default, L("Permission:GrantManagerManagement.ApplicationForms.Default")); + var applicationFormPermissions = grantManagerPermissionsGroup.AddPermission(GrantManagerPermissions.ApplicationForms.Default, L("Permission:GrantManagerManagement.ApplicationForms.Default")); + applicationFormPermissions.AddChild(GrantManagerPermissions.ApplicationForms.Delete, L("Permission:GrantManagerManagement.ApplicationForms.Delete")); var notificationSchedulerPermissions = grantManagerPermissionsGroup.AddPermission(GrantManagerPermissions.NotificationScheduler.Default, L("Permission:GrantManagerManagement.NotificationScheduler.Default")); notificationSchedulerPermissions.AddChild(GrantManagerPermissions.NotificationScheduler.ManageSchedules, L("Permission:GrantManagerManagement.NotificationScheduler.ManageSchedules")); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 0081f20ae6..47376f2db3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -15,6 +15,7 @@ using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; using Volo.Abp.Security.Encryption; @@ -54,7 +55,7 @@ public ApplicationFormAppService( _applicationFormSubmissionRepository = applicationFormSubmissionRepository; _formsApiService = formsApiService; - DeletePolicyName = GrantManagerPermissions.ApplicationForms.Default; + DeletePolicyName = GrantManagerPermissions.ApplicationForms.Delete; } [Authorize(GrantManagerPermissions.ApplicationForms.Default)] @@ -68,7 +69,7 @@ public override async Task CreateAsync(CreateUpdateApplicati [Authorize(GrantManagerPermissions.ApplicationForms.Default)] public override async Task UpdateAsync(Guid id, CreateUpdateApplicationFormDto input) { - var existingForm = await Repository.GetAsync(id); + var existingForm = await GetFormForManagementAsync(id); input.ApiKey = _stringEncryptionService.Encrypt(input.ApiKey); bool hasFormGuidChanged = existingForm.ChefsApplicationFormGuid != input.ChefsApplicationFormGuid; @@ -168,7 +169,7 @@ public async Task> GetVersionsAsync(Guid id) [Authorize(GrantManagerPermissions.ApplicationForms.Default)] public async Task SaveApplicationFormScoresheet(FormScoresheetDto dto) { - var appForm = await Repository.GetAsync(dto.ApplicationFormId); + var appForm = await GetFormForManagementAsync(dto.ApplicationFormId); appForm.ScoresheetId = dto.ScoresheetId; await Repository.UpdateAsync(appForm); } @@ -176,7 +177,7 @@ public async Task SaveApplicationFormScoresheet(FormScoresheetDto dto) [Authorize(GrantManagerPermissions.ApplicationForms.Default)] public async Task PatchOtherConfig(Guid id, OtherConfigDto config) { - var form = await Repository.GetAsync(id); + var form = await GetFormForManagementAsync(id); form.IsDirectApproval = config.IsDirectApproval; form.ElectoralDistrictAddressType = config.ElectoralDistrictAddressType; form.Prefix = config.Prefix; @@ -187,7 +188,7 @@ public async Task PatchOtherConfig(Guid id, OtherConfigDto config) [Authorize(GrantManagerPermissions.ApplicationForms.Default)] public async Task PatchAiConfig(Guid id, AIConfigDto config) { - var form = await Repository.GetAsync(id); + var form = await GetFormForManagementAsync(id); form.AutomaticallyGenerateAIAnalysis = config.AutomaticallyGenerateAIAnalysis; form.ManuallyInitiateAIAnalysis = config.ManuallyInitiateAIAnalysis; await Repository.UpdateAsync(form); @@ -198,7 +199,7 @@ public async Task PatchExternalLinksConfigAsync(Guid id, ExternalLinksConfigDto { ArgumentNullException.ThrowIfNull(config); - var form = await Repository.GetAsync(id); + var form = await GetFormForManagementAsync(id); var renewalLink = config.RenewalLink is null ? null : MapToExternalLink(config.RenewalLink); var relatedLinks = (config.RelatedLinks ?? []).Select(MapToExternalLink).ToList(); @@ -242,7 +243,11 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) { ArgumentNullException.ThrowIfNull(dto); - var appForm = await Repository.GetAsync(dto.ApplicationFormId); + var appForm = await GetFormForManagementAsync(dto.ApplicationFormId); + var parentForm = dto.ParentFormId.HasValue + ? await Repository.FindAsync(dto.ParentFormId.Value) + : null; + parentForm?.EnsureCanBeAssignedAsParent(appForm.ParentFormId); if (dto.Payable) { @@ -263,7 +268,10 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormCannotReferenceSelf); } - _ = await Repository.FindAsync(dto.ParentFormId.Value) ?? throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormRequiresParentForm); + if (parentForm == null) + { + throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormRequiresParentForm); + } } } @@ -288,7 +296,7 @@ public async Task> GetParentFormLookupAsync( var normalizedFilter = string.IsNullOrWhiteSpace(input.Filter) ? null : input.Filter.Trim(); var formsQueryable = await Repository.GetQueryableAsync(); - var query = formsQueryable.AsQueryable(); + var query = formsQueryable.Where(x => !x.IsHiddenFromList); if (input.ExcludeFormId.HasValue) { @@ -351,7 +359,34 @@ public async Task GetFormDetailsByApplicationIdAsync( }; } - [RemoteService(false)] - public override Task DeleteAsync(Guid id) - => base.DeleteAsync(id); + protected override async Task> CreateFilteredQueryAsync(PagedAndSortedResultRequestDto input) + { + var query = await base.CreateFilteredQueryAsync(input); + return query.Where(form => !form.IsHiddenFromList); + } + + private async Task GetFormForManagementAsync(Guid id) + { + var form = await Repository.GetAsync(id); + if (form.IsHiddenFromList) + { + throw new EntityNotFoundException(typeof(ApplicationForm), id); + } + + return form; + } + + [Authorize(GrantManagerPermissions.ApplicationForms.Delete)] + public override async Task DeleteAsync(Guid id) + { + await CheckDeletePolicyAsync(); + var form = await Repository.GetAsync(id); + if (form.IsHiddenFromList) + { + return; + } + + form.HideFromList(); + await Repository.UpdateAsync(form); + } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs index 53c4dc222e..2bfd68c01b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs @@ -375,6 +375,7 @@ public partial class ApplicationFormDtoToEntityMapper : MapperBase