Skip to content

Commit

Permalink
Update match review page for 2024.
Browse files Browse the repository at this point in the history
  • Loading branch information
patfair committed May 14, 2024
1 parent 69bcff2 commit 6b01f00
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 137 deletions.
49 changes: 24 additions & 25 deletions static/js/match_review.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ const renderResults = function(alliance) {
$("#" + alliance + "Score").html(scoreContent);

// Set the values of the form fields from the JSON results data.
getInputElement(alliance, "CoopActivated").prop("checked", result.score.AmpSpeaker.CoopActivated);
getInputElement(alliance, "AutoAmpNotes").val(result.score.AmpSpeaker.AutoAmpNotes);
getInputElement(alliance, "AutoSpeakerNotes").val(result.score.AmpSpeaker.AutoSpeakerNotes);
getInputElement(alliance, "TeleopAmpNotes").val(result.score.AmpSpeaker.TeleopAmpNotes);
getInputElement(alliance, "TeleopUnamplifiedSpeakerNotes").val(result.score.AmpSpeaker.TeleopUnamplifiedSpeakerNotes);
getInputElement(alliance, "TeleopAmplifiedSpeakerNotes").val(result.score.AmpSpeaker.TeleopAmplifiedSpeakerNotes);

for (let i = 0; i < 3; i++) {
const i1 = i + 1;

getInputElement(alliance, "MobilityStatuses" + i1).prop("checked", result.score.MobilityStatuses[i]);
getInputElement(alliance, "AutoDockStatuses" + i1).prop("checked", result.score.AutoDockStatuses[i]);
getInputElement(alliance, "LeaveStatuses" + i1).prop("checked", result.score.LeaveStatuses[i]);
getInputElement(alliance, "EndgameStatuses" + i1, result.score.EndgameStatuses[i]).prop("checked", true);

for (let j = 0; j < 9; j++) {
getInputElement(alliance, `GridAutoScoringRow${i}Node${j}`).prop("checked", result.score.Grid.AutoScoring[i][j]);
getSelectElement(alliance, `GridNodeStatesRow${i}Node${j}`).val(result.score.Grid.Nodes[i][j]);
}
getInputElement(alliance, "MicrophoneStatuses" + i1).prop("checked", result.score.MicrophoneStatuses[i]);
getInputElement(alliance, "TrapStatuses" + i1).prop("checked", result.score.TrapStatuses[i]);
}

getInputElement(alliance, "AutoChargeStationLevel").prop("checked", result.score.AutoChargeStationLevel);
getInputElement(alliance, "EndgameChargeStationLevel").prop("checked", result.score.EndgameChargeStationLevel);

if (result.score.Fouls != null) {
$.each(result.score.Fouls, function(k, v) {
getInputElement(alliance, "Foul" + k + "IsTechnical").prop("checked", v.IsTechnical);
Expand All @@ -70,28 +70,27 @@ const updateResults = function(alliance) {
formData[v.name] = v.value;
});

result.score.MobilityStatuses = [];
result.score.Grid = {AutoScoring: [], Nodes: []};
result.score.AutoDockStatuses = [];
result.score.LeaveStatuses = [];
result.score.AmpSpeaker = {
CoopActivated: formData[alliance + "CoopActivated"] === "on",
AutoAmpNotes: parseInt(formData[alliance + "AutoAmpNotes"]),
AutoSpeakerNotes: parseInt(formData[alliance + "AutoSpeakerNotes"]),
TeleopAmpNotes: parseInt(formData[alliance + "TeleopAmpNotes"]),
TeleopUnamplifiedSpeakerNotes: parseInt(formData[alliance + "TeleopUnamplifiedSpeakerNotes"]),
TeleopAmplifiedSpeakerNotes: parseInt(formData[alliance + "TeleopAmplifiedSpeakerNotes"]),
};
result.score.EndgameStatuses = [];
result.score.MicrophoneStatuses = [];
result.score.TrapStatuses = [];
for (let i = 0; i < 3; i++) {
const i1 = i + 1;

result.score.MobilityStatuses[i] = formData[alliance + "MobilityStatuses" + i1] === "on";
result.score.AutoDockStatuses[i] = formData[alliance + "AutoDockStatuses" + i1] === "on";
result.score.LeaveStatuses[i] = formData[alliance + "LeaveStatuses" + i1] === "on";
result.score.EndgameStatuses[i] = parseInt(formData[alliance + "EndgameStatuses" + i1]);

result.score.Grid.AutoScoring[i] = [];
result.score.Grid.Nodes[i] = [];
for (let j = 0; j < 9; j++) {
result.score.Grid.AutoScoring[i][j] = formData[alliance + `GridAutoScoringRow${i}Node${j}`] === "on";
result.score.Grid.Nodes[i][j] = parseInt(formData[alliance + `GridNodeStatesRow${i}Node${j}`]);
}
result.score.MicrophoneStatuses[i] = formData[alliance + "MicrophoneStatuses" + i1] === "on";
result.score.TrapStatuses[i] = formData[alliance + "TrapStatuses" + i1] === "on";
}

result.score.AutoChargeStationLevel = formData[alliance + "AutoChargeStationLevel"] === "on";
result.score.EndgameChargeStationLevel = formData[alliance + "EndgameChargeStationLevel"] === "on";

result.score.Fouls = [];

for (let i = 0; formData[alliance + "Foul" + i + "Index"]; i++) {
Expand Down
120 changes: 71 additions & 49 deletions templates/edit_match_result.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,46 +27,55 @@
<div class="card card-body bg-{{"{{alliance}}"}} mb-3">
<fieldset>
<legend>Autonomous</legend>
<b>Mobility</b>
<h6 class="fw-bold mb-2">Leave</h6>
<div class="row mb-3">
{{range $i := seq 3}}
<div class="col-lg-2">
<label class="control-label">Team {{"{{team"}}{{$i}}{{"}}"}}</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MobilityStatuses{{$i}}">
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}LeaveStatuses{{$i}}">
</div>
{{end}}
</div>
<b>Charge Station Docking</b>
<div class="row mb-3">
{{range $i := seq 3}}
<div class="col-lg-2">
<label class="control-label">Team {{"{{team"}}{{$i}}{{"}}"}}</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}AutoDockStatuses{{$i}}">
<h6 class="fw-bold mb-2">Notes Scored</h6>
<div class="row">
<label class="col-lg-1 text-end">Amp:</label>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}AutoAmpNotes">
</div>
{{end}}
</div>
<div class="row mb-3">
<div class="col-lg-4">
<label class="control-label">Charge Station Is Level?</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}AutoChargeStationLevel">
<label class="col-lg-1 text-end">Speaker:</label>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}AutoSpeakerNotes">
</div>
</div>
</fieldset>
<fieldset>
<legend>Grid</legend>
<div class="row text-center">
<div class="col-lg-1"></div>
{{range $i := seq 9}}
<label class="col-lg-1 control-label">{{$i}}</label>
{{end}}
<legend>Teleoperated</legend>
<h6 class="fw-bold mb-2">Coopertition</h6>
<div class="row mb-3">
<div class="col-lg-2">
<label class="control-label">Activated</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}CoopActivated">
</div>
</div>
<h6 class="fw-bold mb-2">Notes Scored</h6>
<div class="row">
<label class="col-lg-1 text-end">Amp:</label>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}TeleopAmpNotes">
</div>
<label class="col-lg-2 text-end">Speaker Unamplified:</label>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}TeleopUnamplifiedSpeakerNotes">
</div>
<label class="col-lg-2 text-end">Speaker Amplified:</label>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}TeleopAmplifiedSpeakerNotes">
</div>
</div>
<br />
{{template "gridRow" dict "row" 2 "rowName" "Top" "validNodeStates" .ValidNodeStates}}
{{template "gridRow" dict "row" 1 "rowName" "Middle" "validNodeStates" .ValidNodeStates}}
{{template "gridRow" dict "row" 0 "rowName" "Bottom" "validNodeStates" .ValidNodeStates}}
</fieldset>
<fieldset>
<legend>Endgame</legend>
<h6 class="fw-bold mb-2">Robots On Stage</h6>
<div class="mb-3">
{{range $i := seq 3}}
<div class="row mb-2">
Expand All @@ -75,17 +84,49 @@
<div class="col-lg-1">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="0"> None
</div>
<div class="col-lg-1">
<div class="col-lg-2">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="1"> Parked
</div>
<div class="col-lg-1">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="2"> Docked
<div class="col-lg-2">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="2"> Stage Left
</div>
<div class="col-lg-2">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="3"> Center Stage
</div>
<div class="col-lg-2">
<input type="radio" name="{{"{{alliance}}"}}EndgameStatuses{{$i}}" value="4"> Stage Right
</div>
</div>
{{end}}
<div class="mt-3">
<label class="control-label">Charge Station Is Level?</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}EndgameChargeStationLevel">
</div>
<h6 class="fw-bold mb-2">High Notes on Microphones</h6>
<div class="row mb-3">
<div class="col-lg-2">
<label class="control-label">Stage Left</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses1">
</div>
<div class="col-lg-2">
<label class="control-label">Center Stage</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses2">
</div>
<div class="col-lg-2">
<label class="control-label">Stage Right</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses3">
</div>
</div>
<h6 class="fw-bold mb-2">Notes in Traps</h6>
<div class="row mb-3">
<div class="col-lg-2">
<label class="control-label">Stage Left</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}TrapStatuses1">
</div>
<div class="col-lg-2">
<label class="control-label">Center Stage</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}TrapStatuses2">
</div>
<div class="col-lg-2">
<label class="control-label">Stage Right</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}TrapStatuses3">
</div>
</div>
</fieldset>
Expand Down Expand Up @@ -195,22 +236,3 @@
renderResults("blue");
</script>
{{end}}
{{define "gridRow"}}
<div class="row">
<label class="col-lg-1">{{.rowName}}</label>
{{range $i := seq 9}}
{{template "gridNode" dict "row" $.row "column" (add $i -1) "validNodeStates" $.validNodeStates}}
{{end}}
</div>
<br />
{{end}}
{{define "gridNode"}}
<div class="col-lg-1">
<input type="checkbox" class="" name="{{"{{alliance}}"}}GridAutoScoringRow{{.row}}Node{{.column}}"> Auto?
<select name="{{"{{alliance}}"}}GridNodeStatesRow{{.row}}Node{{.column}}" style="width: 90px; font-size: 11px;">
{{range $i, $nodeState := index .validNodeStates .row .column}}
<option value="{{nodeStateToInt $i}}">{{$nodeState}}</option>
{{end}}
</select>
</div>
{{end}}
122 changes: 59 additions & 63 deletions web/match_review_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,22 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
recorder := web.getHttpResponse("/match_review")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
// TODO(pat): Update for 2024.
//assert.Contains(t, recorder.Body.String(), ">78<") // The red score
//assert.Contains(t, recorder.Body.String(), ">216<") // The blue score
assert.Contains(t, recorder.Body.String(), ">81<") // The red score
assert.Contains(t, recorder.Body.String(), ">256<") // The blue score

// Check response for non-existent match.
//recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", 12345))
//assert.Equal(t, 500, recorder.Code)
//assert.Contains(t, recorder.Body.String(), "No such match")
//
//recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id))
//assert.Equal(t, 200, recorder.Code)
//assert.Contains(t, recorder.Body.String(), " Quarterfinal 4-3 ")
recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", 12345))
assert.Equal(t, 500, recorder.Code)
assert.Contains(t, recorder.Body.String(), "No such match")

recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id))
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), " Quarterfinal 4-3 ")

// Update the score to something else.
postBody := fmt.Sprintf(
"matchResultJson={\"MatchId\":%d,\"RedScore\":{\"EndgameStatuses\":[0,2,1]},\"BlueScore\":{"+
"\"Grid\":{\"Nodes\":[[2, 1],[1, 2]]},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
"\"AmpSpeaker\":{\"AutoSpeakerNotes\":5},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
"\"RedCards\":{\"105\":\"yellow\"},\"BlueCards\":{}}",
match.Id,
)
Expand All @@ -83,9 +82,8 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
recorder = web.getHttpResponse("/match_review")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
// TODO(pat): Update for 2024.
//assert.Contains(t, recorder.Body.String(), ">13<") // The red score
//assert.Contains(t, recorder.Body.String(), ">10<") // The blue score
assert.Contains(t, recorder.Body.String(), ">6<") // The red score
assert.Contains(t, recorder.Body.String(), ">25<") // The blue score
}

func TestMatchReviewCreateNewResult(t *testing.T) {
Expand All @@ -107,27 +105,26 @@ func TestMatchReviewCreateNewResult(t *testing.T) {
assert.NotContains(t, recorder.Body.String(), ">13<") // The red score
assert.NotContains(t, recorder.Body.String(), ">10<") // The blue score

// TODO(pat): Update for 2024.
//recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id))
//assert.Equal(t, 200, recorder.Code)
//assert.Contains(t, recorder.Body.String(), " Quarterfinal 4-3 ")
//
//// Update the score to something else.
//postBody := fmt.Sprintf(
// "matchResultJson={\"MatchId\":%d,\"RedScore\":{\"EndgameStatuses\":[0,2,1]},\"BlueScore\":{"+
// "\"Grid\":{\"Nodes\":[[2, 1],[1, 2]]},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
// "\"RedCards\":{\"105\":\"yellow\"},\"BlueCards\":{}}",
// match.Id,
//)
//recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
//assert.Equal(t, 303, recorder.Code, recorder.Body.String())
//
//// Check for the updated scores back on the match list page.
//recorder = web.getHttpResponse("/match_review")
//assert.Equal(t, 200, recorder.Code)
//assert.Contains(t, recorder.Body.String(), ">QF4-3<")
//assert.Contains(t, recorder.Body.String(), ">13<") // The red score
//assert.Contains(t, recorder.Body.String(), ">10<") // The blue score
recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id))
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), " Quarterfinal 4-3 ")

// Update the score to something else.
postBody := fmt.Sprintf(
"matchResultJson={\"MatchId\":%d,\"RedScore\":{\"EndgameStatuses\":[0,2,1]},\"BlueScore\":{"+
"\"AmpSpeaker\":{\"AutoSpeakerNotes\":5},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
"\"RedCards\":{\"105\":\"yellow\"},\"BlueCards\":{}}",
match.Id,
)
recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
assert.Equal(t, 303, recorder.Code, recorder.Body.String())

// Check for the updated scores back on the match list page.
recorder = web.getHttpResponse("/match_review")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
assert.Contains(t, recorder.Body.String(), ">6<") // The red score
assert.Contains(t, recorder.Body.String(), ">25<") // The blue score
}

func TestMatchReviewEditCurrentMatch(t *testing.T) {
Expand All @@ -148,32 +145,31 @@ func TestMatchReviewEditCurrentMatch(t *testing.T) {
web.arena.LoadMatch(&match)
assert.Equal(t, match, *web.arena.CurrentMatch)

// TODO(pat): Update for 2024.
//recorder := web.getHttpResponse("/match_review/current/edit")
//assert.Equal(t, 200, recorder.Code)
//assert.Contains(t, recorder.Body.String(), " Qualification 352 ")
//
//postBody := fmt.Sprintf(
// "matchResultJson={\"MatchId\":%d,\"RedScore\":{\"EndgameStatuses\":[0,2,1]},\"BlueScore\":{"+
// "\"Grid\":{\"Nodes\":[[2, 1],[1, 2]]},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
// "\"RedCards\":{\"105\":\"yellow\"},\"BlueCards\":{}}",
// match.Id,
//)
//recorder = web.postHttpResponse("/match_review/current/edit", postBody)
//assert.Equal(t, 303, recorder.Code, recorder.Body.String())
//assert.Equal(t, "/match_play", recorder.Header().Get("Location"))
//
//// Check that the persisted match is still unedited and that the realtime scores have been updated instead.
//match2, _ := web.arena.Database.GetMatchById(match.Id)
//assert.Equal(t, game.MatchScheduled, match2.Status)
//assert.Equal(
// t,
// [3]game.EndgameStatus{game.EndgameNone, game.EndgameStageRight, game.EndgameParked},
// web.arena.RedRealtimeScore.CurrentScore.EndgameStatuses,
//)
//assert.Equal(t, [3][9]game.NodeState{{2, 1}, {1, 2}}, web.arena.BlueRealtimeScore.CurrentScore.Grid.Nodes)
//assert.Equal(t, 0, len(web.arena.RedRealtimeScore.CurrentScore.Fouls))
//assert.Equal(t, 1, len(web.arena.BlueRealtimeScore.CurrentScore.Fouls))
//assert.Equal(t, 1, len(web.arena.RedRealtimeScore.Cards))
//assert.Equal(t, 0, len(web.arena.BlueRealtimeScore.Cards))
recorder := web.getHttpResponse("/match_review/current/edit")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), " Qualification 352 ")

postBody := fmt.Sprintf(
"matchResultJson={\"MatchId\":%d,\"RedScore\":{\"EndgameStatuses\":[0,2,1]},\"BlueScore\":{"+
"\"AmpSpeaker\":{\"AutoSpeakerNotes\":5},\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]},"+
"\"RedCards\":{\"105\":\"yellow\"},\"BlueCards\":{}}",
match.Id,
)
recorder = web.postHttpResponse("/match_review/current/edit", postBody)
assert.Equal(t, 303, recorder.Code, recorder.Body.String())
assert.Equal(t, "/match_play", recorder.Header().Get("Location"))

// Check that the persisted match is still unedited and that the realtime scores have been updated instead.
match2, _ := web.arena.Database.GetMatchById(match.Id)
assert.Equal(t, game.MatchScheduled, match2.Status)
assert.Equal(
t,
[3]game.EndgameStatus{game.EndgameNone, game.EndgameStageLeft, game.EndgameParked},
web.arena.RedRealtimeScore.CurrentScore.EndgameStatuses,
)
assert.Equal(t, 5, web.arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.AutoSpeakerNotes)
assert.Equal(t, 0, len(web.arena.RedRealtimeScore.CurrentScore.Fouls))
assert.Equal(t, 1, len(web.arena.BlueRealtimeScore.CurrentScore.Fouls))
assert.Equal(t, 1, len(web.arena.RedRealtimeScore.Cards))
assert.Equal(t, 0, len(web.arena.BlueRealtimeScore.Cards))
}

0 comments on commit 6b01f00

Please sign in to comment.