From 3b7922ab45455ba9609fd3d4c91b06f43521cf39 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Fri, 27 Sep 2024 16:24:32 +0100 Subject: [PATCH 01/28] added links to flood warnings target areas in thresholds --- server/models/views/lib/find-min-threshold.js | 2 +- .../views/lib/process-imtd-thresholds.js | 27 ++- server/models/views/station.js | 6 +- server/routes/station.js | 1 + server/src/js/components/chart.js | 62 ++++--- server/src/js/components/map/tooltip.js | 158 ------------------ server/src/js/components/tooltip.js | 66 ++++++++ server/src/js/core.js | 4 + server/src/sass/application.scss | 1 + .../src/sass/components/_chart-controls.scss | 126 +++++++------- .../sass/components/_flood-impact-list.scss | 149 ++++++++++------- .../sass/components/_toggle-list-display.scss | 5 +- server/src/sass/components/_toggletip.scss | 42 ++--- server/src/sass/components/_tooltip.scss | 121 ++++++++++++++ server/views/partials/latest-levels.html | 4 +- server/views/station.html | 6 +- test/{models => data}/floods.js | 0 test/data/taThresholdsData.json | 30 ++++ test/data/warning.json | 19 +++ test/models/lib/process-imtd-thresholds.js | 21 +-- test/routes/target-area.js | 4 +- 21 files changed, 489 insertions(+), 365 deletions(-) delete mode 100644 server/src/js/components/map/tooltip.js create mode 100644 server/src/js/components/tooltip.js create mode 100644 server/src/sass/components/_tooltip.scss rename test/{models => data}/floods.js (100%) create mode 100644 test/data/warning.json diff --git a/server/models/views/lib/find-min-threshold.js b/server/models/views/lib/find-min-threshold.js index cf0909c36..360990474 100644 --- a/server/models/views/lib/find-min-threshold.js +++ b/server/models/views/lib/find-min-threshold.js @@ -31,7 +31,7 @@ function filterImtdThresholds (imtdThresholds) { return { alert: minObjectA ? minObjectA.value : null, - warning: minObjectW ? minObjectW.value : null + warning: minObjectW || null } } diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 0d84f7e8f..549b6c17f 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -17,17 +17,26 @@ function processThreshold (threshold, stationStageDatum, stationSubtract, postPr function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess) { const thresholds = [] - const imtdThresholdWarning = processThreshold(imtdThresholds?.warning, stationStageDatum, stationSubtract, postProcess) + const imtdThresholdWarning = processThreshold(imtdThresholds?.warning?.value, stationStageDatum, stationSubtract, postProcess) + // Correct threshold value if value > zero (Above Ordnance Datum) [FSR-595] if (imtdThresholdWarning) { - // Correct threshold value if value > zero (Above Ordnance Datum) [FSR-595] - thresholds.push({ - id: 'warningThreshold', - description: 'Property flooding is possible above this level. One or more flood warnings may be issued', - shortname: 'Possible flood warnings', - value: imtdThresholdWarning - }) + if (imtdThresholds.warning.severity_value) { + const warningType = imtdThresholds.warning.severity_value === 3 ? 'Severe Flood Warning' : 'Flood Warning' + thresholds.push({ + id: 'warningThreshold', + description: `${warningType} issued: ${imtdThresholds.warning.ta_name}`, + shortname: 'Possible flood warnings', + value: imtdThresholdWarning + }) + } else { + thresholds.push({ + id: 'warningThreshold', + description: 'Property flooding is possible above this level. One or more flood warnings may be issued', + shortname: 'Possible flood warnings', + value: imtdThresholdWarning + }) + } } - const imtdThresholdAlert = processThreshold(imtdThresholds?.alert, stationStageDatum, stationSubtract, postProcess) if (imtdThresholdAlert) { thresholds.push({ diff --git a/server/models/views/station.js b/server/models/views/station.js index 904cd05da..0c1886542 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -170,7 +170,7 @@ class ViewModel { oneHourAgo.setHours(oneHourAgo.getHours() - 1) - // check if recent value is over one hour old0 + // check if recent value is over one hour old this.dataOverHourOld = new Date(this.recentValue.ts) < oneHourAgo this.recentValue.dateWhen = 'on ' + moment.tz(this.recentValue.ts, tz).format('D/MM/YY') @@ -248,7 +248,7 @@ class ViewModel { id: 'highest', value: this.station.porMaxValue, description: this.station.thresholdPorMaxDate - ? 'Water reaches the highest level recorded at this measuring station (recorded on ' + this.station.thresholdPorMaxDate + ')' + ? `Water reaches the highest level recorded at this measuring station (${this.station.thresholdPorMaxDate})` : 'Water reaches the highest level recorded at this measuring station', shortname: 'Highest level on record' }) @@ -268,7 +268,7 @@ class ViewModel { thresholds.push(...processedImtdThresholds) if (this.station.percentile5) { - // Only push typical range if it has a percentil5 + // Only push typical range if it has a percentile5 thresholds.push({ id: 'pc5', value: this.station.percentile5, diff --git a/server/routes/station.js b/server/routes/station.js index 907d37d64..23664da2e 100644 --- a/server/routes/station.js +++ b/server/routes/station.js @@ -10,6 +10,7 @@ module.exports = { handler: async (request, h) => { const { id } = request.params let { direction } = request.params + // const thresholdId = request.query.tid? // Convert human readable url to service parameter direction = direction === 'downstream' ? 'd' : 'u' diff --git a/server/src/js/components/chart.js b/server/src/js/components/chart.js index 227a6ee4e..914f90f42 100644 --- a/server/src/js/components/chart.js +++ b/server/src/js/components/chart.js @@ -2,13 +2,13 @@ // Chart component import '../utils' +import { area as d3Area, line as d3Line, curveMonotoneX } from 'd3-shape' import { axisBottom, axisLeft } from 'd3-axis' import { scaleLinear, scaleBand, scaleTime } from 'd3-scale' import { timeFormat } from 'd3-time-format' +import { timeHour, timeMinute } from 'd3-time' import { select, selectAll, pointer } from 'd3-selection' import { max, bisector, extent } from 'd3-array' -import { timeHour, timeMinute } from 'd3-time' -import { area as d3Area, line as d3Line, curveMonotoneX } from 'd3-shape' const { forEach, simplify } = window.flood.utils @@ -776,6 +776,9 @@ function LineChart (containerId, stationId, data, options = {}) { .attr('class', 'threshold__line') .attr('aria-hidden', true) .attr('x2', xScale(xExtent[1])).attr('y2', 0) + + // Label + const copy = `${threshold.level}m ${threshold.name}`.match(/[\s\S]{1,35}(?!\S)/g, '$&\n') const label = thresholdContainer.append('g') .attr('class', 'threshold-label') const path = label.append('path') @@ -784,10 +787,13 @@ function LineChart (containerId, stationId, data, options = {}) { const text = label.append('text') .attr('class', 'threshold-label__text') text.append('tspan').attr('font-size', 0).text('Threshold: ') - text.append('tspan').attr('x', 10).attr('y', 22).text(`${threshold.level}m ${threshold.name}`) + copy.map((l, i) => text.append('tspan').attr('x', 10).attr('y', (i + 1) * 22).text(l.trim())) const textWidth = Math.round(text.node().getBBox().width) + const textHeight = Math.round(text.node().getBBox().height) path.attr('d', `m-0.5,-0.5 l${textWidth + 20},0 l0,36 l-${((textWidth + 20) / 2) - 7.5},0 l-7.5,7.5 l-7.5,-7.5 l-${((textWidth + 20) / 2) - 7.5},0 l0,-36 l0,0`) - label.attr('transform', `translate(${Math.round(width / 2 - ((textWidth + 20) / 2))}, -46)`) + label.attr('transform', `translate(${Math.round(width / 2 - ((textWidth + 20) / 2))}, -${29 + textHeight})`) + + // Remove button const remove = thresholdContainer.append('a') .attr('role', 'button') .attr('class', 'threshold__remove') @@ -800,6 +806,7 @@ function LineChart (containerId, stationId, data, options = {}) { remove.append('circle').attr('class', 'threshold__remove-button').attr('r', 11) remove.append('line').attr('x1', -3).attr('y1', -3).attr('x2', 3).attr('y2', 3) remove.append('line').attr('y1', -3).attr('x2', -3).attr('x1', 3).attr('y2', 3) + // Set individual elements size and position thresholdContainer.attr('transform', 'translate(0,' + Math.round(yScale(threshold.level)) + ')') }) @@ -931,7 +938,7 @@ function LineChart (containerId, stationId, data, options = {}) { const showTooltip = (tooltipY = 10) => { if (!dataPoint) return // Hide threshold label - thresholdsContainer.select('.threshold--selected .threshold-label').style('visibility', 'hidden') + // thresholdsContainer.select('.threshold--selected .threshold-label').style('visibility', 'hidden') // Set tooltip text const value = dataCache.type === 'river' && (Math.round(dataPoint.value * 100) / 100) <= 0 ? '0' : dataPoint.value.toFixed(2) // *DBL below zero addition tooltipValue.text(`${value}m`) // *DBL below zero addition @@ -1109,7 +1116,8 @@ function LineChart (containerId, stationId, data, options = {}) { // const defaults = { - btnAddThresholdClass: 'defra-button-text-s' + btnAddThresholdClass: 'defra-button-text-s', + btnAddThresholdText: 'Show on chart (Visual only)' } options = Object.assign({}, defaults, options) @@ -1170,16 +1178,30 @@ function LineChart (containerId, stationId, data, options = {}) { const tooltipDescription = tooltipText.append('tspan').attr('class', 'tooltip-text').attr('x', 12).attr('dy', '1.4em') // Add optional 'Add threshold' buttons - document.querySelectorAll('[data-threshold-add]').forEach(container => { - const button = document.createElement('button') - button.className = options.btnAddThresholdClass - button.innerHTML = `Show ${container.getAttribute('data-level')}m threshold on chart (Visual only)` - button.setAttribute('aria-controls', `${containerId}-visualisation`) - button.setAttribute('data-id', container.getAttribute('data-id')) - button.setAttribute('data-threshold-add', '') - button.setAttribute('data-level', container.getAttribute('data-level')) - button.setAttribute('data-name', container.getAttribute('data-name')) - container.parentElement.replaceChild(button, container) + document.querySelectorAll('[data-threshold-add]').forEach((container, i) => { + const tooltip = document.createElement('div') + tooltip.className = 'defra-tooltip defra-tooltip--left' + tooltip.setAttribute('data-tooltip', '') + tooltip.innerHTML = ` + + \ No newline at end of file + diff --git a/server/views/station.html b/server/views/station.html index d68dc9008..d10da525e 100644 --- a/server/views/station.html +++ b/server/views/station.html @@ -263,10 +263,12 @@

Height {% if model.thresholds.length > 0 %}
-

How levels here could affect nearby areas

- {% if model.station.hasImpacts %} +

How levels here could affect nearby areas

+
+ {% if model.station.hasImpacts %} {% endif %} +
{% for band in model.thresholds %}
diff --git a/test/models/floods.js b/test/data/floods.js similarity index 100% rename from test/models/floods.js rename to test/data/floods.js diff --git a/test/data/taThresholdsData.json b/test/data/taThresholdsData.json index 6297a90d0..e3ebf315b 100644 --- a/test/data/taThresholdsData.json +++ b/test/data/taThresholdsData.json @@ -2,6 +2,7 @@ "singleActiveOffline": [ { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -16,6 +17,7 @@ "singleSuspended": [ { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Suspended", @@ -30,6 +32,7 @@ "singleClosed": [ { "rloi_id": 7202, + "station_threshold_id": 123458, "river_name": "River Test", "agency_name": "Test Road", "status": "Closed", @@ -44,6 +47,7 @@ "multipleNormalClosed": [ { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -56,6 +60,7 @@ }, { "rloi_id": 7202, + "station_threshold_id": 123458, "river_name": "River Test", "agency_name": "Test Road", "status": "Closed", @@ -70,6 +75,7 @@ "multipleNormalActiveOfflineWelshNoValues": [ { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -82,6 +88,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -94,6 +101,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Welsh", "agency_name": "Welsh Station", "status": "Active", @@ -108,6 +116,7 @@ "multipleNormalSuspendedClosed": [ { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -120,6 +129,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Suspended", @@ -132,6 +142,7 @@ }, { "rloi_id": 7202, + "station_threshold_id": 123458, "river_name": "River Test", "agency_name": "Test Road", "status": "Closed", @@ -146,6 +157,7 @@ "allClosedOrWelshNoValues": [ { "rloi_id": 7202, + "station_threshold_id": 123458, "river_name": "River Test", "agency_name": "Test Road", "status": "Closed", @@ -158,6 +170,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Welsh", "agency_name": "Welsh Station", "status": "Active", @@ -172,6 +185,7 @@ "singleWelshWithValues": [ { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Welsh", "agency_name": "Welsh Station", "status": "Active", @@ -186,6 +200,7 @@ "multipleLatestLevels": [ { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -198,6 +213,7 @@ }, { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -210,6 +226,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -222,6 +239,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -234,6 +252,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Active", @@ -246,6 +265,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Active", @@ -260,6 +280,7 @@ "overLimitLatestLevels": [ { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -272,6 +293,7 @@ }, { "rloi_id": 7174, + "station_threshold_id": 123459, "river_name": "River Pinn", "agency_name": "Eastcote Road", "status": "Active", @@ -284,6 +306,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -296,6 +319,7 @@ }, { "rloi_id": 7173, + "station_threshold_id": 123465, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -308,6 +332,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Active", @@ -320,6 +345,7 @@ }, { "rloi_id": 7201, + "station_threshold_id": 123457, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Active", @@ -332,6 +358,7 @@ }, { "rloi_id": 1111, + "station_threshold_id": 123500, "river_name": "River Pinn", "agency_name": "Moss Close", "status": "Active", @@ -344,6 +371,7 @@ }, { "rloi_id": 1111, + "station_threshold_id": 123500, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -356,6 +384,7 @@ }, { "rloi_id": 1112, + "station_threshold_id": 123501, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", @@ -368,6 +397,7 @@ }, { "rloi_id": 1113, + "station_threshold_id": 123502, "river_name": "River Pinn", "agency_name": "Avenue Road", "status": "Active", diff --git a/test/data/warning.json b/test/data/warning.json new file mode 100644 index 000000000..cd72105e4 --- /dev/null +++ b/test/data/warning.json @@ -0,0 +1,19 @@ +{ + "station_threshold_id":"1749487", + "station_id":"7332", + "fwis_code":"062FWF46Harpendn", + "fwis_type":"W", + "direction":"u", + "value":"2.1", + "threshold_type":"FW RES FW", + "rloi_id":7332, + "river_name":"River Lee", + "agency_name":"Harpenden", + "status":"Active", + "iswales":false, + "latest_level":"0.935", + "threshold_value":"1.6", + "value_timestamp":"2024-09-26T15:30:00.000Z", + "ta_name":"River Lee at Harpenden", + "severity_value":2 +} diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index aecbb088c..628c7214d 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -1,10 +1,11 @@ const Lab = require('@hapi/lab') const Code = require('@hapi/code') +const data = require('../../data') const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } -const warningExpectedText = { id: 'warningThreshold', description: 'Property flooding is possible above this level. One or more flood warnings may be issued', shortname: 'Possible flood warnings' } +const warningExpectedText = { id: 'warningThreshold', description: 'Flood Warning issued: River Lee at Harpenden', shortname: 'Possible flood warnings' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { Code.expect(thresholds.length).to.equal(2) @@ -15,7 +16,7 @@ function expectThresholds (thresholds, warningThreshold, alertThreshold) { lab.experiment('process IMTD thresholds test', () => { lab.experiment('given post processing is set to false', () => { lab.test('then thresholds should be returned as is', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 0, 0, false) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, false) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then single null thresholds should not be returned', async () => { @@ -34,35 +35,35 @@ lab.experiment('process IMTD thresholds test', () => { }) lab.experiment('given post processing is set to true', () => { lab.test('then thresholds should be returned as is when stageDatum is zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 0, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is greater than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 2.2, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 2.2, 0, true) expectThresholds(thresholds, '-0.10', '-1.10') }) lab.test('then thresholds should be returned as is when stageDatum is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, -2.2, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0, true) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is less than zero and stationSubtract is greater than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, -2.2, 0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0.5, true) expectThresholds(thresholds, '1.60', '0.60') }) lab.test('then thresholds should be returned as is when stageDatum is less than zero and stationSubtract is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, -2.2, -0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, -0.5, true) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as is when stageDatum is equal to zero and stationSubtract is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 0, -0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, -0.5, true) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is equal to zero and stationSubtract is greater than than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 0, 0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0.5, true) expectThresholds(thresholds, '1.60', '0.60') }) lab.test('then thresholds should be returned as is when stageDatum is equal to zero and stationSubtract is zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: 2.1 }, 0, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true) expectThresholds(thresholds, '2.10', '1.10') }) }) diff --git a/test/routes/target-area.js b/test/routes/target-area.js index 19343980c..04ab378a2 100644 --- a/test/routes/target-area.js +++ b/test/routes/target-area.js @@ -192,9 +192,9 @@ lab.experiment('Target-area tests', () => { Code.expect(response.payload).to.contain('

Latest levels

') Code.expect(response.payload).to.contain('

The River Pinn level at Eastcote Road was 0.35 metres. Property flooding is possible when it goes above 1.40 metres.') Code.expect(response.payload).to.contain('

The River Pinn level at Avenue Road was 0.18 metres. Property flooding is possible when it goes above 1.46 metres.') - Code.expect(response.payload).to.contain(' Monitor the River Pinn level at Avenue Road') + Code.expect(response.payload).to.contain('Monitor the River Pinn level at Avenue Road') Code.expect(response.payload).to.contain('

The River Pinn level at Moss Close was 0.13 metres. Property flooding is possible when it goes above 1.15 metres.') - Code.expect(response.payload).to.contain('Monitor the River Pinn level at Moss Close') + Code.expect(response.payload).to.contain('Monitor the River Pinn level at Moss Close') }) lab.test('Check flood severity banner link for Flood warning', async () => { const floodService = require('../../server/services/flood') From e1f79cb547b189159a6ed8160b4007615f8270ff Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Tue, 1 Oct 2024 16:27:10 +0100 Subject: [PATCH 02/28] altered logic for top of normal range and fixed unit tests --- .../views/lib/process-imtd-thresholds.js | 30 +++++++++++++++---- server/models/views/station.js | 14 ++------- test/models/lib/process-imtd-thresholds.js | 22 +++++++------- test/models/station.js | 20 +++++-------- 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 549b6c17f..13de37aac 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -14,7 +14,7 @@ function processThreshold (threshold, stationStageDatum, stationSubtract, postPr return null } -function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess) { +function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const thresholds = [] const imtdThresholdWarning = processThreshold(imtdThresholds?.warning?.value, stationStageDatum, stationSubtract, postProcess) @@ -31,7 +31,7 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra } else { thresholds.push({ id: 'warningThreshold', - description: 'Property flooding is possible above this level. One or more flood warnings may be issued', + description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings', value: imtdThresholdWarning }) @@ -39,11 +39,29 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra } const imtdThresholdAlert = processThreshold(imtdThresholds?.alert, stationStageDatum, stationSubtract, postProcess) if (imtdThresholdAlert) { + if (Number(imtdThresholdAlert) !== Number(pc5)) { + thresholds.push({ + id: 'alertThreshold', + description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', + shortname: 'Possible flood alerts', + value: imtdThresholdAlert + }) + } else { + thresholds.push({ + id: 'alertThreshold', + description: Number(imtdThresholdAlert) === Number(pc5) + ? 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued' + : 'Top of normal range', + shortname: 'Possible flood alerts', + value: imtdThresholdAlert + }) + } + } else if (pc5) { thresholds.push({ - id: 'alertThreshold', - description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', - shortname: 'Possible flood alerts', - value: imtdThresholdAlert + id: 'pc5', + description: 'Top of normal range. Low lying land flooding possible above this level', + shortname: 'Top of normal range', + value: pc5 }) } return thresholds diff --git a/server/models/views/station.js b/server/models/views/station.js index 0c1886542..e42d27d06 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -262,21 +262,12 @@ class ViewModel { this.imtdThresholds, this.station.stageDatum, this.station.subtract, - this.station.post_process + this.station.post_process, + this.station.percentile5 ) thresholds.push(...processedImtdThresholds) - if (this.station.percentile5) { - // Only push typical range if it has a percentile5 - thresholds.push({ - id: 'pc5', - value: this.station.percentile5, - description: 'This is the top of the normal range', - shortname: 'Top of normal range' - }) - } - // Add impacts if (impacts.length > 0) { this.station.hasImpacts = true @@ -403,6 +394,7 @@ function stationTypeCalculator (stationTypeData) { } return stationType } + function telemetryForecastBuilder (telemetryRawData, forecastRawData, stationType) { const observed = telemetryRawData .filter(telemetry => telemetry._ !== null) // Filter out records where telemetry._ is null diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 628c7214d..ee855c02b 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -4,7 +4,7 @@ const data = require('../../data') const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') -const alertExpectedText = { id: 'alertThreshold', description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } +const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } const warningExpectedText = { id: 'warningThreshold', description: 'Flood Warning issued: River Lee at Harpenden', shortname: 'Possible flood warnings' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { @@ -16,11 +16,11 @@ function expectThresholds (thresholds, warningThreshold, alertThreshold) { lab.experiment('process IMTD thresholds test', () => { lab.experiment('given post processing is set to false', () => { lab.test('then thresholds should be returned as is', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, false) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, false, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then single null thresholds should not be returned', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: null }, 0, 0, false) + const thresholds = processImtdThresholds({ alert: 1.1, warning: null }, 0, 0, false, 1.1) Code.expect(thresholds.length).to.equal(1) Code.expect(thresholds[0]).to.equal({ ...alertExpectedText, value: '1.10' }) }) @@ -35,35 +35,35 @@ lab.experiment('process IMTD thresholds test', () => { }) lab.experiment('given post processing is set to true', () => { lab.test('then thresholds should be returned as is when stageDatum is zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is greater than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 2.2, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 2.2, 0, true, -1.1) expectThresholds(thresholds, '-0.10', '-1.10') }) lab.test('then thresholds should be returned as is when stageDatum is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0, true, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is less than zero and stationSubtract is greater than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, 0.5, true, 0.6) expectThresholds(thresholds, '1.60', '0.60') }) lab.test('then thresholds should be returned as is when stageDatum is less than zero and stationSubtract is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, -0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, -2.2, -0.5, true, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as is when stageDatum is equal to zero and stationSubtract is less than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, -0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, -0.5, true, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) lab.test('then thresholds should be returned as adjusted when stageDatum is equal to zero and stationSubtract is greater than than zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0.5, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0.5, true, 0.6) expectThresholds(thresholds, '1.60', '0.60') }) lab.test('then thresholds should be returned as is when stageDatum is equal to zero and stationSubtract is zero', async () => { - const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true) + const thresholds = processImtdThresholds({ alert: 1.1, warning: data.warning }, 0, 0, true, 1.1) expectThresholds(thresholds, '2.10', '1.10') }) }) diff --git a/test/models/station.js b/test/models/station.js index 02ffd38ff..d373916f4 100644 --- a/test/models/station.js +++ b/test/models/station.js @@ -37,7 +37,7 @@ lab.experiment('Station model test', () => { Code.expect(Result.thresholds[0].values).to.equal([ { id: 'warningThreshold', - description: 'Property flooding is possible above this level. One or more flood warnings may be issued', + description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings', value: '3.64' } @@ -45,12 +45,12 @@ lab.experiment('Station model test', () => { Code.expect(Result.thresholds[2].values).to.equal([ { id: 'alertThreshold', - description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', + description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.22' } ]) - Code.expect(Result.thresholds[4].values).to.equal([ + Code.expect(Result.thresholds[3].values).to.equal([ { id: 'latest', value: '0.81', @@ -68,7 +68,7 @@ lab.experiment('Station model test', () => { Code.expect(Result.thresholds[1].values).to.equal([ { id: 'warningThreshold', - description: 'Property flooding is possible above this level. One or more flood warnings may be issued', + description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings', value: '3.22' } @@ -76,15 +76,9 @@ lab.experiment('Station model test', () => { Code.expect(Result.thresholds[2].values).to.equal([ { id: 'alertThreshold', - description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', + description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '2.84' - }, - { - description: 'This is the top of the normal range', - id: 'pc5', - shortname: 'Top of normal range', - value: '2.84' } ]) }) @@ -225,7 +219,7 @@ lab.experiment('Station model test', () => { Code.expect(Result.thresholds[0].values).to.equal( [ { - description: 'Property flooding is possible above this level. One or more flood warnings may be issued', + description: 'Property flooding is possible above this level', id: 'warningThreshold', shortname: 'Possible flood warnings', value: '4.20' @@ -236,7 +230,7 @@ lab.experiment('Station model test', () => { [ { id: 'alertThreshold', - description: 'Low lying land flooding is possible above this level. One or more flood alerts may be issued', + description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.88' } From 15a2f92aa52e9de4b06c81c6bbf01907bb5ecc79 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 2 Oct 2024 13:55:09 +0100 Subject: [PATCH 03/28] changed chart.js threshold references --- server/src/js/components/chart.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/js/components/chart.js b/server/src/js/components/chart.js index 914f90f42..7cc43d4ad 100644 --- a/server/src/js/components/chart.js +++ b/server/src/js/components/chart.js @@ -1433,8 +1433,8 @@ if (document.getElementById('bar-chart')) { // Line chart if (document.getElementById('line-chart')) { const lineChart = window.flood.charts.createLineChart('line-chart', window.flood.model.id, window.flood.model.telemetry) - const thresholdId = `threshold-${window.flood.model.rloiId}-high` - const threshold = document.querySelector(`[data-id="${window.flood.utils.getParameterByName('tid') || thresholdId}"]`) + const thresholdId = 'threshold-pc5' + const threshold = document.querySelector(`[data-id="${thresholdId}"]`) if (threshold) { lineChart.addThreshold({ id: thresholdId, From 046051802ad886faed9083d5105c6e388e1f573a Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 2 Oct 2024 15:20:47 +0100 Subject: [PATCH 04/28] fixed sonar issues --- .../views/lib/process-imtd-thresholds.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 13de37aac..c293d4cdb 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -1,3 +1,4 @@ +const SEVERE_FLOOD_WARNING_THRESHOLD = 3 function processThreshold (threshold, stationStageDatum, stationSubtract, postProcess) { if (threshold) { if (postProcess) { @@ -21,7 +22,7 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra // Correct threshold value if value > zero (Above Ordnance Datum) [FSR-595] if (imtdThresholdWarning) { if (imtdThresholds.warning.severity_value) { - const warningType = imtdThresholds.warning.severity_value === 3 ? 'Severe Flood Warning' : 'Flood Warning' + const warningType = imtdThresholds.warning.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD ? 'Severe Flood Warning' : 'Flood Warning' thresholds.push({ id: 'warningThreshold', description: `${warningType} issued: ${imtdThresholds.warning.ta_name}`, @@ -56,13 +57,15 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra value: imtdThresholdAlert }) } - } else if (pc5) { - thresholds.push({ - id: 'pc5', - description: 'Top of normal range. Low lying land flooding possible above this level', - shortname: 'Top of normal range', - value: pc5 - }) + } else { + if (pc5) { + thresholds.push({ + id: 'pc5', + description: 'Top of normal range. Low lying land flooding possible above this level', + shortname: 'Top of normal range', + value: pc5 + }) + } } return thresholds } From 8be10c9bed1dfa1891b40e911849c666203f481d Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 3 Oct 2024 11:04:50 +0100 Subject: [PATCH 05/28] refactored code to reduce complexity for Sonarcloud --- .../views/lib/process-imtd-thresholds.js | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index c293d4cdb..d4cfbe96e 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -18,56 +18,63 @@ function processThreshold (threshold, stationStageDatum, stationSubtract, postPr function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const thresholds = [] + const imtdThresholdWarning = calculateWarningThreshold(imtdThresholds, stationStageDatum, stationSubtract, postProcess) + const imtdThresholdAlert = calculateAlertThreshold(imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) + + if (imtdThresholdWarning) { + thresholds.push(imtdThresholdWarning) + } + + if (imtdThresholdAlert) { + thresholds.push(imtdThresholdAlert) + } else if (pc5) { + thresholds.push({ + id: 'pc5', + description: 'Top of normal range. Low lying land flooding possible above this level', + shortname: 'Top of normal range', + value: pc5 + }) + } else { return thresholds } + + return thresholds +} + +function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess) { const imtdThresholdWarning = processThreshold(imtdThresholds?.warning?.value, stationStageDatum, stationSubtract, postProcess) - // Correct threshold value if value > zero (Above Ordnance Datum) [FSR-595] + if (imtdThresholdWarning) { - if (imtdThresholds.warning.severity_value) { - const warningType = imtdThresholds.warning.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD ? 'Severe Flood Warning' : 'Flood Warning' - thresholds.push({ - id: 'warningThreshold', - description: `${warningType} issued: ${imtdThresholds.warning.ta_name}`, - shortname: 'Possible flood warnings', - value: imtdThresholdWarning - }) - } else { - thresholds.push({ - id: 'warningThreshold', - description: 'Property flooding is possible above this level', - shortname: 'Possible flood warnings', - value: imtdThresholdWarning - }) + const warningType = imtdThresholds.warning.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD + ? 'Severe Flood Warning' + : 'Flood Warning' + + return { + id: 'warningThreshold', + description: imtdThresholds.warning.severity_value + ? `${warningType} issued: ${imtdThresholds.warning.ta_name}` + : 'Property flooding is possible above this level', + shortname: 'Possible flood warnings', + value: imtdThresholdWarning } } + + return null +} + +function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const imtdThresholdAlert = processThreshold(imtdThresholds?.alert, stationStageDatum, stationSubtract, postProcess) + if (imtdThresholdAlert) { - if (Number(imtdThresholdAlert) !== Number(pc5)) { - thresholds.push({ - id: 'alertThreshold', - description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', - shortname: 'Possible flood alerts', - value: imtdThresholdAlert - }) - } else { - thresholds.push({ - id: 'alertThreshold', - description: Number(imtdThresholdAlert) === Number(pc5) - ? 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued' - : 'Top of normal range', - shortname: 'Possible flood alerts', - value: imtdThresholdAlert - }) - } - } else { - if (pc5) { - thresholds.push({ - id: 'pc5', - description: 'Top of normal range. Low lying land flooding possible above this level', - shortname: 'Top of normal range', - value: pc5 - }) + return { + id: 'alertThreshold', + description: Number(imtdThresholdAlert) !== Number(pc5) + ? 'Low lying land flooding possible above this level. One or more flood alerts may be issued' + : 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', + shortname: 'Possible flood alerts', + value: imtdThresholdAlert } } - return thresholds + + return null } module.exports = processImtdThresholds From b4fc81ea39432e915114c190415f15119b232eaa Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 3 Oct 2024 12:30:48 +0100 Subject: [PATCH 06/28] updated short name on thresholds to include name of flood warning area --- server/models/views/lib/process-imtd-thresholds.js | 2 +- test/models/lib/process-imtd-thresholds.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index d4cfbe96e..96402de1a 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -52,7 +52,7 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu description: imtdThresholds.warning.severity_value ? `${warningType} issued: ${imtdThresholds.warning.ta_name}` : 'Property flooding is possible above this level', - shortname: 'Possible flood warnings', + shortname: imtdThresholds.warning.severity_value ? `${imtdThresholds.warning.ta_name}` : 'Possible flood warnings', value: imtdThresholdWarning } } diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index ee855c02b..6e5b87016 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -5,7 +5,7 @@ const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } -const warningExpectedText = { id: 'warningThreshold', description: 'Flood Warning issued: River Lee at Harpenden', shortname: 'Possible flood warnings' } +const warningExpectedText = { id: 'warningThreshold', description: 'Flood Warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { Code.expect(thresholds.length).to.equal(2) From 40ca5726fca29107069f8e9c095fb9c46c5c6231 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Tue, 8 Oct 2024 12:15:42 +0100 Subject: [PATCH 07/28] removed incorrect capital letter --- server/models/views/lib/process-imtd-thresholds.js | 4 ++-- test/models/lib/process-imtd-thresholds.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 96402de1a..dd8781d03 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -44,8 +44,8 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu if (imtdThresholdWarning) { const warningType = imtdThresholds.warning.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD - ? 'Severe Flood Warning' - : 'Flood Warning' + ? 'Severe flood warning' + : 'Flood warning' return { id: 'warningThreshold', diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 6e5b87016..0bcabb898 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -5,7 +5,7 @@ const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } -const warningExpectedText = { id: 'warningThreshold', description: 'Flood Warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } +const warningExpectedText = { id: 'warningThreshold', description: 'Flood warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { Code.expect(thresholds.length).to.equal(2) From 33a01cc89689e3f3464a1858c4a7995e67cbcd79 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 9 Oct 2024 14:24:54 +0100 Subject: [PATCH 08/28] CSS fix to handle stations with historical threshold values --- server/src/sass/components/_flood-impact-list.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/sass/components/_flood-impact-list.scss b/server/src/sass/components/_flood-impact-list.scss index d23d58353..356b75b19 100644 --- a/server/src/sass/components/_flood-impact-list.scss +++ b/server/src/sass/components/_flood-impact-list.scss @@ -103,6 +103,8 @@ margin-top: 0; } + + dd:has(+ [style*="display: none"]) &__container, dd:last-of-type &__container { border-bottom: 1px solid $govuk-border-colour; margin-bottom: 10px; From f3acbffd7afe39c51f1f878d1a34da8cf7c1681f Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 14 Oct 2024 14:43:59 +0100 Subject: [PATCH 09/28] added process warning thresholds functions and tests --- .../views/lib/process-imtd-thresholds.js | 13 +-- .../views/lib/process-warning-thresholds.js | 66 ++++++++++++++++ server/models/views/station.js | 6 ++ server/routes/station.js | 1 - test/data/warnings.json | 79 +++++++++++++++++++ test/models/lib/process-imtd-thresholds.js | 2 +- test/models/lib/process-warning-thresholds.js | 37 +++++++++ 7 files changed, 191 insertions(+), 13 deletions(-) create mode 100644 server/models/views/lib/process-warning-thresholds.js create mode 100644 test/data/warnings.json create mode 100644 test/models/lib/process-warning-thresholds.js diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index dd8781d03..fa3df40fb 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -1,4 +1,3 @@ -const SEVERE_FLOOD_WARNING_THRESHOLD = 3 function processThreshold (threshold, stationStageDatum, stationSubtract, postProcess) { if (threshold) { if (postProcess) { @@ -43,21 +42,13 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu const imtdThresholdWarning = processThreshold(imtdThresholds?.warning?.value, stationStageDatum, stationSubtract, postProcess) if (imtdThresholdWarning) { - const warningType = imtdThresholds.warning.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD - ? 'Severe flood warning' - : 'Flood warning' - return { id: 'warningThreshold', - description: imtdThresholds.warning.severity_value - ? `${warningType} issued: ${imtdThresholds.warning.ta_name}` - : 'Property flooding is possible above this level', - shortname: imtdThresholds.warning.severity_value ? `${imtdThresholds.warning.ta_name}` : 'Possible flood warnings', + description: 'Property flooding is possible above this level', + shortname: 'Possible flood warnings', value: imtdThresholdWarning } } - - return null } function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js new file mode 100644 index 000000000..9be307aef --- /dev/null +++ b/server/models/views/lib/process-warning-thresholds.js @@ -0,0 +1,66 @@ +const SEVERE_FLOOD_WARNING_THRESHOLD = 3 +function filterThresholdsBySeverity (thresholds) { + return thresholds.filter(item => + item.fwis_type === 'W' && + item.severity_value !== null && + item.severity_value > 1 + ) +} + +function getMaxForEachFwisCode (thresholds) { + const maxValuesByFwisCode = {} + + thresholds.forEach(threshold => { + const fwisCode = threshold.fwis_code + const severityValue = threshold.severity_value + const thresholdValue = threshold.value + + // Check if there's already a threshold for this fwis_code + if (!maxValuesByFwisCode[fwisCode]) { + // If it's the first threshold for this fwis_code, store it + maxValuesByFwisCode[fwisCode] = threshold + } else { + const currentMax = maxValuesByFwisCode[fwisCode] + + // Compare based on severity_value first + if (severityValue > currentMax.severity_value) { + maxValuesByFwisCode[fwisCode] = threshold + } else if (severityValue === currentMax.severity_value) { + // If severity_value is the same, compare based on the value + if (parseFloat(thresholdValue) > parseFloat(currentMax.value)) { + maxValuesByFwisCode[fwisCode] = threshold + } + } + } + }) + + return Object.values(maxValuesByFwisCode) +} + +function createWarningObject (threshold) { + const warningType = + threshold.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD + ? 'Severe flood warning' + : 'Flood warning' + + return { + id: 'warningThreshold', + description: threshold.severity_value + ? `${warningType} issued: ${threshold.ta_name}` + : 'Property flooding is possible above this level', + shortname: threshold.severity_value + ? `${threshold.ta_name}` + : 'Possible flood warnings', + value: parseFloat(threshold.threshold_value).toFixed(2) + } +} +function processWarningThresholds (thresholds) { + const filteredThresholds = filterThresholdsBySeverity(thresholds) + const maxThresholdsByFwisCode = getMaxForEachFwisCode(filteredThresholds) + + const warningObjects = maxThresholdsByFwisCode.map(createWarningObject) + + return warningObjects +} + +module.exports = processWarningThresholds diff --git a/server/models/views/station.js b/server/models/views/station.js index e42d27d06..a5f922c0c 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -6,6 +6,7 @@ const Forecast = require('./station-forecast') const util = require('../../util') const tz = 'Europe/London' const processImtdThresholds = require('./lib/process-imtd-thresholds') +const processWarningThresholds = require('./lib/process-warning-thresholds') const filterImtdThresholds = require('./lib/find-min-threshold') const bannerIconId3 = 3 @@ -254,6 +255,11 @@ class ViewModel { }) } + if (imtdThresholds?.length > 0) { + const processedWarningThresholds = processWarningThresholds(imtdThresholds) + thresholds.push(...processedWarningThresholds) + } + this.imtdThresholds = imtdThresholds?.length > 0 ? filterImtdThresholds(imtdThresholds) : [] diff --git a/server/routes/station.js b/server/routes/station.js index 23664da2e..907d37d64 100644 --- a/server/routes/station.js +++ b/server/routes/station.js @@ -10,7 +10,6 @@ module.exports = { handler: async (request, h) => { const { id } = request.params let { direction } = request.params - // const thresholdId = request.query.tid? // Convert human readable url to service parameter direction = direction === 'downstream' ? 'd' : 'u' diff --git a/test/data/warnings.json b/test/data/warnings.json new file mode 100644 index 000000000..7c28c02f9 --- /dev/null +++ b/test/data/warnings.json @@ -0,0 +1,79 @@ + +[ + { + "station_threshold_id": "1749487", + "station_id": "7332", + "fwis_code": "062FWF46Harpendn", + "fwis_type": "W", + "direction": "u", + "value": "2.1", + "threshold_type": "FW RES FW", + "rloi_id": 7332, + "river_name": "River Lee", + "agency_name": "Harpenden", + "status": "Active", + "iswales": false, + "latest_level": "0.935", + "threshold_value": "1.6", + "value_timestamp": "2024-09-26T15:30:00.000Z", + "ta_name": "River Lee at Harpenden", + "severity_value": 2 + }, + { + "station_threshold_id": "1749488", + "station_id": "7333", + "fwis_code": "063FWF46Oxford", + "fwis_type": "W", + "direction": "u", + "value": "2.3", + "threshold_type": "FW RES FW", + "rloi_id": 7333, + "river_name": "River Thames", + "agency_name": "Oxford", + "status": "Active", + "iswales": false, + "latest_level": "1.150", + "threshold_value": "1.8", + "value_timestamp": "2024-09-26T15:45:00.000Z", + "ta_name": "River Thames at Oxford", + "severity_value": 2 + }, + { + "station_threshold_id": "1749489", + "station_id": "7334", + "fwis_code": "064FWF46York", + "fwis_type": "W", + "direction": "u", + "value": "2.0", + "threshold_type": "FW RES FW", + "rloi_id": 7334, + "river_name": "River Ouse", + "agency_name": "York", + "status": "Active", + "iswales": false, + "latest_level": "1.050", + "threshold_value": "1.7", + "value_timestamp": "2024-09-26T16:00:00.000Z", + "ta_name": "River Ouse at York", + "severity_value": 3 + }, + { + "station_threshold_id": "1749490", + "station_id": "7335", + "fwis_code": "065FWF46Bath", + "fwis_type": "W", + "direction": "u", + "value": "2.2", + "threshold_type": "FW RES FW", + "rloi_id": 7335, + "river_name": "River Avon", + "agency_name": "Bath", + "status": "Active", + "iswales": false, + "latest_level": "1.100", + "threshold_value": "1.7", + "value_timestamp": "2024-09-26T16:15:00.000Z", + "ta_name": "River Avon at Bath", + "severity_value": 3 + } +] diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 0bcabb898..6f5390cc0 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -5,7 +5,7 @@ const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } -const warningExpectedText = { id: 'warningThreshold', description: 'Flood warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } +const warningExpectedText = { id: 'warningThreshold', description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { Code.expect(thresholds.length).to.equal(2) diff --git a/test/models/lib/process-warning-thresholds.js b/test/models/lib/process-warning-thresholds.js new file mode 100644 index 000000000..34d97d8c0 --- /dev/null +++ b/test/models/lib/process-warning-thresholds.js @@ -0,0 +1,37 @@ +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const data = require('../../data') +const lab = exports.lab = Lab.script() +const processWarningThresholds = require('../../../server/models/views/lib/process-warning-thresholds') + +// const warningExpectedText = { id: 'warningThreshold', description: 'Flood warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } + +lab.experiment('process Warning thresholds test', () => { + lab.test('check warning thresholds are created', async () => { + const thresholds = processWarningThresholds(data.warnings) + console.log(thresholds) + Code.expect(thresholds.length).to.equal(4) + }) + lab.test('check warning threshold text', async () => { + const thresholds = processWarningThresholds(data.warnings) + Code.expect(thresholds[0].description).to.equal('Flood warning issued: River Lee at Harpenden') + Code.expect(thresholds[0].shortname).to.equal('River Lee at Harpenden') + }) + lab.test('check warning threshold value displays with 2 decimal places', async () => { + const thresholds = processWarningThresholds(data.warnings) + Code.expect(thresholds[0].value).to.equal('1.60') + }) + lab.test('check severe warning threshold text', async () => { + const thresholds = processWarningThresholds(data.warnings) + Code.expect(thresholds[2].description).to.equal('Severe flood warning issued: River Ouse at York') + Code.expect(thresholds[2].shortname).to.equal('River Ouse at York') + }) + lab.test('check severe warning threshold value with 2 decimal places', async () => { + const thresholds = processWarningThresholds(data.warnings) + Code.expect(thresholds[2].value).to.equal('1.70') + }) + lab.test('check no warning thresholds is handled', async () => { + const thresholds = processWarningThresholds([]) + Code.expect(thresholds).to.equal([]) + }) +}) From 54c45bdc6d9d10a3fbd3a2c7ef6b63a286c13d09 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 14 Oct 2024 15:02:46 +0100 Subject: [PATCH 10/28] fixing sonar issues --- .../views/lib/process-warning-thresholds.js | 24 +++++++------------ test/data/warnings.json | 19 +++++++++++++++ test/models/lib/process-warning-thresholds.js | 6 ++++- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index 9be307aef..6c5716b5c 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -20,16 +20,12 @@ function getMaxForEachFwisCode (thresholds) { // If it's the first threshold for this fwis_code, store it maxValuesByFwisCode[fwisCode] = threshold } else { - const currentMax = maxValuesByFwisCode[fwisCode] - - // Compare based on severity_value first - if (severityValue > currentMax.severity_value) { - maxValuesByFwisCode[fwisCode] = threshold - } else if (severityValue === currentMax.severity_value) { - // If severity_value is the same, compare based on the value - if (parseFloat(thresholdValue) > parseFloat(currentMax.value)) { - maxValuesByFwisCode[fwisCode] = threshold - } + const currentMax = maxValuesByFwisCode[fwisCode]; + + // Compare based on severity_value first, or if severity_value is the same, compare based on the threshold value + if (severityValue > currentMax.severity_value || + (severityValue === currentMax.severity_value && parseFloat(thresholdValue) > parseFloat(currentMax.value))) { + maxValuesByFwisCode[fwisCode] = threshold; } } }) @@ -45,12 +41,8 @@ function createWarningObject (threshold) { return { id: 'warningThreshold', - description: threshold.severity_value - ? `${warningType} issued: ${threshold.ta_name}` - : 'Property flooding is possible above this level', - shortname: threshold.severity_value - ? `${threshold.ta_name}` - : 'Possible flood warnings', + description: `${warningType} issued: ${threshold.ta_name}`, + shortname: `${threshold.ta_name}`, value: parseFloat(threshold.threshold_value).toFixed(2) } } diff --git a/test/data/warnings.json b/test/data/warnings.json index 7c28c02f9..4906bf292 100644 --- a/test/data/warnings.json +++ b/test/data/warnings.json @@ -75,5 +75,24 @@ "value_timestamp": "2024-09-26T16:15:00.000Z", "ta_name": "River Avon at Bath", "severity_value": 3 + }, + { + "station_threshold_id": "1749490", + "station_id": "7335", + "fwis_code": "065FWF46Bath", + "fwis_type": "W", + "direction": "u", + "value": "2.2", + "threshold_type": "FW RES FW", + "rloi_id": 7335, + "river_name": "River Avon", + "agency_name": "Bath", + "status": "Active", + "iswales": false, + "latest_level": "1.100", + "threshold_value": "1.4", + "value_timestamp": "2024-09-26T16:15:00.000Z", + "ta_name": "River Avon at Bath", + "severity_value": 3 } ] diff --git a/test/models/lib/process-warning-thresholds.js b/test/models/lib/process-warning-thresholds.js index 34d97d8c0..4cc7d9e25 100644 --- a/test/models/lib/process-warning-thresholds.js +++ b/test/models/lib/process-warning-thresholds.js @@ -7,7 +7,7 @@ const processWarningThresholds = require('../../../server/models/views/lib/proce // const warningExpectedText = { id: 'warningThreshold', description: 'Flood warning issued: River Lee at Harpenden', shortname: 'River Lee at Harpenden' } lab.experiment('process Warning thresholds test', () => { - lab.test('check warning thresholds are created', async () => { + lab.test('check correct number of warning thresholds are created', async () => { const thresholds = processWarningThresholds(data.warnings) console.log(thresholds) Code.expect(thresholds.length).to.equal(4) @@ -30,6 +30,10 @@ lab.experiment('process Warning thresholds test', () => { const thresholds = processWarningThresholds(data.warnings) Code.expect(thresholds[2].value).to.equal('1.70') }) + lab.test('check only the highest warning is used when multiple', async () => { + const thresholds = processWarningThresholds(data.warnings) + Code.expect(thresholds[3].value).to.equal('1.70') + }) lab.test('check no warning thresholds is handled', async () => { const thresholds = processWarningThresholds([]) Code.expect(thresholds).to.equal([]) From 1625dc0d7361944d7aa3c3aef9d0553f27e87b84 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 14 Oct 2024 15:09:23 +0100 Subject: [PATCH 11/28] fixed linting issue --- server/models/views/lib/process-warning-thresholds.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index 6c5716b5c..5ef13ed9f 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -20,12 +20,12 @@ function getMaxForEachFwisCode (thresholds) { // If it's the first threshold for this fwis_code, store it maxValuesByFwisCode[fwisCode] = threshold } else { - const currentMax = maxValuesByFwisCode[fwisCode]; - + const currentMax = maxValuesByFwisCode[fwisCode] + // Compare based on severity_value first, or if severity_value is the same, compare based on the threshold value - if (severityValue > currentMax.severity_value || + if (severityValue > currentMax.severity_value || (severityValue === currentMax.severity_value && parseFloat(thresholdValue) > parseFloat(currentMax.value))) { - maxValuesByFwisCode[fwisCode] = threshold; + maxValuesByFwisCode[fwisCode] = threshold } } }) From 634901c04f7467bb9333c2de7f40e9fb4fd2f063 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 14 Oct 2024 15:14:33 +0100 Subject: [PATCH 12/28] sonar fix --- server/models/views/lib/process-imtd-thresholds.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index fa3df40fb..97ccaadf1 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -49,6 +49,8 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu value: imtdThresholdWarning } } + + return null } function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { From 6fc7009c6b18518eeb3bce572f3facce85a3a939 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Tue, 15 Oct 2024 11:05:34 +0100 Subject: [PATCH 13/28] fixed chart label and latest levels CSS --- server/models/views/lib/process-imtd-thresholds.js | 2 +- server/src/sass/components/_latest-levels-box.scss | 4 +++- test/models/lib/process-imtd-thresholds.js | 2 +- test/models/station.js | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 97ccaadf1..c175910ee 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -62,7 +62,7 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt description: Number(imtdThresholdAlert) !== Number(pc5) ? 'Low lying land flooding possible above this level. One or more flood alerts may be issued' : 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', - shortname: 'Possible flood alerts', + shortname: Number(imtdThresholdAlert) !== Number(pc5) ? 'Possible flood alerts' : 'Top of normal range', value: imtdThresholdAlert } } diff --git a/server/src/sass/components/_latest-levels-box.scss b/server/src/sass/components/_latest-levels-box.scss index 98886a2b5..e582444bd 100644 --- a/server/src/sass/components/_latest-levels-box.scss +++ b/server/src/sass/components/_latest-levels-box.scss @@ -9,6 +9,8 @@ @include govuk-font($size: 16); margin-top: 0px; margin-bottom: 15px; + padding-top: 5px; + padding-bottom: 4px; font-weight: bold; text-transform: uppercase; background-color: #1C70B8; @@ -19,4 +21,4 @@ color: $govuk-secondary-text-colour; margin: 0; } -} \ No newline at end of file +} diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 6f5390cc0..797bb9605 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -4,7 +4,7 @@ const data = require('../../data') const lab = exports.lab = Lab.script() const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') -const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts' } +const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Top of normal range' } const warningExpectedText = { id: 'warningThreshold', description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings' } function expectThresholds (thresholds, warningThreshold, alertThreshold) { diff --git a/test/models/station.js b/test/models/station.js index d373916f4..0f3e15916 100644 --- a/test/models/station.js +++ b/test/models/station.js @@ -77,7 +77,7 @@ lab.experiment('Station model test', () => { { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', - shortname: 'Possible flood alerts', + shortname: 'Top of normal range', value: '2.84' } ]) From 12e1abac045f7f811a0147e34f9abb8c82783372 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Tue, 15 Oct 2024 16:55:16 +0100 Subject: [PATCH 14/28] stopped displaying inactive warnings as thresholds --- server/models/views/lib/process-warning-thresholds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index 5ef13ed9f..128abcb04 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -3,7 +3,7 @@ function filterThresholdsBySeverity (thresholds) { return thresholds.filter(item => item.fwis_type === 'W' && item.severity_value !== null && - item.severity_value > 1 + (item.severity_value === 2 || item.severity_value === 3) ) } From 8a711792fbd9f59d68a391f2f01497d9b84c11dd Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 16 Oct 2024 09:30:57 +0100 Subject: [PATCH 15/28] sonar fix --- server/models/views/lib/process-warning-thresholds.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index 128abcb04..e0645b25b 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -1,9 +1,10 @@ +const FLOOD_WARNING_THRESHOLD = 2 const SEVERE_FLOOD_WARNING_THRESHOLD = 3 function filterThresholdsBySeverity (thresholds) { return thresholds.filter(item => item.fwis_type === 'W' && item.severity_value !== null && - (item.severity_value === 2 || item.severity_value === 3) + (item.severity_value === FLOOD_WARNING_THRESHOLD || item.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD) ) } From 7f3a926a68a98437b68602119b2261ecbfe0c4ac Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 16 Oct 2024 16:44:08 +0100 Subject: [PATCH 16/28] rejig of logic to show top of normal range --- .../views/lib/process-imtd-thresholds.js | 38 ++++++++++++++----- test/models/station.js | 13 +++++++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index c175910ee..655ffd851 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -24,8 +24,8 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra thresholds.push(imtdThresholdWarning) } - if (imtdThresholdAlert) { - thresholds.push(imtdThresholdAlert) + if (imtdThresholdAlert.length > 0) { + thresholds.push(...imtdThresholdAlert) } else if (pc5) { thresholds.push({ id: 'pc5', @@ -55,19 +55,37 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const imtdThresholdAlert = processThreshold(imtdThresholds?.alert, stationStageDatum, stationSubtract, postProcess) + const imtdThresholdAlerts = [] if (imtdThresholdAlert) { - return { - id: 'alertThreshold', - description: Number(imtdThresholdAlert) !== Number(pc5) - ? 'Low lying land flooding possible above this level. One or more flood alerts may be issued' - : 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', - shortname: Number(imtdThresholdAlert) !== Number(pc5) ? 'Possible flood alerts' : 'Top of normal range', - value: imtdThresholdAlert + // First condition: if imtdThresholdAlert is not equal to Top of Normal Range (pc5) + if (Number(imtdThresholdAlert) !== Number(pc5)) { + imtdThresholdAlerts.push({ + id: 'alertThreshold', + description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', + shortname: 'Possible flood alerts', + value: imtdThresholdAlert + }) + } + // Second condition: if imtdThresholdAlert is equal to Top of Normal Range (pc5) + if (Number(imtdThresholdAlert) === Number(pc5)) { + imtdThresholdAlerts.push({ + id: 'alertThreshold', + description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', + shortname: 'Top of normal range', + value: imtdThresholdAlert + }) + } else { + imtdThresholdAlerts.push({ + id: 'alertThreshold', + description: 'Top of normal range', + shortname: 'Top of normal range', + value: imtdThresholdAlert + }) } } - return null + return imtdThresholdAlerts } module.exports = processImtdThresholds diff --git a/test/models/station.js b/test/models/station.js index 0f3e15916..7b7b1c683 100644 --- a/test/models/station.js +++ b/test/models/station.js @@ -48,6 +48,12 @@ lab.experiment('Station model test', () => { description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.22' + }, + { + id: 'alertThreshold', + description: 'Top of normal range', + shortname: 'Top of normal range', + value: '3.22' } ]) Code.expect(Result.thresholds[3].values).to.equal([ @@ -226,6 +232,7 @@ lab.experiment('Station model test', () => { } ] ) + console.log(Result.thresholds[1].values) Code.expect(Result.thresholds[1].values).to.equal( [ { @@ -233,6 +240,12 @@ lab.experiment('Station model test', () => { description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.88' + }, + { + id: 'alertThreshold', + description: 'Top of normal range', + shortname: 'Top of normal range', + value: '3.88' } ] ) From b1f76c8a51834f1e845e718d9b0e871efa3aaae6 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Wed, 16 Oct 2024 16:52:52 +0100 Subject: [PATCH 17/28] sonar fixes --- server/models/views/lib/process-imtd-thresholds.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 655ffd851..6df28dc1e 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -1,3 +1,5 @@ +const TOP_OF_NORMAL_RANGE = 'Top of normal range' + function processThreshold (threshold, stationStageDatum, stationSubtract, postProcess) { if (threshold) { if (postProcess) { @@ -30,7 +32,7 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra thresholds.push({ id: 'pc5', description: 'Top of normal range. Low lying land flooding possible above this level', - shortname: 'Top of normal range', + shortname: TOP_OF_NORMAL_RANGE, value: pc5 }) } else { return thresholds } @@ -72,14 +74,14 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt imtdThresholdAlerts.push({ id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', - shortname: 'Top of normal range', + shortname: TOP_OF_NORMAL_RANGE, value: imtdThresholdAlert }) } else { imtdThresholdAlerts.push({ id: 'alertThreshold', - description: 'Top of normal range', - shortname: 'Top of normal range', + description: TOP_OF_NORMAL_RANGE, + shortname: TOP_OF_NORMAL_RANGE, value: imtdThresholdAlert }) } From cba8dc5c2f856f0910049ff55d988793dde47c8e Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 11:55:34 +0100 Subject: [PATCH 18/28] altered value on top of normal range --- .../views/lib/process-imtd-thresholds.js | 9 ++- test/models/station.js | 75 +++++++++++++++---- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 6df28dc1e..741a4c023 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -27,7 +27,9 @@ function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtra } if (imtdThresholdAlert.length > 0) { - thresholds.push(...imtdThresholdAlert) + for (const alert of imtdThresholdAlert) { + thresholds.push(alert) + } } else if (pc5) { thresholds.push({ id: 'pc5', @@ -58,7 +60,6 @@ function calculateWarningThreshold (imtdThresholds, stationStageDatum, stationSu function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const imtdThresholdAlert = processThreshold(imtdThresholds?.alert, stationStageDatum, stationSubtract, postProcess) const imtdThresholdAlerts = [] - if (imtdThresholdAlert) { // First condition: if imtdThresholdAlert is not equal to Top of Normal Range (pc5) if (Number(imtdThresholdAlert) !== Number(pc5)) { @@ -77,12 +78,12 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt shortname: TOP_OF_NORMAL_RANGE, value: imtdThresholdAlert }) - } else { + } else if (Number(pc5)) { imtdThresholdAlerts.push({ id: 'alertThreshold', description: TOP_OF_NORMAL_RANGE, shortname: TOP_OF_NORMAL_RANGE, - value: imtdThresholdAlert + value: Number(pc5) }) } } diff --git a/test/models/station.js b/test/models/station.js index 7b7b1c683..793a23ce1 100644 --- a/test/models/station.js +++ b/test/models/station.js @@ -48,15 +48,9 @@ lab.experiment('Station model test', () => { description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.22' - }, - { - id: 'alertThreshold', - description: 'Top of normal range', - shortname: 'Top of normal range', - value: '3.22' } ]) - Code.expect(Result.thresholds[3].values).to.equal([ + Code.expect(Result.thresholds[4].values).to.equal([ { id: 'latest', value: '0.81', @@ -70,7 +64,6 @@ lab.experiment('Station model test', () => { const viewModel = new ViewModel(stationData) const Result = viewModel - Code.expect(Result.thresholds[1].values).to.equal([ { id: 'warningThreshold', @@ -232,7 +225,6 @@ lab.experiment('Station model test', () => { } ] ) - console.log(Result.thresholds[1].values) Code.expect(Result.thresholds[1].values).to.equal( [ { @@ -240,12 +232,6 @@ lab.experiment('Station model test', () => { description: 'Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Possible flood alerts', value: '3.88' - }, - { - id: 'alertThreshold', - description: 'Top of normal range', - shortname: 'Top of normal range', - value: '3.88' } ] ) @@ -315,4 +301,63 @@ lab.experiment('Station model test', () => { Code.expect(Result.telemetryRefined.observed.length).to.equal(4) }) + lab.test('Test station viewModel one warning in force', async () => { + const stationData = data.stationActiveWarning + + const viewModel = new ViewModel(stationData) + + const Result = viewModel + + Code.expect(Result.station.id).to.equal(1001) + Code.expect(Result.banner).to.equal(1) + Code.expect(Result.severityLevel).to.equal('warning') + Code.expect(Result.warningsBanner).to.equal('Flood warning for Coast from Fleetwood to Blackpool') + Code.expect(Result.warningsLink).to.equal('/target-area/012WACFB') + }) + + lab.test('Test station viewModel one alert in force', async () => { + const stationData = data.stationActiveAlert + + const viewModel = new ViewModel(stationData) + + const Result = viewModel + + Code.expect(Result.station.id).to.equal(1001) + Code.expect(Result.banner).to.equal(1) + Code.expect(Result.severityLevel).to.equal('alert') + Code.expect(Result.alertsBanner).to.equal('There is a flood alert within 5 miles of this measuring station') + Code.expect(Result.alertsLink).to.equal('/target-area/061FAG30Alton') + }) + + lab.test('Test station viewModel one Severe Warning in force', async () => { + const stationData = data.stationSevereWarning + + const viewModel = new ViewModel(stationData) + + const Result = viewModel + + Code.expect(Result.station.id).to.equal(1001) + Code.expect(Result.banner).to.equal(1) + Code.expect(Result.severityLevel).to.equal('severe') + Code.expect(Result.severeBanner).to.equal('Severe flood warning for Coast from Fleetwood to Blackpool') + Code.expect(Result.severeLink).to.equal('/target-area/012WACFB') + }) + + lab.test('Test station viewModel multiple Warnings and Alerts in force', async () => { + const stationData = data.stationMultipleAW + + const viewModel = new ViewModel(stationData) + + const Result = viewModel + + Code.expect(Result.station.id).to.equal(1001) + Code.expect(Result.banner).to.equal(2) + Code.expect(Result.severityLevel).to.equal('severe') + Code.expect(Result.severeBanner).to.equal('There are severe flood warnings within 5 miles of this measuring station') + Code.expect(Result.severeLink).to.equal('/alerts-and-warnings?station=1001#severe') + Code.expect(Result.alertsBanner).to.equal('There are flood alerts within 5 miles of this measuring station') + Code.expect(Result.alertsLink).to.equal('/alerts-and-warnings?station=1001#alerts') + Code.expect(Result.warningsBanner).to.equal('There are flood warnings within 5 miles of this measuring station') + Code.expect(Result.warningsLink).to.equal('/alerts-and-warnings?station=1001#warnings') + }) }) From 48878cefe020a79c23e168f43e110d48d4ac681f Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 12:00:52 +0100 Subject: [PATCH 19/28] sonar fix --- server/models/views/lib/process-imtd-thresholds.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 741a4c023..57f44a319 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -85,6 +85,8 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt shortname: TOP_OF_NORMAL_RANGE, value: Number(pc5) }) + } else { + return imtdThresholdAlerts } } From f747197aafa6eb80c20bc895842baaf365ac28a7 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 12:24:26 +0100 Subject: [PATCH 20/28] changed top of normal range to 2dp --- server/models/views/lib/process-imtd-thresholds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 57f44a319..f8fc32229 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -83,7 +83,7 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt id: 'alertThreshold', description: TOP_OF_NORMAL_RANGE, shortname: TOP_OF_NORMAL_RANGE, - value: Number(pc5) + value: parseFloat(pc5).toFixed(2) }) } else { return imtdThresholdAlerts From 48c17be1a2e6af3832d20d2839a5e3c577f411fa Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 13:04:06 +0100 Subject: [PATCH 21/28] rejig of 2dp fix --- server/models/views/lib/process-imtd-thresholds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index f8fc32229..150901618 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -83,7 +83,7 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt id: 'alertThreshold', description: TOP_OF_NORMAL_RANGE, shortname: TOP_OF_NORMAL_RANGE, - value: parseFloat(pc5).toFixed(2) + value: parseFloat(Number(pc5)).toFixed(2) }) } else { return imtdThresholdAlerts From 1431e6d702d3bb150ff97482e6efe73e328a7fbc Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 14:10:59 +0100 Subject: [PATCH 22/28] altered id of top of normal range thresholds --- server/models/views/lib/process-imtd-thresholds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 150901618..49fa288a7 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -80,7 +80,7 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt }) } else if (Number(pc5)) { imtdThresholdAlerts.push({ - id: 'alertThreshold', + id: 'pc5', description: TOP_OF_NORMAL_RANGE, shortname: TOP_OF_NORMAL_RANGE, value: parseFloat(Number(pc5)).toFixed(2) From 7d592bc9ac81212ab8b2ba295a6b26dc84b8fafb Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Thu, 17 Oct 2024 16:56:41 +0100 Subject: [PATCH 23/28] roll back of _chart-controls.scss --- .../src/sass/components/_chart-controls.scss | 126 ++++++++++-------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/server/src/sass/components/_chart-controls.scss b/server/src/sass/components/_chart-controls.scss index e7f048d16..063d6a447 100644 --- a/server/src/sass/components/_chart-controls.scss +++ b/server/src/sass/components/_chart-controls.scss @@ -1,74 +1,84 @@ .defra-chart-controls { position: relative; - overflow: auto; z-index: 1; - margin: -3px -3px 0px -3px; - padding: 3px 3px 0px 3px; -} -.defra-chart-controls__period { - margin: auto; - display: inline-block; - padding-bottom: 4px; -} -.defra-chart-controls__pagination { - display: block; - padding-bottom: 4px; - float: right; -} -.defra-chart-controls-button { - touch-action: manipulation; - @extend .defra-button-text-s; - padding: 7.5px; - display: inline-block; - position: relative; - text-align: center; - text-decoration: none; - &--selected:not(:focus) { - border-bottom: 4px solid govuk-colour('blue'); - margin-bottom: -4px; + overflow: auto; + margin: -3px -3px 0 -3px; + padding: 3px 3px 0 3px; + + &__group { + margin: auto; + display: inline-block; + padding-bottom: 4px; } - &--selected:hover { - border-bottom-color: $govuk-link-hover-colour; + + &__group--pagination { + float: right; + margin-right: 10px; } - &__icon { + + &__button { + @extend .defra-button-text-s; + touch-action: manipulation; + padding: 7.5px; display: inline-block; - } - svg { position: relative; - top: 1px; - margin-left: 5px; - color: govuk-colour('black'); - forced-color-adjust: auto; + text-align: center; + text-decoration: none; + margin-bottom: -4px; + cursor: pointer; + color: govuk-colour('blue'); } - &--back { - padding-left: 0px; - padding-right: 0px; - margin-right: 15px; - svg { - margin-right: 5px; - margin-left: 0px; + + &__button:hover { + color: $govuk-link-hover-colour; + } + &__button--selected { + border-bottom: 4px solid govuk-colour('blue'); + } + &__button:focus { + border-bottom: 4px solid govuk-colour('black'); + background-color: $govuk-focus-colour; + color: govuk-colour('black'); + @include high-contrast-mode-only { + outline: 3px solid transparent; + margin-bottom: 1px; + border: none; } } - &--forward { - padding-left: 0px; - padding-right: 0px; - margin-right: 0px; + &__button[aria-disabled="true"]:focus { + @include high-contrast-mode-only { + background-color: transparent; + box-shadow: none; + } } - &[aria-disabled="true"] { + &__button[aria-disabled="true"], + &__button[aria-disabled="true"]:after, + &__button[aria-disabled="true"]:before { + color: govuk-colour('mid-grey'); cursor: not-allowed; + forced-color-adjust: none; } - &[aria-disabled="true"]:not(:focus) { - color: govuk-colour('mid-grey'); - svg { - color: govuk-colour('mid-grey'); - } + &__button:after, + &__button:before { + display: inline-block; + border-width: 0 2px 2px 0; + width: 8px; + height: 8px; + border-style: solid; + color: $govuk-link-colour; + margin-right: 2px; + margin-left: 2px; } - @media screen and (-ms-high-contrast: active), screen and (forced-colors: active) { - &[aria-disabled="true"] { - color: GrayText !important; - svg { - color: GrayText !important; - } - } + &__button[data-direction="forward"]:after { + content: ''; + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); + } + &__button[data-direction="back"]:before { + content: ''; + -webkit-transform: rotate(135deg); + -ms-transform: rotate(135deg); + transform: rotate(135deg); } } From 666dc9cfc9781337693aa2e75d582ebed21294fc Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 21 Oct 2024 10:27:35 +0100 Subject: [PATCH 24/28] added stage datum calculations to warnings --- .../models/views/lib/process-imtd-thresholds.js | 5 ++++- .../views/lib/process-warning-thresholds.js | 16 +++++++++++----- server/models/views/station.js | 9 +++++++-- test/models/lib/process-imtd-thresholds.js | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 49fa288a7..e0cf48d10 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -93,4 +93,7 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt return imtdThresholdAlerts } -module.exports = processImtdThresholds +module.exports = { + processThreshold, + processImtdThresholds +} diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index e0645b25b..e92f26fa4 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -1,3 +1,5 @@ +const { processThreshold } = require('./process-imtd-thresholds') + const FLOOD_WARNING_THRESHOLD = 2 const SEVERE_FLOOD_WARNING_THRESHOLD = 3 function filterThresholdsBySeverity (thresholds) { @@ -34,24 +36,28 @@ function getMaxForEachFwisCode (thresholds) { return Object.values(maxValuesByFwisCode) } -function createWarningObject (threshold) { +function createWarningObject (threshold, stationStageDatum, stationSubtract, postProcess, pc5) { const warningType = threshold.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD ? 'Severe flood warning' : 'Flood warning' + const imtdThresholdWarning = processThreshold(parseFloat(threshold.threshold_value).toFixed(2), stationStageDatum, stationSubtract, postProcess) + return { id: 'warningThreshold', description: `${warningType} issued: ${threshold.ta_name}`, shortname: `${threshold.ta_name}`, - value: parseFloat(threshold.threshold_value).toFixed(2) + value: imtdThresholdWarning } } -function processWarningThresholds (thresholds) { - const filteredThresholds = filterThresholdsBySeverity(thresholds) +function processWarningThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { + const filteredThresholds = filterThresholdsBySeverity(imtdThresholds) const maxThresholdsByFwisCode = getMaxForEachFwisCode(filteredThresholds) - const warningObjects = maxThresholdsByFwisCode.map(createWarningObject) + const warningObjects = maxThresholdsByFwisCode.map(threshold => + createWarningObject(threshold, stationStageDatum, stationSubtract, postProcess, pc5) + ) return warningObjects } diff --git a/server/models/views/station.js b/server/models/views/station.js index a5f922c0c..d607eab6f 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -5,7 +5,7 @@ const Station = require('./station-data') const Forecast = require('./station-forecast') const util = require('../../util') const tz = 'Europe/London' -const processImtdThresholds = require('./lib/process-imtd-thresholds') +const { processImtdThresholds } = require('./lib/process-imtd-thresholds') const processWarningThresholds = require('./lib/process-warning-thresholds') const filterImtdThresholds = require('./lib/find-min-threshold') @@ -256,7 +256,12 @@ class ViewModel { } if (imtdThresholds?.length > 0) { - const processedWarningThresholds = processWarningThresholds(imtdThresholds) + const processedWarningThresholds = processWarningThresholds( + imtdThresholds, + this.station.stageDatum, + this.station.subtract, + this.station.post_process, + this.station.percentile5) thresholds.push(...processedWarningThresholds) } diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 797bb9605..16d000934 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -2,7 +2,7 @@ const Lab = require('@hapi/lab') const Code = require('@hapi/code') const data = require('../../data') const lab = exports.lab = Lab.script() -const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') +const { processImtdThresholds } = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Top of normal range' } const warningExpectedText = { id: 'warningThreshold', description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings' } From e015c896abe29cd366470276c1e3501cbd4fdd7d Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 21 Oct 2024 10:39:39 +0100 Subject: [PATCH 25/28] sonar fix --- server/models/views/lib/process-warning-thresholds.js | 6 +++--- server/models/views/station.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index e92f26fa4..887f8b3ef 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -36,7 +36,7 @@ function getMaxForEachFwisCode (thresholds) { return Object.values(maxValuesByFwisCode) } -function createWarningObject (threshold, stationStageDatum, stationSubtract, postProcess, pc5) { +function createWarningObject (threshold, stationStageDatum, stationSubtract, postProcess) { const warningType = threshold.severity_value === SEVERE_FLOOD_WARNING_THRESHOLD ? 'Severe flood warning' @@ -51,12 +51,12 @@ function createWarningObject (threshold, stationStageDatum, stationSubtract, pos value: imtdThresholdWarning } } -function processWarningThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { +function processWarningThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess) { const filteredThresholds = filterThresholdsBySeverity(imtdThresholds) const maxThresholdsByFwisCode = getMaxForEachFwisCode(filteredThresholds) const warningObjects = maxThresholdsByFwisCode.map(threshold => - createWarningObject(threshold, stationStageDatum, stationSubtract, postProcess, pc5) + createWarningObject(threshold, stationStageDatum, stationSubtract, postProcess) ) return warningObjects diff --git a/server/models/views/station.js b/server/models/views/station.js index d607eab6f..d88704c21 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -260,8 +260,7 @@ class ViewModel { imtdThresholds, this.station.stageDatum, this.station.subtract, - this.station.post_process, - this.station.percentile5) + this.station.post_process) thresholds.push(...processedWarningThresholds) } From dec2ddc85cd67a831459a559a4d2a2707d0ddf1c Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 21 Oct 2024 12:42:39 +0100 Subject: [PATCH 26/28] bring process threshold into it's own class --- .../views/lib/process-imtd-thresholds.js | 18 ++---------------- server/models/views/lib/process-threshold.js | 17 +++++++++++++++++ .../views/lib/process-warning-thresholds.js | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 server/models/views/lib/process-threshold.js diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index e0cf48d10..66ab5cdd2 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -1,20 +1,6 @@ -const TOP_OF_NORMAL_RANGE = 'Top of normal range' +const processThreshold = require('./process-threshold') -function processThreshold (threshold, stationStageDatum, stationSubtract, postProcess) { - if (threshold) { - if (postProcess) { - if (stationStageDatum > 0) { - threshold = threshold - stationStageDatum - } else if (stationStageDatum <= 0 && stationSubtract > 0) { - threshold = threshold - stationSubtract - } else { - return parseFloat(threshold).toFixed(2) - } - } - return parseFloat(threshold).toFixed(2) - } - return null -} +const TOP_OF_NORMAL_RANGE = 'Top of normal range' function processImtdThresholds (imtdThresholds, stationStageDatum, stationSubtract, postProcess, pc5) { const thresholds = [] diff --git a/server/models/views/lib/process-threshold.js b/server/models/views/lib/process-threshold.js new file mode 100644 index 000000000..a8519eb92 --- /dev/null +++ b/server/models/views/lib/process-threshold.js @@ -0,0 +1,17 @@ +const processThreshold = (threshold, stationStageDatum, stationSubtract, postProcess) => { + if (threshold) { + if (postProcess) { + if (stationStageDatum > 0) { + threshold = threshold - stationStageDatum + } else if (stationStageDatum <= 0 && stationSubtract > 0) { + threshold = threshold - stationSubtract + } else { + return parseFloat(threshold).toFixed(2) + } + } + return parseFloat(threshold).toFixed(2) + } + return null +} + +module.exports = processThreshold diff --git a/server/models/views/lib/process-warning-thresholds.js b/server/models/views/lib/process-warning-thresholds.js index 887f8b3ef..3cca26d70 100644 --- a/server/models/views/lib/process-warning-thresholds.js +++ b/server/models/views/lib/process-warning-thresholds.js @@ -1,4 +1,4 @@ -const { processThreshold } = require('./process-imtd-thresholds') +const processThreshold = require('./process-threshold') const FLOOD_WARNING_THRESHOLD = 2 const SEVERE_FLOOD_WARNING_THRESHOLD = 3 From be140624775283a5b3bca47bc46cecabd38fd905 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Mon, 21 Oct 2024 12:49:14 +0100 Subject: [PATCH 27/28] removed uneeded export --- server/models/views/lib/process-imtd-thresholds.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 66ab5cdd2..741c35a9b 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -80,6 +80,5 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt } module.exports = { - processThreshold, processImtdThresholds } From dacc6a7d66ad02ff82253799b466c6ff172be883 Mon Sep 17 00:00:00 2001 From: LeeGordon83 Date: Tue, 22 Oct 2024 14:55:26 +0100 Subject: [PATCH 28/28] linting changes --- server/models/views/lib/latest-levels.js | 2 +- .../views/lib/process-imtd-thresholds.js | 4 +--- server/models/views/station.js | 21 ++----------------- server/src/js/components/chart.js | 1 - test/models/lib/process-imtd-thresholds.js | 2 +- 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/server/models/views/lib/latest-levels.js b/server/models/views/lib/latest-levels.js index eb083d682..0161eaf71 100644 --- a/server/models/views/lib/latest-levels.js +++ b/server/models/views/lib/latest-levels.js @@ -1,5 +1,5 @@ const { formatElapsedTime } = require('../../../util') -const { processThreshold } = require('./process-imtd-thresholds') // Import processThreshold from the module +const processThreshold = require('./process-threshold') // Import processThreshold from the module const WARNING_THRESHOLD_TYPES = ['FW RES FW', 'FW ACT FW', 'FW ACTCON FW'] diff --git a/server/models/views/lib/process-imtd-thresholds.js b/server/models/views/lib/process-imtd-thresholds.js index 741c35a9b..cb2cc284b 100644 --- a/server/models/views/lib/process-imtd-thresholds.js +++ b/server/models/views/lib/process-imtd-thresholds.js @@ -79,6 +79,4 @@ function calculateAlertThreshold (imtdThresholds, stationStageDatum, stationSubt return imtdThresholdAlerts } -module.exports = { - processImtdThresholds -} +module.exports = processImtdThresholds diff --git a/server/models/views/station.js b/server/models/views/station.js index 1372538da..261de5612 100644 --- a/server/models/views/station.js +++ b/server/models/views/station.js @@ -5,7 +5,8 @@ const Station = require('./station-data') const Forecast = require('./station-forecast') const util = require('../../util') const tz = 'Europe/London' -const { { processImtdThresholds, processThreshold } } = require('./lib/process-imtd-thresholds') +const processImtdThresholds = require('./lib/process-imtd-thresholds') +const processThreshold = require('./lib/process-threshold') const processWarningThresholds = require('./lib/process-warning-thresholds') const filterImtdThresholds = require('./lib/find-min-threshold') @@ -279,16 +280,6 @@ class ViewModel { ) thresholds.push(...processedImtdThresholds) - if (this.station.percentile5) { - // Only push typical range if it has a percentil5 - thresholds.push({ - id: 'pc5', - value: this.station.percentile5, - description: 'This is the top of the normal range', - shortname: TOP_OF_NORMAL_RANGE - }) - } - // Handle chartThreshold: add tidThreshold if a valid tid is present; if not, fallback to 'pc5'; if 'pc5' is unavailable, use 'alertThreshold' with "Top of normal range" description. // Extract tid from request URL if valid let tid = null @@ -304,13 +295,6 @@ class ViewModel { // Set chartThreshold property this.chartThreshold = chartThreshold - // Retrieve the applicable threshold for chartThreshold - const chartThreshold = [getThresholdByThresholdId(tid, imtdThresholds, thresholds, this.station.stageDatum, this.station.subtract, this.station.post_process)].filter(Boolean) - - // Set chartThreshold property - this.chartThreshold = chartThreshold - ->>>>>>> development // Add impacts if (impacts.length > 0) { this.station.hasImpacts = true @@ -437,7 +421,6 @@ function stationTypeCalculator (stationTypeData) { return stationType } - function telemetryForecastBuilder (telemetryRawData, forecastRawData, stationType) { const observed = telemetryRawData .filter(telemetry => telemetry._ !== null) // Filter out records where telemetry._ is null diff --git a/server/src/js/components/chart.js b/server/src/js/components/chart.js index 771d448ab..af3b0e2e2 100644 --- a/server/src/js/components/chart.js +++ b/server/src/js/components/chart.js @@ -808,7 +808,6 @@ function LineChart (containerId, stationId, data, options = {}) { remove.append('line').attr('x1', -3).attr('y1', -3).attr('x2', 3).attr('y2', 3) remove.append('line').attr('y1', -3).attr('x2', -3).attr('x1', 3).attr('y2', 3) - // Set individual elements size and position thresholdContainer.attr('transform', 'translate(0,' + Math.round(yScale(threshold.level)) + ')') }) diff --git a/test/models/lib/process-imtd-thresholds.js b/test/models/lib/process-imtd-thresholds.js index 16d000934..797bb9605 100644 --- a/test/models/lib/process-imtd-thresholds.js +++ b/test/models/lib/process-imtd-thresholds.js @@ -2,7 +2,7 @@ const Lab = require('@hapi/lab') const Code = require('@hapi/code') const data = require('../../data') const lab = exports.lab = Lab.script() -const { processImtdThresholds } = require('../../../server/models/views/lib/process-imtd-thresholds') +const processImtdThresholds = require('../../../server/models/views/lib/process-imtd-thresholds') const alertExpectedText = { id: 'alertThreshold', description: 'Top of normal range. Low lying land flooding possible above this level. One or more flood alerts may be issued', shortname: 'Top of normal range' } const warningExpectedText = { id: 'warningThreshold', description: 'Property flooding is possible above this level', shortname: 'Possible flood warnings' }