Initial working marker display in shadow dom

This commit is contained in:
Eli Ribble 2026-01-21 21:06:35 +00:00
parent bea7c28af2
commit b94d09696e
No known key found for this signature in database
7 changed files with 208 additions and 39 deletions

View file

@ -0,0 +1,112 @@
// Code generated by BobGen psql v0.42.1. DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package sql
import (
"context"
_ "embed"
"io"
"iter"
"time"
"github.com/aarondl/opt/null"
"github.com/google/uuid"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/dialect"
"github.com/stephenafamo/bob/orm"
"github.com/stephenafamo/scan"
)
//go:embed publicreport_image_with_json_by_quick_id.bob.sql
var formattedQueries_publicreport_image_with_json_by_quick_id string
var publicreportImageWithJSONByQuickIDSQL = formattedQueries_publicreport_image_with_json_by_quick_id[172:965]
type PublicreportImageWithJSONByQuickIDQuery = orm.ModQuery[*dialect.SelectQuery, publicreportImageWithJSONByQuickID, PublicreportImageWithJSONByQuickIDRow, []PublicreportImageWithJSONByQuickIDRow, publicreportImageWithJSONByQuickIDTransformer]
func PublicreportImageWithJSONByQuickID(QuickID int32) *PublicreportImageWithJSONByQuickIDQuery {
var expressionTypArgs publicreportImageWithJSONByQuickID
expressionTypArgs.QuickID = psql.Arg(QuickID)
return &PublicreportImageWithJSONByQuickIDQuery{
Query: orm.Query[publicreportImageWithJSONByQuickID, PublicreportImageWithJSONByQuickIDRow, []PublicreportImageWithJSONByQuickIDRow, publicreportImageWithJSONByQuickIDTransformer]{
ExecQuery: orm.ExecQuery[publicreportImageWithJSONByQuickID]{
BaseQuery: bob.BaseQuery[publicreportImageWithJSONByQuickID]{
Expression: expressionTypArgs,
Dialect: dialect.Dialect,
QueryType: bob.QueryTypeSelect,
},
},
Scanner: func(context.Context, []string) (func(*scan.Row) (any, error), func(any) (PublicreportImageWithJSONByQuickIDRow, error)) {
return func(row *scan.Row) (any, error) {
var t PublicreportImageWithJSONByQuickIDRow
row.ScheduleScanByIndex(0, &t.ID)
row.ScheduleScanByIndex(1, &t.ContentType)
row.ScheduleScanByIndex(2, &t.Created)
row.ScheduleScanByIndex(3, &t.Location)
row.ScheduleScanByIndex(4, &t.LocationJSON)
row.ScheduleScanByIndex(5, &t.ResolutionX)
row.ScheduleScanByIndex(6, &t.ResolutionY)
row.ScheduleScanByIndex(7, &t.StorageUUID)
row.ScheduleScanByIndex(8, &t.StorageSize)
row.ScheduleScanByIndex(9, &t.UploadedFilename)
return &t, nil
}, func(v any) (PublicreportImageWithJSONByQuickIDRow, error) {
return *(v.(*PublicreportImageWithJSONByQuickIDRow)), nil
}
},
},
Mod: bob.ModFunc[*dialect.SelectQuery](func(q *dialect.SelectQuery) {
q.AppendSelect(expressionTypArgs.subExpr(9, 549))
q.SetTable(expressionTypArgs.subExpr(555, 742))
q.AppendWhere(expressionTypArgs.subExpr(750, 792))
}),
}
}
type PublicreportImageWithJSONByQuickIDRow = struct {
ID int32 `db:"id"`
ContentType string `db:"content_type"`
Created time.Time `db:"created"`
Location null.Val[string] `db:"location"`
LocationJSON string `db:"location_json"`
ResolutionX int32 `db:"resolution_x"`
ResolutionY int32 `db:"resolution_y"`
StorageUUID uuid.UUID `db:"storage_uuid"`
StorageSize int64 `db:"storage_size"`
UploadedFilename string `db:"uploaded_filename"`
}
type publicreportImageWithJSONByQuickIDTransformer = bob.SliceTransformer[PublicreportImageWithJSONByQuickIDRow, []PublicreportImageWithJSONByQuickIDRow]
type publicreportImageWithJSONByQuickID struct {
QuickID bob.Expression
}
func (o publicreportImageWithJSONByQuickID) args() iter.Seq[orm.ArgWithPosition] {
return func(yield func(arg orm.ArgWithPosition) bool) {
if !yield(orm.ArgWithPosition{
Name: "quickID",
Start: 790,
Stop: 792,
Expression: o.QuickID,
}) {
return
}
}
}
func (o publicreportImageWithJSONByQuickID) raw(from, to int) string {
return publicreportImageWithJSONByQuickIDSQL[from:to]
}
func (o publicreportImageWithJSONByQuickID) subExpr(from, to int) bob.Expression {
return orm.ArgsToExpression(publicreportImageWithJSONByQuickIDSQL, from, to, o.args())
}
func (o publicreportImageWithJSONByQuickID) WriteSQL(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
return o.subExpr(0, len(publicreportImageWithJSONByQuickIDSQL)).WriteSQL(ctx, w, d, start)
}

View file

@ -0,0 +1,18 @@
-- Code generated by BobGen psql v0.42.1. DO NOT EDIT.
-- This file is meant to be re-generated in place and/or deleted at any time.
-- PublicreportImageWithJSONByQuickID
SELECT
"publicreport.image"."id" AS "id",
"publicreport.image"."content_type" AS "content_type",
"publicreport.image"."created" AS "created",
"publicreport.image"."location" AS "location",
ST_AsGeoJSON("publicreport.image"."location") AS "location_json",
"publicreport.image"."resolution_x" AS "resolution_x",
"publicreport.image"."resolution_y" AS "resolution_y",
"publicreport.image"."storage_uuid" AS "storage_uuid",
"publicreport.image"."storage_size" AS "storage_size",
"publicreport.image"."uploaded_filename" AS "uploaded_filename"
FROM "publicreport"."image" AS "publicreport.image"
INNER JOIN "publicreport"."quick_image" AS "publicreport.quick_image" ON ("publicreport.image"."id" = "publicreport.quick_image"."image_id")
WHERE ("publicreport.quick_image"."quick_id" = $1);

View file

@ -0,0 +1,15 @@
-- PublicreportImageWithJSONByQuickID
SELECT
"publicreport.image"."id" AS "id",
"publicreport.image"."content_type" AS "content_type",
"publicreport.image"."created" AS "created",
"publicreport.image"."location" AS "location",
ST_AsGeoJSON("publicreport.image"."location") AS "location_json",
"publicreport.image"."resolution_x" AS "resolution_x",
"publicreport.image"."resolution_y" AS "resolution_y",
"publicreport.image"."storage_uuid" AS "storage_uuid",
"publicreport.image"."storage_size" AS "storage_size",
"publicreport.image"."uploaded_filename" AS "uploaded_filename"
FROM "publicreport"."image" AS "publicreport.image"
INNER JOIN "publicreport"."quick_image" AS "publicreport.quick_image" ON ("publicreport.image"."id" = "publicreport.quick_image"."image_id")
WHERE ("publicreport.quick_image"."quick_id" = $1)

View file

@ -110,6 +110,8 @@ func bigNumber(n int) string {
func makeFuncMap() template.FuncMap {
funcMap := template.FuncMap{
"bigNumber": bigNumber,
"html": unescapeHTML,
"json": unescapeJS,
"GISStatement": gisStatement,
"latLngDisplay": latLngDisplay,
"publicReportID": publicReportID,
@ -291,6 +293,12 @@ func timeSince(t time.Time) string {
return fmt.Sprintf("%d days ago", int(days))
}
}
func unescapeHTML(s string) template.HTML {
return template.HTML(s)
}
func unescapeJS(s string) template.JS {
return template.JS(s)
}
func uuidShort(uuid uuid.UUID) string {
s := uuid.String()
if len(s) < 7 {

View file

@ -1,6 +1,6 @@
var map = null;
// A map that just shows a single point location, and can't be moved
class MapSinglePoint extends HTMLElement {
// A map that just shows a bunch of markers, it can't change them
class MapWithMarkers extends HTMLElement {
constructor() {
super();
@ -10,8 +10,10 @@ class MapSinglePoint extends HTMLElement {
// Initial render
this.render();
this._map = null;
// markers shown on the map. Should be none or 1, generally.
this._markers = null;
this._markers = [];
}
// Lifecycle: when element is added to the DOM
@ -35,7 +37,7 @@ class MapSinglePoint extends HTMLElement {
mapboxgl.accessToken = apiKey;
const mapElement = this.shadowRoot.querySelector("#map");
map = new mapboxgl.Map({
this._map = new mapboxgl.Map({
container: mapElement,
center: {
lat: lat,
@ -44,7 +46,8 @@ class MapSinglePoint extends HTMLElement {
style: 'mapbox://styles/mapbox/streets-v12', // style URL
zoom: zoom,
});
map.on("load", function() {
this._map.on("load", () => {
console.log("map loaded");
this.dispatchEvent(new CustomEvent('load'), {
bubbles: true,
composed: true, // Allows event to cross shadow DOM boundary
@ -53,11 +56,13 @@ class MapSinglePoint extends HTMLElement {
}
});
});
this._markers = [];
}
// Initial render of component
render() {
this.shadowRoot.innerHTML = `
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' rel='stylesheet' />
<style>
.map-container {
background-color: #e9ecef;
@ -91,28 +96,16 @@ class MapSinglePoint extends HTMLElement {
this._map.jumpTo(args);
}
setMarker(coords) {
console.log("Setting map marker", coords);
this._map.jumpTo({
center: coords,
zoom: 14,
});
clearMarkers() {
this._markers.forEach((marker) => marker.remove());
const marker = new mapboxgl.Marker({
color: "#FF0000",
draggable: true
}).setLngLat(coords).addTo(map);
marker.on('dragend', function(e) {
const markerDraggedEvent = new CustomEvent("markerdragend", {
detail: {
marker: marker
}
});
mapContainer.dispatchEvent(markerDraggedEvent);
});
this._markers = [marker];
}
addMarker(coords, color) {
console.log("Add marker", coords, color);
const el = document.createElement("div");
el.id = "marker";
const marker = new mapboxgl.Marker().setLngLat(coords).addTo(this._map);
this._markers.push(marker);
}
}
customElements.define('map-single-point', MapSinglePoint);
customElements.define('map-with-markers', MapWithMarkers);

View file

@ -19,8 +19,6 @@ import (
"github.com/stephenafamo/bob/dialect/psql/sm"
"github.com/stephenafamo/scan"
/*
"strconv"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
"github.com/aarondl/opt/omit"
@ -33,7 +31,8 @@ type Contact struct {
Phone string
}
type Image struct {
URL string
Location string
URL string
}
type Report struct {
Address string
@ -167,7 +166,7 @@ func contentFromQuick(ctx context.Context, report_id string) (result ContentStat
return result, fmt.Errorf("Failed to query nuisance %s: %w", report_id, err)
}
images, err := quick.Images().All(ctx, db.PGInstance.BobDB)
images, err := sql.PublicreportImageWithJSONByQuickID(quick.ID).All(ctx, db.PGInstance.BobDB)
if err != nil {
return result, fmt.Errorf("Failed to get images %s: %w", report_id, err)
}
@ -183,23 +182,24 @@ func contentFromQuick(ctx context.Context, report_id string) (result ContentStat
for _, image := range images {
result.Report.Images = append(result.Report.Images, Image{
URL: fmt.Sprintf("https://%s/image/%s", config.RMODomain, image.StorageUUID),
Location: image.LocationJSON,
URL: fmt.Sprintf("https://%s/image/%s", config.RMODomain, image.StorageUUID),
})
}
type LocationGeoJSON struct {
Location string
}
row, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
location, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
sm.Columns(
psql.F("ST_AsGeoJSON", "location"),
),
sm.From("publicreport.quick"),
sm.Where(psql.Quote("public_id").EQ(psql.Arg(report_id))),
), scan.StructMapper[LocationGeoJSON]())
), scan.SingleColumnMapper[string])
if err != nil {
return result, fmt.Errorf("Failed to query nuisance %s: %w", report_id, err)
}
result.Report.Location = row.Location
result.Report.Location = location
return result, err
}

View file

@ -2,7 +2,8 @@
{{define "title"}}Status of report {{.Report.ID|publicReportID}}{{end}}
{{define "extraheader"}}
<script src="/static/js/map-single-point.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>
<style>
.timeline {
border-left: 3px solid #dee2e6;
@ -39,6 +40,25 @@
font-size: 1rem;
}
</style>
<script>
const GEOJSON_LOCATION = {{.Report.Location|json}};
const GEOJSON_IMAGE_LOCATIONS = [
{{ range .Report.Images }}
{{ .Location|json }},
{{ end }}
];
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, "#FF0000");
});
}
document.addEventListener("DOMContentLoaded", onLoad);
</script>
{{end}}
{{define "content"}}
<div class="container my-4">
@ -101,7 +121,9 @@
<h5 class="mb-0"><i class="fas fa-history me-2"></i>Report Detail</h5>
</div>
<div class="card-body">
<p><strong>Foo:</strong>Bar</p>
{{ if not (eq .Report.Comments "") }}
<p><strong>Comments:</strong>{{ .Report.Comments }}</p>
{{ end }}
</div>
</div>
@ -111,10 +133,9 @@
<h5 class="mb-0"><i class="fas fa-map-marked-alt me-2"></i>Location Map</h5>
</div>
<div class="card-body p-0">
<map-single-point
<map-with-markers
api-key="{{ .MapboxToken }}"
geojson="{{ .Report.Location }}"
zoom="14"></map-single-point>
zoom="14"/>
</div>
</div>
@ -134,6 +155,7 @@
</div>
<!-- History Timeline -->
<!--
<div class="card">
<div class="card-header bg-success text-white">
<h5 class="mb-0"><i class="fas fa-history me-2"></i>Request History</h5>
@ -163,5 +185,6 @@
</div>
</div>
</div>
-->
</div>
{{end}}