Fix map display on RMO status-by-id page

This involves rebuilding the "publicreport.report_location" view after
making a bunch of changes to making publicreport.water the consistent
name (over pool) throughout RMA tables.
This commit is contained in:
Eli Ribble 2026-03-11 14:59:04 +00:00
parent a7c34ca3b2
commit 5e7c547670
No known key found for this signature in database
8 changed files with 121 additions and 76 deletions

View file

@ -31,8 +31,8 @@ var PublicreportReportLocations = Table[
Generated: false, Generated: false,
AutoIncr: false, AutoIncr: false,
}, },
Address: column{ AddressRaw: column{
Name: "address", Name: "address_raw",
DBType: "text", DBType: "text",
Default: "NULL", Default: "NULL",
Comment: "", Comment: "",
@ -84,7 +84,7 @@ var PublicreportReportLocations = Table[
type publicreportReportLocationColumns struct { type publicreportReportLocationColumns struct {
ID column ID column
TableName column TableName column
Address column AddressRaw column
Created column Created column
Location column Location column
PublicID column PublicID column
@ -93,7 +93,7 @@ type publicreportReportLocationColumns struct {
func (c publicreportReportLocationColumns) AsSlice() []column { func (c publicreportReportLocationColumns) AsSlice() []column {
return []column{ return []column{
c.ID, c.TableName, c.Address, c.Created, c.Location, c.PublicID, c.Status, c.ID, c.TableName, c.AddressRaw, c.Created, c.Location, c.PublicID, c.Status,
} }
} }

View file

@ -0,0 +1,60 @@
-- +goose Up
DROP VIEW publicreport.report_location;
CREATE VIEW publicreport.report_location AS
SELECT
ROW_NUMBER() OVER (ORDER BY table_name, public_id) AS id,
table_name,
address_raw,
created,
location,
public_id,
status
FROM (
SELECT
'nuisance' AS table_name,
address_raw,
created,
location,
public_id,
status
FROM publicreport.nuisance
UNION
SELECT
'water' AS table_name,
address_raw,
created,
location,
public_id,
status
FROM publicreport.water
) AS combined_data;
-- +goose Down
DROP VIEW publicreport.report_location;
CREATE VIEW publicreport.report_location AS
SELECT
ROW_NUMBER() OVER (ORDER BY table_name, public_id) AS id,
table_name,
address_raw,
created,
location,
public_id,
status
FROM (
SELECT
'nuisance' AS table_name,
address_raw,
created,
location,
public_id,
status
FROM publicreport.nuisance
UNION
SELECT
'pool' AS table_name,
address_raw,
created,
location,
public_id,
status
FROM publicreport.water
) AS combined_data;

View file

@ -18,7 +18,7 @@ import (
type PublicreportReportLocation struct { type PublicreportReportLocation struct {
ID null.Val[int64] `db:"id" ` ID null.Val[int64] `db:"id" `
TableName null.Val[string] `db:"table_name" ` TableName null.Val[string] `db:"table_name" `
Address null.Val[string] `db:"address" ` AddressRaw null.Val[string] `db:"address_raw" `
Created null.Val[time.Time] `db:"created" ` Created null.Val[time.Time] `db:"created" `
Location null.Val[string] `db:"location" ` Location null.Val[string] `db:"location" `
PublicID null.Val[string] `db:"public_id" ` PublicID null.Val[string] `db:"public_id" `
@ -38,12 +38,12 @@ type PublicreportReportLocationsQuery = *psql.ViewQuery[*PublicreportReportLocat
func buildPublicreportReportLocationColumns(alias string) publicreportReportLocationColumns { func buildPublicreportReportLocationColumns(alias string) publicreportReportLocationColumns {
return publicreportReportLocationColumns{ return publicreportReportLocationColumns{
ColumnsExpr: expr.NewColumnsExpr( ColumnsExpr: expr.NewColumnsExpr(
"id", "table_name", "address", "created", "location", "public_id", "status", "id", "table_name", "address_raw", "created", "location", "public_id", "status",
).WithParent("publicreport.report_location"), ).WithParent("publicreport.report_location"),
tableAlias: alias, tableAlias: alias,
ID: psql.Quote(alias, "id"), ID: psql.Quote(alias, "id"),
TableName: psql.Quote(alias, "table_name"), TableName: psql.Quote(alias, "table_name"),
Address: psql.Quote(alias, "address"), AddressRaw: psql.Quote(alias, "address_raw"),
Created: psql.Quote(alias, "created"), Created: psql.Quote(alias, "created"),
Location: psql.Quote(alias, "location"), Location: psql.Quote(alias, "location"),
PublicID: psql.Quote(alias, "public_id"), PublicID: psql.Quote(alias, "public_id"),
@ -56,7 +56,7 @@ type publicreportReportLocationColumns struct {
tableAlias string tableAlias string
ID psql.Expression ID psql.Expression
TableName psql.Expression TableName psql.Expression
Address psql.Expression AddressRaw psql.Expression
Created psql.Expression Created psql.Expression
Location psql.Expression Location psql.Expression
PublicID psql.Expression PublicID psql.Expression
@ -98,7 +98,7 @@ func (o PublicreportReportLocationSlice) AfterQueryHook(ctx context.Context, exe
type publicreportReportLocationWhere[Q psql.Filterable] struct { type publicreportReportLocationWhere[Q psql.Filterable] struct {
ID psql.WhereNullMod[Q, int64] ID psql.WhereNullMod[Q, int64]
TableName psql.WhereNullMod[Q, string] TableName psql.WhereNullMod[Q, string]
Address psql.WhereNullMod[Q, string] AddressRaw psql.WhereNullMod[Q, string]
Created psql.WhereNullMod[Q, time.Time] Created psql.WhereNullMod[Q, time.Time]
Location psql.WhereNullMod[Q, string] Location psql.WhereNullMod[Q, string]
PublicID psql.WhereNullMod[Q, string] PublicID psql.WhereNullMod[Q, string]
@ -113,7 +113,7 @@ func buildPublicreportReportLocationWhere[Q psql.Filterable](cols publicreportRe
return publicreportReportLocationWhere[Q]{ return publicreportReportLocationWhere[Q]{
ID: psql.WhereNull[Q, int64](cols.ID), ID: psql.WhereNull[Q, int64](cols.ID),
TableName: psql.WhereNull[Q, string](cols.TableName), TableName: psql.WhereNull[Q, string](cols.TableName),
Address: psql.WhereNull[Q, string](cols.Address), AddressRaw: psql.WhereNull[Q, string](cols.AddressRaw),
Created: psql.WhereNull[Q, time.Time](cols.Created), Created: psql.WhereNull[Q, time.Time](cols.Created),
Location: psql.WhereNull[Q, string](cols.Location), Location: psql.WhereNull[Q, string](cols.Location),
PublicID: psql.WhereNull[Q, string](cols.PublicID), PublicID: psql.WhereNull[Q, string](cols.PublicID),

View file

@ -47,7 +47,6 @@ class MapLocatorReadOnly extends HTMLElement {
}) })
.setLngLat(marker.coordinates) .setLngLat(marker.coordinates)
.addTo(this._map); .addTo(this._map);
this.dispatchEvent(markerDraggedEvent);
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("load", { new CustomEvent("load", {
bubbles: true, bubbles: true,

View file

@ -2,8 +2,12 @@
{{ define "title" }}Status of report {{ .Report.ID|publicReportID }}{{ end }} {{ define "title" }}Status of report {{ .Report.ID|publicReportID }}{{ end }}
{{ define "extraheader" }} {{ define "extraheader" }}
<script
type="text/javascript"
src="//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.js"
></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js"></script> <script src="https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js"></script>
<script src="/static/js/map-with-markers.js"></script> <script src="/static/js/map-locator-ro.js"></script>
<style> <style>
.timeline { .timeline {
border-left: 3px solid #dee2e6; border-left: 3px solid #dee2e6;
@ -28,30 +32,12 @@
font-size: 0.85rem; font-size: 0.85rem;
color: #6c757d; color: #6c757d;
} }
.map-container {
height: 300px;
}
@media (max-width: 768px) {
.map-container {
height: 200px;
}
}
.status-badge { .status-badge {
font-size: 1rem; font-size: 1rem;
} }
</style> </style>
<script> <script>
const GEOJSON_LOCATION = {{.Report.Location|json}}; function onLoad() {}
function onLoad() {
const map = document.querySelector("map-with-markers");
map.addEventListener("load", (event) => {
map.jumpTo({
center: GEOJSON_LOCATION.coordinates,
zoom: 14,
});
map.addMarker(GEOJSON_LOCATION.coordinates, "#DC3545");
});
}
document.addEventListener("DOMContentLoaded", onLoad); document.addEventListener("DOMContentLoaded", onLoad);
</script> </script>
{{ end }} {{ end }}
@ -133,7 +119,12 @@ document.addEventListener("DOMContentLoaded", onLoad);
</h5> </h5>
</div> </div>
<div class="card-body p-0"> <div class="card-body p-0">
<map-with-markers zoom="14" /> <div class="map-container">
<map-locator-ro
id="map"
marker="{{ .Report.Location|json }}"
></map-locator-ro>
</div>
</div> </div>
</div> </div>

View file

@ -19,7 +19,7 @@ var markers = [];
// Because features come from tiled vector data, feature geometries may be split // Because features come from tiled vector data, feature geometries may be split
// or duplicated across tile boundaries. As a result, features may appear // or duplicated across tile boundaries. As a result, features may appear
// multiple times in query results. // multiple times in query results.
function getUniqueFeatures(nuisances, pools, comparatorProperty) { function getUniqueFeatures(nuisances, waters, comparatorProperty) {
const uniqueIds = new Set(); const uniqueIds = new Set();
const uniqueFeatures = []; const uniqueFeatures = [];
for (const feature of nuisances) { for (const feature of nuisances) {
@ -31,12 +31,12 @@ function getUniqueFeatures(nuisances, pools, comparatorProperty) {
uniqueFeatures.push(f); uniqueFeatures.push(f);
} }
} }
for (const feature of pools) { for (const feature of waters) {
const id = feature.properties[comparatorProperty]; const id = feature.properties[comparatorProperty];
if (!uniqueIds.has(id)) { if (!uniqueIds.has(id)) {
uniqueIds.add(id); uniqueIds.add(id);
let f = structuredClone(feature); let f = structuredClone(feature);
f.type = "pool"; f.type = "water";
uniqueFeatures.push(f); uniqueFeatures.push(f);
} }
} }
@ -88,9 +88,9 @@ function onLoad() {
} }
}); });
map.addLayer({ map.addLayer({
'id': 'pool', 'id': 'water',
'source': 'tegola', 'source': 'tegola',
'source-layer': 'pool_location', 'source-layer': 'water_location',
'type': 'circle', 'type': 'circle',
'paint': { 'paint': {
'circle-color': "#0D6EfD", 'circle-color': "#0D6EfD",
@ -110,16 +110,16 @@ function onLoad() {
} }
} }
_addCheckboxClick(checkboxNuisance, "nuisance"); _addCheckboxClick(checkboxNuisance, "nuisance");
_addCheckboxClick(checkboxWater, "pool"); _addCheckboxClick(checkboxWater, "water");
checkboxNuisance.onclick() checkboxNuisance.onclick()
checkboxWater.onclick() checkboxWater.onclick()
}); });
function _updateReports() { function _updateReports() {
const nuisances = map.queryRenderedFeatures({target: {layerId: 'nuisance'}}); const nuisances = map.queryRenderedFeatures({target: {layerId: 'nuisance'}});
const pools = map.queryRenderedFeatures({target: {layerId: 'pool'}}); const waters = map.queryRenderedFeatures({target: {layerId: 'water'}});
const nidus_nuisances = nuisances.filter((feature) => feature.source == "tegola"); const nidus_nuisances = nuisances.filter((feature) => feature.source == "tegola");
const nidus_pools = pools.filter((feature) => feature.source == "tegola"); const nidus_waters = waters.filter((feature) => feature.source == "tegola");
const uniqueFeatures = getUniqueFeatures(nidus_nuisances, nidus_pools, 'public_id'); const uniqueFeatures = getUniqueFeatures(nidus_nuisances, nidus_waters, 'public_id');
// Populate features for the listing overlay. // Populate features for the listing overlay.
renderReports(uniqueFeatures); renderReports(uniqueFeatures);
} }

View file

@ -16,7 +16,7 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db/sql" "github.com/Gleipnir-Technology/nidus-sync/db/sql"
"github.com/Gleipnir-Technology/nidus-sync/html" "github.com/Gleipnir-Technology/nidus-sync/html"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/rs/zerolog/log" //"github.com/rs/zerolog/log"
"github.com/stephenafamo/scan" "github.com/stephenafamo/scan"
/* /*
"github.com/Gleipnir-Technology/nidus-sync/db" "github.com/Gleipnir-Technology/nidus-sync/db"
@ -266,9 +266,6 @@ func contentFromWater(ctx context.Context, report_id string) (result ContentStat
Title: "Created", Title: "Created",
}, },
} }
type LocationGeoJSON struct {
Location string
}
location, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select( location, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
sm.Columns( sm.Columns(
psql.F("ST_AsGeoJSON", "location"), psql.F("ST_AsGeoJSON", "location"),
@ -301,6 +298,8 @@ func getStatusByID(w http.ResponseWriter, r *http.Request) {
content, err = contentFromNuisance(ctx, report_id) content, err = contentFromNuisance(ctx, report_id)
case "water": case "water":
content, err = contentFromWater(ctx, report_id) content, err = contentFromWater(ctx, report_id)
default:
err = fmt.Errorf("table name %s not in switch", location.TableName.MustGet())
} }
if err != nil { if err != nil {
respondError(w, "Failed to generate report content", err, http.StatusInternalServerError) respondError(w, "Failed to generate report content", err, http.StatusInternalServerError)

View file

@ -31,10 +31,6 @@ body {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
#map {
width: 510px;
height: 300px;
}
.address-container { .address-container {
background-color: #f8f9fa; background-color: #f8f9fa;
border-radius: 10px; border-radius: 10px;