mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Add queueing display.
This commit is contained in:
@@ -265,14 +265,15 @@ func (arena *Arena) LoadNextMatch() error {
|
||||
}
|
||||
for _, match := range matches {
|
||||
if match.Status != "complete" {
|
||||
err = arena.LoadMatch(&match)
|
||||
if err != nil {
|
||||
if err = arena.LoadMatch(&match); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
// There are no matches left in the series; just load a test match.
|
||||
return arena.LoadTestMatch()
|
||||
}
|
||||
|
||||
// Assigns the given team to the given station, also substituting it into the match record.
|
||||
|
||||
@@ -412,8 +412,8 @@ func TestLoadNextMatch(t *testing.T) {
|
||||
arena.Database.SaveMatch(&practiceMatch3)
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, practiceMatch3.Id, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, "complete", practiceMatch3.Status)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, "test", arena.CurrentMatch.Type)
|
||||
|
||||
err = arena.LoadMatch(&qualificationMatch1)
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -31,6 +31,7 @@ const (
|
||||
AudienceDisplay
|
||||
FieldMonitorDisplay
|
||||
PitDisplay
|
||||
QueueingDisplay
|
||||
TwitchStreamDisplay
|
||||
)
|
||||
|
||||
@@ -41,6 +42,7 @@ var DisplayTypeNames = map[DisplayType]string{
|
||||
AudienceDisplay: "Audience",
|
||||
FieldMonitorDisplay: "Field Monitor",
|
||||
PitDisplay: "Pit",
|
||||
QueueingDisplay: "Queueing",
|
||||
TwitchStreamDisplay: "Twitch Stream",
|
||||
}
|
||||
|
||||
@@ -51,6 +53,7 @@ var displayTypePaths = map[DisplayType]string{
|
||||
AudienceDisplay: "/displays/audience",
|
||||
FieldMonitorDisplay: "/displays/fta",
|
||||
PitDisplay: "/displays/pit",
|
||||
QueueingDisplay: "/displays/queueing",
|
||||
TwitchStreamDisplay: "/displays/twitch",
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,6 @@ body {
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#logo {
|
||||
margin-bottom: 10px;
|
||||
height: 50px;
|
||||
}
|
||||
#standings {
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
|
||||
63
static/css/queueing_display.css
Normal file
63
static/css/queueing_display.css
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2018 Team 254. All Rights Reserved.
|
||||
Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
*/
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
cursor: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
body {
|
||||
height: 100%;
|
||||
background: -moz-linear-gradient(top, #003375 1%, #3C679D 100%); /* FF3.6+ */
|
||||
background: -webkit-linear-gradient(top, #003375 1%, #3C679D 100%); /* Chrome10+,Safari5.1+ */
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
}
|
||||
#header {
|
||||
padding: 10px 0px;
|
||||
font-size: 40px;
|
||||
font-family: "FuturaLTBold";
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.well {
|
||||
background-color: #ccc;
|
||||
border: 1px solid #333;
|
||||
padding: 10px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
#matchState, #matchTime {
|
||||
font-size: 35px;
|
||||
color: #666;
|
||||
}
|
||||
#matchTime {
|
||||
font-weight: bold;
|
||||
}
|
||||
.red-teams, .blue-teams {
|
||||
font-family: FuturaLTBold;
|
||||
line-height: 51px;
|
||||
font-size: 45px;
|
||||
}
|
||||
.red-teams {
|
||||
color: #ff4444;
|
||||
}
|
||||
.blue-teams {
|
||||
color: #2080ff;
|
||||
}
|
||||
.avatars {
|
||||
line-height: 51px;
|
||||
}
|
||||
#footer {
|
||||
font-size: 25px;
|
||||
font-family: "FuturaLTBold";
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
41
static/js/queueing_display.js
Normal file
41
static/js/queueing_display.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Client-side logic for the queueing display.
|
||||
|
||||
var websocket;
|
||||
var firstMatchLoad = true;
|
||||
|
||||
// Handles a websocket message to update the teams for the current match.
|
||||
var handleMatchLoad = function(data) {
|
||||
// Since the server always sends a matchLoad message upon establishing the websocket connection, ignore the first one.
|
||||
if (!firstMatchLoad) {
|
||||
location.reload();
|
||||
}
|
||||
firstMatchLoad = false;
|
||||
};
|
||||
|
||||
// Handles a websocket message to update the match time countdown.
|
||||
var handleMatchTime = function(data) {
|
||||
translateMatchTime(data, function(matchState, matchStateText, countdownSec) {
|
||||
$("#matchState").text(matchStateText);
|
||||
var countdownString = String(countdownSec % 60);
|
||||
if (countdownString.length === 1) {
|
||||
countdownString = "0" + countdownString;
|
||||
}
|
||||
countdownString = Math.floor(countdownSec / 60) + ":" + countdownString;
|
||||
$("#matchTime").text(countdownString);
|
||||
});
|
||||
};
|
||||
|
||||
$(function() {
|
||||
// Fall back to a blank avatar if one doesn't exist for the team.
|
||||
$(".avatar").attr("onerror", "this.src='/static/img/avatars/0.png';");
|
||||
|
||||
// Set up the websocket back to the server.
|
||||
websocket = new CheesyWebsocket("/displays/queueing/websocket", {
|
||||
matchLoad: function(event) { handleMatchLoad(event.data); },
|
||||
matchTime: function(event) { handleMatchTime(event.data); },
|
||||
matchTiming: function(event) { handleMatchTiming(event.data); }
|
||||
});
|
||||
});
|
||||
@@ -86,6 +86,7 @@
|
||||
<li><a href="/displays/audience">Audience</a></li>
|
||||
<li><a href="/displays/fta">Field Monitor</a></li>
|
||||
<li><a href="/displays/pit">Pit</a></li>
|
||||
<li><a href="/displays/queueing">Queueing</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Alliance Station</li>
|
||||
<li><a href="/displays/alliance_station?station=R1">Red 1</a></li>
|
||||
|
||||
83
templates/queueing_display.html
Normal file
83
templates/queueing_display.html
Normal file
@@ -0,0 +1,83 @@
|
||||
{{/*
|
||||
Copyright 2018 Team 254. All Rights Reserved.
|
||||
Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
Display that shows upcoming matches and timing information.
|
||||
*/}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Queueing Display - {{.EventSettings.Name}} - Cheesy Arena</title>
|
||||
<link rel="shortcut icon" href="/static/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/static/css/lib/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/static/css/cheesy-arena.css" />
|
||||
<link rel="stylesheet" href="/static/css/queueing_display.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="header" class="col-lg-10 col-lg-offset-1">
|
||||
<div class="pull-left">Match Queue</div>
|
||||
<div class="pull-right">{{.EventSettings.Name}}</div>
|
||||
</div>
|
||||
{{range $i, $match := .Matches}}
|
||||
<div class="col-lg-10 col-lg-offset-1 well">
|
||||
<div class="col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col-lg-5">
|
||||
<h1>
|
||||
{{if eq $i 0}}
|
||||
On Field
|
||||
{{else if eq $i 1}}
|
||||
On Deck
|
||||
{{else if eq $i 2}}
|
||||
Last Call
|
||||
{{else if eq $i 3}}
|
||||
Second Call
|
||||
{{else if eq $i 4}}
|
||||
First Call
|
||||
{{end}}
|
||||
</h1>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<h1>{{$.MatchTypePrefix}}{{$match.DisplayName}}</h1>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<h1>{{$match.Time.Local.Format "3:04 PM"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{{if eq $i 0}}
|
||||
<div class="row">
|
||||
<div id="matchState" class="col-lg-5"></div>
|
||||
<div id="matchTime" class="col-lg-3"></div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-lg-1 avatars text-right">
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Red1}}.png" /><br />
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Red2}}.png" /><br />
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Red3}}.png" />
|
||||
</div>
|
||||
<div class="col-lg-2 red-teams">
|
||||
{{$match.Red1}}<br />{{$match.Red2}}<br />{{$match.Red3}}
|
||||
</div>
|
||||
<div class="col-lg-2 blue-teams text-right">
|
||||
{{$match.Blue1}}<br />{{$match.Blue2}}<br />{{$match.Blue3}}
|
||||
</div>
|
||||
<div class="col-lg-1 avatars">
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Blue1}}.png" /><br />
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Blue2}}.png" /><br />
|
||||
<img class="avatar" src="/static/img/avatars/{{$match.Blue3}}.png" />
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div id="footer" class="col-lg-10 col-lg-offset-1">{{.StatusMessage}}</div>
|
||||
</body>
|
||||
<script src="/static/js/lib/jquery.min.js"></script>
|
||||
<script src="/static/js/lib/jquery.json-2.4.min.js"></script>
|
||||
<script src="/static/js/lib/jquery.websocket-0.0.1.js"></script>
|
||||
<script src="/static/js/lib/jquery.transit.min.js"></script>
|
||||
<script src="/static/js/lib/bootstrap.min.js"></script>
|
||||
<script src="/static/js/cheesy-websocket.js"></script>
|
||||
<script src="/static/js/match_timing.js"></script>
|
||||
<script src="/static/js/queueing_display.js"></script>
|
||||
</html>
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
UI for entering realtime scores.
|
||||
*/}}
|
||||
{{define "title"}}Scoring{{end}}
|
||||
{{define "title"}}Scoring Panel{{end}}
|
||||
{{define "body"}}
|
||||
<br />
|
||||
<div class="row">
|
||||
|
||||
@@ -30,9 +30,6 @@ type MatchPlayListItem struct {
|
||||
|
||||
type MatchPlayList []MatchPlayListItem
|
||||
|
||||
// Global var to hold the current active tournament so that its matches are displayed by default.
|
||||
var currentMatchType string
|
||||
|
||||
// Shows the match play control interface.
|
||||
func (web *Web) matchPlayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsAdmin(w, r) {
|
||||
@@ -62,7 +59,8 @@ func (web *Web) matchPlayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
matchesByType := map[string]MatchPlayList{"practice": practiceMatches,
|
||||
"qualification": qualificationMatches, "elimination": eliminationMatches}
|
||||
if currentMatchType == "" {
|
||||
currentMatchType := web.arena.CurrentMatch.Type
|
||||
if currentMatchType == "test" {
|
||||
currentMatchType = "practice"
|
||||
}
|
||||
allowSubstitution := web.arena.CurrentMatch.Type != "qualification"
|
||||
@@ -79,7 +77,8 @@ func (web *Web) matchPlayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Match *model.Match
|
||||
AllowSubstitution bool
|
||||
IsReplay bool
|
||||
}{web.arena.EventSettings, matchesByType, currentMatchType, web.arena.CurrentMatch, allowSubstitution, isReplay}
|
||||
}{web.arena.EventSettings, matchesByType, currentMatchType, web.arena.CurrentMatch, allowSubstitution,
|
||||
isReplay}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -115,7 +114,6 @@ func (web *Web) matchPlayLoadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
currentMatchType = web.arena.CurrentMatch.Type
|
||||
|
||||
http.Redirect(w, r, "/match_play", 303)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ func (web *Web) matchReviewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
matchesByType := map[string][]MatchReviewListItem{"practice": practiceMatches,
|
||||
"qualification": qualificationMatches, "elimination": eliminationMatches}
|
||||
if currentMatchType == "" {
|
||||
currentMatchType := web.arena.CurrentMatch.Type
|
||||
if currentMatchType == "test" {
|
||||
currentMatchType = "practice"
|
||||
}
|
||||
data := struct {
|
||||
|
||||
113
web/queueing_display.go
Normal file
113
web/queueing_display.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Web handlers for queueing display.
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const numMatchesToShow = 5
|
||||
|
||||
// Renders the queueing display that shows upcoming matches and timing information.
|
||||
func (web *Web) queueingDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, nil) {
|
||||
return
|
||||
}
|
||||
|
||||
matchTypePrefix := ""
|
||||
currentMatchType := web.arena.CurrentMatch.Type
|
||||
if currentMatchType == "practice" {
|
||||
matchTypePrefix = "P"
|
||||
} else if currentMatchType == "qualification" {
|
||||
matchTypePrefix = "Q"
|
||||
}
|
||||
matches, err := web.arena.Database.GetMatchesByType(currentMatchType)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
var upcomingMatches []model.Match
|
||||
for _, match := range matches {
|
||||
if match.Status == "complete" {
|
||||
continue
|
||||
}
|
||||
upcomingMatches = append(upcomingMatches, match)
|
||||
if len(upcomingMatches) == numMatchesToShow {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
template, err := web.parseFiles("templates/queueing_display.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := struct {
|
||||
*model.EventSettings
|
||||
MatchTypePrefix string
|
||||
Matches []model.Match
|
||||
StatusMessage string
|
||||
}{web.arena.EventSettings, matchTypePrefix, upcomingMatches, generateEventStatusMessage(matches)}
|
||||
err = template.ExecuteTemplate(w, "queueing_display.html", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// The websocket endpoint for the queueing display to receive updates.
|
||||
func (web *Web) queueingDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer web.arena.MarkDisplayDisconnected(display)
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
|
||||
ws.HandleNotifiers(web.arena.MatchTimingNotifier, web.arena.MatchLoadNotifier, web.arena.MatchTimeNotifier,
|
||||
web.arena.DisplayConfigurationNotifier, web.arena.ReloadDisplaysNotifier)
|
||||
}
|
||||
|
||||
// Returns a message indicating how early or late the event is running.
|
||||
func generateEventStatusMessage(matches []model.Match) string {
|
||||
for i := len(matches) - 1; i >= 0; i-- {
|
||||
match := matches[i]
|
||||
if match.Status == "complete" {
|
||||
minutesLate := match.StartedAt.Sub(match.Time).Minutes()
|
||||
if minutesLate > 2 {
|
||||
return fmt.Sprintf("Event is running %d minutes late", int(minutesLate))
|
||||
} else if minutesLate < -2 {
|
||||
return fmt.Sprintf("Event is running %d minutes early", int(-minutesLate))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(matches) > 0 {
|
||||
return "Event is running on schedule"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
83
web/queueing_display_test.go
Normal file
83
web/queueing_display_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
gorillawebsocket "github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestQueueingDisplay(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
recorder := web.getHttpResponse("/displays/queueing?displayId=1")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Queueing Display - Untitled Event - Cheesy Arena")
|
||||
}
|
||||
|
||||
func TestQueueingDisplayWebsocket(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
server, wsUrl := web.startTestServer()
|
||||
defer server.Close()
|
||||
conn, _, err := gorillawebsocket.DefaultDialer.Dial(wsUrl+"/displays/queueing/websocket?displayId=1", nil)
|
||||
assert.Nil(t, err)
|
||||
defer conn.Close()
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
readWebsocketType(t, ws, "matchTiming")
|
||||
readWebsocketType(t, ws, "matchLoad")
|
||||
readWebsocketType(t, ws, "matchTime")
|
||||
readWebsocketType(t, ws, "displayConfiguration")
|
||||
}
|
||||
|
||||
func TestQueueingStatusMessage(t *testing.T) {
|
||||
assert.Equal(t, "", generateEventStatusMessage([]model.Match{}))
|
||||
|
||||
matches := make([]model.Match, 3)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
|
||||
// Check within threshold considered to be on time.
|
||||
setMatchLateness(&matches[1], 0)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], 60)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], -60)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], 90)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], -90)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], 110)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], -110)
|
||||
assert.Equal(t, "Event is running on schedule", generateEventStatusMessage(matches))
|
||||
|
||||
// Check lateness.
|
||||
setMatchLateness(&matches[1], 130)
|
||||
assert.Equal(t, "Event is running 2 minutes late", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], 3601)
|
||||
assert.Equal(t, "Event is running 60 minutes late", generateEventStatusMessage(matches))
|
||||
|
||||
// Check earliness.
|
||||
setMatchLateness(&matches[1], -130)
|
||||
assert.Equal(t, "Event is running 2 minutes early", generateEventStatusMessage(matches))
|
||||
setMatchLateness(&matches[1], -3601)
|
||||
assert.Equal(t, "Event is running 60 minutes early", generateEventStatusMessage(matches))
|
||||
|
||||
// Check that later matches supersede earlier ones.
|
||||
setMatchLateness(&matches[2], 180)
|
||||
assert.Equal(t, "Event is running 3 minutes late", generateEventStatusMessage(matches))
|
||||
}
|
||||
|
||||
func setMatchLateness(match *model.Match, secondsLate int) {
|
||||
match.Time = time.Now()
|
||||
match.StartedAt = time.Now().Add(time.Second * time.Duration(secondsLate))
|
||||
match.Status = "complete"
|
||||
}
|
||||
@@ -22,7 +22,7 @@ func TestScoringPanel(t *testing.T) {
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
recorder = web.getHttpResponse("/panels/scoring/blue")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Scoring - Untitled Event - Cheesy Arena")
|
||||
assert.Contains(t, recorder.Body.String(), "Scoring Panel - Untitled Event - Cheesy Arena")
|
||||
}
|
||||
|
||||
func TestScoringPanelWebsocket(t *testing.T) {
|
||||
|
||||
@@ -146,6 +146,8 @@ func (web *Web) newHandler() http.Handler {
|
||||
router.HandleFunc("/displays/fta/websocket", web.ftaDisplayWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/pit", web.pitDisplayHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/pit/websocket", web.pitDisplayWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/queueing", web.queueingDisplayHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/queueing/websocket", web.queueingDisplayWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/twitch", web.twitchDisplayHandler).Methods("GET")
|
||||
router.HandleFunc("/displays/twitch/websocket", web.twitchDisplayWebsocketHandler).Methods("GET")
|
||||
router.HandleFunc("/login", web.loginHandler).Methods("GET")
|
||||
|
||||
Reference in New Issue
Block a user