mirror of
https://github.com/MeshTender/MeshTender.git
synced 2026-09-26 05:13:53 +00:00
162 lines
7.2 KiB
HTML
162 lines
7.2 KiB
HTML
{{define "title"}}Recommended configuration · {{.Org.Name}} · MeshTender{{end}}
|
|
{{define "header"}}
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col">
|
|
<div class="page-pretitle">{{.Org.Name}}</div>
|
|
<h2 class="page-title">Recommended configuration</h2>
|
|
</div>
|
|
<div class="col-auto ms-auto d-print-none">
|
|
<a class="btn" href="/orgs/{{.Org.Slug}}">Back to organization</a>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{define "content"}}
|
|
|
|
{{if .Errors}}
|
|
<div class="alert alert-danger">
|
|
<div class="fw-bold">Nothing was published — fix these first:</div>
|
|
<ul class="mb-0">{{range .Errors}}<li>{{.}}</li>{{end}}</ul>
|
|
</div>
|
|
{{end}}
|
|
{{if .RiskyWarn}}
|
|
<div class="alert alert-warning">
|
|
<div class="fw-bold">Risky commands in this profile</div>
|
|
<p class="mb-1">These can take over or brick a node — included on purpose?</p>
|
|
<ul class="mb-0">{{range .RiskyWarn}}<li><code>{{.}}</code></li>{{end}}</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<p class="text-secondary mb-0">
|
|
The commands an operator should run to bring a repeater in spec for this org.
|
|
{{if .IsAdmin}}This is a reference members can copy; those with a KISS modem can apply it from a repeater's
|
|
console. Region commands can vary by location — add <strong>zones</strong> with a geofence and they'll
|
|
only apply to repeaters inside them.{{else}}Copy these into a repeater's console, or apply them directly
|
|
from the console if you have a modem connected.{{end}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{{if .IsAdmin}}
|
|
{{/* ---------- Admin editor ---------- */}}
|
|
<form method="post" action="/orgs/{{.Org.Slug}}/config">
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h3 class="card-title">Base steps</h3></div>
|
|
<div class="card-body">
|
|
<p class="text-secondary">Applied to every repeater. One command per line; lines starting with <code>#</code> are notes.</p>
|
|
<textarea class="form-control font-monospace" name="base" rows="6" spellcheck="false"
|
|
placeholder="set tx 22 # radio plan below">{{.BaseText}}</textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h3 class="card-title">Region zones</h3></div>
|
|
<div class="card-body">
|
|
<p class="text-secondary">Steps that apply only to repeaters inside a geofence. Leave all four corners blank for a zone that applies everywhere. Lower priority applies first; same-priority overlapping zones both apply.</p>
|
|
<div id="zones">
|
|
{{range .Zones}}{{template "zone-block" .}}{{end}}
|
|
</div>
|
|
<button type="button" class="btn btn-outline-primary mt-2" onclick="addZone()">{{template "icon-plus" "me-1"}}Add zone</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label" for="note">Change note</label>
|
|
<input type="text" class="form-control" id="note" name="note" maxlength="200" placeholder="e.g. added the metro region hierarchy">
|
|
</div>
|
|
<div class="btn-list">
|
|
<button type="submit" class="btn btn-primary">Publish new version</button>
|
|
<a class="btn" href="/orgs/{{.Org.Slug}}">Cancel</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
{{/* Hidden prototype block cloned by addZone(); kept out of the form via a template tag. */}}
|
|
<template id="zone-proto">{{template "zone-block" .EmptyZone}}</template>
|
|
<script>
|
|
function addZone() {
|
|
const proto = document.getElementById('zone-proto');
|
|
const node = proto.content.cloneNode(true);
|
|
document.getElementById('zones').appendChild(node);
|
|
}
|
|
function removeZone(btn) { btn.closest('.zone-block').remove(); }
|
|
</script>
|
|
|
|
{{else}}
|
|
{{/* ---------- Read-only reference ---------- */}}
|
|
{{if .HasProfile}}
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h3 class="card-title">Base steps</h3>
|
|
<span class="card-subtitle ms-auto">v{{.Version}}</span>
|
|
</div>
|
|
<div class="card-body">{{template "step-list" .BaseSteps}}</div>
|
|
</div>
|
|
{{range .Zones}}
|
|
<div class="card mt-3">
|
|
<div class="card-header">
|
|
<h3 class="card-title">{{.Name}}</h3>
|
|
<span class="card-subtitle ms-auto">{{if .MatchAll}}everywhere{{else}}lat {{.MinLat}}…{{.MaxLat}}, lon {{.MinLon}}…{{.MaxLon}}{{end}} · priority {{.Priority}}</span>
|
|
</div>
|
|
<div class="card-body">{{template "step-list" .Steps}}</div>
|
|
</div>
|
|
{{end}}
|
|
{{else}}
|
|
<div class="card mt-3"><div class="card-body text-secondary">This organization hasn't published a recommended configuration yet.</div></div>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{/* ---------- Location preview (admin convenience) ---------- */}}
|
|
{{if .HasProfile}}
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h3 class="card-title">Preview for a location</h3></div>
|
|
<div class="card-body">
|
|
<form method="get" action="/orgs/{{.Org.Slug}}/config" class="row g-2 align-items-end">
|
|
<div class="col-auto"><label class="form-label" for="lat">Latitude</label>
|
|
<input class="form-control" type="text" id="lat" name="lat" value="{{if .PreviewLat}}{{.PreviewLat}}{{end}}"></div>
|
|
<div class="col-auto"><label class="form-label" for="lon">Longitude</label>
|
|
<input class="form-control" type="text" id="lon" name="lon" value="{{if .PreviewLon}}{{.PreviewLon}}{{end}}"></div>
|
|
<div class="col-auto"><button class="btn" type="submit">Resolve</button></div>
|
|
</form>
|
|
{{if .Preview}}
|
|
<div class="mt-3">
|
|
<div class="text-secondary mb-1">Commands a repeater at {{.PreviewLat}}, {{.PreviewLon}} should run:</div>
|
|
{{template "step-list" .Preview}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{/* step-list renders a sequence of ConfigStep as a copy-pasteable block. */}}
|
|
{{define "step-list"}}
|
|
{{if .}}<pre class="mb-0"><code>{{range .}}{{if .IsComment}}# {{.Comment}}{{else}}{{.CommandLine}}{{end}}
|
|
{{end}}</code></pre>{{else}}<div class="text-secondary">No steps.</div>{{end}}
|
|
{{end}}
|
|
|
|
{{/* zone-block is one editable zone in the admin form. */}}
|
|
{{define "zone-block"}}
|
|
<div class="zone-block border rounded p-3 mb-3">
|
|
<div class="row g-2">
|
|
<div class="col-md"><label class="form-label">Name</label>
|
|
<input class="form-control" name="zone_name" value="{{.Name}}" placeholder="Metro"></div>
|
|
<div class="col-md-auto"><label class="form-label">Priority</label>
|
|
<input class="form-control" type="number" name="zone_priority" value="{{.Priority}}" style="width:6rem"></div>
|
|
</div>
|
|
<div class="row g-2 mt-1">
|
|
<div class="col"><label class="form-label">Min lat</label><input class="form-control" name="zone_minlat" value="{{.MinLat}}"></div>
|
|
<div class="col"><label class="form-label">Min lon</label><input class="form-control" name="zone_minlon" value="{{.MinLon}}"></div>
|
|
<div class="col"><label class="form-label">Max lat</label><input class="form-control" name="zone_maxlat" value="{{.MaxLat}}"></div>
|
|
<div class="col"><label class="form-label">Max lon</label><input class="form-control" name="zone_maxlon" value="{{.MaxLon}}"></div>
|
|
</div>
|
|
<div class="mt-2"><label class="form-label">Steps</label>
|
|
<textarea class="form-control font-monospace" name="zone_steps" rows="4" spellcheck="false" placeholder="region put Metro region home Metro">{{.StepsText}}</textarea>
|
|
</div>
|
|
<button type="button" class="btn btn-ghost-danger btn-sm mt-2" onclick="removeZone(this)">Remove zone</button>
|
|
</div>
|
|
{{end}}
|