Skip to content

Commit

Permalink
Ability to remote start matches
Browse files Browse the repository at this point in the history
  • Loading branch information
thordy committed Feb 10, 2025
1 parent 1bae856 commit c821f07
Show file tree
Hide file tree
Showing 19 changed files with 194 additions and 62 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ A preview of major changes can be found in the Wiki ([Latest Changes](https://gi
## [2.9.0] - TBD
#### Feature
- Option to see `All` or `Unique` tournament statistics per player
- Ability to "Remote Start" matches on a selected venue

#### Changed
- Updated to latest version of dependencies
Expand Down
4 changes: 1 addition & 3 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ app.locals.kcapp = {};
app.locals.kcapp.api = process.env.KCAPP_API || 'http://localhost:8001';
app.locals.kcapp.api_path = process.env.KCAPP_API_PATH || ':8001';
app.locals.kcapp.local_admin = process.env.KCAPP_LOCAL_ADMIN ? process.env.KCAPP_LOCAL_ADMIN === "true" : true;
app.locals.serializedGlobals = { kcapp: true };

// Create all routes
const socketHandler = require('./routes/lib/socketio_handler')(io, app);
Expand All @@ -63,9 +64,6 @@ const venues = require('./routes/venues')(app, socketHandler);
const badges = require('./routes/badges');
socketHandler.setupActiveNamespace();

app.locals.moment = require('moment');
app.locals._ = require('underscore');

// Write access log to a daily rotated file in /log
const pad = num => (num > 9 ? "" : "0") + num;
const generator = (time, index) => {
Expand Down
4 changes: 4 additions & 0 deletions routes/lib/socketio_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ module.exports = (io, app) => {
nsp.on('connection', function (client) {
const ip = getClientIP(client);
debug("Client %s connected to '%s'", ip, namespace);

client.on('start_remote', (data) => {
nsp.emit('start_remote', data);
})
});
debug("Created socket.io namespace '%s'", namespace);
}
Expand Down
2 changes: 1 addition & 1 deletion routes/matches.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ router.post('/:id/rematch', function (req, res, next) {

/* Method for finishing a match */
router.put('/:id/finish', function (req, res, next) {
axios.put(`${req.app.locals.kcapp.api}/match/${req.params.id}`, req.body)
axios.put(`${req.app.locals.kcapp.api}/match/${req.params.id}/score`, req.body)
.then(response => {
res.end();
}).catch(error => {
Expand Down
9 changes: 6 additions & 3 deletions routes/tournaments.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ router.post('/admin/generate', function (req, res, next) {
const body = req.body;

const players = [];
["group1", "group2", "group3", "group4"].forEach(key => {
["group1", "group2", "group3", "group4", "group5", "group6", "group7", "group8"].forEach(key => {
if (body[key]) {
body[key].players.forEach(player => {
players.push({
Expand All @@ -215,7 +215,7 @@ router.post('/admin/generate', function (req, res, next) {
}
});
const venues = {};
["group1", "group2", "group3", "group4"].forEach(key => {
["group1", "group2", "group3", "group4", "group5", "group6", "group7", "group8"].forEach(key => {
if (body[key]) {
venues[body[key].group.id] = body[key].venueId;
}
Expand Down Expand Up @@ -313,13 +313,14 @@ router.post('/:id/player', function (req, res, next) {
router.get('/:id', function (req, res, next) {
axios.all([
axios.get(`${req.app.locals.kcapp.api}/player`),
axios.get(`${req.app.locals.kcapp.api}/venue`),
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}`),
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/overview`),
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/matches`),
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/statistics`),
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/metadata`),
axios.get(`${req.app.locals.kcapp.api}/match/modes`)
]).then(axios.spread((playersResponse, tournamentResponse, overviewData, matchesData, statisticsResponse, metadataResponse, modesResponse) => {
]).then(axios.spread((playersResponse, venueResponse, tournamentResponse, overviewData, matchesData, statisticsResponse, metadataResponse, modesResponse) => {
const statistics = statisticsResponse.data;
if (!_.isEmpty(statistics)) {
statistics.checkout_highest = _.sortBy(statistics.checkout_highest, (stats) => -stats.value);
Expand Down Expand Up @@ -357,6 +358,7 @@ router.get('/:id', function (req, res, next) {
playoffs_matches: playoffsMatches,
statistics: statistics,
modes: modesResponse.data,
venues: venueResponse.data,
});
});
})).catch(error => {
Expand All @@ -373,6 +375,7 @@ router.get('/:id', function (req, res, next) {
matches: matches,
statistics: statistics,
modes: modesResponse.data,
venues: venueResponse.data,
});
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
onModalPressed(event) {
this.emit('show-modal', this.input.data);
this.emit('show-modal', this.input.data, this.input.modal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = {
match: match
}
},
onShowModal(matchId) {
this.emit('show-modal', matchId);
onShowModal(matchId, modal) {
this.emit('show-modal', matchId, modal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ $ var columns = input.columns;
<if(!match.has_scores)>
<td class="text-center">
<match-button title="View" icon="fa-cog" modal=`set-score-modal` data=match.id on-show-modal("onShowModal")/>
</td>
<match-button title="Start Remote" icon="fa-fast-forward" modal='start-remote-modal' data=match.id on-show-modal("onShowModal")/>
</td>
</if>
<else>
<td/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/matches-table/matches-table.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = {
columns: columns
}
},
onShowModal(matchId) {
this.emit('show-modal', matchId);
onShowModal(matchId, modal) {
this.emit('show-modal', matchId, modal);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
const axios = require('axios');
const localStorage = require('../../../../util/localstorage');

module.exports = {
onCreate(input) {
onCreate(input, out) {
this.state = {
layouts: [ {id: "wide", name: "Wide"}, {id: "compact", name: "Compact"}, {id: "compact-large", name: "Compact (Large)"} ],
buttonLayout: "wide",
volume: 100,
confirmBusts: true,
autoFinishLegs: false,
autoFinishTime: 10
autoFinishTime: 10,
remoteControl: false,
venueId: -1,
venues: [],
locals: out.global.kcapp
}
},
onMount() {
Expand All @@ -22,20 +27,30 @@ module.exports = {
this.state.volume = Math.min(Math.max(parseInt(volume * 100), 0), 100);
}

const confirmBusts = localStorage.get("confirm-busts");
if (confirmBusts !== null) {
this.state.confirmBusts = confirmBusts === 'true';
}

const autoFinishLegs = localStorage.get("auto-finish-legs");
if (autoFinishLegs !== null) {
this.state.autoFinishLegs = autoFinishLegs === 'true';
}
this.state.confirmBusts = localStorage.getBool("confirm-busts", true);
this.state.autoFinishLegs = localStorage.getBool("auto-finish-legs", false);
this.state.remoteControl = localStorage.getBool("remote-control", false);

const autoFinishTime = localStorage.get("auto-finish-time");
if (autoFinishTime !== null) {
this.state.autoFinishTime = parseInt(autoFinishTime, 10) || 10;
}

const venueId = localStorage.get('venue_id');
if (venueId !== null) {
this.state.venueId = parseInt(venueId);
}

$(function() {
$("#modal-configure-kcapp").on('shown.bs.modal', function(){
axios.get(`${window.location.protocol}//${window.location.hostname}${this.state.locals.api_path}/venue`)
.then(response => {
this.state.venues = response.data;
}).catch(error => {
console.log('Error when getting venues ' + error);
});
}.bind(this));
}.bind(this));
},
updateVolume(event, selected) {
this.state.volume = selected.value;
Expand All @@ -46,15 +61,23 @@ module.exports = {
toggleAutoFinishLegs(event) {
this.state.autoFinishLegs = event.target.checked;
},
toggleRemoteControl(event) {
this.state.remoteControl = event.target.checked;
},
updateAutoFinishTime(event) {
this.state.autoFinishTime = parseInt(event.target.value, 10);
},
onSave() {
this.state.buttonLayout = document.getElementById("buttonLayout").value;
localStorage.set('button-layout', this.state.buttonLayout);

this.state.venueId = parseInt(document.getElementById("venueSelect").value);
localStorage.set('venue_id', this.state.venueId);

localStorage.set('confirm-busts', this.state.confirmBusts);
localStorage.set('auto-finish-legs', this.state.autoFinishLegs);
localStorage.set('auto-finish-time', this.state.autoFinishTime);
localStorage.set('volume', this.state.volume / 100);
localStorage.set('remote-control', this.state.remoteControl);
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<for|layout| of=state.layouts>
<option style="text-transform: capitalize;" value=layout.id selected=(layout.id === state.buttonLayout)>${layout.name}</option>
</for>
</select>
</select>
</div>
</div>
</div>
Expand Down Expand Up @@ -59,6 +59,27 @@
</div>
</div>
</div>
<div>
<div class="block-container-header">
<span>Venue Options</span>
</div>
<div class="block-container-with-header">
<div class="form-group form-check" style="margin-bottom: 1em;">
<select id='venueSelect' class="form-select" style="width: 100%">
<for|venue| of=state.venues>
<option value=venue.id selected=(venue.id === state.venueId)>${venue.name}</option>
</for>
</select>
</div>
<div class="form-group form-check">
<input type="checkbox" id="remoteControl" class="form-check-input" checked=state.remoteControl on-change("toggleRemoteControl")>
<label class="toggle-button" for="remoteControl">
<span class="toggle-slider"></span>
</label>
<span style="margin-left: 8px;">Remote Control</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" on-click("onSave") data-dismiss="modal">Save</button>
Expand Down
11 changes: 8 additions & 3 deletions src/components/venue-socket/venue-socket.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ module.exports = {
}
},
onMount() {
const isController = localStorage.get('controller');
const hasController = localStorage.get('has_controller');
if (isController || hasController) {
const isController = localStorage.getBool('controller', false);
const hasController = localStorage.getBool('has_controller', false);
const isRemote = localStorage.getBool('remote-control', false);
if (isController || hasController || isRemote) {
const venue = localStorage.get('venue_id');
if (venue) {
this.state.venueId = parseInt(venue);
Expand All @@ -29,6 +30,10 @@ module.exports = {
}
location.href = isController ? `/legs/${data.leg.id}/controller` : `/legs/${data.leg.id}`;
});

socket.on('start_remote', (data) => {
location.href = isController ? `/legs/${data.match.current_leg_id}/controller` : `/legs/${data.match.current_leg_id}`;
});
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const io = require('../../../../../../util/socket.io-helper');
const axios = require('axios');

module.exports = {
onCreate(input, out) {
this.state = {
match: undefined,
venueId: -1,
locals: out.global.kcapp
}
},
onMount() {
$(function() {
$("#start-remote-modal").on('shown.bs.modal', function(){
const matchId = $("#start-remote-modal").data('matchId');
if (matchId) {
this.setMatch(matchId, true);
}
}.bind(this));
}.bind(this));
},
onVenueChange(event) {
this.state.venueId = parseInt(event.target.value);
},
setMatch(matchId, isBracket) {
const match = this.input.matches[matchId];
this.state.match = match;
this.state.venueId = match.venue ? match.venue.id : -1;
},
startRemote(event) {
const socket = io.connect(`${window.location.origin}/venue/${this.state.venueId}`);
socket.on("connect", () => {
const match = this.state.match;
match.venue.id = this.state.venueId;

axios.put(`${window.location.protocol}//${window.location.hostname}${this.state.locals.api_path}/match/${match.id}`, match)
.then(response => {
this.state.venues = response.data;
socket.emit('start_remote', { match: match });
$("#start-remote-modal").modal('hide');
}).catch(error => {
console.log('Error when updating match ' + error);
alert(`Error updating match ${error}`);
});
});
event.preventDefault();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="modal fade start-remote-modal" id=`start-remote-modal` data-matchId="-1" tabindex="-1" role="dialog" aria-labelledby=`start-remote-modal-label`>
<div class="modal-dialog" role="document">
<div class="block-container-header">
<i class="fas fa-user-plus"/>
<span class="ml-10">Start Remote</span>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="block-container-with-header">
<form>
<select class="form-control" onChange("onVenueChange")>
<for|venue| of=input.venues>
<option value=venue.id selected=(venue.id === state.venueId)>${venue.name}</option>
</for>
</select>
<button class="btn btn-primary btn-submit mt-10" type="submit" on-click("startRemote")>
<i class="fas fa-user-plus"/>
<span class="ml-10">Start Remote</span>
</button>
</form>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ module.exports = {
}, {}));
}



this.state = {
hasStatistics: !_.isEmpty(input.statistics.best_three_dart_avg),
matches: matches,
Expand Down Expand Up @@ -91,8 +89,8 @@ module.exports = {
}
});
},
onShowModal(matchId) {
this.getComponent('set-score-modal').setMatch(matchId);
onShowModal(matchId, modal) {
this.getComponent(modal).setMatch(matchId);
},
onUpdatePredictions(groupId, overview) {
const comp = this.getComponent(`predictor-overview-${groupId}`);
Expand All @@ -102,6 +100,5 @@ module.exports = {
this.state.showAllStats = value;
this.state.statistics = value ? this.input.statistics : this.state.unq_statistics;
this.setStateDirty("statistics");
console.log(this.state.statistics);
}
}
Loading

0 comments on commit c821f07

Please sign in to comment.