Add traps to cell details page
This commit is contained in:
parent
0bd1a10753
commit
885b58a0ab
6 changed files with 109 additions and 22 deletions
|
|
@ -132,14 +132,13 @@ class MapAggregate extends HTMLElement {
|
|||
'fill-color': '#0dcaf0'
|
||||
}
|
||||
});
|
||||
var self = this;
|
||||
map.addInteraction("tegola-click-interaction", {
|
||||
type: "click",
|
||||
target: { layerId: "mosquito_source" },
|
||||
handler: (e) => {
|
||||
const coordinates = e.feature.geometry.coordinates.slice();
|
||||
const properties = e.feature.properties;
|
||||
self.dispatchEvent(new CustomEvent("cell-click", {
|
||||
this.dispatchEvent(new CustomEvent("cell-click", {
|
||||
bubbles: true,
|
||||
composed: true, // Allows event to cross shadow DOM boundary
|
||||
detail: {
|
||||
|
|
|
|||
18
sync/dash.go
18
sync/dash.go
|
|
@ -33,6 +33,15 @@ type Config struct {
|
|||
URLTegola string
|
||||
}
|
||||
|
||||
type ContextCell struct {
|
||||
BreedingSources []BreedingSourceSummary
|
||||
CellBoundary h3.CellBoundary
|
||||
Inspections []Inspection
|
||||
MapData ComponentMap
|
||||
Traps []Trap
|
||||
Treatments []Treatment
|
||||
User User
|
||||
}
|
||||
type ContextDashboard struct {
|
||||
Config Config
|
||||
CountTraps int
|
||||
|
|
@ -161,12 +170,18 @@ func cell(ctx context.Context, w http.ResponseWriter, user *models.User, c int64
|
|||
respondError(w, "Failed to get sources", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
traps, err := trapsByCell(ctx, org, h3.Cell(c))
|
||||
if err != nil {
|
||||
respondError(w, "Failed to get traps", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
treatments, err := treatmentsByCell(ctx, org, h3.Cell(c))
|
||||
if err != nil {
|
||||
respondError(w, "Failed to get treatments", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data := ContentCell{
|
||||
data := ContextCell{
|
||||
BreedingSources: sources,
|
||||
CellBoundary: boundary,
|
||||
Inspections: inspections,
|
||||
|
|
@ -179,6 +194,7 @@ func cell(ctx context.Context, w http.ResponseWriter, user *models.User, c int64
|
|||
MapboxToken: config.MapboxToken,
|
||||
Zoom: resolution + 5,
|
||||
},
|
||||
Traps: traps,
|
||||
Treatments: treatments,
|
||||
User: userContent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,13 @@ type TrapData struct {
|
|||
Comments string `json:"comments"`
|
||||
}
|
||||
|
||||
type Trap struct {
|
||||
Active bool
|
||||
Comments string
|
||||
Description string
|
||||
GlobalID uuid.UUID
|
||||
}
|
||||
|
||||
type Treatment struct {
|
||||
CadenceDelta time.Duration
|
||||
Date *time.Time
|
||||
|
|
@ -162,7 +169,18 @@ type Treatment struct {
|
|||
Product string
|
||||
}
|
||||
|
||||
func toTemplateTraps(locations []sql.TrapLocationBySourceIDRow, trap_data []sql.TrapDataByLocationIDRecentRow, counts []sql.TrapCountByLocationIDRow) ([]TrapNearby, error) {
|
||||
func toTemplateTrap(traps models.FieldseekerTraplocationSlice) (results []Trap, err error) {
|
||||
for _, t := range traps {
|
||||
results = append(results, Trap{
|
||||
Active: toBool16Or(t.Active, false),
|
||||
Comments: t.Comments.GetOr(""),
|
||||
Description: t.Description.GetOr(""),
|
||||
GlobalID: t.Globalid,
|
||||
})
|
||||
}
|
||||
return results, err
|
||||
}
|
||||
func toTemplateTrapsNearby(locations []sql.TrapLocationBySourceIDRow, trap_data []sql.TrapDataByLocationIDRecentRow, counts []sql.TrapCountByLocationIDRow) ([]TrapNearby, error) {
|
||||
results := make([]TrapNearby, 0)
|
||||
count_by_trap_data_id := make(map[uuid.UUID]*sql.TrapCountByLocationIDRow)
|
||||
for _, c := range counts {
|
||||
|
|
@ -409,3 +427,17 @@ func getTimeOrNull(v null.Val[time.Time]) *time.Time {
|
|||
val := v.MustGet()
|
||||
return &val
|
||||
}
|
||||
|
||||
func toBool16Or(t null.Val[int16], def bool) bool {
|
||||
if t.IsNull() {
|
||||
return def
|
||||
}
|
||||
val := t.MustGet()
|
||||
var b bool
|
||||
if val == 0 {
|
||||
b = false
|
||||
} else {
|
||||
b = true
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,36 @@
|
|||
|
||||
<!-- Right Column -->
|
||||
<div class="col-md-6">
|
||||
<h2 class="section-header">Traps</h2>
|
||||
{{ if gt (len .Traps) 0}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Active</th>
|
||||
<th>Comments</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Traps }}
|
||||
<tr>
|
||||
<td><a href="/trap/{{.GlobalID}}">{{.GlobalID|uuidShort}}</a></td>
|
||||
<td>{{.Active}}</td>
|
||||
<td>{{.Comments}}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
<p>No traps</p>
|
||||
{{ end }}
|
||||
|
||||
<!-- Treatments Section -->
|
||||
<h2 class="section-header">Treatment History</h2>
|
||||
<div class="card mb-4">
|
||||
|
|
|
|||
|
|
@ -28,14 +28,6 @@ type ComponentMap struct {
|
|||
type ContentAuthenticatedPlaceholder struct {
|
||||
User User
|
||||
}
|
||||
type ContentCell struct {
|
||||
BreedingSources []BreedingSourceSummary
|
||||
CellBoundary h3.CellBoundary
|
||||
Inspections []Inspection
|
||||
MapData ComponentMap
|
||||
Treatments []Treatment
|
||||
User User
|
||||
}
|
||||
type ContentMockURLs struct {
|
||||
Dispatch string
|
||||
DispatchResults string
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func contentForUser(ctx context.Context, user *models.User) (User, error) {
|
|||
DisplayName: user.DisplayName,
|
||||
Initials: extractInitials(user.DisplayName),
|
||||
Notifications: notifications,
|
||||
Organization: Organization {
|
||||
Organization: Organization{
|
||||
ID: int(org.ID),
|
||||
Name: org.Name,
|
||||
},
|
||||
|
|
@ -181,7 +181,7 @@ func trapsBySource(ctx context.Context, org *models.Organization, sourceID uuid.
|
|||
return nil, fmt.Errorf("Failed to query trap counts: %w", err)
|
||||
}
|
||||
|
||||
traps, err := toTemplateTraps(locations, trap_data, counts)
|
||||
traps, err := toTemplateTrapsNearby(locations, trap_data, counts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to convert trap data: %w", err)
|
||||
}
|
||||
|
|
@ -203,6 +203,24 @@ func treatmentsBySource(ctx context.Context, org *models.Organization, sourceID
|
|||
return toTemplateTreatment(rows)
|
||||
}
|
||||
|
||||
func trapsByCell(ctx context.Context, org *models.Organization, c h3.Cell) (results []Trap, err error) {
|
||||
boundary, err := c.Boundary()
|
||||
if err != nil {
|
||||
return results, fmt.Errorf("Failed to get cell boundary: %w", err)
|
||||
}
|
||||
geom_query := gisStatement(boundary)
|
||||
rows, err := org.Traplocations(
|
||||
sm.Where(
|
||||
psql.F("ST_Within", "geospatial", geom_query),
|
||||
),
|
||||
sm.OrderBy("objectid"),
|
||||
).All(ctx, db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
return results, fmt.Errorf("Failed to query rows: %w", err)
|
||||
}
|
||||
return toTemplateTrap(rows)
|
||||
}
|
||||
|
||||
func treatmentsByCell(ctx context.Context, org *models.Organization, c h3.Cell) ([]Treatment, error) {
|
||||
var results []Treatment
|
||||
boundary, err := c.Boundary()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue