Added functionality to add and remove connections to other signals.
This commit is contained in:
parent
25e59cd92c
commit
fd2cf357dd
|
@ -65,7 +65,7 @@ public class SignalService {
|
||||||
branch = this.branchRepository.findByNameAndRailSystem(branchData.name(), rs)
|
branch = this.branchRepository.findByNameAndRailSystem(branchData.name(), rs)
|
||||||
.orElse(new Branch(rs, branchData.name(), BranchStatus.FREE));
|
.orElse(new Branch(rs, branchData.name(), BranchStatus.FREE));
|
||||||
}
|
}
|
||||||
Direction dir = Direction.valueOf(branchData.direction().trim().toUpperCase());
|
Direction dir = Direction.parse(branchData.direction());
|
||||||
branchConnections.add(new SignalBranchConnection(signal, branch, dir));
|
branchConnections.add(new SignalBranchConnection(signal, branch, dir));
|
||||||
}
|
}
|
||||||
signal = signalRepository.save(signal);
|
signal = signalRepository.save(signal);
|
||||||
|
|
|
@ -132,10 +132,34 @@ function railSystemChanged() {
|
||||||
canvasTranslation.y = -1 * (bb.y + (bb.height / 2));
|
canvasTranslation.y = -1 * (bb.y + (bb.height / 2));
|
||||||
canvasScaleIndex = SCALE_INDEX_NORMAL;
|
canvasScaleIndex = SCALE_INDEX_NORMAL;
|
||||||
drawRailSystem();
|
drawRailSystem();
|
||||||
|
window.setInterval(railSystemUpdated, 1000);
|
||||||
});
|
});
|
||||||
$.get("/api/railSystems/" + railSystem.id + "/branches")
|
$.get("/api/railSystems/" + railSystem.id + "/branches")
|
||||||
.done(branches => {
|
.done(branches => {
|
||||||
railSystem.branches = branches;
|
railSystem.branches = branches;
|
||||||
|
const branchSelects = $('.js_branch_list');
|
||||||
|
branchSelects.empty();
|
||||||
|
railSystem.branches.forEach(branch => {
|
||||||
|
branchSelects.append($('<option value="' + branch.name + '"></option>'))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function railSystemUpdated() {
|
||||||
|
console.log("Refreshing...");
|
||||||
|
$.get("/api/railSystems/" + railSystem.id + "/signals")
|
||||||
|
.done(signals => {
|
||||||
|
railSystem.signals = signals;
|
||||||
|
drawRailSystem();
|
||||||
|
});
|
||||||
|
$.get("/api/railSystems/" + railSystem.id + "/branches")
|
||||||
|
.done(branches => {
|
||||||
|
railSystem.branches = branches;
|
||||||
|
const branchSelects = $('.js_branch_list');
|
||||||
|
branchSelects.empty();
|
||||||
|
railSystem.branches.forEach(branch => {
|
||||||
|
branchSelects.append($('<option value="' + branch.name + '"></option>'))
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +176,29 @@ function onSignalSelected(signal) {
|
||||||
if (signal !== null) {
|
if (signal !== null) {
|
||||||
const tpl = Handlebars.compile($('#signalTemplate').html());
|
const tpl = Handlebars.compile($('#signalTemplate').html());
|
||||||
detailPanel.html(tpl(signal));
|
detailPanel.html(tpl(signal));
|
||||||
|
signal.branchConnections.forEach(con => {
|
||||||
|
const select = $('#signalPotentialConnectionsSelect-' + con.id);
|
||||||
|
$.get("/api/railSystems/" + railSystem.id + "/branches/" + con.branch.id + "/signals")
|
||||||
|
.done(signals => {
|
||||||
|
signals = signals.filter(s => s.id !== signal.id);
|
||||||
|
let connections = [];
|
||||||
|
signals.forEach(s => {
|
||||||
|
s.branchConnections
|
||||||
|
.filter(c => c.branch.id === con.branch.id && !con.reachableSignalConnections.some(rc => rc.connectionId === c.id))
|
||||||
|
.forEach(potentialConnection => {
|
||||||
|
potentialConnection.signalName = s.name;
|
||||||
|
potentialConnection.signalId = s.id;
|
||||||
|
connections.push(potentialConnection);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
select.empty();
|
||||||
|
const row = $('#signalPotentialConnectionsRow-' + con.id);
|
||||||
|
row.toggle(connections.length > 0);
|
||||||
|
connections.forEach(c => {
|
||||||
|
select.append($(`<option value="${c.id}">${c.signalName} via ${c.direction} connection ${c.id}</option>`))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +219,15 @@ function addRailSystem() {
|
||||||
|
|
||||||
function deleteRailSystem() {
|
function deleteRailSystem() {
|
||||||
if (railSystem !== null && railSystem.id) {
|
if (railSystem !== null && railSystem.id) {
|
||||||
$.ajax({
|
confirm("Are you sure you want to permanently remove rail system " + railSystem.id + "?")
|
||||||
url: "/api/railSystems/" + railSystem.id,
|
.then(() => {
|
||||||
type: "DELETE"
|
$.ajax({
|
||||||
})
|
url: "/api/railSystems/" + railSystem.id,
|
||||||
.always(() => {
|
type: "DELETE"
|
||||||
refreshRailSystems(true);
|
})
|
||||||
|
.always(() => {
|
||||||
|
refreshRailSystems(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,3 +246,134 @@ function refreshRailSystems(selectFirst) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addNewSignal() {
|
||||||
|
const modalElement = $('#addSignalModal');
|
||||||
|
const form = $('#addSignalForm');
|
||||||
|
form.validate();
|
||||||
|
if (!form.valid()) return;
|
||||||
|
const data = {
|
||||||
|
name: $('#addSignalName').val().trim(),
|
||||||
|
position: {
|
||||||
|
x: $('#addSignalPositionX').val(),
|
||||||
|
y: $('#addSignalPositionY').val(),
|
||||||
|
z: $('#addSignalPositionZ').val()
|
||||||
|
},
|
||||||
|
branchConnections: [
|
||||||
|
{
|
||||||
|
direction: $('#addSignalFirstConnectionDirection').val(),
|
||||||
|
name: $('#addSignalFirstConnectionBranch').val()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
direction: $('#addSignalSecondConnectionDirection').val(),
|
||||||
|
name: $('#addSignalSecondConnectionBranch').val()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const modal = bootstrap.Modal.getInstance(modalElement[0]);
|
||||||
|
modal.hide();
|
||||||
|
modalElement.on("hidden.bs.modal", () => {
|
||||||
|
confirm("Are you sure you want to add this new signal to the system?")
|
||||||
|
.then(() => {
|
||||||
|
$.post({
|
||||||
|
url: "/api/railSystems/" + railSystem.id + "/signals",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
contentType: "application/json"
|
||||||
|
})
|
||||||
|
.done((response) => {
|
||||||
|
form.trigger("reset");
|
||||||
|
railSystemChanged();
|
||||||
|
})
|
||||||
|
.fail((response) => {
|
||||||
|
$('#addSignalAlertsContainer').append($('<div class="alert alert-danger">An error occurred.</div>'));
|
||||||
|
modal.show();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
form.trigger("reset");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeReachableConnection(signalId, fromId, toId) {
|
||||||
|
confirm(`Are you sure you want to remove the connection from ${fromId} to ${toId} from signal ${signalId}?`)
|
||||||
|
.then(() => {
|
||||||
|
$.get(`/api/railSystems/${railSystem.id}/signals/${signalId}`)
|
||||||
|
.done(signal => {
|
||||||
|
let connections = [];
|
||||||
|
signal.branchConnections.forEach(con => {
|
||||||
|
con.reachableSignalConnections.forEach(reachableCon => {
|
||||||
|
connections.push({from: con.id, to: reachableCon.connectionId});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
connections = connections.filter(c => !(c.from === fromId && c.to === toId));
|
||||||
|
$.post({
|
||||||
|
url: `/api/railSystems/${railSystem.id}/signals/${signal.id}/signalConnections`,
|
||||||
|
data: JSON.stringify({connections: connections}),
|
||||||
|
contentType: "application/json"
|
||||||
|
})
|
||||||
|
.done((response) => {
|
||||||
|
railSystemChanged();
|
||||||
|
})
|
||||||
|
.fail((response) => {
|
||||||
|
console.error(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addReachableConnectionBtn(signalId, fromId) {
|
||||||
|
const select = $('#signalPotentialConnectionsSelect-' + fromId);
|
||||||
|
const toId = select.val();
|
||||||
|
if (toId) {
|
||||||
|
addReachableConnection(signalId, fromId, toId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addReachableConnection(signalId, fromId, toId) {
|
||||||
|
confirm(`Are you sure you want to add a connection from ${fromId} to ${toId} from signal ${signalId}?`)
|
||||||
|
.then(() => {
|
||||||
|
$.get(`/api/railSystems/${railSystem.id}/signals/${signalId}`)
|
||||||
|
.done(signal => {
|
||||||
|
let connections = [];
|
||||||
|
signal.branchConnections.forEach(con => {
|
||||||
|
con.reachableSignalConnections.forEach(reachableCon => {
|
||||||
|
connections.push({from: con.id, to: reachableCon.connectionId});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!connections.find(c => c.from === fromId && c.to === toId)) {
|
||||||
|
connections.push({from: fromId, to: toId});
|
||||||
|
$.post({
|
||||||
|
url: `/api/railSystems/${railSystem.id}/signals/${signal.id}/signalConnections`,
|
||||||
|
data: JSON.stringify({connections: connections}),
|
||||||
|
contentType: "application/json"
|
||||||
|
})
|
||||||
|
.done((response) => {
|
||||||
|
railSystemChanged();
|
||||||
|
})
|
||||||
|
.fail((response) => {
|
||||||
|
console.error(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirm(message) {
|
||||||
|
const modalElement = $('#confirmModal');
|
||||||
|
if (message) {
|
||||||
|
$('#confirmModalBody').html(message);
|
||||||
|
} else {
|
||||||
|
$('#confirmModalBody').html("Are you sure you want to continue?");
|
||||||
|
}
|
||||||
|
const modal = new bootstrap.Modal(modalElement[0], {keyboard: false});
|
||||||
|
modal.show();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
$('#confirmModalOkButton').click(() => {
|
||||||
|
modalElement.on("hidden.bs.modal", () => resolve());
|
||||||
|
});
|
||||||
|
$('#confirmModalCancelButton').click(() => {
|
||||||
|
modalElement.on("hidden.bs.modal", () => reject());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -43,9 +43,17 @@
|
||||||
<div id="railMapDetailPanel" class="col p-2 border">
|
<div id="railMapDetailPanel" class="col p-2 border">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4"/>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSignalModal">Add Signal</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: none;">
|
<div>
|
||||||
<script id="signalTemplate" type="text/x-handlebars-template">
|
<script id="signalTemplate" type="text/x-handlebars-template">
|
||||||
<h3>{{name}}</h3>
|
<h3>{{name}}</h3>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -65,20 +73,132 @@
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-3">Branch</dt>
|
<dt class="col-sm-3">Branch</dt>
|
||||||
<dd class="col-sm-9">{{this.branch.name}} <small class="text-muted">{{this.branch.id}}</small></dd>
|
<dd class="col-sm-9">{{this.branch.name}} <small class="text-muted">{{this.branch.id}}</small></dd>
|
||||||
{{#if this.reachableSignalConnections.length}}
|
<dt class="col-sm-3">Reachable Signals</dt>
|
||||||
<dt class="col-sm-3">Reachable Signals</dt>
|
<dd class="col-sm-9">
|
||||||
<dd class="col-sm-9">
|
{{#each this.reachableSignalConnections}}
|
||||||
{{#each this.reachableSignalConnections}}
|
<p>
|
||||||
<p><a onclick="selectSignalById({{this.signalId}})" href="#">{{this.signalName}}</a> <small class="text-muted">{{this.signalId}}</small> via {{this.direction}} connection {{this.connectionId}}</p>
|
<a onclick="selectSignalById({{this.signalId}})" href="#">{{this.signalName}}</a>
|
||||||
{{/each}}
|
<small class="text-muted">{{this.signalId}}</small> via
|
||||||
</dd>
|
{{this.direction}} connection {{this.connectionId}}
|
||||||
{{/if}}
|
<span
|
||||||
|
class="btn btn-sm btn-danger js_removeSignalConnection"
|
||||||
|
onclick="removeReachableConnection({{../../id}}, {{../id}}, {{this.connectionId}})"
|
||||||
|
>Remove</span>
|
||||||
|
</p>
|
||||||
|
{{/each}}
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<div class="row" id="signalPotentialConnectionsRow-{{this.id}}">
|
||||||
|
<div class="col-auto">
|
||||||
|
<select id="signalPotentialConnectionsSelect-{{this.id}}" class="form-select form-select-sm">
|
||||||
|
{{#each this.potentialSignalConnections}}
|
||||||
|
<option value="{{this.connectionId}}">{{this.signalName}} via {{this.branchName}} on {{this.direction}} connection</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" onclick="addReachableConnectionBtn({{../id}}, {{this.id}})">Add Connection</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="modal fade" tabindex="-1" id="confirmModal" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 id="confirmModalHeader">Confirm</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p id="confirmModalBody">Are you sure you want to continue?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="confirmModalCancelButton">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="confirmModalOkButton">Ok</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" tabindex="-1" id="addSignalModal" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Add Signal</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Fill in the following data to add a new signal to the system.</p>
|
||||||
|
<form id="addSignalForm">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalName" type="text" class="form-control" placeholder="Name" aria-label="Name" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<h6>Position</h6>
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalPositionX" class="form-control" placeholder="X" aria-label="X" type="number" step="0.1" required>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalPositionY" class="form-control" placeholder="Y" aria-label="Y" type="number" step="0.1" required>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalPositionZ" class="form-control" placeholder="Z" aria-label="Z" type="number" step="0.1" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h6>Connections</h6>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
<select id="addSignalFirstConnectionDirection" class="form-select" required>
|
||||||
|
<option value="N">North</option>
|
||||||
|
<option value="S">South</option>
|
||||||
|
<option value="E">East</option>
|
||||||
|
<option value="W">West</option>
|
||||||
|
<option value="NW">NorthWest</option>
|
||||||
|
<option value="NE">NorthEast</option>
|
||||||
|
<option value="SW">SouthWest</option>
|
||||||
|
<option value="SE">SouthEast</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalFirstConnectionBranch" type="text" class="form-control" placeholder="Branch Name" list="addSignalFirstConnectionBranchList" required>
|
||||||
|
<datalist id="addSignalFirstConnectionBranchList" class="js_branch_list">
|
||||||
|
</datalist>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
<select id="addSignalSecondConnectionDirection" class="form-select" required>
|
||||||
|
<option value="N">North</option>
|
||||||
|
<option value="S">South</option>
|
||||||
|
<option value="E">East</option>
|
||||||
|
<option value="W">West</option>
|
||||||
|
<option value="NW">NorthWest</option>
|
||||||
|
<option value="NE">NorthEast</option>
|
||||||
|
<option value="SW">SouthWest</option>
|
||||||
|
<option value="SE">SouthEast</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<input id="addSignalSecondConnectionBranch" type="text" class="form-control" placeholder="Branch Name" list="addSignalSecondConnectionBranchList" required>
|
||||||
|
<datalist id="addSignalSecondConnectionBranchList" class="js_branch_list">
|
||||||
|
</datalist>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="addSignalAlertsContainer"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="addNewSignal()">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.3/dist/jquery.validate.min.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue