From 3ee918afbda742558b30df0f79b754a48ab0c63e Mon Sep 17 00:00:00 2001 From: arsforza Date: Fri, 1 Dec 2023 09:47:17 +0100 Subject: [PATCH 01/33] feat: add river gauge pin AB#25130 --- .../src/app/components/map/map.component.ts | 6 ++++++ interfaces/IBF-dashboard/src/app/config.ts | 6 ++++++ .../IBF-dashboard/src/app/models/poi.model.ts | 6 ++++++ .../src/app/services/point-marker.service.ts | 21 +++++++++++++++++++ .../src/assets/markers/river-gauge-marker.svg | 6 ++++++ 5 files changed, 45 insertions(+) create mode 100644 interfaces/IBF-dashboard/src/assets/markers/river-gauge-marker.svg diff --git a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts index d2ea3158b..3d6645c06 100644 --- a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts +++ b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts @@ -42,6 +42,7 @@ import { EvacuationCenter, HealthSite, RedCrossBranch, + RiverGauge, School, Station, TyphoonTrackPoint, @@ -492,6 +493,11 @@ export class MapComponent implements AfterViewInit, OnDestroy { geoJsonPoint.properties as CommunityNotification, latlng, ); + case IbfLayerName.gauges: + return this.pointMarkerService.createMarkerRiverGauges( + geoJsonPoint.properties as RiverGauge, + latlng, + ); default: return this.pointMarkerService.createMarkerDefault(latlng); } diff --git a/interfaces/IBF-dashboard/src/app/config.ts b/interfaces/IBF-dashboard/src/app/config.ts index 9d6c2dceb..0a3379ace 100644 --- a/interfaces/IBF-dashboard/src/app/config.ts +++ b/interfaces/IBF-dashboard/src/app/config.ts @@ -79,6 +79,12 @@ export const LEAFLET_MARKER_ICON_OPTIONS_COMMUNITY_NOTIFICATION: IconOptions = { iconRetinaUrl: 'assets/markers/community-notification-marker.svg', }; +export const LEAFLET_MARKER_ICON_OPTIONS_RIVER_GAUGE: IconOptions = { + ...LEAFLET_MARKER_ICON_OPTIONS_BASE, + iconUrl: 'assets/markers/river-gauge-marker.svg', + iconRetinaUrl: 'assets/markers/river-gauge-marker.svg', +}; + export const LEAFLET_MAP_OPTIONS: MapOptions = { zoom: 5, layers: [], diff --git a/interfaces/IBF-dashboard/src/app/models/poi.model.ts b/interfaces/IBF-dashboard/src/app/models/poi.model.ts index 994549921..6d79e064f 100644 --- a/interfaces/IBF-dashboard/src/app/models/poi.model.ts +++ b/interfaces/IBF-dashboard/src/app/models/poi.model.ts @@ -79,3 +79,9 @@ export class CommunityNotification { public pointDataId: string; public photoUrl: string; } + +export class RiverGauge { + gaugeName: string; + currentLevel: number; + normalLevel: string; +} diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 4c1d87558..9b82dc328 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -15,6 +15,7 @@ import { LEAFLET_MARKER_ICON_OPTIONS_HEALTH_POINT, LEAFLET_MARKER_ICON_OPTIONS_HEALTH_POINT_EXPOSED, LEAFLET_MARKER_ICON_OPTIONS_RED_CROSS_BRANCH, + LEAFLET_MARKER_ICON_OPTIONS_RIVER_GAUGE, LEAFLET_MARKER_ICON_OPTIONS_SCHOOL, LEAFLET_MARKER_ICON_OPTIONS_SCHOOL_EXPOSED, LEAFLET_MARKER_ICON_OPTIONS_WATER_POINT, @@ -26,6 +27,7 @@ import { EvacuationCenter, HealthSite, RedCrossBranch, + RiverGauge, School, Station, TyphoonTrackPoint, @@ -382,6 +384,25 @@ export class PointMarkerService { return markerInstance; } + public createMarkerRiverGauges( + markerProperties: RiverGauge, + markerLatLng: LatLng, + ): Marker { + const markerTitle = markerProperties.gaugeName; + + const markerInstance = marker(markerLatLng, { + title: markerTitle, + icon: icon(LEAFLET_MARKER_ICON_OPTIONS_RIVER_GAUGE), + }); + // markerInstance.bindPopup(this.createMarkerRedCrossPopup(markerProperties)); + // markerInstance.on( + // 'click', + // this.onMapMarkerClick(AnalyticsEvent.redCrossBranch), + // ); + + return markerInstance; + } + public createThresholdPopup( eapStatusColorText: string, title: string, diff --git a/interfaces/IBF-dashboard/src/assets/markers/river-gauge-marker.svg b/interfaces/IBF-dashboard/src/assets/markers/river-gauge-marker.svg new file mode 100644 index 000000000..175604fba --- /dev/null +++ b/interfaces/IBF-dashboard/src/assets/markers/river-gauge-marker.svg @@ -0,0 +1,6 @@ + + + + + + From 99fa03be22829a16c2abc803a7c7d1e97cc42ebc Mon Sep 17 00:00:00 2001 From: arsforza Date: Fri, 1 Dec 2023 10:08:01 +0100 Subject: [PATCH 02/33] feat: add gauges to legend AB#25130 --- interfaces/IBF-dashboard/src/app/services/map-legend.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts b/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts index 82daf4e46..f3663a91f 100644 --- a/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/map-legend.service.ts @@ -43,6 +43,7 @@ export class MapLegendService { [IbfLayerName.evacuationCenters]: 'evacuation-center-marker.svg', [IbfLayerName.schools]: 'school-marker.svg', [IbfLayerName.communityNotifications]: 'community-notification-marker.svg', + [IbfLayerName.gauges]: 'river-gauge-marker.svg', }; constructor( From 961f40fff974c7f62fd427bcf2984df84af36bd6 Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Fri, 1 Dec 2023 15:30:44 +0100 Subject: [PATCH 03/33] feat: mock data reference & previous water level --- .../dynamic-point-data_water-level-previous.json | 14 ++++++++++++++ .../dynamic-point-data_water-level-reference.json | 14 ++++++++++++++ .../API-service/src/scripts/scripts.service.ts | 6 +++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json create mode 100644 services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json new file mode 100644 index 000000000..142ab1010 --- /dev/null +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json @@ -0,0 +1,14 @@ +[ + { + "fid": 1, + "value": 100 + }, + { + "fid": 2, + "value": 100 + }, + { + "fid": 3, + "value": 100 + } +] diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json new file mode 100644 index 000000000..142ab1010 --- /dev/null +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json @@ -0,0 +1,14 @@ +[ + { + "fid": 1, + "value": 100 + }, + { + "fid": 2, + "value": 100 + }, + { + "fid": 3, + "value": 100 + } +] diff --git a/services/API-service/src/scripts/scripts.service.ts b/services/API-service/src/scripts/scripts.service.ts index 3c7437444..003685671 100644 --- a/services/API-service/src/scripts/scripts.service.ts +++ b/services/API-service/src/scripts/scripts.service.ts @@ -1035,7 +1035,11 @@ export class ScriptsService { return; } - const keys = ['water-level']; + const keys = [ + 'water-level', + 'water-level-reference', + 'water-level-previous', + ]; for (const key of keys) { const payload = new UploadDynamicPointDataDto(); payload.key = key; From 511845ae0bae723b41fa20358c946fd5a56e9b29 Mon Sep 17 00:00:00 2001 From: arsforza Date: Mon, 4 Dec 2023 09:13:39 +0100 Subject: [PATCH 04/33] WIP refactor dynamic point popup AB#25131 --- .../src/app/services/point-marker.service.ts | 124 +++++++++++------- interfaces/IBF-dashboard/src/global.scss | 3 +- 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 9b82dc328..cd02160f3 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -429,6 +429,8 @@ export class PointMarkerService { const addComma = (n) => Math.round(n).toLocaleString('en-US'); + const headerContent = `${title}`; + const forecastBar = `
@@ -446,28 +448,39 @@ export class PointMarkerService {
`; - const infoPopup = ` -
\ - ${title} - \ -
\ -
\ -
\ - ${subtitle} \ -
\ - ${forecastBar} -
\ - ${thresholdName}:
\ - \ -
${addComma( - thresholdValue, - )}
\ -
\ -
\ - ${eapStatusText} \ -
`; - - return infoPopup; + const middleContent = ` +
+ ${subtitle} +
+ ${forecastBar} +
+ ${thresholdName}: +
+
+ ${addComma(thresholdValue)} +
+ `; + const footerContent = ` +
+ ${eapStatusText} +
+ `; + + return this.createDynamicPointPopup( + eapStatusColor, + headerContent, + middleContent, + footerContent, + ); } private createMarkerStationPopup( @@ -520,30 +533,32 @@ export class PointMarkerService { passed: string, ): string { const bg = 'var(--ion-color-ibf-primary)'; - const color = 'var(--ion-color-ibf-white)'; - const trackpointInfoPopup = ` -
-
- TYPHOON TRACK ${passed} -
-
-
-
Date and time: ${dateAndTime}
-
Category (ECWMF): ${category}
-
-
- - - -
-
-
- Coordinate: ${coordinate} -
+ const headerContent = `Typhoon track ${passed}`; + + const middleContent = ` +
+
+
Date and time: ${dateAndTime}
+
Category (ECWMF): ${category}
- `; - return trackpointInfoPopup; +
+ + + +
+
`; + + const footerContent = `
+ Coordinate: ${coordinate} +
`; + + return this.createDynamicPointPopup( + bg, + headerContent, + middleContent, + footerContent, + ); } private createMarkerRedCrossPopup(markerProperties: RedCrossBranch): string { @@ -668,4 +683,25 @@ export class PointMarkerService { return markerInstance; } + + public createDynamicPointPopup( + accentColor: string, + headerContent: string, + middleContent: string, + footerContent: string, + ): string { + const textColor = 'var(--ion-color-ibf-white)'; + + return ` +
+ ${headerContent} +
+
+ ${middleContent} +
+
+ ${footerContent} +
+ `; + } } diff --git a/interfaces/IBF-dashboard/src/global.scss b/interfaces/IBF-dashboard/src/global.scss index 7d23bb52e..eec3a28f1 100644 --- a/interfaces/IBF-dashboard/src/global.scss +++ b/interfaces/IBF-dashboard/src/global.scss @@ -70,7 +70,8 @@ } .leaflet-popup-content-wrapper { - border-radius: 0; + border-radius: 8px; + font-size: 12px; } .leaflet-ibf-aggregate-pane { From 93cc6cd00af233e8512c6b3aa6bee12f6ffa7c6e Mon Sep 17 00:00:00 2001 From: arsforza Date: Mon, 4 Dec 2023 10:37:30 +0100 Subject: [PATCH 05/33] fix: add key to delete point AB#25179 --- services/API-service/src/api/point-data/point-data.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/services/API-service/src/api/point-data/point-data.service.ts b/services/API-service/src/api/point-data/point-data.service.ts index 5c1d5c6bb..23cd863a0 100644 --- a/services/API-service/src/api/point-data/point-data.service.ts +++ b/services/API-service/src/api/point-data/point-data.service.ts @@ -304,6 +304,7 @@ export class PointDataService { await this.dynamicPointDataRepository.delete({ point: { pointDataId: asset.pointDataId }, leadTime: dynamicPointData.leadTime || IsNull(), + key: dynamicPointData.key, timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( dynamicPointData.disasterType, From 44d9012d1fb4e8d4368df67e9a673d19e320fb67 Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Mon, 4 Dec 2023 14:48:36 +0100 Subject: [PATCH 06/33] refactor: merge point-data-dynamic-status into dynamic-point-data AB#25127 --- .../src/app/components/map/map.component.ts | 6 +- .../IBF-dashboard/src/app/models/poi.model.ts | 6 +- .../src/app/services/point-marker.service.ts | 7 +- .../1701157179286-DynamicPointData.ts | 6 + .../flash-floods/waterpoints_internal.json | 486 +++++++++--------- .../point-data-dynamic-status.entity.ts | 37 -- .../src/api/point-data/point-data.module.ts | 7 +- .../src/api/point-data/point-data.service.ts | 62 +-- .../src/scripts/scripts.service.ts | 19 +- 9 files changed, 279 insertions(+), 357 deletions(-) delete mode 100644 services/API-service/src/api/point-data/point-data-dynamic-status.entity.ts diff --git a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts index 3d6645c06..62ce7e3cb 100644 --- a/interfaces/IBF-dashboard/src/app/components/map/map.component.ts +++ b/interfaces/IBF-dashboard/src/app/components/map/map.component.ts @@ -508,7 +508,7 @@ export class MapComponent implements AfterViewInit, OnDestroy { const exposedClass = cluster .getAllChildMarkers() - .some((marker) => marker.feature.properties.exposed) + .some((marker) => marker.feature.properties.dynamicData?.exposure) ? ' exposed' : ''; @@ -563,7 +563,7 @@ export class MapComponent implements AfterViewInit, OnDestroy { }); const exposedLayerData = JSON.parse(JSON.stringify(layer.data)); exposedLayerData.features = exposedLayerData.features.filter( - (f) => f.properties.exposed, + (f) => f.properties.dynamicData?.exposure, ); const mapLayerExposed = geoJSON(exposedLayerData, { pointToLayer: this.getPointToLayerByLayer(layer.name), @@ -577,7 +577,7 @@ export class MapComponent implements AfterViewInit, OnDestroy { }); const nonExposedLayerData = JSON.parse(JSON.stringify(layer.data)); nonExposedLayerData.features = nonExposedLayerData.features.filter( - (f) => !f.properties.exposed, + (f) => !f.properties.dynamicData?.exposure, ); const mapLayerNotExposed = geoJSON(nonExposedLayerData, { pointToLayer: this.getPointToLayerByLayer(layer.name), diff --git a/interfaces/IBF-dashboard/src/app/models/poi.model.ts b/interfaces/IBF-dashboard/src/app/models/poi.model.ts index 6d79e064f..a7b8b9922 100644 --- a/interfaces/IBF-dashboard/src/app/models/poi.model.ts +++ b/interfaces/IBF-dashboard/src/app/models/poi.model.ts @@ -35,7 +35,7 @@ export class Waterpoint { export class HealthSite { name: string; type: string; - exposed: boolean; + dynamicData?: { exposure: string }; } export enum HealthSiteType { @@ -61,13 +61,13 @@ export class EvacuationCenter { export class School { name: string; type: string; - exposed: boolean; + dynamicData?: { exposure: string }; } export class WaterpointInternal { name: string; type: string; - exposed: boolean; + dynamicData?: { exposure: string }; } export class CommunityNotification { public nameVolunteer: string; diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index cd02160f3..5027e9e0a 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -275,7 +275,7 @@ export class PointMarkerService { const markerInstance = marker(markerLatLng, { title: markerTitle, icon: icon( - markerProperties.exposed + markerProperties.dynamicData?.exposure ? LEAFLET_MARKER_ICON_OPTIONS_HEALTH_POINT_EXPOSED : LEAFLET_MARKER_ICON_OPTIONS_HEALTH_POINT, ), @@ -343,7 +343,7 @@ export class PointMarkerService { const markerInstance = marker(markerLatLng, { title: markerTitle, icon: icon( - markerProperties.exposed + markerProperties.dynamicData?.exposure ? LEAFLET_MARKER_ICON_OPTIONS_SCHOOL_EXPOSED : LEAFLET_MARKER_ICON_OPTIONS_SCHOOL, ), @@ -364,11 +364,12 @@ export class PointMarkerService { markerLatLng: LatLng, ): Marker { const markerTitle = markerProperties.name; + console.log('markerProperties: ', markerProperties); const markerInstance = marker(markerLatLng, { title: markerTitle, icon: icon( - markerProperties.exposed + markerProperties.dynamicData?.exposure ? LEAFLET_MARKER_ICON_OPTIONS_WATER_POINT_EXPOSED : LEAFLET_MARKER_ICON_OPTIONS_WATER_POINT, ), diff --git a/services/API-service/migration/1701157179286-DynamicPointData.ts b/services/API-service/migration/1701157179286-DynamicPointData.ts index 1df918513..b096ec9d8 100644 --- a/services/API-service/migration/1701157179286-DynamicPointData.ts +++ b/services/API-service/migration/1701157179286-DynamicPointData.ts @@ -14,6 +14,8 @@ export class DynamicPointData1701157179286 implements MigrationInterface { `ALTER TABLE "IBF-app"."dynamic-point-data" ADD CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, ); + await queryRunner.query(`DROP TABLE "IBF-app"."point-data-dynamic-status"`); + // NOTE: Do not prioritize this, but leave the code here for future reference // await queryRunner.query(`INSERT INTO "IBF-app"."point-data" // ("pointDataId", "countryCodeISO3", "pointDataCategory", "attributes", geom, "referenceId") @@ -36,6 +38,10 @@ export class DynamicPointData1701157179286 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "IBF-app"."point-data-dynamic-status" ("pointDataDynamicStatusId" uuid NOT NULL DEFAULT uuid_generate_v4(), "referenceId" uuid NOT NULL, "timestamp" TIMESTAMP NOT NULL, "exposed" boolean NOT NULL, "leadTime" character varying, CONSTRAINT "PK_e4a407d1bb1af9141b6c659a985" PRIMARY KEY ("pointDataDynamicStatusId"))`, + ); + await queryRunner.query( `ALTER TABLE "IBF-app"."dynamic-point-data" DROP CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a"`, ); diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/waterpoints_internal.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/waterpoints_internal.json index 6d1226fbf..f3fa50ea3 100644 --- a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/waterpoints_internal.json +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/waterpoints_internal.json @@ -1,249 +1,249 @@ { "24-hour": [ - "179", - "273", - "408", - "908", - "1255", - "3413", - "3583", - "3952", - "5402", - "5984", - "6116", - "6142", - "6146", - "7386", - "7889", - "7955", - "11607", - "11647", - "11691", - "13455", - "13953", - "13957", - "14502", - "14511", - "14522", - "14556", - "14835", - "15356", - "15849", - "15871", - "16611", - "16998", - "18130", - "18134", - "18138", - "18143", - "19855", - "20594", - "23129", - "23213", - "23553", - "23833", - "23979", - "23995", - "24286", - "25295", - "25727", - "26497", - "27415", - "27420", - "27468", - "27706", - "27730", - "27949", - "29078", - "29392", - "29553", - "29656", - "29667", - "29811", - "30225", - "30524", - "30720", - "31152", - "31365", - "31442", - "31458", - "31460", - "31607", - "33759", - "34206", - "35588" + { "fid": "179", "value": "true" }, + { "fid": "273", "value": "true" }, + { "fid": "408", "value": "true" }, + { "fid": "908", "value": "true" }, + { "fid": "1255", "value": "true" }, + { "fid": "3413", "value": "true" }, + { "fid": "3583", "value": "true" }, + { "fid": "3952", "value": "true" }, + { "fid": "5402", "value": "true" }, + { "fid": "5984", "value": "true" }, + { "fid": "6116", "value": "true" }, + { "fid": "6142", "value": "true" }, + { "fid": "6146", "value": "true" }, + { "fid": "7386", "value": "true" }, + { "fid": "7889", "value": "true" }, + { "fid": "7955", "value": "true" }, + { "fid": "11607", "value": "true" }, + { "fid": "11647", "value": "true" }, + { "fid": "11691", "value": "true" }, + { "fid": "13455", "value": "true" }, + { "fid": "13953", "value": "true" }, + { "fid": "13957", "value": "true" }, + { "fid": "14502", "value": "true" }, + { "fid": "14511", "value": "true" }, + { "fid": "14522", "value": "true" }, + { "fid": "14556", "value": "true" }, + { "fid": "14835", "value": "true" }, + { "fid": "15356", "value": "true" }, + { "fid": "15849", "value": "true" }, + { "fid": "15871", "value": "true" }, + { "fid": "16611", "value": "true" }, + { "fid": "16998", "value": "true" }, + { "fid": "18130", "value": "true" }, + { "fid": "18134", "value": "true" }, + { "fid": "18138", "value": "true" }, + { "fid": "18143", "value": "true" }, + { "fid": "19855", "value": "true" }, + { "fid": "20594", "value": "true" }, + { "fid": "23129", "value": "true" }, + { "fid": "23213", "value": "true" }, + { "fid": "23553", "value": "true" }, + { "fid": "23833", "value": "true" }, + { "fid": "23979", "value": "true" }, + { "fid": "23995", "value": "true" }, + { "fid": "24286", "value": "true" }, + { "fid": "25295", "value": "true" }, + { "fid": "25727", "value": "true" }, + { "fid": "26497", "value": "true" }, + { "fid": "27415", "value": "true" }, + { "fid": "27420", "value": "true" }, + { "fid": "27468", "value": "true" }, + { "fid": "27706", "value": "true" }, + { "fid": "27730", "value": "true" }, + { "fid": "27949", "value": "true" }, + { "fid": "29078", "value": "true" }, + { "fid": "29392", "value": "true" }, + { "fid": "29553", "value": "true" }, + { "fid": "29656", "value": "true" }, + { "fid": "29667", "value": "true" }, + { "fid": "29811", "value": "true" }, + { "fid": "30225", "value": "true" }, + { "fid": "30524", "value": "true" }, + { "fid": "30720", "value": "true" }, + { "fid": "31152", "value": "true" }, + { "fid": "31365", "value": "true" }, + { "fid": "31442", "value": "true" }, + { "fid": "31458", "value": "true" }, + { "fid": "31460", "value": "true" }, + { "fid": "31607", "value": "true" }, + { "fid": "33759", "value": "true" }, + { "fid": "34206", "value": "true" }, + { "fid": "35588", "value": "true" } ], "6-hour": [ - "48", - "79", - "156", - "620", - "910", - "1070", - "1229", - "1646", - "1751", - "1810", - "2244", - "2587", - "2669", - "3190", - "3257", - "3407", - "3608", - "3684", - "3751", - "3853", - "3920", - "3992", - "4375", - "4447", - "4987", - "5591", - "5704", - "5828", - "5923", - "5923", - "5923", - "5923", - "6098", - "6128", - "6246", - "6253", - "6377", - "6445", - "6872", - "7346", - "7700", - "7873", - "7929", - "8088", - "11181", - "11498", - "12066", - "12191", - "12876", - "13446", - "13592", - "14413", - "14433", - "14528", - "14571", - "14635", - "15071", - "15080", - "15086", - "15174", - "15240", - "15246", - "15267", - "15286", - "15415", - "15701", - "15702", - "16576", - "16991", - "17311", - "17864", - "18066", - "18184", - "18187", - "18190", - "18199", - "18203", - "18205", - "18275", - "18415", - "18483", - "19029", - "19901", - "19977", - "20154", - "20345", - "20406", - "20456", - "20466", - "20531", - "20532", - "20725", - "20881", - "21180", - "21180", - "21180", - "21180", - "21623", - "21624", - "21627", - "21633", - "21634", - "21635", - "21640", - "21642", - "21772", - "22706", - "22720", - "23387", - "23884", - "24333", - "24903", - "25527", - "27789", - "28063", - "28107", - "28130", - "28760", - "28777", - "28915", - "28990", - "29059", - "29062", - "29312", - "29500", - "29931", - "30031", - "30100", - "30395", - "30583", - "31151", - "31817", - "31958", - "31987", - "32158", - "32164", - "32285", - "32309", - "32315", - "32348", - "32354", - "32369", - "32513", - "32547", - "32568", - "32657", - "32735", - "32764", - "32797", - "32801", - "32819", - "32832", - "32936", - "32964", - "33064", - "33163", - "33238", - "33257", - "33688", - "33731", - "33731", - "33731", - "33731", - "33965", - "34116", - "34121", - "34141", - "35825", - "35825", - "35825", - "35825" + { "fid": "48", "value": "true" }, + { "fid": "79", "value": "true" }, + { "fid": "156", "value": "true" }, + { "fid": "620", "value": "true" }, + { "fid": "910", "value": "true" }, + { "fid": "1070", "value": "true" }, + { "fid": "1229", "value": "true" }, + { "fid": "1646", "value": "true" }, + { "fid": "1751", "value": "true" }, + { "fid": "1810", "value": "true" }, + { "fid": "2244", "value": "true" }, + { "fid": "2587", "value": "true" }, + { "fid": "2669", "value": "true" }, + { "fid": "3190", "value": "true" }, + { "fid": "3257", "value": "true" }, + { "fid": "3407", "value": "true" }, + { "fid": "3608", "value": "true" }, + { "fid": "3684", "value": "true" }, + { "fid": "3751", "value": "true" }, + { "fid": "3853", "value": "true" }, + { "fid": "3920", "value": "true" }, + { "fid": "3992", "value": "true" }, + { "fid": "4375", "value": "true" }, + { "fid": "4447", "value": "true" }, + { "fid": "4987", "value": "true" }, + { "fid": "5591", "value": "true" }, + { "fid": "5704", "value": "true" }, + { "fid": "5828", "value": "true" }, + { "fid": "5923", "value": "true" }, + { "fid": "5923", "value": "true" }, + { "fid": "5923", "value": "true" }, + { "fid": "5923", "value": "true" }, + { "fid": "6098", "value": "true" }, + { "fid": "6128", "value": "true" }, + { "fid": "6246", "value": "true" }, + { "fid": "6253", "value": "true" }, + { "fid": "6377", "value": "true" }, + { "fid": "6445", "value": "true" }, + { "fid": "6872", "value": "true" }, + { "fid": "7346", "value": "true" }, + { "fid": "7700", "value": "true" }, + { "fid": "7873", "value": "true" }, + { "fid": "7929", "value": "true" }, + { "fid": "8088", "value": "true" }, + { "fid": "11181", "value": "true" }, + { "fid": "11498", "value": "true" }, + { "fid": "12066", "value": "true" }, + { "fid": "12191", "value": "true" }, + { "fid": "12876", "value": "true" }, + { "fid": "13446", "value": "true" }, + { "fid": "13592", "value": "true" }, + { "fid": "14413", "value": "true" }, + { "fid": "14433", "value": "true" }, + { "fid": "14528", "value": "true" }, + { "fid": "14571", "value": "true" }, + { "fid": "14635", "value": "true" }, + { "fid": "15071", "value": "true" }, + { "fid": "15080", "value": "true" }, + { "fid": "15086", "value": "true" }, + { "fid": "15174", "value": "true" }, + { "fid": "15240", "value": "true" }, + { "fid": "15246", "value": "true" }, + { "fid": "15267", "value": "true" }, + { "fid": "15286", "value": "true" }, + { "fid": "15415", "value": "true" }, + { "fid": "15701", "value": "true" }, + { "fid": "15702", "value": "true" }, + { "fid": "16576", "value": "true" }, + { "fid": "16991", "value": "true" }, + { "fid": "17311", "value": "true" }, + { "fid": "17864", "value": "true" }, + { "fid": "18066", "value": "true" }, + { "fid": "18184", "value": "true" }, + { "fid": "18187", "value": "true" }, + { "fid": "18190", "value": "true" }, + { "fid": "18199", "value": "true" }, + { "fid": "18203", "value": "true" }, + { "fid": "18205", "value": "true" }, + { "fid": "18275", "value": "true" }, + { "fid": "18415", "value": "true" }, + { "fid": "18483", "value": "true" }, + { "fid": "19029", "value": "true" }, + { "fid": "19901", "value": "true" }, + { "fid": "19977", "value": "true" }, + { "fid": "20154", "value": "true" }, + { "fid": "20345", "value": "true" }, + { "fid": "20406", "value": "true" }, + { "fid": "20456", "value": "true" }, + { "fid": "20466", "value": "true" }, + { "fid": "20531", "value": "true" }, + { "fid": "20532", "value": "true" }, + { "fid": "20725", "value": "true" }, + { "fid": "20881", "value": "true" }, + { "fid": "21180", "value": "true" }, + { "fid": "21180", "value": "true" }, + { "fid": "21180", "value": "true" }, + { "fid": "21180", "value": "true" }, + { "fid": "21623", "value": "true" }, + { "fid": "21624", "value": "true" }, + { "fid": "21627", "value": "true" }, + { "fid": "21633", "value": "true" }, + { "fid": "21634", "value": "true" }, + { "fid": "21635", "value": "true" }, + { "fid": "21640", "value": "true" }, + { "fid": "21642", "value": "true" }, + { "fid": "21772", "value": "true" }, + { "fid": "22706", "value": "true" }, + { "fid": "22720", "value": "true" }, + { "fid": "23387", "value": "true" }, + { "fid": "23884", "value": "true" }, + { "fid": "24333", "value": "true" }, + { "fid": "24903", "value": "true" }, + { "fid": "25527", "value": "true" }, + { "fid": "27789", "value": "true" }, + { "fid": "28063", "value": "true" }, + { "fid": "28107", "value": "true" }, + { "fid": "28130", "value": "true" }, + { "fid": "28760", "value": "true" }, + { "fid": "28777", "value": "true" }, + { "fid": "28915", "value": "true" }, + { "fid": "28990", "value": "true" }, + { "fid": "29059", "value": "true" }, + { "fid": "29062", "value": "true" }, + { "fid": "29312", "value": "true" }, + { "fid": "29500", "value": "true" }, + { "fid": "29931", "value": "true" }, + { "fid": "30031", "value": "true" }, + { "fid": "30100", "value": "true" }, + { "fid": "30395", "value": "true" }, + { "fid": "30583", "value": "true" }, + { "fid": "31151", "value": "true" }, + { "fid": "31817", "value": "true" }, + { "fid": "31958", "value": "true" }, + { "fid": "31987", "value": "true" }, + { "fid": "32158", "value": "true" }, + { "fid": "32164", "value": "true" }, + { "fid": "32285", "value": "true" }, + { "fid": "32309", "value": "true" }, + { "fid": "32315", "value": "true" }, + { "fid": "32348", "value": "true" }, + { "fid": "32354", "value": "true" }, + { "fid": "32369", "value": "true" }, + { "fid": "32513", "value": "true" }, + { "fid": "32547", "value": "true" }, + { "fid": "32568", "value": "true" }, + { "fid": "32657", "value": "true" }, + { "fid": "32735", "value": "true" }, + { "fid": "32764", "value": "true" }, + { "fid": "32797", "value": "true" }, + { "fid": "32801", "value": "true" }, + { "fid": "32819", "value": "true" }, + { "fid": "32832", "value": "true" }, + { "fid": "32936", "value": "true" }, + { "fid": "32964", "value": "true" }, + { "fid": "33064", "value": "true" }, + { "fid": "33163", "value": "true" }, + { "fid": "33238", "value": "true" }, + { "fid": "33257", "value": "true" }, + { "fid": "33688", "value": "true" }, + { "fid": "33731", "value": "true" }, + { "fid": "33731", "value": "true" }, + { "fid": "33731", "value": "true" }, + { "fid": "33731", "value": "true" }, + { "fid": "33965", "value": "true" }, + { "fid": "34116", "value": "true" }, + { "fid": "34121", "value": "true" }, + { "fid": "34141", "value": "true" }, + { "fid": "35825", "value": "true" }, + { "fid": "35825", "value": "true" }, + { "fid": "35825", "value": "true" }, + { "fid": "35825", "value": "true" } ] } diff --git a/services/API-service/src/api/point-data/point-data-dynamic-status.entity.ts b/services/API-service/src/api/point-data/point-data-dynamic-status.entity.ts deleted file mode 100644 index 997877cc1..000000000 --- a/services/API-service/src/api/point-data/point-data-dynamic-status.entity.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { - Entity, - PrimaryGeneratedColumn, - Column, - JoinColumn, - ManyToOne, -} from 'typeorm'; -import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; -import { LeadTimeEntity } from '../lead-time/lead-time.entity'; -import { PointDataEntity } from './point-data.entity'; - -@Entity('point-data-dynamic-status') -export class PointDataDynamicStatusEntity { - @PrimaryGeneratedColumn('uuid') - public pointDataDynamicStatusId: string; - - @ApiProperty({ example: 12345 }) - @ManyToOne(() => PointDataEntity) - @JoinColumn({ name: 'referenceId' }) - public pointData: PointDataEntity; - @Column() - public referenceId: number; - - @ApiProperty({ example: new Date() }) - @Column({ type: 'timestamp' }) - public timestamp: Date; - - @ApiProperty({ example: LeadTime.hour1 }) - @ManyToOne((): typeof LeadTimeEntity => LeadTimeEntity) - @JoinColumn({ name: 'leadTime', referencedColumnName: 'leadTimeName' }) - public leadTime: string; - - @ApiProperty({ example: true }) - @Column() - public exposed: boolean; -} diff --git a/services/API-service/src/api/point-data/point-data.module.ts b/services/API-service/src/api/point-data/point-data.module.ts index 798d4b9f5..d615a9994 100644 --- a/services/API-service/src/api/point-data/point-data.module.ts +++ b/services/API-service/src/api/point-data/point-data.module.ts @@ -6,7 +6,6 @@ import { UserModule } from '../user/user.module'; import { PointDataController } from './point-data.controller'; import { PointDataEntity } from './point-data.entity'; import { PointDataService } from './point-data.service'; -import { PointDataDynamicStatusEntity } from './point-data-dynamic-status.entity'; import { HttpModule } from '@nestjs/axios'; import { DynamicPointDataEntity } from './dynamic-point-data.entity'; @@ -14,11 +13,7 @@ import { DynamicPointDataEntity } from './dynamic-point-data.entity'; imports: [ HttpModule, UserModule, - TypeOrmModule.forFeature([ - PointDataEntity, - PointDataDynamicStatusEntity, - DynamicPointDataEntity, - ]), + TypeOrmModule.forFeature([PointDataEntity, DynamicPointDataEntity]), WhatsappModule, ], providers: [PointDataService, HelperService], diff --git a/services/API-service/src/api/point-data/point-data.service.ts b/services/API-service/src/api/point-data/point-data.service.ts index 23cd863a0..37ffecca6 100644 --- a/services/API-service/src/api/point-data/point-data.service.ts +++ b/services/API-service/src/api/point-data/point-data.service.ts @@ -17,7 +17,6 @@ import { UploadAssetExposureStatusDto, UploadDynamicPointDataDto, } from './dto/upload-asset-exposure-status.dto'; -import { PointDataDynamicStatusEntity } from './point-data-dynamic-status.entity'; import { DisasterType } from '../disaster/disaster-type.enum'; import { GaugeDto } from './dto/upload-gauge.dto'; import { DynamicPointDataEntity } from './dynamic-point-data.entity'; @@ -26,8 +25,6 @@ import { DynamicPointDataEntity } from './dynamic-point-data.entity'; export class PointDataService { @InjectRepository(PointDataEntity) private readonly pointDataRepository: Repository; - @InjectRepository(PointDataDynamicStatusEntity) - private readonly pointDataDynamicStatusRepo: Repository; @InjectRepository(DynamicPointDataEntity) private readonly dynamicPointDataRepository: Repository; @@ -84,22 +81,6 @@ export class PointDataService { ) .addSelect('dynamic."dynamicData" as "dynamicData"'); - // TO DO: hard-code for now - if (disasterType === DisasterType.FlashFloods) { - pointDataQuery - .leftJoin( - PointDataDynamicStatusEntity, - 'status', - 'point."pointDataId" = status."referenceId"', - ) - .andWhere( - '(status."timestamp" IS NULL OR status.timestamp = :modelTimestamp)', - { - modelTimestamp: recentDate.timestamp, - }, - ) - .addSelect('COALESCE(status.exposed,FALSE) as "exposed"'); - } const pointData = await pointDataQuery.getRawMany(); return this.helperService.toGeojson(pointData); } @@ -249,42 +230,19 @@ export class PointDataService { await this.whatsappService.sendCommunityNotification(countryCodeISO3); } + // The old endpoint is left in for a grace period, and here the input is transformed to the required input for the new endpoint public async uploadAssetExposureStatus( assetFids: UploadAssetExposureStatusDto, ) { - const assetForecasts: PointDataDynamicStatusEntity[] = []; - for (const fid of assetFids.exposedFids) { - const asset = await this.pointDataRepository.findOne({ - where: { - referenceId: Number(fid), - pointDataCategory: assetFids.pointDataCategory, - countryCodeISO3: assetFids.countryCodeISO3, - }, - }); - if (!asset) { - continue; - } - - // Delete existing entries with same date, leadTime and countryCodeISO3 and stationCode - await this.pointDataDynamicStatusRepo.delete({ - pointData: { pointDataId: asset.pointDataId }, - leadTime: assetFids.leadTime, - timestamp: MoreThanOrEqual( - this.helperService.getUploadCutoffMoment( - assetFids.disasterType, - assetFids.date || new Date(), - ), - ), - }); - - const assetForecast = new PointDataDynamicStatusEntity(); - assetForecast.pointData = asset; - assetForecast.leadTime = assetFids.leadTime; - assetForecast.timestamp = assetFids.date || new Date(); - assetForecast.exposed = true; - assetForecasts.push(assetForecast); - } - await this.pointDataDynamicStatusRepo.save(assetForecasts); + const dynamicPointData = new UploadDynamicPointDataDto(); + dynamicPointData.date = assetFids.date; + dynamicPointData.leadTime = assetFids.leadTime; + dynamicPointData.disasterType = assetFids.disasterType; + dynamicPointData.key = 'exposure'; + dynamicPointData.dynamicPointData = assetFids.exposedFids.map((fid) => { + return { fid: fid, value: 'true' }; + }); + await this.uploadDynamicPointData(dynamicPointData); } async uploadDynamicPointData(dynamicPointData: UploadDynamicPointDataDto) { diff --git a/services/API-service/src/scripts/scripts.service.ts b/services/API-service/src/scripts/scripts.service.ts index 003685671..4f80c8ed4 100644 --- a/services/API-service/src/scripts/scripts.service.ts +++ b/services/API-service/src/scripts/scripts.service.ts @@ -994,34 +994,33 @@ export class ScriptsService { } for (const pointAssetType of pointDataCategories) { - const payload = new UploadAssetExposureStatusDto(); - payload.countryCodeISO3 = countryCodeISO3; + const payload = new UploadDynamicPointDataDto(); payload.disasterType = DisasterType.FlashFloods; - payload.pointDataCategory = pointAssetType; + payload.key = 'exposure'; payload.leadTime = leadTime; payload.date = date || new Date(); if (pointAssetType === PointDataEnum.healthSites) { leadTime === LeadTime.hour24 - ? (payload.exposedFids = []) + ? (payload.dynamicPointData = []) : leadTime === LeadTime.hour6 - ? (payload.exposedFids = ['124']) + ? (payload.dynamicPointData = [{ fid: '124', value: 'true' }]) : []; } else if (pointAssetType === PointDataEnum.schools) { leadTime === LeadTime.hour24 - ? (payload.exposedFids = ['167']) + ? (payload.dynamicPointData = [{ fid: '167', value: 'true' }]) : leadTime === LeadTime.hour6 - ? (payload.exposedFids = []) + ? (payload.dynamicPointData = []) : []; } else if (pointAssetType === PointDataEnum.waterpointsInternal) { const filename = `./src/api/point-data/dto/example/${countryCodeISO3}/${DisasterType.FlashFloods}/${pointAssetType}.json`; const assets = JSON.parse(fs.readFileSync(filename, 'utf-8')); leadTime === LeadTime.hour24 - ? (payload.exposedFids = assets[LeadTime.hour24]) + ? (payload.dynamicPointData = assets[LeadTime.hour24]) : leadTime === LeadTime.hour6 - ? (payload.exposedFids = assets[LeadTime.hour6]) + ? (payload.dynamicPointData = assets[LeadTime.hour6]) : []; } - await this.pointDataService.uploadAssetExposureStatus(payload); + await this.pointDataService.uploadDynamicPointData(payload); } } } From 02b057940631dfa7a94023a13bb3812bb551bc37 Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Mon, 4 Dec 2023 15:15:10 +0100 Subject: [PATCH 07/33] fix: index on timestamp AB#25127 --- .../IBF-dashboard/src/app/services/point-marker.service.ts | 1 - .../API-service/migration/1701157179286-DynamicPointData.ts | 6 ++++++ .../src/api/point-data/dynamic-point-data.entity.ts | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 5027e9e0a..377156c8f 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -364,7 +364,6 @@ export class PointMarkerService { markerLatLng: LatLng, ): Marker { const markerTitle = markerProperties.name; - console.log('markerProperties: ', markerProperties); const markerInstance = marker(markerLatLng, { title: markerTitle, diff --git a/services/API-service/migration/1701157179286-DynamicPointData.ts b/services/API-service/migration/1701157179286-DynamicPointData.ts index b096ec9d8..cb1534cea 100644 --- a/services/API-service/migration/1701157179286-DynamicPointData.ts +++ b/services/API-service/migration/1701157179286-DynamicPointData.ts @@ -13,6 +13,9 @@ export class DynamicPointData1701157179286 implements MigrationInterface { await queryRunner.query( `ALTER TABLE "IBF-app"."dynamic-point-data" ADD CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a" FOREIGN KEY ("leadTime") REFERENCES "IBF-app"."lead-time"("leadTimeName") ON DELETE NO ACTION ON UPDATE NO ACTION`, ); + await queryRunner.query( + `CREATE INDEX "IDX_9ca340240072b8ece6e7b8ae61" ON "IBF-app"."dynamic-point-data" ("timestamp") `, + ); await queryRunner.query(`DROP TABLE "IBF-app"."point-data-dynamic-status"`); @@ -42,6 +45,9 @@ export class DynamicPointData1701157179286 implements MigrationInterface { `CREATE TABLE "IBF-app"."point-data-dynamic-status" ("pointDataDynamicStatusId" uuid NOT NULL DEFAULT uuid_generate_v4(), "referenceId" uuid NOT NULL, "timestamp" TIMESTAMP NOT NULL, "exposed" boolean NOT NULL, "leadTime" character varying, CONSTRAINT "PK_e4a407d1bb1af9141b6c659a985" PRIMARY KEY ("pointDataDynamicStatusId"))`, ); + await queryRunner.query( + `DROP INDEX "IBF-app"."IDX_9ca340240072b8ece6e7b8ae61"`, + ); await queryRunner.query( `ALTER TABLE "IBF-app"."dynamic-point-data" DROP CONSTRAINT "FK_289a1f52e25e270d9a28bd9d35a"`, ); diff --git a/services/API-service/src/api/point-data/dynamic-point-data.entity.ts b/services/API-service/src/api/point-data/dynamic-point-data.entity.ts index 0d5ad54d0..b8b228b96 100644 --- a/services/API-service/src/api/point-data/dynamic-point-data.entity.ts +++ b/services/API-service/src/api/point-data/dynamic-point-data.entity.ts @@ -4,6 +4,7 @@ import { Column, ManyToOne, JoinColumn, + Index, } from 'typeorm'; import { PointDataEntity } from './point-data.entity'; import { LeadTimeEntity } from '../lead-time/lead-time.entity'; @@ -24,6 +25,7 @@ export class DynamicPointDataEntity { public leadTime: string; @Column({ type: 'timestamp' }) + @Index() public timestamp: Date; @Column() From 8f98503c1eff0a8c7e06976b631ac003aade9fa8 Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Fri, 8 Dec 2023 09:55:53 +0100 Subject: [PATCH 08/33] fix: real static data AB#25128 --- .../scripts/git-lfs/standard-point-layers/gauges_MWI.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv index 7b65a6109..37192aee4 100644 --- a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv +++ b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv @@ -1,4 +1,4 @@ -id,fid,name,Country,lat,lon -1,1,Kariba,MWI,-9.940606036,33.92438203 -2,2,Tugwi Mukosi,MWI,-9.938750283,33.92635764 -3,3,Mutirikwi,MWI,-11.89861174,33.59389079 \ No newline at end of file +id,lon,lat,fid,name,Country +1,33.65612777,-11.13575247,1,Lake Kazuni,MWI +2,33.88461925,-11.10706701,2,Kasitu River,MWI +3,33.82902969,-9.943700455,4,Karonga,MWI \ No newline at end of file From bdd657a0f5a85c182789c0072d2820f4d59f097b Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Fri, 8 Dec 2023 09:57:18 +0100 Subject: [PATCH 09/33] fix: make fid unique AB#25128 --- .../scripts/git-lfs/standard-point-layers/gauges_MWI.csv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv index 37192aee4..c25fb2ec6 100644 --- a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv +++ b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv @@ -1,4 +1,4 @@ id,lon,lat,fid,name,Country -1,33.65612777,-11.13575247,1,Lake Kazuni,MWI -2,33.88461925,-11.10706701,2,Kasitu River,MWI -3,33.82902969,-9.943700455,4,Karonga,MWI \ No newline at end of file +1,33.65612777,-11.13575247,gauge-MWI-1,Lake Kazuni,MWI +2,33.88461925,-11.10706701,gauge-MWI-2,Kasitu River,MWI +3,33.82902969,-9.943700455,gauge-MWI-4,Karonga,MWI \ No newline at end of file From e053ddd8a2bdaaa936e3b83729c6978eb2da572f Mon Sep 17 00:00:00 2001 From: arsforza Date: Tue, 5 Dec 2023 09:29:03 +0100 Subject: [PATCH 10/33] fix: update seed and mock AB#25131 --- .../dynamic-point-data_water-level-previous.json | 6 +++--- .../dynamic-point-data_water-level-reference.json | 6 +++--- .../MWI/flash-floods/dynamic-point-data_water-level.json | 4 ++-- .../scripts/git-lfs/standard-point-layers/gauges_MWI.csv | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json index 142ab1010..132b8fa82 100644 --- a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-previous.json @@ -1,14 +1,14 @@ [ { "fid": 1, - "value": 100 + "value": 71 }, { "fid": 2, - "value": 100 + "value": 83 }, { "fid": 3, - "value": 100 + "value": 114 } ] diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json index 142ab1010..4f206b111 100644 --- a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level-reference.json @@ -1,14 +1,14 @@ [ { "fid": 1, - "value": 100 + "value": 90 }, { "fid": 2, - "value": 100 + "value": 90 }, { "fid": 3, - "value": 100 + "value": 110 } ] diff --git a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level.json b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level.json index 142ab1010..421098273 100644 --- a/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level.json +++ b/services/API-service/src/api/point-data/dto/example/MWI/flash-floods/dynamic-point-data_water-level.json @@ -1,11 +1,11 @@ [ { "fid": 1, - "value": 100 + "value": 85 }, { "fid": 2, - "value": 100 + "value": 95 }, { "fid": 3, diff --git a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv index c25fb2ec6..4ef8e63fa 100644 --- a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv +++ b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv @@ -1,4 +1,4 @@ id,lon,lat,fid,name,Country 1,33.65612777,-11.13575247,gauge-MWI-1,Lake Kazuni,MWI 2,33.88461925,-11.10706701,gauge-MWI-2,Kasitu River,MWI -3,33.82902969,-9.943700455,gauge-MWI-4,Karonga,MWI \ No newline at end of file +3,33.82902969,-9.943700455,gauge-MWI-4,Karonga,MWI From 80ca4cf7ee36f7f64163c5f3faeacf4a600a994b Mon Sep 17 00:00:00 2001 From: arsforza Date: Tue, 5 Dec 2023 09:30:09 +0100 Subject: [PATCH 11/33] feat: add river gauge popup AB#25131 --- .../IBF-dashboard/src/app/models/poi.model.ts | 12 +- .../src/app/services/point-marker.service.ts | 193 ++++++++++++++---- .../IBF-dashboard/src/assets/i18n/en.json | 8 + interfaces/IBF-dashboard/src/global.scss | 38 +--- .../src/theme/ibf-colors/_index.scss | 7 + 5 files changed, 183 insertions(+), 75 deletions(-) diff --git a/interfaces/IBF-dashboard/src/app/models/poi.model.ts b/interfaces/IBF-dashboard/src/app/models/poi.model.ts index a7b8b9922..efbf49a87 100644 --- a/interfaces/IBF-dashboard/src/app/models/poi.model.ts +++ b/interfaces/IBF-dashboard/src/app/models/poi.model.ts @@ -81,7 +81,13 @@ export class CommunityNotification { } export class RiverGauge { - gaugeName: string; - currentLevel: number; - normalLevel: string; + fid: string; + name: string; + dynamicData: { + 'water-level': string; + 'water-level-previous': string; + 'water-level-reference': string; + }; + exposed: boolean; + pointDataId: string; } diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 377156c8f..96bea0d3c 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -388,17 +388,23 @@ export class PointMarkerService { markerProperties: RiverGauge, markerLatLng: LatLng, ): Marker { - const markerTitle = markerProperties.gaugeName; + const markerTitle = markerProperties; const markerInstance = marker(markerLatLng, { - title: markerTitle, + title: markerTitle.name, icon: icon(LEAFLET_MARKER_ICON_OPTIONS_RIVER_GAUGE), }); - // markerInstance.bindPopup(this.createMarkerRedCrossPopup(markerProperties)); - // markerInstance.on( - // 'click', - // this.onMapMarkerClick(AnalyticsEvent.redCrossBranch), - // ); + markerInstance.bindPopup( + this.createMarkerRiverGaugePopup(markerProperties), + { + minWidth: 300, + className: 'river-gauge-popup', + }, + ); + markerInstance.on( + 'click', + this.onMapMarkerClick(AnalyticsEvent.redCrossBranch), + ); return markerInstance; } @@ -431,43 +437,21 @@ export class PointMarkerService { const headerContent = `${title}`; - const forecastBar = ` -
-
-
${addComma(forecastValue)}
-
-
- `; + const thresholdBar = this.createThresholdBar( + eapStatusColor, + eapStatusColorText, + triggerWidth, + addComma(forecastValue), + thresholdName, + addComma(thresholdValue), + 80, + ); const middleContent = `
${subtitle}
- ${forecastBar} -
- ${thresholdName}: -
-
- ${addComma(thresholdValue)} -
+ ${thresholdBar} `; const footerContent = `
@@ -684,24 +668,145 @@ export class PointMarkerService { return markerInstance; } - public createDynamicPointPopup( + private createMarkerRiverGaugePopup(markerProperties: RiverGauge): string { + const accentColor = 'var(--ion-color-ibf-no-alert-primary)'; + + const current = Number(markerProperties.dynamicData['water-level']); + const previous = Number( + markerProperties.dynamicData['water-level-previous'], + ); + const reference = Number( + markerProperties.dynamicData['water-level-reference'], + ); + + const difference = current - previous; + + const triggerWidth = Math.max( + Math.min(Math.round((current / reference) * 100), 115), + 0, + ); + + const translatedString = (key: string): string => + this.translate.instant(`map-popups.river-gauge.${key}`); + + const thresholdBar = this.createThresholdBar( + accentColor, + 'var(--ion-color-ibf-white)', + triggerWidth, + `${current} ${translatedString('unit')}`, + translatedString('normal'), + `${reference}`, + 45, + ); + + const headerContent = ` +
+ ${translatedString('header')} ${markerProperties.fid} ${ + markerProperties.name + } +
+ `; + const middleContent = ` +
+ ${current} ${translatedString( + 'unit', + )} + + ${Math.abs(difference)} cm +
+
+ ${translatedString('current')} +
+ ${thresholdBar} + `; + + const footerString = + current <= reference + ? translatedString('below') + : translatedString('above'); + const footerContent = `
${footerString}
`; + + return this.createDynamicPointPopup( + accentColor, + headerContent, + middleContent, + footerContent, + ); + } + + private createDynamicPointPopup( accentColor: string, headerContent: string, middleContent: string, footerContent: string, ): string { - const textColor = 'var(--ion-color-ibf-white)'; + const contrastColor = 'var(--ion-color-ibf-white)'; return ` -
+
${headerContent}
${middleContent}
-
- ${footerContent} +
+
+ ${footerContent} +
+
+ + `; + } + + private createThresholdBar( + backgroundColor: string, + textColor: string, + barWidth: number, + barValue: string, + thresholdDescription: string, + thresholdValue: string, + thresholdPosition: number, // width percentage to position threshold on bar + ): string { + return ` +
+
+
+
${barValue} +
+
+
+
+ ${thresholdDescription}: +
+
+ ${thresholdValue} +
`; } } diff --git a/interfaces/IBF-dashboard/src/assets/i18n/en.json b/interfaces/IBF-dashboard/src/assets/i18n/en.json index 3d85dad90..1d62c98ae 100644 --- a/interfaces/IBF-dashboard/src/assets/i18n/en.json +++ b/interfaces/IBF-dashboard/src/assets/i18n/en.json @@ -380,6 +380,14 @@ "photo-popup": { "title": "Community notification - photo" } + }, + "river-gauge": { + "unit": "cm", + "header": "River gauge #", + "current": "Current water level", + "normal": "Normal water level", + "below": "Below normal level", + "above": "Above normal level" } }, "breadcrumbs": { diff --git a/interfaces/IBF-dashboard/src/global.scss b/interfaces/IBF-dashboard/src/global.scss index eec3a28f1..ad5a272d1 100644 --- a/interfaces/IBF-dashboard/src/global.scss +++ b/interfaces/IBF-dashboard/src/global.scss @@ -99,7 +99,8 @@ .trigger-popup-min, .trigger-popup-med, .trigger-popup-max, -.typhoon-track-popup { +.typhoon-track-popup, +.river-gauge-popup { .leaflet-popup-content-wrapper { padding: 0; @@ -108,40 +109,21 @@ } } } -.trigger-popup-no { - .leaflet-popup-tip { - background-color: var(--ion-color-ibf-no-alert-primary); - } -} -.trigger-popup-min { - .leaflet-popup-tip { - background-color: var(--ion-color-ibf-yellow); - } -} -.trigger-popup-med { - .leaflet-popup-tip { - background-color: var(--ion-color-ibf-orange); - } -} -.trigger-popup-max { - .leaflet-popup-tip { - background-color: var(--ion-color-ibf-trigger-alert-primary); - } -} -.typhoon-track-popup { +.trigger-popup-no, +.trigger-popup-min, +.trigger-popup-med, +.trigger-popup-max, +.typhoon-track-popup, +.river-gauge-popup { a { &.leaflet-popup-close-button { color: var(--ion-color-ibf-white); font-size: 20px; - padding-top: 11px; - margin-right: 7px; + padding-top: 5px; + margin-right: 3px; } } - - .leaflet-popup-tip { - background-color: var(--ion-color-ibf-primary); - } } .waterpoint-cluster-10 { diff --git a/interfaces/IBF-dashboard/src/theme/ibf-colors/_index.scss b/interfaces/IBF-dashboard/src/theme/ibf-colors/_index.scss index e7be0be4d..89a053819 100644 --- a/interfaces/IBF-dashboard/src/theme/ibf-colors/_index.scss +++ b/interfaces/IBF-dashboard/src/theme/ibf-colors/_index.scss @@ -81,6 +81,13 @@ --ion-color-ibf-outline-red: var(--fiveten-error-500); + --ion-color-success: var(--fiveten-success-500); + --ion-color-success-rgb: var(--fiveten-success-500-rgb); + --ion-color-success-contrast: var(--fiveten-neutral-000); + --ion-color-success-contrast-rgb: var(--fiveten-neutral-000); + --ion-color-success-shade: var(--fiveten-success-700); + --ion-color-success-tint: var(--fiveten-success-300); + --ion-color-danger: var(--fiveten-error-500); --ion-color-danger-rgb: var(--fiveten-error-500-rgb); --ion-color-danger-contrast: var(--fiveten-neutral-000); From d07c78be40ea1d6a613aaf4c796eb8a581cfeaf1 Mon Sep 17 00:00:00 2001 From: arsforza Date: Fri, 8 Dec 2023 15:20:54 +0100 Subject: [PATCH 12/33] reafactor: move popups to angular component AB#25131 --- .../app/components/chat/chat.component.html | 1 + .../dynamic-point-popup.component.html | 20 +++ .../dynamic-point-popup.component.scss | 34 +++++ .../dynamic-point-popup.component.spec.ts | 23 +++ .../dynamic-point-popup.component.ts | 99 +++++++++++++ .../river-gauge-popup-content.component.html | 35 +++++ .../river-gauge-popup-content.component.scss | 22 +++ ...iver-gauge-popup-content.component.spec.ts | 23 +++ .../river-gauge-popup-content.component.ts | 40 +++++ .../threshold-bar.component.html | 13 ++ .../threshold-bar.component.scss | 0 .../threshold-bar.component.spec.ts | 23 +++ .../threshold-bar/threshold-bar.component.ts | 101 +++++++++++++ ...on-trackpoint-popup-content.component.html | 27 ++++ ...on-trackpoint-popup-content.component.scss | 0 ...trackpoint-popup-content.component.spec.ts | 23 +++ ...hoon-trackpoint-popup-content.component.ts | 37 +++++ .../src/app/services/point-marker.service.ts | 140 ++++-------------- .../IBF-dashboard/src/app/shared.module.ts | 12 ++ interfaces/IBF-dashboard/src/global.scss | 8 +- 20 files changed, 567 insertions(+), 114 deletions(-) create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.scss create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.spec.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.html create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.scss create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.spec.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.html create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.scss create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.spec.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.html create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.scss create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.spec.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.ts diff --git a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html index e14d6309d..d40ec44d4 100644 --- a/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html +++ b/interfaces/IBF-dashboard/src/app/components/chat/chat.component.html @@ -18,6 +18,7 @@ | translate: { supportEmailAddress: supportEmailAddress } " color="danger" + class="absolute" >

diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html new file mode 100644 index 000000000..27d291b5f --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html @@ -0,0 +1,20 @@ +
+ {{ title }} +
+
+ + + + +
+ diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.scss b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.scss new file mode 100644 index 000000000..20b0cc6a5 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.scss @@ -0,0 +1,34 @@ +.leaflet--dynamic-point-popup--header { + &.gauges { + background: var(--ion-color-ibf-no-alert-primary); + } + &.typhoon_track { + background: var(--ion-color-ibf-primary); + } + + color: white; + padding: 8px; + border-radius: 8px 8px 0 0; +} + +.leaflet--dynamic-point-popup--content { + padding: 8px; +} + +.leaflet--dynamic-point-popup--footer { + &.gauges { + color: var(--ion-color-ibf-no-alert-primary); + } + &.typhoon_track { + color: var(--ion-color-ibf-primary); + } + + padding: 0 8px; + border-radius: 0 0 8px 8px; + + div { + padding: 8px 0; + text-align: center; + border-top: 1px solid var(--ion-color-ibf-grey-light); + } +} diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.spec.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.spec.ts new file mode 100644 index 000000000..708c5f439 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { DynamicPointPopupComponent } from './dynamic-point-popup.component'; + +describe('DynamicPointPopupComponent', () => { + let component: DynamicPointPopupComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DynamicPointPopupComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DynamicPointPopupComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.ts new file mode 100644 index 000000000..b2a77e84f --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.ts @@ -0,0 +1,99 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { LatLng } from 'leaflet'; +import { RiverGauge } from '../../../models/poi.model'; +import { IbfLayerName } from '../../../types/ibf-layer'; + +@Component({ + selector: 'app-dynamic-point-popup', + templateUrl: './dynamic-point-popup.component.html', + styleUrls: ['./dynamic-point-popup.component.scss'], +}) +export class DynamicPointPopupComponent implements OnInit { + @Input() + public layerName: IbfLayerName; + + @Input() + public riverGauge?: RiverGauge; + + @Input() + public typhoonTrackPoint?: { + timestamp: string; + category: string; + markerLatLng: LatLng; + passed: boolean; + }; + + public typhoonData: { + timestamp: string; + category: string; + }; + + public ibfLayerName = IbfLayerName; + + public title: string; + public footerContent: string; + + private allowedLayers = [ + IbfLayerName.gauges, + IbfLayerName.typhoonTrack, + IbfLayerName.glofasStations, + ]; + + constructor(private translate: TranslateService) {} + + ngOnInit(): void { + if (!this.layerName || !this.allowedLayers.includes(this.layerName)) { + return; + } + + if (!this.riverGauge && !this.typhoonTrackPoint) { + return; + } + + if (this.layerName === IbfLayerName.typhoonTrack) { + this.typhoonData = { + timestamp: this.typhoonTrackPoint.timestamp, + category: this.typhoonTrackPoint.category, + }; + } + + this.title = this.getTitle(); + this.footerContent = this.getFooterContent(); + } + + private getTitle(): string { + if (this.layerName === IbfLayerName.gauges) { + return `${this.translate.instant('map-popups.river-gauge.header')} ${ + this.riverGauge.fid + } ${this.riverGauge.name}`; + } + + if (this.layerName === IbfLayerName.typhoonTrack) { + return `Typhoon track${this.typhoonTrackPoint.passed ? ' (passed)' : ''}`; + } + + return ''; + } + + private getFooterContent(): string { + if (this.layerName === IbfLayerName.gauges) { + return this.riverGauge.dynamicData['water-level'] <= + this.riverGauge.dynamicData['water-level-reference'] + ? this.translate.instant('map-popups.river-gauge.below') + : this.translate.instant('map-popups.river-gauge.above'); + } + + if (this.layerName === IbfLayerName.typhoonTrack) { + const lat = `${Math.abs(this.typhoonTrackPoint.markerLatLng.lat).toFixed( + 4, + )}° ${this.typhoonTrackPoint.markerLatLng.lat > 0 ? 'N' : 'S'}`; + const lng = `${Math.abs(this.typhoonTrackPoint.markerLatLng.lng).toFixed( + 4, + )}° ${this.typhoonTrackPoint.markerLatLng.lng > 0 ? 'E' : 'W'}`; + return `${lat}, ${lng}`; + } + + return ''; + } +} diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.html b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.html new file mode 100644 index 000000000..dbd01cfe5 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.html @@ -0,0 +1,35 @@ +
+
+ + {{ current }} + {{ 'map-popups.river-gauge.unit' | translate }} + + + {{ differenceAbsolute }} + {{ 'map-popups.river-gauge.unit' | translate }} +
+ +
+
+ {{ + 'map-popups.river-gauge.current' | translate + }} +
+ diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.scss b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.scss new file mode 100644 index 000000000..36879e670 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.scss @@ -0,0 +1,22 @@ +.leaflet--dynamic-point-popup--header { + background: var(--ion-color-ibf-no-alert-primary); + color: white; + padding: 8px; + border-radius: 8px 8px 0 0; +} + +.leaflet--dynamic-point-popup--content { + padding: 8px; +} + +.leaflet--dynamic-point-popup--footer { + color: var(--ion-color-ibf-no-alert-primary); + padding: 0 8px; + border-radius: 0 0 8px 8px; + + div { + padding: 8px 0; + text-align: center; + border-top: 1px solid var(--ion-color-ibf-grey-light); + } +} diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.spec.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.spec.ts new file mode 100644 index 000000000..44408e750 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RiverGaugePopupContentComponent } from './river-gauge-popup-content.component'; + +describe('DynamicPointPopupComponent', () => { + let component: RiverGaugePopupContentComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [RiverGaugePopupContentComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RiverGaugePopupContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.ts new file mode 100644 index 000000000..6558893d1 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component.ts @@ -0,0 +1,40 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { RiverGauge } from '../../../models/poi.model'; + +@Component({ + selector: 'app-river-gauge-popup-content', + templateUrl: './river-gauge-popup-content.component.html', + styleUrls: ['./river-gauge-popup-content.component.scss'], +}) +export class RiverGaugePopupContentComponent implements OnInit { + @Input() + data: RiverGauge; + + public current: number; + public currentString: string; + public previous: number; + public reference: number; + public difference: number; + public differenceAbsolute: number; + public triggerWidth: number; + + constructor(public translate: TranslateService) {} + ngOnInit(): void { + if (!this.data) { + return; + } + + this.current = Number(this.data.dynamicData['water-level']); + this.currentString = String(this.current); + this.previous = Number(this.data.dynamicData['water-level-previous']); + this.reference = Number(this.data.dynamicData['water-level-reference']); + this.difference = this.current - this.previous; + this.differenceAbsolute = Math.abs(this.difference); + + this.triggerWidth = Math.max( + Math.min(Math.round((this.current / this.reference) * 100), 115), + 0, + ); + } +} diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.html b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.html new file mode 100644 index 000000000..655d5e5d4 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.html @@ -0,0 +1,13 @@ +
+
+
+
+ {{ barValue }} +
+
+
+
+
{{ thresholdDescription }}:
+
+ {{ thresholdValue }} +
diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.scss b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.spec.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.spec.ts new file mode 100644 index 000000000..405692903 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ThresholdBarComponent } from './threshold-bar.component'; + +describe('ThresholdBarComponent', () => { + let component: ThresholdBarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ThresholdBarComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ThresholdBarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.ts new file mode 100644 index 000000000..413f9b710 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/threshold-bar/threshold-bar.component.ts @@ -0,0 +1,101 @@ +import { Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-threshold-bar', + templateUrl: './threshold-bar.component.html', + styleUrls: ['./threshold-bar.component.scss'], +}) +export class ThresholdBarComponent implements OnInit { + @Input() public backgroundColor: string; + @Input() public textColor: string; + @Input() public barWidth: number; + @Input() public barValue: string; + @Input() public thresholdDescription: string; + @Input() public thresholdValue: number; + @Input() public thresholdPosition: number; // width percentage to position threshold on bar + + public barBackgroundStyle: string; + public barThresholdStyle: string; + public barLevelStyle: string; + public descriptionStyle: string; + public valueStyle: string; + + ngOnInit(): void { + if ( + !this.backgroundColor || + !this.textColor || + !this.barWidth || + !this.barValue || + !this.thresholdDescription || + !this.thresholdValue || + !this.thresholdPosition + ) { + return; + } + + this.barBackgroundStyle = this.getBarBackgroundStyle(); + this.barThresholdStyle = this.getBarThresholdStyle(); + this.barLevelStyle = this.getBarLevelStyle(); + this.descriptionStyle = this.getDescriptionStyle(); + this.valueStyle = this.getValueStyle(); + } + + private getBarBackgroundStyle(): string { + return ` + border-radius: 10px; + height: 20px; + background-color: #d4d3d2; + width: 100%; + `; + } + + private getBarThresholdStyle(): string { + return ` + border-radius:10px 0 0 10px; + border-right: dashed; + border-right-width: thin; + height:20px; + width: ${this.thresholdPosition}% + `; + } + + private getBarLevelStyle(): string { + return ` + border-radius:10px; + height:20px; + line-height:20px; + background-color:${this.backgroundColor}; + color:${this.textColor}; + text-align:center; + white-space: nowrap; + min-width: 15%; + width:${this.barWidth}% + `; + } + + private getDescriptionStyle(): string { + return ` + + height:20px; + background-color:none; + border-right: dashed; + border-right-width: thin; + float: left; width: ${this.thresholdPosition}%; + padding-top: 5px; + margin-bottom:10px; + text-align: right; + padding-right: 2px`; + } + + private getValueStyle(): string { + return ` + height:20px; + background-color:none; + margin-left: ${this.thresholdPosition + 1}%; + text-align: left; + width: 20%; + padding-top: 5px; + margin-bottom:10px + `; + } +} diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.html b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.html new file mode 100644 index 000000000..993392fe0 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.html @@ -0,0 +1,27 @@ +
+
+
+ Date and time: {{ dateAndTime }} +
+
+ Category (ECWMF): + {{ + 'map-popups.PHL.typhoon.category.' + category | translate + }} +
+
+
+ + + +
+
diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.scss b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.spec.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.spec.ts new file mode 100644 index 000000000..6608ff0c2 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TyphoonTrackpointPopupContentComponent } from './typhoon-trackpoint-popup-content.component'; + +describe('TyphoonTrackpointPopupContentComponent', () => { + let component: TyphoonTrackpointPopupContentComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TyphoonTrackpointPopupContentComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TyphoonTrackpointPopupContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.ts b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.ts new file mode 100644 index 000000000..549b504f4 --- /dev/null +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component.ts @@ -0,0 +1,37 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { DateTime } from 'luxon'; + +@Component({ + selector: 'app-typhoon-trackpoint-popup-content', + templateUrl: './typhoon-trackpoint-popup-content.component.html', + styleUrls: ['./typhoon-trackpoint-popup-content.component.scss'], +}) +export class TyphoonTrackpointPopupContentComponent implements OnInit { + @Input() + public data: { + timestamp: string; + category: string; + }; + + public dateAndTime: string; + public category: string; + public iconColor: string; + + constructor(public translate: TranslateService) {} + + ngOnInit(): void { + if (!this.data) { + return; + } + + this.dateAndTime = this.getDateAndTime(); + this.category = this.data.category; + } + + private getDateAndTime() { + return DateTime.fromISO(this.data.timestamp).toFormat( + 'ccc, dd LLLL, HH:mm', + ); + } +} diff --git a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts index 96bea0d3c..f60561aae 100644 --- a/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts +++ b/interfaces/IBF-dashboard/src/app/services/point-marker.service.ts @@ -37,10 +37,12 @@ import { import { AnalyticsEvent, AnalyticsPage } from '../analytics/analytics.enum'; import { AnalyticsService } from '../analytics/analytics.service'; import { CommunityNotificationPopupComponent } from '../components/community-notification-popup/community-notification-popup.component'; +import { DynamicPointPopupComponent } from '../components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component'; import { CountryDisasterSettings, EapAlertClasses, } from '../models/country.model'; +import { IbfLayerName } from '../types/ibf-layer'; import { LeadTime } from '../types/lead-time'; import { EventService } from './event.service'; @@ -167,12 +169,10 @@ export class PointMarkerService { ); let className = 'typhoon-track-icon'; - let passed = ''; if (markerDateTime > modelDateTime) { className += ' typhoon-track-icon-future'; } else { - passed = '(Passed)'; if (isLatest) { className += ' typhoon-track-icon-latest'; } else { @@ -188,12 +188,6 @@ export class PointMarkerService { markerProperties.timestampOfTrackpoint, ).toFormat('ccc, dd LLLL, HH:mm'); - const category = this.translate.instant( - 'map-popups.PHL.typhoon.category.' + markerProperties.category, - ); - - const coordinate = this.formatAsCoordinate(markerLatLng); - const markerInstance = marker(markerLatLng, { title: dateAndTime, icon: divIcon({ @@ -213,10 +207,10 @@ export class PointMarkerService { markerInstance.bindPopup( this.createMarkerTyphoonTrackPopup( - dateAndTime, - category, - coordinate, - passed, + markerProperties.timestampOfTrackpoint, + markerProperties.category, + markerLatLng, + markerDateTime <= modelDateTime, ), { minWidth: 300, @@ -511,38 +505,23 @@ export class PointMarkerService { } private createMarkerTyphoonTrackPopup( - dateAndTime: string, + timestamp: string, category: string, - coordinate: string, - passed: string, + markerLatLng: LatLng, + passed: boolean, ): string { - const bg = 'var(--ion-color-ibf-primary)'; - - const headerContent = `Typhoon track ${passed}`; - - const middleContent = ` -
-
-
Date and time: ${dateAndTime}
-
Category (ECWMF): ${category}
-
-
- - - -
-
`; - - const footerContent = `
- Coordinate: ${coordinate} -
`; - - return this.createDynamicPointPopup( - bg, - headerContent, - middleContent, - footerContent, - ); + const component = this.componentFactoryResolver + .resolveComponentFactory(DynamicPointPopupComponent) + .create(this.injector); + component.instance.layerName = IbfLayerName.typhoonTrack; + component.instance.typhoonTrackPoint = { + timestamp, + category, + markerLatLng, + passed, + }; + component.changeDetectorRef.detectChanges(); + return component.location.nativeElement; } private createMarkerRedCrossPopup(markerProperties: RedCrossBranch): string { @@ -668,75 +647,14 @@ export class PointMarkerService { return markerInstance; } - private createMarkerRiverGaugePopup(markerProperties: RiverGauge): string { - const accentColor = 'var(--ion-color-ibf-no-alert-primary)'; - - const current = Number(markerProperties.dynamicData['water-level']); - const previous = Number( - markerProperties.dynamicData['water-level-previous'], - ); - const reference = Number( - markerProperties.dynamicData['water-level-reference'], - ); - - const difference = current - previous; - - const triggerWidth = Math.max( - Math.min(Math.round((current / reference) * 100), 115), - 0, - ); - - const translatedString = (key: string): string => - this.translate.instant(`map-popups.river-gauge.${key}`); - - const thresholdBar = this.createThresholdBar( - accentColor, - 'var(--ion-color-ibf-white)', - triggerWidth, - `${current} ${translatedString('unit')}`, - translatedString('normal'), - `${reference}`, - 45, - ); - - const headerContent = ` -
- ${translatedString('header')} ${markerProperties.fid} ${ - markerProperties.name - } -
- `; - const middleContent = ` -
- ${current} ${translatedString( - 'unit', - )} - - ${Math.abs(difference)} cm -
-
- ${translatedString('current')} -
- ${thresholdBar} - `; - - const footerString = - current <= reference - ? translatedString('below') - : translatedString('above'); - const footerContent = `
${footerString}
`; - - return this.createDynamicPointPopup( - accentColor, - headerContent, - middleContent, - footerContent, - ); + private createMarkerRiverGaugePopup(markerProperties: RiverGauge) { + const component = this.componentFactoryResolver + .resolveComponentFactory(DynamicPointPopupComponent) + .create(this.injector); + component.instance.layerName = IbfLayerName.gauges; + component.instance.riverGauge = markerProperties; + component.changeDetectorRef.detectChanges(); + return component.location.nativeElement; } private createDynamicPointPopup( diff --git a/interfaces/IBF-dashboard/src/app/shared.module.ts b/interfaces/IBF-dashboard/src/app/shared.module.ts index 550c79a4c..6cbcf30f7 100644 --- a/interfaces/IBF-dashboard/src/app/shared.module.ts +++ b/interfaces/IBF-dashboard/src/app/shared.module.ts @@ -30,6 +30,10 @@ import { IbfButtonComponent } from './components/ibf-button/ibf-button.component import { IbfGuideButtonComponent } from './components/ibf-guide-button/ibf-guide-button.component'; import { IbfGuidePopoverComponent } from './components/ibf-guide-popover/ibf-guide-popover.component'; import { LayerControlInfoPopoverComponent } from './components/layer-control-info-popover/layer-control-info-popover.component'; +import { DynamicPointPopupComponent } from './components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component'; +import { RiverGaugePopupContentComponent } from './components/leaflet-popup/river-gauge-popup-content/river-gauge-popup-content.component'; +import { ThresholdBarComponent } from './components/leaflet-popup/threshold-bar/threshold-bar.component'; +import { TyphoonTrackpointPopupContentComponent } from './components/leaflet-popup/typhoon-trackpoint-popup-content/typhoon-trackpoint-popup-content.component'; import { LoginFormComponent } from './components/login-form/login-form.component'; import { LogosComponent } from './components/logos/logos.component'; import { MapControlsComponent } from './components/map-controls/map-controls.component'; @@ -91,6 +95,10 @@ import { BackendMockScenarioComponent } from './mocks/backend-mock-scenario-comp TooltipComponent, TooltipPopoverComponent, UserStateComponent, + RiverGaugePopupContentComponent, + ThresholdBarComponent, + DynamicPointPopupComponent, + TyphoonTrackpointPopupContentComponent, ], exports: [ AboutBtnComponent, @@ -131,6 +139,10 @@ import { BackendMockScenarioComponent } from './mocks/backend-mock-scenario-comp TooltipPopoverComponent, TranslateModule, UserStateComponent, + RiverGaugePopupContentComponent, + ThresholdBarComponent, + DynamicPointPopupComponent, + TyphoonTrackpointPopupContentComponent, ], }) export class SharedModule {} diff --git a/interfaces/IBF-dashboard/src/global.scss b/interfaces/IBF-dashboard/src/global.scss index ad5a272d1..7a17c23fe 100644 --- a/interfaces/IBF-dashboard/src/global.scss +++ b/interfaces/IBF-dashboard/src/global.scss @@ -259,9 +259,11 @@ input:-webkit-autofill:focus { } app-tooltip { - position: absolute; - top: 4px; - right: 8px; + &.absolute { + position: absolute; + top: 4px; + right: 8px; + } } .tooltip--container { From 9a13271075773d5c2273fdc128c9e89e320e9a12 Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Mon, 11 Dec 2023 15:46:02 +0100 Subject: [PATCH 13/33] fix: chane fid to numeric + basics to get out glofas data AB#25126 --- .../dto/upload-glofas-station.dto.ts | 20 +++++++++++++++++++ .../src/api/point-data/point-data.entity.ts | 1 + .../src/api/point-data/point-data.service.ts | 3 +++ .../standard-point-layers/gauges_MWI.csv | 6 +++--- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 services/API-service/src/api/point-data/dto/upload-glofas-station.dto.ts diff --git a/services/API-service/src/api/point-data/dto/upload-glofas-station.dto.ts b/services/API-service/src/api/point-data/dto/upload-glofas-station.dto.ts new file mode 100644 index 000000000..1255a533a --- /dev/null +++ b/services/API-service/src/api/point-data/dto/upload-glofas-station.dto.ts @@ -0,0 +1,20 @@ +import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class GlofasStationDto { + @ApiProperty({ example: 'G5100' }) + @IsString() + public stationCode: string = undefined; + + @ApiProperty({ example: 'Station name' }) + @IsOptional() + public stationName: string = undefined; + + @ApiProperty({ example: 0 }) + @IsNotEmpty() + public lat: number; + + @ApiProperty({ example: 0 }) + @IsNotEmpty() + public lon: number; +} diff --git a/services/API-service/src/api/point-data/point-data.entity.ts b/services/API-service/src/api/point-data/point-data.entity.ts index 98f3801fe..f4f581358 100644 --- a/services/API-service/src/api/point-data/point-data.entity.ts +++ b/services/API-service/src/api/point-data/point-data.entity.ts @@ -10,6 +10,7 @@ export enum PointDataEnum { schools = 'schools', waterpointsInternal = 'waterpoints_internal', gauges = 'gauges', + glofasStations = 'glofas_stations', } @Entity('point-data') diff --git a/services/API-service/src/api/point-data/point-data.service.ts b/services/API-service/src/api/point-data/point-data.service.ts index 37ffecca6..72ccdc574 100644 --- a/services/API-service/src/api/point-data/point-data.service.ts +++ b/services/API-service/src/api/point-data/point-data.service.ts @@ -20,6 +20,7 @@ import { import { DisasterType } from '../disaster/disaster-type.enum'; import { GaugeDto } from './dto/upload-gauge.dto'; import { DynamicPointDataEntity } from './dynamic-point-data.entity'; +import { GlofasStationDto } from './dto/upload-glofas-station.dto'; @Injectable() export class PointDataService { @@ -103,6 +104,8 @@ export class PointDataService { return new WaterpointDto(); case PointDataEnum.gauges: return new GaugeDto(); + case PointDataEnum.glofasStations: + return new GlofasStationDto(); default: throw new HttpException( 'Not a known point layer', diff --git a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv index 4ef8e63fa..916d6b187 100644 --- a/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv +++ b/services/API-service/src/scripts/git-lfs/standard-point-layers/gauges_MWI.csv @@ -1,4 +1,4 @@ id,lon,lat,fid,name,Country -1,33.65612777,-11.13575247,gauge-MWI-1,Lake Kazuni,MWI -2,33.88461925,-11.10706701,gauge-MWI-2,Kasitu River,MWI -3,33.82902969,-9.943700455,gauge-MWI-4,Karonga,MWI +1,33.65612777,-11.13575247,1,Lake Kazuni,MWI +2,33.88461925,-11.10706701,2,Kasitu River,MWI +3,33.82902969,-9.943700455,3,Karonga,MWI From 9a41aa0d70093af840c00ef88fef7ba35a4713ee Mon Sep 17 00:00:00 2001 From: jannisvisser Date: Mon, 11 Dec 2023 15:52:24 +0100 Subject: [PATCH 14/33] update migration --- .../API-service/migration/1701157179286-DynamicPointData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/API-service/migration/1701157179286-DynamicPointData.ts b/services/API-service/migration/1701157179286-DynamicPointData.ts index cb1534cea..06c65088f 100644 --- a/services/API-service/migration/1701157179286-DynamicPointData.ts +++ b/services/API-service/migration/1701157179286-DynamicPointData.ts @@ -33,7 +33,7 @@ export class DynamicPointData1701157179286 implements MigrationInterface { // await queryRunner.query(`INSERT INTO "IBF-app"."dynamic-point-data" // ("dynamicPointDataId", "timestamp", "key", value, "pointPointDataId") // select uuid_generate_v4() - // ,date + // ,'2023-12-11 14:29:06.012' -- NOTE: Put in here exact timestamp of main model run // ,unnest(array['forecastLevel','forecastReturnPeriod','triggerLevel','eapAlertClass']) as key // ,unnest(array[cast("forecastLevel" as varchar),cast("forecastReturnPeriod" as varchar),cast("triggerLevel" as varchar),"eapAlertClass"]) as value // ,"glofasStationId" From 3b849d5fc6a7d56de6ff635534aeba777a4a8a3d Mon Sep 17 00:00:00 2001 From: arsforza Date: Tue, 12 Dec 2023 09:05:59 +0100 Subject: [PATCH 15/33] refactor: use new popup for glofas AB#25280 --- .../dynamic-point-popup.component.html | 8 ++- .../dynamic-point-popup.component.scss | 3 ++ .../dynamic-point-popup.component.ts | 34 +++++++++++- ...glofas-station-popup-content.component.css | 0 ...lofas-station-popup-content.component.html | 28 ++++++++++ ...as-station-popup-content.component.spec.ts | 25 +++++++++ .../glofas-station-popup-content.component.ts | 54 +++++++++++++++++++ .../src/app/services/point-marker.service.ts | 47 ++++++---------- .../IBF-dashboard/src/app/shared.module.ts | 3 ++ 9 files changed, 166 insertions(+), 36 deletions(-) create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/glofas-station-popup-content/glofas-station-popup-content.component.css create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/glofas-station-popup-content/glofas-station-popup-content.component.html create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/glofas-station-popup-content/glofas-station-popup-content.component.spec.ts create mode 100644 interfaces/IBF-dashboard/src/app/components/leaflet-popup/glofas-station-popup-content/glofas-station-popup-content.component.ts diff --git a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html index 27d291b5f..e3146e112 100644 --- a/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html +++ b/interfaces/IBF-dashboard/src/app/components/leaflet-popup/dynamic-point-popup/dynamic-point-popup.component.html @@ -1,4 +1,4 @@ -
+
{{ title }}
@@ -11,9 +11,13 @@ *ngSwitchCase="ibfLayerName.typhoonTrack" [data]="typhoonData" > +
-