diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js
index 8bc5385e7..0b00bdc5e 100644
--- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js
+++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js
@@ -229,7 +229,8 @@ function initializeDataTable(options) {
onStateLoadParams,
onStateLoaded,
fixedHeaders = false,
- lengthMenu = [25, 50, 75, 100, -1]
+ lengthMenu = [25, 50, 75, 100, -1],
+ deferRender = false
} = options;
// Process columns and visibility
@@ -255,7 +256,7 @@ function initializeDataTable(options) {
scrollX: true,
scrollCollapse: true,
autoWidth: true,
- deferRender: false,
+ deferRender: deferRender,
deferLoading: serverSideEnabled ? 0 : null,
ajax: abp.libs.datatables.createAjax(
dataEndpoint,
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/DbWarmupOptions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/DbWarmupOptions.cs
new file mode 100644
index 000000000..04aa7a77b
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/DbWarmupOptions.cs
@@ -0,0 +1,40 @@
+namespace Unity.GrantManager.EntityFrameworkCore;
+
+///
+/// Configuration options for .
+/// Bind from appsettings.json under the "DbWarmup" section.
+///
+/// Example:
+///
+/// "DbWarmup": {
+/// "IsPhase2Enabled": true,
+/// "MaxTenants": 5,
+/// "Phase2TimeoutSeconds": 30
+/// }
+///
+///
+public class DbWarmupOptions
+{
+ public const string SectionName = "DbWarmup";
+
+ ///
+ /// When false, Phase 2 (per-tenant DB round-trips) is skipped entirely.
+ /// Phase 1 (EF Core model compilation) always runs regardless of this setting.
+ /// Default: true.
+ ///
+ public bool IsPhase2Enabled { get; set; } = true;
+
+ ///
+ /// Maximum number of tenants to warm in Phase 2.
+ /// 0 means no limit. Default: 0.
+ /// Useful in constrained environments or when tenant count is very large.
+ ///
+ public int MaxTenants { get; set; } = 0;
+
+ ///
+ /// Total seconds allowed for Phase 2 across all tenants before it is abandoned.
+ /// 0 means no timeout. Default: 0.
+ /// Remaining tenants are skipped gracefully when the timeout elapses.
+ ///
+ public int Phase2TimeoutSeconds { get; set; } = 0;
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbWarmupService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbWarmupService.cs
new file mode 100644
index 000000000..723f7638e
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbWarmupService.cs
@@ -0,0 +1,225 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Unity.GrantManager.Applications;
+
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.TenantManagement;
+using Volo.Abp.Uow;
+
+namespace Unity.GrantManager.EntityFrameworkCore;
+
+///
+/// Background service that pre-warms the EF Core query pipeline after application startup.
+///
+/// On first use, EF Core performs three expensive one-time operations:
+/// 1. Model snapshot compilation — GrantTenantDbContext.OnModelCreating (30+ entity types)
+/// 2. LINQ→SQL expression tree translation — especially costly for multi-JOIN includes
+/// 3. Npgsql connection pool establishment + PostgreSQL query plan caching
+///
+/// These costs are normally deferred to the first HTTP request, causing 6-8 second cold-start
+/// latency for the GrantApplications DataTable. This service fires the most expensive query
+/// shape (GetApplicationListRecordsAsync with typical date filters) shortly after startup so the
+/// cache is warm before any user makes a request.
+///
+/// Warmup is split into two independent phases:
+/// Phase 1 (model compilation) — always succeeds; no DB connection required.
+/// Phase 2 (per-tenant DB round-trip) — iterates tenants from the host database and warms
+/// Npgsql's connection pool and PostgreSQL's query plan cache for each.
+///
+/// Phase 2 behaviour is configurable via (appsettings "DbWarmup" section):
+/// IsPhase2Enabled — set false to skip Phase 2 entirely (default: true).
+/// MaxTenants — cap the number of tenants warmed; 0 = unlimited (default: 0).
+/// Phase2TimeoutSeconds — abandon Phase 2 after N seconds; 0 = no timeout (default: 0).
+///
+///
+public class GrantManagerDbWarmupService : BackgroundService
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private readonly ILogger _logger;
+ private readonly IHostApplicationLifetime _hostApplicationLifetime;
+ private readonly DbWarmupOptions _options;
+
+ public GrantManagerDbWarmupService(
+ IServiceScopeFactory scopeFactory,
+ ILogger logger,
+ IHostApplicationLifetime hostApplicationLifetime,
+ IOptions options)
+ {
+ _scopeFactory = scopeFactory;
+ _logger = logger;
+ _hostApplicationLifetime = hostApplicationLifetime;
+ _options = options.Value;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ // Wait until the host has fully started so ABP module initialization and startup hooks
+ // are complete before issuing any warmup queries.
+ if (!_hostApplicationLifetime.ApplicationStarted.IsCancellationRequested)
+ {
+ var applicationStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ using var applicationStartedRegistration = _hostApplicationLifetime.ApplicationStarted.Register(
+ static state => ((TaskCompletionSource)state!).TrySetResult(),
+ applicationStartedTcs);
+ using var cancellationRegistration = stoppingToken.Register(
+ static state => ((TaskCompletionSource)state!).TrySetCanceled(),
+ applicationStartedTcs);
+
+ await applicationStartedTcs.Task;
+ }
+
+ if (stoppingToken.IsCancellationRequested) return;
+
+ _logger.LogInformation("[DbWarmup] Starting EF Core query pipeline warmup.");
+
+ // Step 1: Model
+ // Accessing dbContext.Model forces EF Core to run OnModelCreating synchronously.
+ // This is a pure in-process operation; no DB connection is opened.
+ using (var phase1Scope = _scopeFactory.CreateScope())
+ {
+ var unitOfWorkManager = phase1Scope.ServiceProvider.GetRequiredService();
+ try
+ {
+ using var uow = unitOfWorkManager.Begin(requiresNew: true, isTransactional: false);
+ var dbContextProvider = phase1Scope.ServiceProvider
+ .GetRequiredService>();
+ var dbContext = await dbContextProvider.GetDbContextAsync();
+
+ // Accessing Model triggers OnModelCreating if not yet compiled.
+ // The result is cached for the lifetime of the application.
+ _ = dbContext.Model;
+
+ await uow.CompleteAsync();
+ _logger.LogInformation("[DbWarmup] Phase 1 complete — EF Core model compiled.");
+ }
+ catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { return; }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "[DbWarmup] Phase 1 (model compilation) failed — this is unexpected.");
+ }
+ }
+
+ // Step 2: Per-tenant DB connection + PostgreSQL query plan warmup
+ // Enumerates all tenants (ITenantRepository -> GrantManagerDbContext -> accessible without an active tenant scope).
+ // Foreach tenant, opens a new DI scope, activates the tenant via ICurrentTenant.Change, and issues a Take(1) query so that:
+ // - Opens and pools a connection to that tenant's database
+ // - PostgreSQL parses and caches the parameterised execution plan for the query shape
+ // - EFCore's compiled query cache is populated for this tenant
+ // Each tenant is isolated in its own scope to prevent UoW state from leaking between tenants.
+ // Uses GetApplicationListRecordsAsync — the same optimized projected query the DataTable endpoint calls.
+ if (!_options.IsPhase2Enabled)
+ {
+ _logger.LogInformation("[DbWarmup] Phase 2 disabled via configuration — skipping per-tenant warmup.");
+ return;
+ }
+
+ IReadOnlyList tenants;
+
+ using (var tenantListScope = _scopeFactory.CreateScope())
+ {
+ var tenantUowManager = tenantListScope.ServiceProvider.GetRequiredService();
+ try
+ {
+ using var uow = tenantUowManager.Begin(requiresNew: true, isTransactional: false);
+ var tenantRepository = tenantListScope.ServiceProvider.GetRequiredService();
+ tenants = await tenantRepository.GetListAsync();
+ await uow.CompleteAsync();
+ }
+ catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { return; }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "[DbWarmup] Phase 2 — could not retrieve tenant list from host database. Skipping per-tenant warmup.");
+ return;
+ }
+ }
+
+ if (tenants.Count == 0)
+ {
+ _logger.LogDebug("[DbWarmup] Phase 2 — no tenants found in host database. Skipping per-tenant DB warmup.");
+ return;
+ }
+
+ // Apply MaxTenants cap
+ var tenantsToWarm = _options.MaxTenants > 0
+ ? tenants.Take(_options.MaxTenants).ToList()
+ : (IReadOnlyList)tenants;
+
+ if (_options.MaxTenants > 0 && tenants.Count > _options.MaxTenants)
+ {
+ _logger.LogInformation(
+ "[DbWarmup] Phase 2 — capped at {MaxTenants} of {TotalTenants} tenant(s) (MaxTenants setting).",
+ _options.MaxTenants, tenants.Count);
+ }
+
+ _logger.LogInformation("[DbWarmup] Phase 2 — warming {TenantCount} tenant(s).", tenantsToWarm.Count);
+
+ // Apply Phase2TimeoutSeconds — link a deadline token with stoppingToken
+ using var phase2Cts = _options.Phase2TimeoutSeconds > 0
+ ? CancellationTokenSource.CreateLinkedTokenSource(stoppingToken)
+ : null;
+ if (phase2Cts != null)
+ {
+ phase2Cts.CancelAfter(TimeSpan.FromSeconds(_options.Phase2TimeoutSeconds));
+ _logger.LogDebug("[DbWarmup] Phase 2 — timeout set to {Seconds}s.", _options.Phase2TimeoutSeconds);
+ }
+ var phase2Token = phase2Cts?.Token ?? stoppingToken;
+
+ var warmed = 0;
+ foreach (var tenant in tenantsToWarm)
+ {
+ if (phase2Token.IsCancellationRequested)
+ {
+ // Distinguish between a Phase 2 timeout and a host shutdown
+ if (!stoppingToken.IsCancellationRequested)
+ _logger.LogInformation(
+ "[DbWarmup] Phase 2 — timeout reached after {Warmed}/{Total} tenant(s).",
+ warmed, tenantsToWarm.Count);
+ return;
+ }
+
+ using var tenantScope = _scopeFactory.CreateScope();
+ var currentTenant = tenantScope.ServiceProvider.GetRequiredService();
+ var tenantUowManager = tenantScope.ServiceProvider.GetRequiredService();
+
+ using (currentTenant.Change(tenant.Id))
+ {
+ try
+ {
+ using var uow = tenantUowManager.Begin(requiresNew: true, isTransactional: false);
+ var repository = tenantScope.ServiceProvider.GetRequiredService();
+
+ await repository.GetApplicationListRecordsAsync(
+ skipCount: 0,
+ maxResultCount: 1,
+ sorting: null,
+ submittedFromDate: DateTime.UtcNow.AddMonths(-6),
+ submittedToDate: DateTime.UtcNow);
+
+ await uow.CompleteAsync();
+ warmed++;
+ _logger.LogDebug("[DbWarmup] Tenant '{TenantName}' ({TenantId}) warmed.", tenant.Name, tenant.Id);
+ }
+ catch (OperationCanceledException) when (phase2Token.IsCancellationRequested) { return; }
+ catch (Exception ex)
+ {
+ _logger.LogDebug(ex,
+ "[DbWarmup] Tenant '{TenantName}' ({TenantId}) — DB round-trip skipped. " +
+ "Tenant database may not be accessible in this environment.",
+ tenant.Name, tenant.Id);
+ }
+ }
+ }
+
+ _logger.LogInformation("[DbWarmup] Phase 2 complete — {Warmed}/{Total} tenant(s) warmed.", warmed, tenantsToWarm.Count);
+ }
+}
\ No newline at end of file
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs
index e6f9d5eb1..081fa8dd7 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs
@@ -135,6 +135,10 @@ public override void ConfigureServices(ServiceConfigurationContext context)
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
+ // Pre-warm the EF Core query pipeline after startup (web host only, not DbMigrator)
+ context.Services.Configure(configuration.GetSection(DbWarmupOptions.SectionName));
+ context.Services.AddHostedService();
+
ConfgureFormsApiAuhentication(context);
ConfigureAuthentication(context, configuration);
ConfigurePolicies(context);
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 0c752256c..7c10cc14d 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
@@ -9,6 +9,8 @@ $(function () {
const l = abp.localization.getResource('GrantManager');
const defaultQuickDateRange = 'last6months';
const guidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
+ const canViewApplicants = abp.auth.isGranted('GrantApplicationManagement.Applicants.ViewList');
+ const dtTextRenderer = $.fn.dataTable.render.text();
let dt = $('#GrantApplicationsTable');
let dataTable;
@@ -89,6 +91,7 @@ $(function () {
}
})
dt.colReorder.order(orderedIndexes);
+ dt.columns.adjust();
if (typeof dt.filterRow === 'function') {
const filterRowApi = dt.filterRow();
@@ -168,13 +171,15 @@ $(function () {
};
let formatItems = function (items) {
- const newData = items.map((item, index) => {
- return {
- ...item,
- rowCount: index
- };
+ // Previously used
+ // const newData = items.map((item, index) => { return { ...item, rowCount: index }; });
+ // return newData;
+ // While in clientside mode, we're always retrieving the full dataset.
+ // Can be reverted for server-side
+ items.forEach((item, index) => {
+ item.rowCount = index;
});
- return newData;
+ return items;
}
init();
@@ -350,12 +355,10 @@ $(function () {
UIElements.quickDateRange.val('custom');
localStorage.setItem('GrantApplications_QuickRange', 'custom');
- const dtInstance = $('#GrantApplicationsTable').DataTable();
-
localStorage.setItem("GrantApplications_FromDate", grantTableFilters.submittedFromDate);
localStorage.setItem("GrantApplications_ToDate", grantTableFilters.submittedToDate);
- dtInstance.ajax.reload(null, true);
+ dataTable.ajax.reload(null, true);
}
function handleQuickDateRangeChange() {
const selectedRange = $(this).val();
@@ -375,8 +378,7 @@ $(function () {
setDateRangeLocalStorage(selectedRange, range);
// Reload the table with new filters
- const dtInstance = $('#GrantApplicationsTable').DataTable();
- dtInstance.ajax.reload(null, true);
+ dataTable.ajax.reload(null, true);
}
function initializeDataTableAndEvents() {
@@ -424,6 +426,7 @@ $(function () {
},
responseCallback,
actionButtons,
+ deferRender: true,
serverSideEnabled: false,
pagingEnabled: true,
reorderEnabled: true,
@@ -511,8 +514,7 @@ $(function () {
}
$('#search').on('input', function () {
- let table = $('#GrantApplicationsTable').DataTable();
- table.search($(this).val()).draw();
+ dataTable.search($(this).val()).draw();
});
//For savedStates
@@ -622,7 +624,7 @@ $(function () {
getNonRegisteredOrganizationNameColumn(columnIndex++),
getUnityApplicationIdColumn(columnIndex++),
getLinkRelationshipType(columnIndex++),
- ].map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] }))
+ ].map((column) => ({ ...column, targets: [column.index] }))
.sort((a, b) => a.index - b.index);
return sortedColumns;
}
@@ -637,13 +639,13 @@ $(function () {
render: function(data, type, row) {
let applicantName = (typeof data !== 'string' || data.trim() === '') ? 'Applicant Name' : data;
- if (type === 'sort' || type === 'filter') {
+ if (type !== 'display') {
return applicantName;
}
- const safeApplicantName = $.fn.dataTable.render.text().display(applicantName);
+ const safeApplicantName = dtTextRenderer.display(applicantName);
- if (type === 'display' && abp.auth.isGranted('GrantApplicationManagement.Applicants.ViewList')) {
+ if (canViewApplicants) {
const applicantId = row?.applicant?.id;
const isGuid = applicantId && guidPattern.test(applicantId);
@@ -666,6 +668,7 @@ $(function () {
name: 'referenceNo',
className: 'data-table-header text-nowrap',
render: function (data, type, row) {
+ if (type !== 'display') return data ?? '';
return `${data}`;
},
index: columnIndex
@@ -760,10 +763,13 @@ $(function () {
displayText = getNames(data);
}
+ if (type !== 'display') return displayText.trim();
+
+ const tooltipText = data?.length ? getNames(data) : '';
return `
' + displayText + '' +
+ + tooltipText + '">' + displayText + '' +
``;
},
index: columnIndex
@@ -884,10 +890,8 @@ $(function () {
name: 'projectStartDate',
data: 'projectStartDate',
className: 'data-table-header',
- render: function (data) {
- return data != null ? luxon.DateTime.fromISO(data, {
- locale: abp.localization.currentCulture.name,
- }).toUTC().toLocaleString() : '';
+ render: function (data, type) {
+ return DateUtils.formatUtcDateToLocal(data, type);
},
index: columnIndex
}
@@ -899,10 +903,8 @@ $(function () {
name: 'projectEndDate',
data: 'projectEndDate',
className: 'data-table-header',
- render: function (data) {
- return data != null ? luxon.DateTime.fromISO(data, {
- locale: abp.localization.currentCulture.name,
- }).toUTC().toLocaleString() : '';
+ render: function (data, type) {
+ return DateUtils.formatUtcDateToLocal(data, type);
},
index: columnIndex
}
@@ -1107,11 +1109,10 @@ $(function () {
className: '',
refreshData: true,
render: function (data) {
-
- let tagNames = data
- .filter(x => x?.tag?.name)
- .map(x => x.tag.name);
- return tagNames.join(', ') ?? '';
+ return data
+ .filter(x => x?.tag?.name)
+ .map(x => x.tag.name)
+ .join(', ');
},
index: columnIndex
}
@@ -1167,10 +1168,8 @@ $(function () {
name: 'dueDate',
data: 'dueDate',
className: 'data-table-header',
- render: function (data) {
- return data != null ? luxon.DateTime.fromISO(data, {
- locale: abp.localization.currentCulture.name,
- }).toUTC().toLocaleString() : '';
+ render: function (data, type) {
+ return DateUtils.formatUtcDateToLocal(data, type);
},
index: columnIndex
}
@@ -1196,10 +1195,8 @@ $(function () {
name: 'finalDecisionDate',
data: 'finalDecisionDate',
className: 'data-table-header',
- render: function (data) {
- return data != null ? luxon.DateTime.fromISO(data, {
- locale: abp.localization.currentCulture.name,
- }).toUTC().toLocaleString() : '';
+ render: function (data, type) {
+ return DateUtils.formatUtcDateToLocal(data, type);
},
index: columnIndex
}
@@ -1290,7 +1287,10 @@ $(function () {
data: 'applicationLinks',
className: 'data-table-header',
refreshData: true,
- render: function (data) {
+ render: function (data, type) {
+ if (type !== 'display' && type !== 'fullName') {
+ return (data || []).filter(x => x?.linkType).map(x => x.linkType).join(', ');
+ }
const linkNames = Array.from(new Set((data || [])
.filter(x => x?.linkType)
.map(x => {
@@ -1504,9 +1504,6 @@ $(function () {
data: 'notes',
className: 'data-table-header multi-line',
width: "20rem",
- createdCell: function (td) {
- $(td).css('min-width', '20rem');
- },
render: function (data) {
return data ?? '';
},
@@ -1600,50 +1597,47 @@ $(function () {
return data.duty ? (" [" + data.duty + "]") : '';
}
+ const _companyTypeMap = new Map([
+ ['BC', 'BC Company'],
+ ['CP', 'Cooperative'],
+ ['GP', 'General Partnership'],
+ ['S', 'Society'],
+ ['SP', 'Sole Proprietorship'],
+ ['A', 'Extraprovincial Company'],
+ ['B', 'Extraprovincial'],
+ ['BEN', 'Benefit Company'],
+ ['C', 'Continuation In'],
+ ['CC', 'BC Community Contribution Company'],
+ ['CS', 'Continued In Society'],
+ ['CUL', 'Continuation In as a BC ULC'],
+ ['EPR', 'Extraprovincial Registration'],
+ ['FI', 'Financial Institution'],
+ ['FOR', 'Foreign Registration'],
+ ['LIB', 'Public Library Association'],
+ ['LIC', 'Licensed (Extra-Pro)'],
+ ['LL', 'Limited Liability Partnership'],
+ ['LLC', 'Limited Liability Company'],
+ ['LP', 'Limited Partnership'],
+ ['MF', 'Miscellaneous Firm'],
+ ['PA', 'Private Act'],
+ ['PAR', 'Parish'],
+ ['QA', 'CO 1860'],
+ ['QB', 'CO 1862'],
+ ['QC', 'CO 1878'],
+ ['QD', 'CO 1890'],
+ ['QE', 'CO 1897'],
+ ['REG', 'Registraton (Extra-pro)'],
+ ['ULC', 'BC Unlimited Liability Company'],
+ ['XCP', 'Extraprovincial Cooperative'],
+ ['XL', 'Extrapro Limited Liability Partnership'],
+ ['XP', 'Extraprovincial Limited Partnership'],
+ ['XS', 'Extraprovincial Society']
+ ]);
+
function getFullType(code) {
- const companyTypes = [
- { code: "BC", name: "BC Company" },
- { code: "CP", name: "Cooperative" },
- { code: "GP", name: "General Partnership" },
- { code: "S", name: "Society" },
- { code: "SP", name: "Sole Proprietorship" },
- { code: "A", name: "Extraprovincial Company" },
- { code: "B", name: "Extraprovincial" },
- { code: "BEN", name: "Benefit Company" },
- { code: "C", name: "Continuation In" },
- { code: "CC", name: "BC Community Contribution Company" },
- { code: "CS", name: "Continued In Society" },
- { code: "CUL", name: "Continuation In as a BC ULC" },
- { code: "EPR", name: "Extraprovincial Registration" },
- { code: "FI", name: "Financial Institution" },
- { code: "FOR", name: "Foreign Registration" },
- { code: "LIB", name: "Public Library Association" },
- { code: "LIC", name: "Licensed (Extra-Pro)" },
- { code: "LL", name: "Limited Liability Partnership" },
- { code: "LLC", name: "Limited Liability Company" },
- { code: "LP", name: "Limited Partnership" },
- { code: "MF", name: "Miscellaneous Firm" },
- { code: "PA", name: "Private Act" },
- { code: "PAR", name: "Parish" },
- { code: "QA", name: "CO 1860" },
- { code: "QB", name: "CO 1862" },
- { code: "QC", name: "CO 1878" },
- { code: "QD", name: "CO 1890" },
- { code: "QE", name: "CO 1897" },
- { code: "REG", name: "Registraton (Extra-pro)" },
- { code: "ULC", name: "BC Unlimited Liability Company" },
- { code: "XCP", name: "Extraprovincial Cooperative" },
- { code: "XL", name: "Extrapro Limited Liability Partnership" },
- { code: "XP", name: "Extraprovincial Limited Partnership" },
- { code: "XS", name: "Extraprovincial Society" }
- ];
- const match = companyTypes.find(entry => entry.code === code);
- return match ? match.name : "Unknown";
- }
-
-
- window.addEventListener('resize', () => {
- });
+ return _companyTypeMap.get(code) ?? 'Unknown';
+ }
+
PubSub.subscribe(
'refresh_application_list',
@@ -1655,22 +1649,17 @@ $(function () {
);
function getNames(data) {
- let name = '';
- data.forEach((d, index) => {
- name = name + (' ' + d.fullName + getDutyText(d));
- if (index != (data.length - 1)) {
- name = name + ',';
- }
- });
-
- return name;
+ return data.map(d => d.fullName + getDutyText(d)).join(', ');
}
+ const _titleCaseCache = new Map();
function titleCase(str) {
- str = str.toLowerCase().split(' ');
- for (let i = 0; i < str.length; i++) {
- str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1);
- }
- return str.join(' ');
+ //This funciton is currently called by 6 columns, all of which are status types or predetermined values
+ //Caching the results in this case is to improve large data table loads while we're in client side.
+ //Columns: likelihoodOfFunding, assessmentResult, riskRanking, acquisition, fyeMonth, dueDiligenceStatus
+ if (_titleCaseCache.has(str)) return _titleCaseCache.get(str);
+ const result = str.toLowerCase().split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
+ _titleCaseCache.set(str, result);
+ return result;
}
function convertToYesNo(str) {