Skip to content

Commit

Permalink
EHD-1052: Re-build Search page: Paginate search API to improve perfor…
Browse files Browse the repository at this point in the history
…mance
  • Loading branch information
jamesgriff committed Nov 20, 2024
1 parent 223df55 commit b74bca8
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 47 deletions.
1 change: 1 addition & 0 deletions GenderPayGap.WebUI/Models/Search/SearchApiResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class SearchApiResult

public Dictionary<string, string> Sectors { get; set; }
public SearchPageViewModel SearchParameters { get; set; }
public int NumberOfEmployers { get; set; }
public List<SearchApiResultEmployer> Employers { get; set; }

}
Expand Down
1 change: 1 addition & 0 deletions GenderPayGap.WebUI/Models/Search/SearchPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class SearchPageViewModel
public List<string> Sector { get; set; } = new List<string>();
public List<string> ReportedLateYear { get; set; } = new List<string>();
public string OrderBy { get; set; } = "relevance";
public int Page { get; set; } = 0;

[BindNever]
public List<SicSection> PossibleSectors { get; set; }
Expand Down
18 changes: 16 additions & 2 deletions GenderPayGap.WebUI/Search/ViewingSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class ViewingSearchService
private readonly List<SicSection> sicSections;
private readonly Dictionary<string,string> sectorsDictionary;

private const int NumberOfSearchResultsPerTable = 100;

public ViewingSearchService(IDataRepository dataRepository)
{
sicSections = dataRepository.GetAll<SicSection>().ToList();
Expand All @@ -53,12 +55,18 @@ public SearchApiResult Search(SearchPageViewModel searchParams)
{
List<SearchCachedOrganisation> orderedOrganisations =
filteredOrganisations.OrderBy(o => o.OrganisationName.OriginalValue).ToList();

List<SearchCachedOrganisation> paginatedOrderedOrganisations = orderedOrganisations
.Skip(searchParams.Page * NumberOfSearchResultsPerTable)
.Take(NumberOfSearchResultsPerTable)
.ToList();

return new SearchApiResult
{
Sectors = sectorsDictionary,
SearchParameters = searchParams,
Employers = orderedOrganisations.Select(ConvertToSearchApiResultEmployer).ToList()
NumberOfEmployers = orderedOrganisations.Count,
Employers = paginatedOrderedOrganisations.Select(ConvertToSearchApiResultEmployer).ToList()
};
}

Expand All @@ -85,11 +93,17 @@ public SearchApiResult Search(SearchPageViewModel searchParams)
? OrderOrganisationsByRank(organisationsWithRankings)
: OrderOrganisationsAlphabetically(organisationsWithRankings);

List<RankedViewingSearchOrganisation> paginatedRankedOrganisations = rankedOrganisations
.Skip(searchParams.Page * NumberOfSearchResultsPerTable)
.Take(NumberOfSearchResultsPerTable)
.ToList();

return new SearchApiResult
{
Sectors = sectorsDictionary,
SearchParameters = searchParams,
Employers = rankedOrganisations.Select(ConvertRankedOrgsToSearchApiResultEmployer).ToList()
NumberOfEmployers = rankedOrganisations.Count,
Employers = paginatedRankedOrganisations.Select(ConvertRankedOrgsToSearchApiResultEmployer).ToList()
};
}

Expand Down
88 changes: 43 additions & 45 deletions GenderPayGap.WebUI/Views/Search/SearchPage.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,11 @@
updateSelectedCount('Sector', 'gpg-search-page--filters--sector--selected');
updateSelectedCount('ReportedLateYear', 'gpg-search-page--filters--reported-late-years--selected');
updateOrderByVisibility(document.getElementById('EmployerName').value);
updateOrderByRadiosVisibility(document.getElementById('EmployerName').value);
const urlQuery = getPageUrlQuery();
setPageUrl(urlQuery);
hideCurrentSearchResults();
loadSearchResults(urlQuery);
}
Expand Down Expand Up @@ -414,27 +415,26 @@
window.history.replaceState(null, '', newUrl);
}
async function loadSearchResults(urlQuery) {
hideCurrentSearchResults();
async function loadSearchResults(urlQuery, page = 0) {
const searchApiPath = '@(Url.Action("SearchApi", "Search"))';
const searchResultsId = searchResultsIdGenerator.getNextId();
try {
const MIN_LOADING_DELAY_MILLISECONDS = 400;
const fetchStartTime = Date.now();
const response = await fetch(`${searchApiPath}${urlQuery}`, { signal: aborter.abortPreviousFetchesAndGetNewAbortSignal() });
const urlQueryIncludingPage = urlQuery ? `${urlQuery}&Page=${page}` : `${urlQuery}?Page=${page}`;
const response = await fetch(`${searchApiPath}${urlQueryIncludingPage}`, { signal: aborter.abortPreviousFetchesAndGetNewAbortSignal() });
if (response.ok) {
const json = await response.json();
if (searchResultsIdGenerator.isCurrentId(searchResultsId)) {
const fetchEndTime = Date.now();
const fetchTimeTaken = fetchEndTime - fetchStartTime;
if (fetchTimeTaken > MIN_LOADING_DELAY_MILLISECONDS) {
displaySearchResults(json);
if (page > 0 || fetchTimeTaken > MIN_LOADING_DELAY_MILLISECONDS) {
displaySearchResults(json, urlQuery);
}
else {
window.setTimeout(() => displaySearchResults(json), MIN_LOADING_DELAY_MILLISECONDS - fetchTimeTaken);
window.setTimeout(() => displaySearchResults(json, urlQuery), MIN_LOADING_DELAY_MILLISECONDS - fetchTimeTaken);
}
}
}
Expand All @@ -448,52 +448,51 @@
function hideCurrentSearchResults() {
document.getElementById('gpg-search-page--loading').style.display = 'block';
// document.getElementById('gpg-search-page--order-by').style.display = 'none';
document.getElementById('gpg-search-page--results-info').style.display = 'none';
document.getElementById('gpg-search-page--results-info--no-results').style.display = 'none';
document.getElementById('gpg-search-page--results').style.display = 'none';
}
function displaySearchResults(json) {
document.getElementById('gpg-search-page--loading').style.display = 'none';
updateOrderByVisibility(json.SearchParameters.EmployerName);
document.getElementById('gpg-search-page--results-info--number-of-results').innerText = json.Employers.length.toLocaleString();
document.getElementById('gpg-search-page--results-info--employer-employers').innerText = json.Employers.length === 1 ? 'employer' : 'employers';
document.getElementById('gpg-search-page--results-info--containing-search-term').innerText = json.SearchParameters.EmployerName;
document.getElementById('gpg-search-page--results-info--containing').style.display = json.SearchParameters.EmployerName ? 'inline' : 'none';
document.getElementById('gpg-search-page--results-info').style.display = 'block';
document.getElementById('gpg-search-page--results-info--no-results').style.display = json.Employers.length > 0 ? 'none' : 'block';
document.getElementById('gpg-search-page--results').style.display = 'block';
document.getElementById('gpg-search-page--results').innerHTML = '';
function displaySearchResults(json, urlQuery) {
if (json.SearchParameters.Page === 0) {
document.getElementById('gpg-search-page--loading').style.display = 'none';
updateOrderByRadiosVisibility(json.SearchParameters.EmployerName);
document.getElementById('gpg-search-page--results-info--number-of-results').innerText = json.NumberOfEmployers.toLocaleString();
document.getElementById('gpg-search-page--results-info--employer-employers').innerText = json.NumberOfEmployers === 1 ? 'employer' : 'employers';
document.getElementById('gpg-search-page--results-info--containing-search-term').innerText = json.SearchParameters.EmployerName;
document.getElementById('gpg-search-page--results-info--containing').style.display = json.SearchParameters.EmployerName ? 'inline' : 'none';
document.getElementById('gpg-search-page--results-info').style.display = 'block';
document.getElementById('gpg-search-page--results-info--no-results').style.display = json.NumberOfEmployers > 0 ? 'none' : 'block';
document.getElementById('gpg-search-page--results').style.display = 'block';
document.getElementById('gpg-search-page--results').innerHTML = '';
}
displaySearchResultsFromIndex(json, 0);
addSearchResultsForPage(json, urlQuery);
}
function updateOrderByVisibility(employerName) {
function updateOrderByRadiosVisibility(employerName) {
const employerNameIsEmpty = (employerName == null || employerName.trim() === '');
const orderByRadios = document.getElementById('gpg-search-page--order-by');
orderByRadios.style.display = employerNameIsEmpty ? 'none' : 'block';
}
function displaySearchResultsFromIndex(json, startIndex) {
if (json.Employers.length > startIndex) {
const numberOfResultsInThisBlock = Math.min(json.Employers.length, startIndex + NUMBER_OF_SEARCH_RESULTS_PER_TABLE);
const moreResults = json.Employers.length > numberOfResultsInThisBlock;
createTableOfResultsForThisBlock(json, startIndex, numberOfResultsInThisBlock);
function addSearchResultsForPage(json, urlQuery) {
if (json.Employers.length > 0) {
createTableOfResultsForThisBlock(json);
const moreResults = json.NumberOfEmployers > ((json.SearchParameters.Page + 1) * NUMBER_OF_SEARCH_RESULTS_PER_TABLE);
if (moreResults) {
createMoreButton(json, numberOfResultsInThisBlock);
createMoreButton(json, urlQuery);
}
}
}
function createTableOfResultsForThisBlock(json, startIndex, numberOfResultsInThisBlock) {
function createTableOfResultsForThisBlock(json) {
function createThWithTextAndAddToTr(tr, th_text) {
const th = document.createElement('th');
th.innerText = th_text;
Expand Down Expand Up @@ -551,12 +550,12 @@
const results_new_table = document.createElement('table');
const results_new_caption = document.createElement('caption');
results_new_caption.innerText = `Search results ${startIndex + 1} to ${numberOfResultsInThisBlock}`;
// results_new_caption.classList.add('govuk-visually-hidden');
const firstResultIndex = json.SearchParameters.Page * NUMBER_OF_SEARCH_RESULTS_PER_TABLE + 1;
const lastResultIndex = Math.min(json.NumberOfEmployers, (json.SearchParameters.Page * NUMBER_OF_SEARCH_RESULTS_PER_TABLE) + json.Employers.length);
results_new_caption.innerText = `Search results ${firstResultIndex} to ${lastResultIndex}`;
results_new_table.appendChild(results_new_caption);
const results_new_thead = document.createElement('thead');
// results_new_thead.classList.add('govuk-visually-hidden');
const results_new_thead_tr = document.createElement('tr');
createThWithTextAndAddToTr(results_new_thead_tr, 'Employer name');
createThWithTextAndAddToTr(results_new_thead_tr, 'Previous name');
Expand All @@ -567,8 +566,7 @@
results_new_table.appendChild(results_new_thead);
const results_new_tbody = document.createElement('tbody');
const employersInThisBlock = json.Employers.slice(startIndex, startIndex + numberOfResultsInThisBlock);
employersInThisBlock.forEach((employer) => {
json.Employers.forEach((employer) => {
const results_new_tbody_tr = document.createElement('tr');
createThWithLinkToEmployerAndAddToTr(results_new_tbody_tr, employer.Id, employer.Name);
createTdWithTextAndAddToTr(results_new_tbody_tr, employer.PreviousName, 'No previous name');
Expand All @@ -591,16 +589,16 @@
return compareCookieValue.length > 0 ? compareCookieValue.split(encodeURIComponent(',')) : [];
}
function createMoreButton(json, numberOfResultsInThisBlock) {
function createMoreButton(json, urlQuery) {
const resultsSection = document.getElementById('gpg-search-page--results');
const numberOfResultsInNextBlock = Math.min(json.Employers.length, numberOfResultsInThisBlock + NUMBER_OF_SEARCH_RESULTS_PER_TABLE);
const more_button = document.createElement('button');
more_button.innerText = `Show search results ${numberOfResultsInThisBlock+1} to ${numberOfResultsInNextBlock}`;
const nextBlockFirstResultIndex = ((json.SearchParameters.Page + 1) * NUMBER_OF_SEARCH_RESULTS_PER_TABLE) + 1;
const nextBlockLastResultIndex = Math.min(json.NumberOfEmployers, (json.SearchParameters.Page + 2) * NUMBER_OF_SEARCH_RESULTS_PER_TABLE);
more_button.innerText = `Show search results ${nextBlockFirstResultIndex} to ${nextBlockLastResultIndex}`;
more_button.addEventListener('click', () => {
resultsSection.removeChild(more_button);
displaySearchResultsFromIndex(json, numberOfResultsInThisBlock);
loadSearchResults(urlQuery, json.SearchParameters.Page + 1);
})
resultsSection.appendChild(more_button);
}
Expand All @@ -617,7 +615,7 @@
document.getElementById('compare-employers-notification-banner--number-of-employees').innerText = numberOfEmployersText;
}
// Do what the button SAYS ("Add" or "Remove"), regardless of whether the org is currently in currently in the compare basket
// Do what the button SAYS ("Add" or "Remove"), regardless of whether the org is currently in the compare basket
const isAddButton = compare_button.classList.contains('gpg-search-results--add-button');
try {
Expand Down

0 comments on commit b74bca8

Please sign in to comment.