Add district setting page and display of district boundary

This commit is contained in:
Eli Ribble 2026-02-16 15:03:26 +00:00
parent 4c8da3b96a
commit a1cc2dbaff
No known key found for this signature in database
11 changed files with 648 additions and 168 deletions

View file

@ -222,6 +222,24 @@ var ImportDistricts = Table[
Generated: true,
AutoIncr: false,
},
Centroid4326: column{
Name: "centroid_4326",
DBType: "geometry",
Default: "GENERATED",
Comment: "",
Nullable: true,
Generated: true,
AutoIncr: false,
},
Extent4326: column{
Name: "extent_4326",
DBType: "geometry",
Default: "GENERATED",
Comment: "",
Nullable: true,
Generated: true,
AutoIncr: false,
},
},
Indexes: importDistrictIndexes{
DistrictPkey: index{
@ -269,34 +287,36 @@ var ImportDistricts = Table[
}
type importDistrictColumns struct {
Gid column
ID column
Website column
Contact column
Address column
Regionid column
PostalCod column
Phone1 column
Fax1 column
Agency column
Code1 column
City1 column
ShapeLeng column
Address2 column
GeneralMG column
City2 column
PostalC1 column
Fax2 column
Phone2 column
ShapeLe1 column
ShapeArea column
Geom column
Geom4326 column
Gid column
ID column
Website column
Contact column
Address column
Regionid column
PostalCod column
Phone1 column
Fax1 column
Agency column
Code1 column
City1 column
ShapeLeng column
Address2 column
GeneralMG column
City2 column
PostalC1 column
Fax2 column
Phone2 column
ShapeLe1 column
ShapeArea column
Geom column
Geom4326 column
Centroid4326 column
Extent4326 column
}
func (c importDistrictColumns) AsSlice() []column {
return []column{
c.Gid, c.ID, c.Website, c.Contact, c.Address, c.Regionid, c.PostalCod, c.Phone1, c.Fax1, c.Agency, c.Code1, c.City1, c.ShapeLeng, c.Address2, c.GeneralMG, c.City2, c.PostalC1, c.Fax2, c.Phone2, c.ShapeLe1, c.ShapeArea, c.Geom, c.Geom4326,
c.Gid, c.ID, c.Website, c.Contact, c.Address, c.Regionid, c.PostalCod, c.Phone1, c.Fax1, c.Agency, c.Code1, c.City1, c.ShapeLeng, c.Address2, c.GeneralMG, c.City2, c.PostalC1, c.Fax2, c.Phone2, c.ShapeLe1, c.ShapeArea, c.Geom, c.Geom4326, c.Centroid4326, c.Extent4326,
}
}

View file

@ -2622,6 +2622,8 @@ func (f *Factory) FromExistingImportDistrict(m *models.ImportDistrict) *ImportDi
o.ShapeArea = func() null.Val[decimal.Decimal] { return m.ShapeArea }
o.Geom = func() null.Val[string] { return m.Geom }
o.Geom4326 = func() null.Val[string] { return m.Geom4326 }
o.Centroid4326 = func() null.Val[string] { return m.Centroid4326 }
o.Extent4326 = func() null.Val[string] { return m.Extent4326 }
ctx := context.Background()
if m.R.ImportDistrictGidOrganization != nil {

View file

@ -37,29 +37,31 @@ func (mods ImportDistrictModSlice) Apply(ctx context.Context, n *ImportDistrictT
// ImportDistrictTemplate is an object representing the database table.
// all columns are optional and should be set by mods
type ImportDistrictTemplate struct {
Gid func() int32
ID func() null.Val[decimal.Decimal]
Website func() null.Val[string]
Contact func() null.Val[string]
Address func() null.Val[string]
Regionid func() null.Val[decimal.Decimal]
PostalCod func() null.Val[decimal.Decimal]
Phone1 func() null.Val[string]
Fax1 func() null.Val[string]
Agency func() null.Val[string]
Code1 func() null.Val[string]
City1 func() null.Val[string]
ShapeLeng func() null.Val[decimal.Decimal]
Address2 func() null.Val[string]
GeneralMG func() null.Val[string]
City2 func() null.Val[string]
PostalC1 func() null.Val[decimal.Decimal]
Fax2 func() null.Val[string]
Phone2 func() null.Val[string]
ShapeLe1 func() null.Val[decimal.Decimal]
ShapeArea func() null.Val[decimal.Decimal]
Geom func() null.Val[string]
Geom4326 func() null.Val[string]
Gid func() int32
ID func() null.Val[decimal.Decimal]
Website func() null.Val[string]
Contact func() null.Val[string]
Address func() null.Val[string]
Regionid func() null.Val[decimal.Decimal]
PostalCod func() null.Val[decimal.Decimal]
Phone1 func() null.Val[string]
Fax1 func() null.Val[string]
Agency func() null.Val[string]
Code1 func() null.Val[string]
City1 func() null.Val[string]
ShapeLeng func() null.Val[decimal.Decimal]
Address2 func() null.Val[string]
GeneralMG func() null.Val[string]
City2 func() null.Val[string]
PostalC1 func() null.Val[decimal.Decimal]
Fax2 func() null.Val[string]
Phone2 func() null.Val[string]
ShapeLe1 func() null.Val[decimal.Decimal]
ShapeArea func() null.Val[decimal.Decimal]
Geom func() null.Val[string]
Geom4326 func() null.Val[string]
Centroid4326 func() null.Val[string]
Extent4326 func() null.Val[string]
r importDistrictR
f *Factory
@ -277,6 +279,12 @@ func (o ImportDistrictTemplate) Build() *models.ImportDistrict {
if o.Geom4326 != nil {
m.Geom4326 = o.Geom4326()
}
if o.Centroid4326 != nil {
m.Centroid4326 = o.Centroid4326()
}
if o.Extent4326 != nil {
m.Extent4326 = o.Extent4326()
}
o.setModelRels(m)
@ -439,6 +447,8 @@ func (m importDistrictMods) RandomizeAllColumns(f *faker.Faker) ImportDistrictMo
ImportDistrictMods.RandomShapeArea(f),
ImportDistrictMods.RandomGeom(f),
ImportDistrictMods.RandomGeom4326(f),
ImportDistrictMods.RandomCentroid4326(f),
ImportDistrictMods.RandomExtent4326(f),
}
}
@ -1639,6 +1649,112 @@ func (m importDistrictMods) RandomGeom4326NotNull(f *faker.Faker) ImportDistrict
})
}
// Set the model columns to this value
func (m importDistrictMods) Centroid4326(val null.Val[string]) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Centroid4326 = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m importDistrictMods) Centroid4326Func(f func() null.Val[string]) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Centroid4326 = f
})
}
// Clear any values for the column
func (m importDistrictMods) UnsetCentroid4326() ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Centroid4326 = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m importDistrictMods) RandomCentroid4326(f *faker.Faker) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Centroid4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m importDistrictMods) RandomCentroid4326NotNull(f *faker.Faker) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Centroid4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Set the model columns to this value
func (m importDistrictMods) Extent4326(val null.Val[string]) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Extent4326 = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m importDistrictMods) Extent4326Func(f func() null.Val[string]) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Extent4326 = f
})
}
// Clear any values for the column
func (m importDistrictMods) UnsetExtent4326() ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Extent4326 = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m importDistrictMods) RandomExtent4326(f *faker.Faker) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Extent4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m importDistrictMods) RandomExtent4326NotNull(f *faker.Faker) ImportDistrictMod {
return ImportDistrictModFunc(func(_ context.Context, o *ImportDistrictTemplate) {
o.Extent4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
func (m importDistrictMods) WithParentsCascading() ImportDistrictMod {
return ImportDistrictModFunc(func(ctx context.Context, o *ImportDistrictTemplate) {
if isDone, _ := importDistrictWithParentsCascadingCtx.Value(ctx); isDone {

View file

@ -26,29 +26,31 @@ import (
// ImportDistrict is an object representing the database table.
type ImportDistrict struct {
Gid int32 `db:"gid,pk" `
ID null.Val[decimal.Decimal] `db:"id" `
Website null.Val[string] `db:"website" `
Contact null.Val[string] `db:"contact" `
Address null.Val[string] `db:"address" `
Regionid null.Val[decimal.Decimal] `db:"regionid" `
PostalCod null.Val[decimal.Decimal] `db:"postal_cod" `
Phone1 null.Val[string] `db:"phone1" `
Fax1 null.Val[string] `db:"fax1" `
Agency null.Val[string] `db:"agency" `
Code1 null.Val[string] `db:"code1" `
City1 null.Val[string] `db:"city1" `
ShapeLeng null.Val[decimal.Decimal] `db:"shape_leng" `
Address2 null.Val[string] `db:"address2" `
GeneralMG null.Val[string] `db:"general_mg" `
City2 null.Val[string] `db:"city2" `
PostalC1 null.Val[decimal.Decimal] `db:"postal_c_1" `
Fax2 null.Val[string] `db:"fax2" `
Phone2 null.Val[string] `db:"phone2" `
ShapeLe1 null.Val[decimal.Decimal] `db:"shape_le_1" `
ShapeArea null.Val[decimal.Decimal] `db:"shape_area" `
Geom null.Val[string] `db:"geom" `
Geom4326 null.Val[string] `db:"geom_4326,generated" `
Gid int32 `db:"gid,pk" `
ID null.Val[decimal.Decimal] `db:"id" `
Website null.Val[string] `db:"website" `
Contact null.Val[string] `db:"contact" `
Address null.Val[string] `db:"address" `
Regionid null.Val[decimal.Decimal] `db:"regionid" `
PostalCod null.Val[decimal.Decimal] `db:"postal_cod" `
Phone1 null.Val[string] `db:"phone1" `
Fax1 null.Val[string] `db:"fax1" `
Agency null.Val[string] `db:"agency" `
Code1 null.Val[string] `db:"code1" `
City1 null.Val[string] `db:"city1" `
ShapeLeng null.Val[decimal.Decimal] `db:"shape_leng" `
Address2 null.Val[string] `db:"address2" `
GeneralMG null.Val[string] `db:"general_mg" `
City2 null.Val[string] `db:"city2" `
PostalC1 null.Val[decimal.Decimal] `db:"postal_c_1" `
Fax2 null.Val[string] `db:"fax2" `
Phone2 null.Val[string] `db:"phone2" `
ShapeLe1 null.Val[decimal.Decimal] `db:"shape_le_1" `
ShapeArea null.Val[decimal.Decimal] `db:"shape_area" `
Geom null.Val[string] `db:"geom" `
Geom4326 null.Val[string] `db:"geom_4326,generated" `
Centroid4326 null.Val[string] `db:"centroid_4326,generated" `
Extent4326 null.Val[string] `db:"extent_4326,generated" `
R importDistrictR `db:"-" `
}
@ -71,61 +73,65 @@ type importDistrictR struct {
func buildImportDistrictColumns(alias string) importDistrictColumns {
return importDistrictColumns{
ColumnsExpr: expr.NewColumnsExpr(
"gid", "id", "website", "contact", "address", "regionid", "postal_cod", "phone1", "fax1", "agency", "code1", "city1", "shape_leng", "address2", "general_mg", "city2", "postal_c_1", "fax2", "phone2", "shape_le_1", "shape_area", "geom", "geom_4326",
"gid", "id", "website", "contact", "address", "regionid", "postal_cod", "phone1", "fax1", "agency", "code1", "city1", "shape_leng", "address2", "general_mg", "city2", "postal_c_1", "fax2", "phone2", "shape_le_1", "shape_area", "geom", "geom_4326", "centroid_4326", "extent_4326",
).WithParent("import.district"),
tableAlias: alias,
Gid: psql.Quote(alias, "gid"),
ID: psql.Quote(alias, "id"),
Website: psql.Quote(alias, "website"),
Contact: psql.Quote(alias, "contact"),
Address: psql.Quote(alias, "address"),
Regionid: psql.Quote(alias, "regionid"),
PostalCod: psql.Quote(alias, "postal_cod"),
Phone1: psql.Quote(alias, "phone1"),
Fax1: psql.Quote(alias, "fax1"),
Agency: psql.Quote(alias, "agency"),
Code1: psql.Quote(alias, "code1"),
City1: psql.Quote(alias, "city1"),
ShapeLeng: psql.Quote(alias, "shape_leng"),
Address2: psql.Quote(alias, "address2"),
GeneralMG: psql.Quote(alias, "general_mg"),
City2: psql.Quote(alias, "city2"),
PostalC1: psql.Quote(alias, "postal_c_1"),
Fax2: psql.Quote(alias, "fax2"),
Phone2: psql.Quote(alias, "phone2"),
ShapeLe1: psql.Quote(alias, "shape_le_1"),
ShapeArea: psql.Quote(alias, "shape_area"),
Geom: psql.Quote(alias, "geom"),
Geom4326: psql.Quote(alias, "geom_4326"),
tableAlias: alias,
Gid: psql.Quote(alias, "gid"),
ID: psql.Quote(alias, "id"),
Website: psql.Quote(alias, "website"),
Contact: psql.Quote(alias, "contact"),
Address: psql.Quote(alias, "address"),
Regionid: psql.Quote(alias, "regionid"),
PostalCod: psql.Quote(alias, "postal_cod"),
Phone1: psql.Quote(alias, "phone1"),
Fax1: psql.Quote(alias, "fax1"),
Agency: psql.Quote(alias, "agency"),
Code1: psql.Quote(alias, "code1"),
City1: psql.Quote(alias, "city1"),
ShapeLeng: psql.Quote(alias, "shape_leng"),
Address2: psql.Quote(alias, "address2"),
GeneralMG: psql.Quote(alias, "general_mg"),
City2: psql.Quote(alias, "city2"),
PostalC1: psql.Quote(alias, "postal_c_1"),
Fax2: psql.Quote(alias, "fax2"),
Phone2: psql.Quote(alias, "phone2"),
ShapeLe1: psql.Quote(alias, "shape_le_1"),
ShapeArea: psql.Quote(alias, "shape_area"),
Geom: psql.Quote(alias, "geom"),
Geom4326: psql.Quote(alias, "geom_4326"),
Centroid4326: psql.Quote(alias, "centroid_4326"),
Extent4326: psql.Quote(alias, "extent_4326"),
}
}
type importDistrictColumns struct {
expr.ColumnsExpr
tableAlias string
Gid psql.Expression
ID psql.Expression
Website psql.Expression
Contact psql.Expression
Address psql.Expression
Regionid psql.Expression
PostalCod psql.Expression
Phone1 psql.Expression
Fax1 psql.Expression
Agency psql.Expression
Code1 psql.Expression
City1 psql.Expression
ShapeLeng psql.Expression
Address2 psql.Expression
GeneralMG psql.Expression
City2 psql.Expression
PostalC1 psql.Expression
Fax2 psql.Expression
Phone2 psql.Expression
ShapeLe1 psql.Expression
ShapeArea psql.Expression
Geom psql.Expression
Geom4326 psql.Expression
tableAlias string
Gid psql.Expression
ID psql.Expression
Website psql.Expression
Contact psql.Expression
Address psql.Expression
Regionid psql.Expression
PostalCod psql.Expression
Phone1 psql.Expression
Fax1 psql.Expression
Agency psql.Expression
Code1 psql.Expression
City1 psql.Expression
ShapeLeng psql.Expression
Address2 psql.Expression
GeneralMG psql.Expression
City2 psql.Expression
PostalC1 psql.Expression
Fax2 psql.Expression
Phone2 psql.Expression
ShapeLe1 psql.Expression
ShapeArea psql.Expression
Geom psql.Expression
Geom4326 psql.Expression
Centroid4326 psql.Expression
Extent4326 psql.Expression
}
func (c importDistrictColumns) Alias() string {
@ -913,29 +919,31 @@ func (importDistrict0 *ImportDistrict) AttachImportDistrictGidOrganization(ctx c
}
type importDistrictWhere[Q psql.Filterable] struct {
Gid psql.WhereMod[Q, int32]
ID psql.WhereNullMod[Q, decimal.Decimal]
Website psql.WhereNullMod[Q, string]
Contact psql.WhereNullMod[Q, string]
Address psql.WhereNullMod[Q, string]
Regionid psql.WhereNullMod[Q, decimal.Decimal]
PostalCod psql.WhereNullMod[Q, decimal.Decimal]
Phone1 psql.WhereNullMod[Q, string]
Fax1 psql.WhereNullMod[Q, string]
Agency psql.WhereNullMod[Q, string]
Code1 psql.WhereNullMod[Q, string]
City1 psql.WhereNullMod[Q, string]
ShapeLeng psql.WhereNullMod[Q, decimal.Decimal]
Address2 psql.WhereNullMod[Q, string]
GeneralMG psql.WhereNullMod[Q, string]
City2 psql.WhereNullMod[Q, string]
PostalC1 psql.WhereNullMod[Q, decimal.Decimal]
Fax2 psql.WhereNullMod[Q, string]
Phone2 psql.WhereNullMod[Q, string]
ShapeLe1 psql.WhereNullMod[Q, decimal.Decimal]
ShapeArea psql.WhereNullMod[Q, decimal.Decimal]
Geom psql.WhereNullMod[Q, string]
Geom4326 psql.WhereNullMod[Q, string]
Gid psql.WhereMod[Q, int32]
ID psql.WhereNullMod[Q, decimal.Decimal]
Website psql.WhereNullMod[Q, string]
Contact psql.WhereNullMod[Q, string]
Address psql.WhereNullMod[Q, string]
Regionid psql.WhereNullMod[Q, decimal.Decimal]
PostalCod psql.WhereNullMod[Q, decimal.Decimal]
Phone1 psql.WhereNullMod[Q, string]
Fax1 psql.WhereNullMod[Q, string]
Agency psql.WhereNullMod[Q, string]
Code1 psql.WhereNullMod[Q, string]
City1 psql.WhereNullMod[Q, string]
ShapeLeng psql.WhereNullMod[Q, decimal.Decimal]
Address2 psql.WhereNullMod[Q, string]
GeneralMG psql.WhereNullMod[Q, string]
City2 psql.WhereNullMod[Q, string]
PostalC1 psql.WhereNullMod[Q, decimal.Decimal]
Fax2 psql.WhereNullMod[Q, string]
Phone2 psql.WhereNullMod[Q, string]
ShapeLe1 psql.WhereNullMod[Q, decimal.Decimal]
ShapeArea psql.WhereNullMod[Q, decimal.Decimal]
Geom psql.WhereNullMod[Q, string]
Geom4326 psql.WhereNullMod[Q, string]
Centroid4326 psql.WhereNullMod[Q, string]
Extent4326 psql.WhereNullMod[Q, string]
}
func (importDistrictWhere[Q]) AliasedAs(alias string) importDistrictWhere[Q] {
@ -944,29 +952,31 @@ func (importDistrictWhere[Q]) AliasedAs(alias string) importDistrictWhere[Q] {
func buildImportDistrictWhere[Q psql.Filterable](cols importDistrictColumns) importDistrictWhere[Q] {
return importDistrictWhere[Q]{
Gid: psql.Where[Q, int32](cols.Gid),
ID: psql.WhereNull[Q, decimal.Decimal](cols.ID),
Website: psql.WhereNull[Q, string](cols.Website),
Contact: psql.WhereNull[Q, string](cols.Contact),
Address: psql.WhereNull[Q, string](cols.Address),
Regionid: psql.WhereNull[Q, decimal.Decimal](cols.Regionid),
PostalCod: psql.WhereNull[Q, decimal.Decimal](cols.PostalCod),
Phone1: psql.WhereNull[Q, string](cols.Phone1),
Fax1: psql.WhereNull[Q, string](cols.Fax1),
Agency: psql.WhereNull[Q, string](cols.Agency),
Code1: psql.WhereNull[Q, string](cols.Code1),
City1: psql.WhereNull[Q, string](cols.City1),
ShapeLeng: psql.WhereNull[Q, decimal.Decimal](cols.ShapeLeng),
Address2: psql.WhereNull[Q, string](cols.Address2),
GeneralMG: psql.WhereNull[Q, string](cols.GeneralMG),
City2: psql.WhereNull[Q, string](cols.City2),
PostalC1: psql.WhereNull[Q, decimal.Decimal](cols.PostalC1),
Fax2: psql.WhereNull[Q, string](cols.Fax2),
Phone2: psql.WhereNull[Q, string](cols.Phone2),
ShapeLe1: psql.WhereNull[Q, decimal.Decimal](cols.ShapeLe1),
ShapeArea: psql.WhereNull[Q, decimal.Decimal](cols.ShapeArea),
Geom: psql.WhereNull[Q, string](cols.Geom),
Geom4326: psql.WhereNull[Q, string](cols.Geom4326),
Gid: psql.Where[Q, int32](cols.Gid),
ID: psql.WhereNull[Q, decimal.Decimal](cols.ID),
Website: psql.WhereNull[Q, string](cols.Website),
Contact: psql.WhereNull[Q, string](cols.Contact),
Address: psql.WhereNull[Q, string](cols.Address),
Regionid: psql.WhereNull[Q, decimal.Decimal](cols.Regionid),
PostalCod: psql.WhereNull[Q, decimal.Decimal](cols.PostalCod),
Phone1: psql.WhereNull[Q, string](cols.Phone1),
Fax1: psql.WhereNull[Q, string](cols.Fax1),
Agency: psql.WhereNull[Q, string](cols.Agency),
Code1: psql.WhereNull[Q, string](cols.Code1),
City1: psql.WhereNull[Q, string](cols.City1),
ShapeLeng: psql.WhereNull[Q, decimal.Decimal](cols.ShapeLeng),
Address2: psql.WhereNull[Q, string](cols.Address2),
GeneralMG: psql.WhereNull[Q, string](cols.GeneralMG),
City2: psql.WhereNull[Q, string](cols.City2),
PostalC1: psql.WhereNull[Q, decimal.Decimal](cols.PostalC1),
Fax2: psql.WhereNull[Q, string](cols.Fax2),
Phone2: psql.WhereNull[Q, string](cols.Phone2),
ShapeLe1: psql.WhereNull[Q, decimal.Decimal](cols.ShapeLe1),
ShapeArea: psql.WhereNull[Q, decimal.Decimal](cols.ShapeArea),
Geom: psql.WhereNull[Q, string](cols.Geom),
Geom4326: psql.WhereNull[Q, string](cols.Geom4326),
Centroid4326: psql.WhereNull[Q, string](cols.Centroid4326),
Extent4326: psql.WhereNull[Q, string](cols.Extent4326),
}
}

View file

@ -0,0 +1,135 @@
// A test of maplibre-gl in a custom element
class MapDistrict extends HTMLElement {
constructor() {
super();
// Create a shadow DOM
this.attachShadow({ mode: "open" });
// Initial render
this.render();
this._map = null;
// markers shown on the map
this._markers = [];
}
// Lifecycle: when element is added to the DOM
connectedCallback() {
// Initialize the map when the element is added to the DOM
setTimeout(() => this._initializeMap(), 0);
}
disconnectedCallback() {
if (this._map) {
this._map.remove();
}
}
_initializeMap() {
const apiKey = this.getAttribute("api-key");
const centroid = JSON.parse(this.getAttribute("centroid"));
const csv_file = this.getAttribute("csv-file");
const district_id = this.getAttribute("district-id");
const lat = Number(this.getAttribute("latitude") || 36.2);
const lng = Number(this.getAttribute("longitude") || -119.2);
const mapElement = this.shadowRoot.querySelector("#map");
const tegola = this.getAttribute("tegola");
const xmin = parseFloat(this.getAttribute("xmin"));
const ymin = parseFloat(this.getAttribute("ymin"));
const xmax = parseFloat(this.getAttribute("xmax"));
const ymax = parseFloat(this.getAttribute("ymax"));
const bounds = [
[xmin, ymin],
[xmax, ymax],
];
console.log("fitting", bounds);
this._map = new maplibregl.Map({
container: mapElement,
center: centroid.coordinates,
style: "https://tiles.stadiamaps.com/styles/alidade_smooth.json", // Style URL; see our documentation for more options
}).fitBounds(bounds, {
padding: { top: 10, bottom: 10, left: 10, right: 10 },
});
this._map.on("load", () => {
this._map.addSource("tegola-nidus", {
type: "vector",
tiles: [
`${tegola}maps/district/{z}/{x}/{y}?district_id=${district_id}`,
],
});
this._map.addLayer({
id: "bounds",
source: "tegola-nidus",
"source-layer": "bounds",
type: "fill",
paint: {
"fill-opacity": 0.4,
"fill-color": "#dc3545",
},
});
});
}
// Initial render of component
render() {
this.shadowRoot.innerHTML = `
<style>
@import url('//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.css');
.mapboxgl-ctrl-bottom-right {
display: none;
}
.map-container {
background-color: #e9ecef;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
height: 500px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
#map {
height: 500px;
width:100%;
margin-bottom: 10px;
}
#map img {
max-width: none;
min-width: 0px;
height: auto;
}
</style>
<div id="map-container" class="map-container">
<div id="map"></div>
</div>
`;
}
addLayer(a) {
return this._map.addLayer(a);
}
addSource(a, b) {
return this._map.addSource(a, b);
}
jumpTo(args) {
return this._map.jumpTo(args);
}
on(a, b) {
return this._map.on(a, b);
}
once(a, b) {
return this._map.once(a, b);
}
queryRenderedFeatures(a) {
return this._map.queryRenderedFeatures(a);
}
SetLayoutProperty(layout, property, value) {
return this._map.setLayoutProperty(layout, property, value);
}
}
customElements.define("map-district", MapDistrict);

View file

@ -0,0 +1,136 @@
{{ template "sync/layout/authenticated.html" . }}
{{ define "title" }}Settings - Integrations{{ end }}
{{ define "extraheader" }}
<script
type="text/javascript"
src="//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.js"
></script>
<script src="/static/js/map-district.js"></script>
<style>
.settings-card {
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
margin-bottom: 30px;
}
</style>
{{ end }}
{{ define "content" }}
<div class="container py-4">
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="bi bi-geo-alt-fill text-primary me-2"></i> District Settings</h1>
<button class="btn btn-primary"><i class="bi bi-save me-2"></i>Save Changes</button>
</div>
<map-district
district-id="{{.District.GID}}"
centroid="{{.District.Centroid|json}}"
xmin="{{.District.XMin}}"
ymin="{{.District.YMin}}"
xmax="{{.District.XMax}}"
ymax="{{.District.YMax}}"
tegola="{{.URL.Tegola}}"></map-district>
<div class="row">
<!-- Basic Information -->
<div class="col-md-6">
<div class="card settings-card">
<div class="card-header bg-light">
<h5><i class="bi bi-building me-2"></i> Organization Information</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="agencyName" class="form-label"><i class="bi bi-briefcase me-1"></i> Agency Name</label>
<input type="text" class="form-control" id="agencyName" value="Central District Water Authority">
</div>
<div class="mb-3">
<label for="website" class="form-label"><i class="bi bi-globe me-1"></i> Website</label>
<input type="url" class="form-control" id="website" value="https://cdwa.example.org">
</div>
<div class="mb-3">
<label for="generalManager" class="form-label"><i class="bi bi-person-badge me-1"></i> General Manager Name</label>
<input type="text" class="form-control" id="generalManager" value="Jane Smithson">
</div>
<div class="mb-3">
<label for="contactPerson" class="form-label"><i class="bi bi-person me-1"></i> Contact Person</label>
<input type="text" class="form-control" id="contactPerson" value="John Doe">
</div>
</div>
</div>
</div>
<!-- Contact Information -->
<div class="col-md-6">
<div class="card settings-card">
<div class="card-header bg-light">
<h5><i class="bi bi-telephone me-2"></i> Contact Information</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="address" class="form-label"><i class="bi bi-geo me-1"></i> Address</label>
<input type="text" class="form-control" id="address" value="123 Main Street, Suite 400">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="city" class="form-label"><i class="bi bi-building me-1"></i> City</label>
<input type="text" class="form-control" id="city" value="Centerville">
</div>
<div class="col-md-6 mb-3">
<label for="postalCode" class="form-label"><i class="bi bi-mailbox me-1"></i> Postal Code</label>
<input type="text" class="form-control" id="postalCode" value="12345">
</div>
</div>
<div class="mb-3">
<label for="phoneNumber" class="form-label"><i class="bi bi-telephone me-1"></i> Phone Number (Primary)</label>
<input type="tel" class="form-control" id="phoneNumber" value="(555) 123-4567">
</div>
<div class="mb-3">
<label for="secondaryPhone" class="form-label"><i class="bi bi-telephone-plus me-1"></i> Phone Number (Secondary)</label>
<input type="tel" class="form-control" id="secondaryPhone" value="(555) 987-6543">
</div>
<div class="mb-3">
<label for="faxNumber" class="form-label"><i class="bi bi-printer me-1"></i> Fax Number</label>
<input type="tel" class="form-control" id="faxNumber" value="(555) 765-4321">
</div>
</div>
</div>
</div>
<!-- District Coverage Information -->
<div class="col-12">
<div class="card settings-card">
<div class="card-header bg-light">
<h5><i class="bi bi-map me-2"></i> District Coverage</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="totalArea" class="form-label"><i class="bi bi-rulers me-1"></i> Total Area (square kilometers)</label>
<input type="number" class="form-control" id="totalArea" value="1250">
</div>
<div class="col-md-6 mb-3">
<label for="countiesServed" class="form-label"><i class="bi bi-pin-map me-1"></i> Counties Served</label>
<select class="form-select" id="countiesServed" multiple size="3">
<option selected>Franklin County</option>
<option selected>Jefferson County</option>
<option selected>Washington County</option>
<option>Lincoln County</option>
<option>Adams County</option>
</select>
<small class="form-text text-muted">Hold Ctrl (or Cmd) to select multiple counties</small>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end mt-3">
<button class="btn btn-secondary me-2"><i class="bi bi-x-circle me-1"></i> Cancel</button>
<button class="btn btn-primary"><i class="bi bi-save me-1"></i> Save Changes</button>
</div>
</div>
</div>
</div>
{{ end }}

View file

@ -101,7 +101,7 @@
Manage your district location and information.
</p>
<div class="d-flex justify-content-between align-items-center">
<a href="equipment.html" class="btn btn-outline-danger">
<a href="{{ .URL.SettingDistrict }}" class="btn btn-outline-danger">
Manage District
<i class="bi bi-arrow-right ms-1"></i>
</a>

View file

@ -67,6 +67,7 @@ func Router() chi.Router {
r.Method("GET", "/pool/upload/{id}", auth.NewEnsureAuth(getPoolUploadByID))
r.Method("POST", "/pool/upload", auth.NewEnsureAuth(postPoolUpload))
r.Method("GET", "/setting", auth.NewEnsureAuth(getSetting))
r.Method("GET", "/setting/district", auth.NewEnsureAuth(getSettingDistrict))
r.Method("GET", "/setting/integration", auth.NewEnsureAuth(getSettingIntegration))
r.Method("GET", "/signout", auth.NewEnsureAuth(getSignout))
r.Method("GET", "/source/{globalid}", auth.NewEnsureAuth(getSource))

View file

@ -3,12 +3,32 @@ package sync
import (
"net/http"
"github.com/Gleipnir-Technology/bob"
"github.com/Gleipnir-Technology/bob/dialect/psql"
"github.com/Gleipnir-Technology/bob/dialect/psql/sm"
"github.com/Gleipnir-Technology/nidus-sync/arcgis"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/html"
//"github.com/rs/zerolog/log"
"github.com/stephenafamo/scan"
)
type ContentSettingIntegration struct {
type contentDistrict struct {
Centroid string `db:"st_asgeojson"`
GID int32 `db:"gid"`
XMin float32 `db:"st_xmin"`
YMin float32 `db:"st_ymin"`
XMax float32 `db:"st_xmax"`
YMax float32 `db:"st_ymax"`
}
type contentSettingDistrict struct {
District contentDistrict
URL ContentURL
User User
}
type contentSettingIntegration struct {
ArcGISOAuth *models.OauthToken
URL ContentURL
User User
@ -26,6 +46,42 @@ func getSetting(w http.ResponseWriter, r *http.Request, u *models.User) {
}
html.RenderOrError(w, "sync/settings.html", data)
}
func getSettingDistrict(w http.ResponseWriter, r *http.Request, u *models.User) {
ctx := r.Context()
userContent, err := contentForUser(ctx, u)
if err != nil {
respondError(w, "Failed to get user content", err, http.StatusInternalServerError)
return
}
org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
var district contentDistrict
gid := int32(0)
if org.ImportDistrictGid.IsValue() {
gid = org.ImportDistrictGid.MustGet()
district, err = bob.One[contentDistrict](ctx, db.PGInstance.BobDB, psql.Select(
sm.From("import.district"),
sm.Columns(
"gid",
psql.F("ST_AsGeoJSON", "centroid_4326"),
psql.F("ST_XMin", "extent_4326"),
psql.F("ST_YMin", "extent_4326"),
psql.F("ST_XMax", "extent_4326"),
psql.F("ST_YMax", "extent_4326"),
),
sm.Where(psql.Quote("gid").EQ(psql.Arg(gid))),
), scan.StructMapper[contentDistrict]())
if err != nil {
respondError(w, "Failed to get extents", err, http.StatusInternalServerError)
return
}
}
data := contentSettingDistrict{
District: district,
URL: newContentURL(),
User: userContent,
}
html.RenderOrError(w, "sync/setting-district.html", data)
}
func getSettingIntegration(w http.ResponseWriter, r *http.Request, u *models.User) {
ctx := r.Context()
userContent, err := contentForUser(ctx, u)
@ -38,7 +94,7 @@ func getSettingIntegration(w http.ResponseWriter, r *http.Request, u *models.Use
respondError(w, "Failed to get oauth", err, http.StatusInternalServerError)
return
}
data := ContentSettingIntegration{
data := contentSettingIntegration{
ArcGISOAuth: oauth,
URL: newContentURL(),
User: userContent,

View file

@ -9,6 +9,7 @@ type ContentURL struct {
PoolCSVUpload string
SamplePoolCSV string
Setting string
SettingDistrict string
SettingIntegration string
SettingPesticide string
SettingPesticideAdd string
@ -23,6 +24,7 @@ func newContentURL() ContentURL {
PoolCSVUpload: config.MakeURLNidus("/pool/upload"),
SamplePoolCSV: config.MakeURLNidus("/static/file/sample-pool.csv"),
Setting: config.MakeURLNidus("/setting"),
SettingDistrict: config.MakeURLNidus("/setting/district"),
SettingIntegration: config.MakeURLNidus("/setting/integration"),
SettingPesticide: config.MakeURLNidus("/setting/pesticide"),
SettingPesticideAdd: config.MakeURLNidus("/setting/pesticide/add"),

View file

@ -18,3 +18,5 @@ GRANT SELECT ON publicreport.report_location TO "tegola";
GRANT ALL PRIVILEGES ON SCHEMA public TO $1;
-- do import of district data
ALTER TABLE import.district ADD COLUMN geom_4326 geometry(MultiPolygon,4326) GENERATED ALWAYS AS (ST_Transform(geom, 4326)) STORED;
ALTER TABLE import.district ADD COLUMN centroid_4326 geometry(Point,4326) GENERATED ALWAYS AS (ST_Transform(ST_Centroid(geom), 4326)) STORED;
ALTER TABLE import.district ADD COLUMN extent_4326 geometry(Polygon,4326) GENERATED ALWAYS AS (ST_Transform(ST_Envelope(geom), 4326)) STORED;