mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Split up display configuration and LED/PLC testing into separate setup pages.
This commit is contained in:
@@ -37,7 +37,7 @@ var handlePlcIoChange = function(data) {
|
||||
|
||||
$(function() {
|
||||
// Set up the websocket back to the server.
|
||||
websocket = new CheesyWebsocket("/setup/field/websocket", {
|
||||
websocket = new CheesyWebsocket("/setup/led_plc/websocket", {
|
||||
ledMode: function(event) {handleLedMode(event.data); },
|
||||
plcIoChange: function(event) { handlePlcIoChange(event.data); }
|
||||
});
|
||||
@@ -38,12 +38,13 @@
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Setup</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/setup/settings">Settings</a></li>
|
||||
<li><a href="/setup/field">Field Configuration</a></li>
|
||||
<li><a href="/setup/teams">Team List</a></li>
|
||||
<li><a href="/setup/schedule">Match Scheduling</a></li>
|
||||
<li><a href="/setup/alliance_selection">Alliance Selection</a></li>
|
||||
<li><a href="/setup/lower_thirds">Lower Thirds</a></li>
|
||||
<li><a href="/setup/sponsor_slides">Sponsor Slides</a></li>
|
||||
<li><a href="/setup/displays">Display Configuration</a></li>
|
||||
<li><a href="/setup/led_plc">LED and PLC Testing</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
|
||||
41
templates/setup_displays.html
Normal file
41
templates/setup_displays.html
Normal file
@@ -0,0 +1,41 @@
|
||||
{{/*
|
||||
Copyright 2018 Team 254. All Rights Reserved.
|
||||
Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
UI for configuring the field displays.
|
||||
*/}}
|
||||
{{define "title"}}Display Configuration{{end}}
|
||||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="well">
|
||||
<legend>Alliance Station Displays</legend>
|
||||
{{range $displayId, $station := .AllianceStationDisplays}}
|
||||
<form class="form-horizontal" action="" method="POST">
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Display {{$displayId}}</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="hidden" name="displayId" value="{{$displayId}}" />
|
||||
<select class="form-control" name="allianceStation" onchange="this.form.submit();">
|
||||
<option value=""></option>
|
||||
<option value="R1"{{if eq $station "R1"}} selected{{end}}>Red 1</option>
|
||||
<option value="R2"{{if eq $station "R2"}} selected{{end}}>Red 2</option>
|
||||
<option value="R3"{{if eq $station "R3"}} selected{{end}}>Red 3</option>
|
||||
<option value="B1"{{if eq $station "B1"}} selected{{end}}>Blue 1</option>
|
||||
<option value="B2"{{if eq $station "B2"}} selected{{end}}>Blue 2</option>
|
||||
<option value="B3"{{if eq $station "B3"}} selected{{end}}>Blue 3</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
<legend>Reload All Displays</legend>
|
||||
<div class="form-group">
|
||||
<a href="/setup/displays/reload" class="btn btn-primary">Force Reload of All Displays</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
{{end}}
|
||||
@@ -1,113 +0,0 @@
|
||||
{{/*
|
||||
Copyright 2014 Team 254. All Rights Reserved.
|
||||
Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
UI for controlling ephemeral aspects of the playing field.
|
||||
*/}}
|
||||
{{define "title"}}Field Configuration{{end}}
|
||||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="well">
|
||||
<legend>Alliance Station Displays</legend>
|
||||
{{range $displayId, $station := .AllianceStationDisplays}}
|
||||
<form class="form-horizontal" action="/setup/field" method="POST">
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Display {{$displayId}}</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="hidden" name="displayId" value="{{$displayId}}" />
|
||||
<select class="form-control" name="allianceStation" onchange="this.form.submit();">
|
||||
<option value=""></option>
|
||||
<option value="R1"{{if eq $station "R1"}} selected{{end}}>Red 1</option>
|
||||
<option value="R2"{{if eq $station "R2"}} selected{{end}}>Red 2</option>
|
||||
<option value="R3"{{if eq $station "R3"}} selected{{end}}>Red 3</option>
|
||||
<option value="B1"{{if eq $station "B1"}} selected{{end}}>Blue 1</option>
|
||||
<option value="B2"{{if eq $station "B2"}} selected{{end}}>Blue 2</option>
|
||||
<option value="B3"{{if eq $station "B3"}} selected{{end}}>Blue 3</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
<legend>Reload All Displays</legend>
|
||||
<div class="form-group">
|
||||
<a href="/setup/field/reload_displays" class="btn btn-primary">Force Reload of All Displays</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7">
|
||||
<div class="well">
|
||||
<legend>PLC</legend>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Inputs</th>
|
||||
</tr>
|
||||
{{range $i, $name := .InputNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="input{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Registers</th>
|
||||
</tr>
|
||||
{{range $i, $name := .RegisterNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="register{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Coils</th>
|
||||
</tr>
|
||||
{{range $i, $name := .CoilNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="coil{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<div class="well">
|
||||
<legend>LEDs</legend>
|
||||
<div class="form-group">
|
||||
<label>Switch/Scale</label>
|
||||
{{range $i, $name := .LedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="ledMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Vault</label>
|
||||
{{range $i, $name := .VaultLedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="vaultLedMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
<script src="/static/js/setup_field.js"></script>
|
||||
{{end}}
|
||||
84
templates/setup_led_plc.html
Normal file
84
templates/setup_led_plc.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{{/*
|
||||
Copyright 2018 Team 254. All Rights Reserved.
|
||||
Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
UI for testing the LEDs and PLC connected to the field.
|
||||
*/}}
|
||||
{{define "title"}}LED and PLC Testing{{end}}
|
||||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-lg-7">
|
||||
<div class="well">
|
||||
<legend>PLC</legend>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Inputs</th>
|
||||
</tr>
|
||||
{{range $i, $name := .InputNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="input{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Registers</th>
|
||||
</tr>
|
||||
{{range $i, $name := .RegisterNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="register{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="2">Coils</th>
|
||||
</tr>
|
||||
{{range $i, $name := .CoilNames}}
|
||||
<tr>
|
||||
<td>{{$name}}</td>
|
||||
<td id="coil{{$i}}"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="well">
|
||||
<legend>Switch/Scale LEDs</legend>
|
||||
{{range $i, $name := .LedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="ledMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<div class="well">
|
||||
<legend>Vault LEDs</legend>
|
||||
{{range $i, $name := .VaultLedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="vaultLedMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
<script src="/static/js/setup_led_plc.js"></script>
|
||||
{{end}}
|
||||
@@ -29,7 +29,7 @@ func TestPitDisplayWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Check forced reloading as that is the only purpose the pit websocket serves.
|
||||
recorder := web.getHttpResponse("/setup/field/reload_displays")
|
||||
recorder := web.getHttpResponse("/setup/displays/reload")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
readWebsocketType(t, ws, "reload")
|
||||
}
|
||||
|
||||
56
web/setup_displays.go
Normal file
56
web/setup_displays.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Web routes for configuring the field displays.
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Shows the displays configuration page.
|
||||
func (web *Web) displaysGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := web.parseFiles("templates/setup_displays.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
data := struct {
|
||||
*model.EventSettings
|
||||
AllianceStationDisplays map[string]string
|
||||
}{web.arena.EventSettings, web.arena.AllianceStationDisplays}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the display-station mapping for a single display.
|
||||
func (web *Web) displaysPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
displayId := r.PostFormValue("displayId")
|
||||
allianceStation := r.PostFormValue("allianceStation")
|
||||
web.arena.AllianceStationDisplays[displayId] = allianceStation
|
||||
web.arena.MatchLoadNotifier.Notify()
|
||||
http.Redirect(w, r, "/setup/displays", 303)
|
||||
}
|
||||
|
||||
// Force-reloads all the websocket-connected displays.
|
||||
func (web *Web) displaysReloadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
web.arena.ReloadDisplaysNotifier.Notify()
|
||||
http.Redirect(w, r, "/setup/displays", 303)
|
||||
}
|
||||
25
web/setup_displays_test.go
Normal file
25
web/setup_displays_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetupDisplays(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
web.arena.AllianceStationDisplays["12345"] = ""
|
||||
recorder := web.getHttpResponse("/setup/displays")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "12345")
|
||||
assert.NotContains(t, recorder.Body.String(), "selected")
|
||||
|
||||
recorder = web.postHttpResponse("/setup/displays", "displayId=12345&allianceStation=B1")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
recorder = web.getHttpResponse("/setup/displays")
|
||||
assert.Contains(t, recorder.Body.String(), "12345")
|
||||
assert.Contains(t, recorder.Body.String(), "selected")
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Web routes for configuring the field components.
|
||||
// Web routes for testing the field LEDs and PLC.
|
||||
|
||||
package web
|
||||
|
||||
@@ -18,13 +18,13 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Shows the field configuration page.
|
||||
func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Shows the LED/PLC test page.
|
||||
func (web *Web) ledPlcGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
template, err := web.parseFiles("templates/setup_field.html", "templates/base.html")
|
||||
template, err := web.parseFiles("templates/setup_led_plc.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -32,14 +32,13 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
plc := web.arena.Plc
|
||||
data := struct {
|
||||
*model.EventSettings
|
||||
AllianceStationDisplays map[string]string
|
||||
InputNames []string
|
||||
RegisterNames []string
|
||||
CoilNames []string
|
||||
LedModeNames map[led.Mode]string
|
||||
VaultLedModeNames map[vaultled.Mode]string
|
||||
}{web.arena.EventSettings, web.arena.AllianceStationDisplays, plc.GetInputNames(), plc.GetRegisterNames(),
|
||||
plc.GetCoilNames(), led.ModeNames, vaultled.ModeNames}
|
||||
InputNames []string
|
||||
RegisterNames []string
|
||||
CoilNames []string
|
||||
LedModeNames map[led.Mode]string
|
||||
VaultLedModeNames map[vaultled.Mode]string
|
||||
}{web.arena.EventSettings, plc.GetInputNames(), plc.GetRegisterNames(), plc.GetCoilNames(), led.ModeNames,
|
||||
vaultled.ModeNames}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -47,31 +46,8 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the display-station mapping for a single display.
|
||||
func (web *Web) fieldPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
displayId := r.PostFormValue("displayId")
|
||||
allianceStation := r.PostFormValue("allianceStation")
|
||||
web.arena.AllianceStationDisplays[displayId] = allianceStation
|
||||
web.arena.MatchLoadNotifier.Notify()
|
||||
http.Redirect(w, r, "/setup/field", 303)
|
||||
}
|
||||
|
||||
// Force-reloads all the websocket-connected displays.
|
||||
func (web *Web) fieldReloadDisplaysHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
web.arena.ReloadDisplaysNotifier.Notify()
|
||||
http.Redirect(w, r, "/setup/field", 303)
|
||||
}
|
||||
|
||||
// The websocket endpoint for sending realtime updates to the field setup page.
|
||||
func (web *Web) fieldWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// The websocket endpoint for sending realtime updates to the LED/PLC test page.
|
||||
func (web *Web) ledPlcWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package web
|
||||
@@ -15,28 +15,12 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func TestSetupField(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
web.arena.AllianceStationDisplays["12345"] = ""
|
||||
recorder := web.getHttpResponse("/setup/field")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "12345")
|
||||
assert.NotContains(t, recorder.Body.String(), "selected")
|
||||
|
||||
recorder = web.postHttpResponse("/setup/field", "displayId=12345&allianceStation=B1")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
recorder = web.getHttpResponse("/setup/field")
|
||||
assert.Contains(t, recorder.Body.String(), "12345")
|
||||
assert.Contains(t, recorder.Body.String(), "selected")
|
||||
}
|
||||
|
||||
func TestSetupFieldWebsocket(t *testing.T) {
|
||||
func TestSetupLedPlcWebsocket(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
server, wsUrl := web.startTestServer()
|
||||
defer server.Close()
|
||||
conn, _, err := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/setup/field/websocket", nil)
|
||||
conn, _, err := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/setup/led_plc/websocket", nil)
|
||||
assert.Nil(t, err)
|
||||
defer conn.Close()
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
@@ -148,10 +148,11 @@ func (web *Web) newHandler() http.Handler {
|
||||
router.HandleFunc("/setup/alliance_selection/reset", web.allianceSelectionResetHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/alliance_selection/finalize", web.allianceSelectionFinalizeHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/alliance_selection/publish", web.allianceSelectionPublishHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/field", web.fieldGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/field", web.fieldPostHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/field/reload_displays", web.fieldReloadDisplaysHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/field/websocket", web.fieldWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/displays", web.displaysGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/displays", web.displaysPostHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/displays/reload", web.displaysReloadHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/led_plc", web.ledPlcGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/led_plc/websocket", web.ledPlcWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/lower_thirds", web.lowerThirdsGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/lower_thirds/websocket", web.lowerThirdsWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/sponsor_slides", web.sponsorSlidesGetHandler).Methods("GET")
|
||||
|
||||
Reference in New Issue
Block a user