From 0e0bf76688c97e9ad09b45596f7e8fb6c3ceaf7f Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Sun, 8 Mar 2026 16:22:22 +1100 Subject: [PATCH 1/2] declared dams layer (#337) --- src/pages/tasking/main.js | 2 + src/pages/tasking/mapLayers/dams.js | 88 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/pages/tasking/mapLayers/dams.js diff --git a/src/pages/tasking/main.js b/src/pages/tasking/main.js index ecca7c41..0d579408 100644 --- a/src/pages/tasking/main.js +++ b/src/pages/tasking/main.js @@ -59,6 +59,7 @@ import { renderFRAOSLayer } from "./mapLayers/frao.js"; import { registerHazardWatchWarningsLayer } from "./mapLayers/hazardwatch.js" import { registerPowerBoundariesGridLayer } from "./mapLayers/power.js"; import { registerWaterNSWBoundariesLayer, registerEPAContaminationSitesLayer } from "./mapLayers/waternsw.js"; +import { registerNSWDeclaredDamsLayer } from "./mapLayers/dams.js"; import { registerBOMLandWarningsLayer } from "./mapLayers/bom.js"; import { registerRainRadarLayer } from "./mapLayers/rainviewer.js"; import { @@ -2464,6 +2465,7 @@ function VM() { registerPowerBoundariesGridLayer(self, map); registerWaterNSWBoundariesLayer(self); registerEPAContaminationSitesLayer(self); + registerNSWDeclaredDamsLayer(self); registerBOMLandWarningsLayer(self); registerBOMRainfallLayer(self, sourceUrl); registerBOMRadarLayer(self, sourceUrl); diff --git a/src/pages/tasking/mapLayers/dams.js b/src/pages/tasking/mapLayers/dams.js new file mode 100644 index 00000000..ea4a48a8 --- /dev/null +++ b/src/pages/tasking/mapLayers/dams.js @@ -0,0 +1,88 @@ +import L from "leaflet"; +import * as esri from "esri-leaflet"; + +const DAMS_URL = + "https://portal.data.nsw.gov.au/arcgis/rest/services/Hosted/Dam_Safety_NSW_Declared_Dams/FeatureServer/0"; + +function getNameFromProps(p) { + if (!p) return "Dam"; + return ( + p.dam_name || + p.place_name || + p.DAM_NAME || + p.NAME || + p.DAM || + p.FACILITY_NAME || + p.STORAGE_NAME || + "Dam" + ); +} + +export function registerNSWDeclaredDamsLayer(vm) { + vm.mapVM.registerPollingLayer("nswDeclaredDams", { + label: "NSW Declared Dams", + menuGroup: "Public Service", + refreshMs: 0, // reference data – no auto-refresh + visibleByDefault: localStorage.getItem("ov.nswDeclaredDams") || false, + fetchFn: async () => ({ ok: true }), + drawFn: (layerGroup, data) => { + if (!data) return; + + const featureLayer = esri.featureLayer({ + url: DAMS_URL, + where: "1=1", + fields: [ + "objectid", + "pkdamid", + "dam_name", + "place_name", + "company", + "owner_type", + "declared_status", + "longitude", + "latitude", + ], + pane: "pane-middle", + pointToLayer: (_geojson, latlng) => { + return L.circleMarker(latlng, { + pane: "pane-middle", + radius: 5, + weight: 1, + color: "#163a63", + fillColor: "#2b7bbb", + fillOpacity: 0.85, + }); + }, + style: () => ({ + weight: 1.2, + color: "#163a63", + fillColor: "#2b7bbb", + fillOpacity: 0.25, + }), + }); + + featureLayer.bindPopup((layer) => { + const p = layer?.feature?.properties || {}; + const name = getNameFromProps(p); + const place = p.place_name || ""; + const company = p.company || ""; + const ownerType = p.owner_type || ""; + const declaredStatus = p.declared_status || ""; + const damId = p.pkdamid ?? ""; + + return [ + `${name}`, + place ? `
Place: ${place}` : "", + company ? `
Company: ${company}` : "", + ownerType ? `
Owner Type: ${ownerType}` : "", + declaredStatus + ? `
Declared Status: ${declaredStatus}` + : "", + damId !== "" ? `
Dam ID: ${damId}` : "", + ].join(""); + }); + + layerGroup.addLayer(featureLayer); + }, + }); +} From 574317a0de1ef25e9ed1e8838798b1e30897eebf Mon Sep 17 00:00:00 2001 From: Tim Dykes Date: Thu, 12 Mar 2026 07:58:05 +1100 Subject: [PATCH 2/2] bug fix with something collapsed re-collaping (#338) --- src/pages/tasking/components/alerts.js | 69 ++++++++++++++++---------- src/pages/tasking/viewmodels/Config.js | 9 ++++ static/pages/tasking.html | 13 +++++ 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/pages/tasking/components/alerts.js b/src/pages/tasking/components/alerts.js index d7945c9c..62eed616 100644 --- a/src/pages/tasking/components/alerts.js +++ b/src/pages/tasking/components/alerts.js @@ -1,7 +1,7 @@ import L from 'leaflet'; import ko from 'knockout'; -const ruleState = new Map(); // key: rule.id -> { collapsed: boolean, lastCount: number } +const ruleState = new Map(); // key: rule.id -> { collapsed: boolean, open: boolean, lastCount: number } /** * SVG hazard icon used in the header @@ -37,7 +37,8 @@ function createLeafletControl(L) { * Render a list of active rules into the container. - RAW html no KO here yet * Each rule: { id, level, title, items:[{id,label}], count, onClick? } */ -function renderRules(container, rules) { +function renderRules(container, rules, opts = {}) { + const allowCollapse = opts.allowCollapse !== false; container.style.display = rules.length ? '' : 'none'; container.innerHTML = ''; @@ -45,7 +46,7 @@ function renderRules(container, rules) { // --- restore / update state for this rule --- let state = ruleState.get(rule.id); if (!state) { - state = { collapsed: false, lastCount: rule.count }; + state = { collapsed: false, open: false, lastCount: rule.count }; } else { // if the count changed while collapsed, auto-expand if (state.collapsed && rule.count !== state.lastCount) { @@ -53,6 +54,10 @@ function renderRules(container, rules) { } state.lastCount = rule.count; } + if (!allowCollapse) { + state.collapsed = false; + state.open = true; + } ruleState.set(rule.id, state); const div = document.createElement('div'); @@ -61,12 +66,15 @@ function renderRules(container, rules) { if (state.collapsed) { div.classList.add('alerts--collapsed'); width = "24px" - } + } + if (!state.collapsed && state.open) { + div.classList.add('alerts--open'); + } div.innerHTML = `
-
Reduces eye strain in low light environments.
+
+ +
+ + +
+
Alerts will start collapsed.
+