From 8283a5a457ff2c5606a76ec403d5f2527a8f2311 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Wed, 8 Apr 2026 11:49:15 -0700 Subject: [PATCH 1/4] AB#32346 - Add Applicant Detail routing from ApplicationId --- .../Pages/Applicants/Details.cshtml.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs index 07537bffb..4d5375606 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs @@ -13,10 +13,14 @@ namespace Unity.GrantManager.Web.Pages.Applicants public class DetailsModel : GrantManagerPageModel { private readonly IApplicantRepository _applicantRepository; + private readonly IApplicationRepository _applicationRepository; [BindProperty(SupportsGet = true)] public Guid ApplicantId { get; set; } + [BindProperty(SupportsGet = true)] + public Guid? ApplicationId { get; set; } = null; + public Applicant? Applicant { get; set; } public string ApplicantDisplayName { get; set; } = string.Empty; public string UnityApplicantId { get; set; } = string.Empty; @@ -28,10 +32,12 @@ public class DetailsModel : GrantManagerPageModel public DetailsModel( IApplicantRepository applicantRepository, + IApplicationRepository applicationRepository, ICurrentUser currentUser, IConfiguration configuration) { _applicantRepository = applicantRepository; + _applicationRepository = applicationRepository; CurrentUserId = currentUser.Id; CurrentUserName = currentUser.SurName + ", " + currentUser.Name; Extensions = configuration["S3:DisallowedFileTypes"] ?? ""; @@ -40,6 +46,13 @@ public DetailsModel( public async Task OnGetAsync() { + // Resolve ApplicantId from ApplicationId if needed + if (ApplicantId == Guid.Empty && ApplicationId.HasValue) + { + var application = await _applicationRepository.WithBasicDetailsAsync(ApplicationId.Value); + ApplicantId = application.ApplicantId; + } + if (ApplicantId == Guid.Empty) { return NotFound(); From 2e84fb19f66e624e407b6b534e31bf84207c82f5 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Wed, 8 Apr 2026 11:51:42 -0700 Subject: [PATCH 2/4] AB#32346 - Add default applicant naming --- .../Pages/PaymentRequests/Index.js | 24 ++++++++++++++++++- .../Pages/Applicants/Index.js | 24 ++++++++++++++++++- .../Pages/GrantApplications/Index.js | 2 +- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index dc9371b52..4b1e27dff 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -2,6 +2,7 @@ $(function () { const l = abp.localization.getResource('Payments'); const nullPlaceholder = '—'; const formatter = createNumberFormatter(); + const guidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; let dt = $('#PaymentRequestListTable'); let dataTable; let isApprove = false; @@ -377,7 +378,28 @@ $(function () { name: 'applicantName', data: 'payeeName', className: 'data-table-header', - index: columnIndex + index: columnIndex, + render: function (data, type, row) { + let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; + + if (type === 'sort' || type === 'filter') { + return applicantName; + } + + if (type === 'display' && abp.auth.isGranted('GrantApplicationManagement.Applicants.ViewList')) { + const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); + const applicantId = row?.correlationId; + const isGuid = applicantId && guidPattern.test(applicantId); + + if (row?.correlationProvider === 'Application' && isGuid) { + return `${safeApplicantName}`; + } + + return safeApplicantName; + } + + return applicantName; + }, }; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js index 88fed040f..48531814a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js @@ -1,6 +1,7 @@ $(function () { let dt = $('#ApplicantsTable'); let dataTable; + const guidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; // Default visible columns as per requirements const defaultVisibleColumns = [ @@ -87,7 +88,28 @@ $(function () { data: 'applicantName', name: 'applicantName', className: 'data-table-header', - index: columnIndex + index: columnIndex, + render: function (data, type, row) { + let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; + + if (type === 'sort' || type === 'filter') { + return applicantName; + } + + if (type === 'display') { + const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); + const applicantId = row?.id; + const isGuid = applicantId && guidPattern.test(applicantId); + + if (isGuid) { + return `${safeApplicantName}`; + } + + return safeApplicantName; + } + + return applicantName; + } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index 838c32d51..005ad2dd6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -587,7 +587,7 @@ $(function () { className: 'data-table-header', index: columnIndex, render: function(data, type, row) { - let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Unknown Applicant)' : data; + let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; if (type === 'sort' || type === 'filter') { return applicantName; From 4a6383e0745520d1d553d8ac18a7a288e48fb877 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:15:24 -0700 Subject: [PATCH 3/4] AB#32346 - Code Quality Improvements --- .../Unity.Payments.Web/Pages/PaymentRequests/Index.js | 5 +++-- .../Pages/Applicants/Details.cshtml.cs | 11 +++++++++-- .../Unity.GrantManager.Web/Pages/Applicants/Index.js | 5 +++-- .../Pages/GrantApplications/Index.js | 5 +++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index 4b1e27dff..ba06ae76b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -380,14 +380,15 @@ $(function () { className: 'data-table-header', index: columnIndex, render: function (data, type, row) { - let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; + let applicantName = (typeof data !== 'string' || data.trim() === '') ? 'Applicant Name' : data; if (type === 'sort' || type === 'filter') { return applicantName; } + const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); + if (type === 'display' && abp.auth.isGranted('GrantApplicationManagement.Applicants.ViewList')) { - const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); const applicantId = row?.correlationId; const isGuid = applicantId && guidPattern.test(applicantId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs index 4d5375606..4ecba7831 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs @@ -49,8 +49,15 @@ public async Task OnGetAsync() // Resolve ApplicantId from ApplicationId if needed if (ApplicantId == Guid.Empty && ApplicationId.HasValue) { - var application = await _applicationRepository.WithBasicDetailsAsync(ApplicationId.Value); - ApplicantId = application.ApplicantId; + try + { + var application = await _applicationRepository.WithBasicDetailsAsync(ApplicationId.Value); + ApplicantId = application.ApplicantId; + } + catch (Exception) + { + return NotFound(); + } } if (ApplicantId == Guid.Empty) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js index 48531814a..06ffa13a6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Index.js @@ -90,14 +90,15 @@ $(function () { className: 'data-table-header', index: columnIndex, render: function (data, type, row) { - let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; + let applicantName = (typeof data !== 'string' || data.trim() === '') ? 'Applicant Name' : data; if (type === 'sort' || type === 'filter') { return applicantName; } + const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); + if (type === 'display') { - const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); const applicantId = row?.id; const isGuid = applicantId && guidPattern.test(applicantId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index 005ad2dd6..9b4004bbe 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -587,14 +587,15 @@ $(function () { className: 'data-table-header', index: columnIndex, render: function(data, type, row) { - let applicantName = (typeof data !== 'string' || data.trim() === '') ? '(Applicant Name)' : data; + let applicantName = (typeof data !== 'string' || data.trim() === '') ? 'Applicant Name' : data; if (type === 'sort' || type === 'filter') { return applicantName; } + const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); + if (type === 'display' && abp.auth.isGranted('GrantApplicationManagement.Applicants.ViewList')) { - const safeApplicantName = $.fn.dataTable.render.text().display(applicantName); const applicantId = row?.applicant?.id; const isGuid = applicantId && guidPattern.test(applicantId); From 8b8d96d5563b6979d094bd3185eaaba07298ab0e Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:19:40 -0700 Subject: [PATCH 4/4] AB#32346 - Add additional applicant name placeholders --- .../Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs | 2 +- .../ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidget.cs | 2 +- .../ApplicantBreadcrumbWidgetViewComponent.cs | 2 +- .../Components/ApplicationBreadcrumbWidget/Default.cshtml | 2 +- .../Views/Shared/Components/ApplicationLinksWidget/Default.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs index 4ecba7831..c81d8d95d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Applicants/Details.cshtml.cs @@ -72,7 +72,7 @@ public async Task OnGetAsync() // Set properties for breadcrumb and display ApplicantDisplayName = !string.IsNullOrEmpty(Applicant.ApplicantName) ? Applicant.ApplicantName - : "Unknown Applicant"; + : "Applicant Name"; UnityApplicantId = Applicant.UnityApplicantId ?? "N/A"; Status = Applicant.Status ?? "Active"; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidget.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidget.cs index 2952ad5e8..2e54cc6a8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidget.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidget.cs @@ -36,7 +36,7 @@ public async Task GetApplicantBreadcrumbWidgetAsync(Guid applican UnityApplicantId = applicant.UnityApplicantId ?? "N/A", ApplicantName = !string.IsNullOrEmpty(applicant.ApplicantName) ? applicant.ApplicantName - : "Unknown Applicant", + : "Applicant Name", Status = applicant.Status ?? "Active" }; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidgetViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidgetViewComponent.cs index fedc11ab5..3c8442049 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidgetViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantBreadcrumbWidget/ApplicantBreadcrumbWidgetViewComponent.cs @@ -27,7 +27,7 @@ public async Task InvokeAsync(Guid applicantId) UnityApplicantId = applicant.UnityApplicantId ?? "N/A", ApplicantName = !string.IsNullOrEmpty(applicant.ApplicantName) ? applicant.ApplicantName - : "Unknown Applicant", + : "Applicant Name", Status = applicant.Status ?? "Active" }; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml index bcd543883..3b9d1d321 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml @@ -7,7 +7,7 @@ @model ApplicationBreadcrumbWidgetViewModel @{ - var renderedApplicantName = string.IsNullOrWhiteSpace(Model.ApplicantName) ? "Unknown Applicant" : Model.ApplicantName; + var renderedApplicantName = string.IsNullOrWhiteSpace(Model.ApplicantName) ? "Applicant Name" : Model.ApplicantName; var hasViewPermission = await PermissionChecker.IsGrantedAsync(GrantApplicationPermissions.Applicants.ViewList); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationLinksWidget/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationLinksWidget/Default.js index fa97add6d..5b6e28b20 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationLinksWidget/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationLinksWidget/Default.js @@ -484,7 +484,7 @@ $(function () { prepareDisplayData: function(link) { const referenceNumber = escapeHtml(link.referenceNumber || 'Unknown Reference'); - const applicantName = escapeHtml(link.applicantName || 'Unknown Applicant'); + const applicantName = escapeHtml(link.applicantName || 'Applicant Name'); const category = escapeHtml(link.category || 'Unknown Category'); const applicationStatus = escapeHtml(link.applicationStatus || 'Status Unavailable'); const linkType = escapeHtml(link.linkType || 'Related');