From c0fdb4c47cfc60a086ca911f2f7b52007d12371f Mon Sep 17 00:00:00 2001 From: Feba Date: Thu, 10 Jul 2025 10:16:00 +0100 Subject: [PATCH 1/4] combine error and issue counts into a single total --- src/middleware/lpa-overview.middleware.js | 12 ++--- src/routes/schemas.js | 3 +- src/views/organisations/overview.html | 3 +- .../lpa-overview.middleware.test.js | 48 +++++++++++++++---- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/middleware/lpa-overview.middleware.js b/src/middleware/lpa-overview.middleware.js index 489e545ea..369b956b8 100644 --- a/src/middleware/lpa-overview.middleware.js +++ b/src/middleware/lpa-overview.middleware.js @@ -51,12 +51,14 @@ const fetchEntityCounts = fetchOneFromAllDatasets({ * @param {string} [dataset.endpoint] - Optional endpoint URL * @param {string} dataset.status - Dataset status * @param {number} dataset.endpointCount - Number of endpoints + * @param {number} dataset.endpointErrorCount - Number of endpoints with error + * @param {number} dataset.issueCount - Number of issues * @returns {number[]} Updated accumulator */ const orgStatsReducer = (accumulator, dataset) => { if (dataset.endpointCount > 0) accumulator[0]++ - if (dataset.status === 'Needs fixing') accumulator[1]++ - if (dataset.status === 'Error') accumulator[2]++ + if (dataset.issueCount > 0) accumulator[1]++ + if (dataset.endpointErrorCount > 0) accumulator[2]++ return accumulator } @@ -214,6 +216,7 @@ export function prepareDatasetObjects (req, res, next) { } const endpointCount = datasetEndpoints.length + const endpointErrorCount = datasetEndpoints.filter(endpoint => endpoint.latest_status !== '200').length const allError = datasetEndpoints.every(endpoint => endpoint.latest_status !== '200') const someError = datasetEndpoints.some(endpoint => endpoint.latest_status !== '200') const httpStatus = allError ? datasetEndpoints[0]?.latest_status : undefined @@ -230,7 +233,7 @@ export function prepareDatasetObjects (req, res, next) { status = 'Live' } - return { dataset, error, issueCount, status, endpointCount } + return { dataset, error, issueCount, status, endpointCount, endpointErrorCount } }) next() @@ -259,7 +262,6 @@ export function prepareOverviewTemplateParams (req, res, next) { for (const provision of provisions ?? []) { provisionData.set(provision.dataset, provision) } - // add in any of the missing key 8 datasets const keys = new Set(datasets.map(d => d.dataset)) availableDatasets.forEach((dataset) => { @@ -276,10 +278,8 @@ export function prepareOverviewTemplateParams (req, res, next) { }) const isODPMember = provisions.findIndex((p) => p.project === 'open-digital-planning') >= 0 - const totalDatasets = datasets.length const [datasetsWithEndpoints, datasetsWithIssues, datasetsWithErrors] = datasets.reduce(orgStatsReducer, [0, 0, 0]) - const datasetsByReason = _.groupBy(datasets, (ds) => { const reason = provisionData.get(ds.dataset)?.provision_reason switch (reason) { diff --git a/src/routes/schemas.js b/src/routes/schemas.js index e30314c04..af2c006e2 100644 --- a/src/routes/schemas.js +++ b/src/routes/schemas.js @@ -128,7 +128,8 @@ const DatasetItem = v.strictObject({ project: v.optional(v.string()), // synthetic entry, represents a user friendly count (e.g. count missing value in a column as 1 issue) numIssues: v.optional(v.number()), - notice: v.optional(DeadlineNoticeField) + notice: v.optional(DeadlineNoticeField), + endpointErrorCount: v.optional(v.number()) }) export const OrgOverviewPage = v.strictObject({ diff --git a/src/views/organisations/overview.html b/src/views/organisations/overview.html index 7c120fbe9..ead6617a4 100644 --- a/src/views/organisations/overview.html +++ b/src/views/organisations/overview.html @@ -38,7 +38,8 @@

{{ dataset.error }}

{% endif %} {% elif dataset.status == 'Needs fixing' %} -

There {{ "is" | pluralise(dataset.issueCount) }} {{ dataset.issueCount }} {{ "issue" | pluralise(dataset.issueCount) }} in this dataset

+ {% set totalIssues = (dataset.issueCount or 0) + (dataset.endpointErrorCount or 0) %} +

There {{ "is" | pluralise(totalIssues) }} {{ totalIssues }} {{ "issue" | pluralise(totalIssues) }} in this dataset

{% else %}

Endpoint URL submitted

{% endif %} diff --git a/test/unit/middleware/lpa-overview.middleware.test.js b/test/unit/middleware/lpa-overview.middleware.test.js index a0617a891..8514047ea 100644 --- a/test/unit/middleware/lpa-overview.middleware.test.js +++ b/test/unit/middleware/lpa-overview.middleware.test.js @@ -30,28 +30,32 @@ const reqTemplate = { issueCount: 0, endpointCount: 1, error: undefined, - status: 'Live' + status: 'Live', + endpointErrorCount: 0 }, { dataset: 'dataset2', issueCount: 0, endpointCount: 0, error: undefined, - status: 'Needs fixing' + status: 'Needs fixing', + endpointErrorCount: 0 }, { dataset: 'dataset3', issueCount: 0, endpointCount: 1, error: undefined, - status: 'Error' + status: 'Error', + endpointErrorCount: 1 }, { dataset: 'dataset4', issueCount: 0, endpointCount: 0, error: 'There was a 404 error', - status: 'Error' + status: 'Error', + endpointErrorCount: 1 } ], @@ -80,6 +84,7 @@ describe('lpa-overview.middleware', () => { describe('prepareOverviewTemplateParams', () => { it('should render the overview page', async () => { const req = structuredClone(reqTemplate) + req.datasets[1].issueCount = 1 const res = { render: vi.fn() } prepareOverviewTemplateParams(req, res, () => { }) @@ -88,12 +93,12 @@ describe('lpa-overview.middleware', () => { organisation: { name: 'Example LPA', organisation: 'LPA' }, datasets: { statutory: expect.arrayContaining([ - { endpointCount: 1, status: 'Live', dataset: 'dataset1', error: undefined, issueCount: 0 }, - { endpointCount: 1, status: 'Error', dataset: 'dataset3', error: undefined, issueCount: 0 } + { endpointCount: 1, status: 'Live', dataset: 'dataset1', error: undefined, issueCount: 0, endpointErrorCount: 0 }, + { endpointCount: 1, status: 'Error', dataset: 'dataset3', error: undefined, issueCount: 0, endpointErrorCount: 1 } ]), other: expect.arrayContaining([ - { endpointCount: 0, status: 'Needs fixing', dataset: 'dataset2', error: undefined, issueCount: 0 }, - { endpointCount: 0, status: 'Error', dataset: 'dataset4', error: 'There was a 404 error', issueCount: 0 } + { endpointCount: 0, status: 'Needs fixing', dataset: 'dataset2', error: undefined, issueCount: 1, endpointErrorCount: 0 }, + { endpointCount: 0, status: 'Error', dataset: 'dataset4', error: 'There was a 404 error', issueCount: 0, endpointErrorCount: 1 } ]) }, totalDatasets: 4, @@ -138,6 +143,33 @@ describe('lpa-overview.middleware', () => { expect(ds4.status).toBe('Error') expect(ds4.error).toBe(req.datasets[3].error) // Error message should be left untouched }) + + it('should display a combined count of issues and endpoint errors in the dataset', () => { + const req = structuredClone(reqTemplate) + req.datasets[1].issueCount = 1 + req.datasets[1].endpointErrorCount = 2 + const res = { render: vi.fn() } + + prepareOverviewTemplateParams(req, res, () => { }) + + const { doc } = getRenderedErrorCards(req.templateParams) + const hint = doc.querySelector('[data-dataset-status="Needs fixing"] .govuk-task-list__hint') + + expect(hint?.textContent.trim()).toBe('There are 3 issues in this dataset') + }) + + it('should display a count of issue when there is only one issue', () => { + const req = structuredClone(reqTemplate) + req.datasets[1].issueCount = 1 + const res = { render: vi.fn() } + + prepareOverviewTemplateParams(req, res, () => { }) + + const { doc } = getRenderedErrorCards(req.templateParams) + const hint = doc.querySelector('[data-dataset-status="Needs fixing"] .govuk-task-list__hint') + + expect(hint?.textContent.trim()).toBe('There is 1 issue in this dataset') + }) }) describe('prepareDatasetObjects()', () => { From 28ff1173df0de8046203685956c48f5e0c9fbfdb Mon Sep 17 00:00:00 2001 From: Feba Date: Thu, 10 Jul 2025 11:36:28 +0100 Subject: [PATCH 2/4] update endpoint url error count --- src/middleware/lpa-overview.middleware.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware/lpa-overview.middleware.js b/src/middleware/lpa-overview.middleware.js index 369b956b8..f940a2474 100644 --- a/src/middleware/lpa-overview.middleware.js +++ b/src/middleware/lpa-overview.middleware.js @@ -57,8 +57,8 @@ const fetchEntityCounts = fetchOneFromAllDatasets({ */ const orgStatsReducer = (accumulator, dataset) => { if (dataset.endpointCount > 0) accumulator[0]++ - if (dataset.issueCount > 0) accumulator[1]++ - if (dataset.endpointErrorCount > 0) accumulator[2]++ + if (dataset.issueCount > 0 && dataset.status === 'Needs fixing') accumulator[1]++ + if (dataset.endpointErrorCount > 0) accumulator[2] += dataset.endpointErrorCount return accumulator } From 47fac00a8455bf33529e2a3829356c8d36097e7c Mon Sep 17 00:00:00 2001 From: Feba Date: Thu, 10 Jul 2025 15:16:31 +0100 Subject: [PATCH 3/4] revert last commit change --- src/middleware/lpa-overview.middleware.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware/lpa-overview.middleware.js b/src/middleware/lpa-overview.middleware.js index f940a2474..d5b4ffcd1 100644 --- a/src/middleware/lpa-overview.middleware.js +++ b/src/middleware/lpa-overview.middleware.js @@ -57,8 +57,8 @@ const fetchEntityCounts = fetchOneFromAllDatasets({ */ const orgStatsReducer = (accumulator, dataset) => { if (dataset.endpointCount > 0) accumulator[0]++ - if (dataset.issueCount > 0 && dataset.status === 'Needs fixing') accumulator[1]++ - if (dataset.endpointErrorCount > 0) accumulator[2] += dataset.endpointErrorCount + if (dataset.status === 'Needs fixing') accumulator[1]++ + if (dataset.status === 'Error') accumulator[2]++ return accumulator } From e6a17240dbe0520890a725869a526afc41f484c6 Mon Sep 17 00:00:00 2001 From: Feba Date: Tue, 15 Jul 2025 11:39:07 +0100 Subject: [PATCH 4/4] updated middle box text --- src/views/organisations/overview.html | 2 +- test/unit/views/organisations/lpaOverviewPage.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/organisations/overview.html b/src/views/organisations/overview.html index ead6617a4..3c2f4e682 100644 --- a/src/views/organisations/overview.html +++ b/src/views/organisations/overview.html @@ -112,7 +112,7 @@

{{datasetsWithErrors}} - endpoint URL{{ "s" if (datasetsWithErrors != 1) }} with errors + dataset{{ "s" if (datasetsWithErrors != 1) }} with endpoint errors
diff --git a/test/unit/views/organisations/lpaOverviewPage.test.js b/test/unit/views/organisations/lpaOverviewPage.test.js index 92c0cf67b..652f768b9 100644 --- a/test/unit/views/organisations/lpaOverviewPage.test.js +++ b/test/unit/views/organisations/lpaOverviewPage.test.js @@ -58,7 +58,7 @@ describe(`LPA Overview Page (seed: ${seed})`, () => { it('Datasets with errors gives the correct value', () => { expect(statsBoxes[1].textContent).toContain(params.datasetsWithErrors) - expect(statsBoxes[1].textContent).toMatch(/endpoint URLs? with errors/) + expect(statsBoxes[1].textContent).toMatch(/datasets? with endpoint errors/) }) it('Datasets with issues gives the correct value', () => {