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:
parent
a7c34ca3b2
commit
5e7c547670
8 changed files with 121 additions and 76 deletions
|
|
@ -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: "",
|
||||||
|
|
@ -82,18 +82,18 @@ 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
|
||||||
Status column
|
Status column
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
60
db/migrations/00099_publicreport_location_water.sql
Normal file
60
db/migrations/00099_publicreport_location_water.sql
Normal 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;
|
||||||
|
|
@ -16,13 +16,13 @@ import (
|
||||||
|
|
||||||
// PublicreportReportLocation is an object representing the database table.
|
// PublicreportReportLocation is an object representing the database table.
|
||||||
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" `
|
||||||
Status null.Val[enums.PublicreportReportstatustype] `db:"status" `
|
Status null.Val[enums.PublicreportReportstatustype] `db:"status" `
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicreportReportLocationSlice is an alias for a slice of pointers to PublicreportReportLocation.
|
// PublicreportReportLocationSlice is an alias for a slice of pointers to PublicreportReportLocation.
|
||||||
|
|
@ -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
|
||||||
|
|
@ -96,13 +96,13 @@ 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]
|
||||||
Status psql.WhereNullMod[Q, enums.PublicreportReportstatustype]
|
Status psql.WhereNullMod[Q, enums.PublicreportReportstatustype]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (publicreportReportLocationWhere[Q]) AliasedAs(alias string) publicreportReportLocationWhere[Q] {
|
func (publicreportReportLocationWhere[Q]) AliasedAs(alias string) publicreportReportLocationWhere[Q] {
|
||||||
|
|
@ -111,12 +111,12 @@ func (publicreportReportLocationWhere[Q]) AliasedAs(alias string) publicreportRe
|
||||||
|
|
||||||
func buildPublicreportReportLocationWhere[Q psql.Filterable](cols publicreportReportLocationColumns) publicreportReportLocationWhere[Q] {
|
func buildPublicreportReportLocationWhere[Q psql.Filterable](cols publicreportReportLocationColumns) publicreportReportLocationWhere[Q] {
|
||||||
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),
|
||||||
Status: psql.WhereNull[Q, enums.PublicreportReportstatustype](cols.Status),
|
Status: psql.WhereNull[Q, enums.PublicreportReportstatustype](cols.Status),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,32 +32,14 @@
|
||||||
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() {
|
document.addEventListener("DOMContentLoaded", onLoad);
|
||||||
const map = document.querySelector("map-with-markers");
|
</script>
|
||||||
map.addEventListener("load", (event) => {
|
|
||||||
map.jumpTo({
|
|
||||||
center: GEOJSON_LOCATION.coordinates,
|
|
||||||
zoom: 14,
|
|
||||||
});
|
|
||||||
map.addMarker(GEOJSON_LOCATION.coordinates, "#DC3545");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
document.addEventListener("DOMContentLoaded", onLoad);
|
|
||||||
</script>
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
{{ if (eq .District nil) }}
|
{{ if (eq .District nil) }}
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue