mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-17 10:00:46 -04:00
did stuff
This commit is contained in:
@@ -12,11 +12,21 @@
|
||||
.row { margin-bottom: 8px; }
|
||||
#alerts { margin-top: 12px; max-width: 600px; }
|
||||
.alert { background: #fff1d2; border: 1px solid #f0b651; padding: 6px 8px; margin-bottom: 6px; font-size: 0.9rem; }
|
||||
#authPanel { margin: 12px 0; display: flex; gap: 8px; align-items: center; }
|
||||
#authPanel input { padding: 4px; }
|
||||
#activeDriver { margin-bottom: 8px; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Multi Roomba Rover</h1>
|
||||
<div id="status">Connecting…</div>
|
||||
<div id="authPanel">
|
||||
<input id="username" placeholder="Username" />
|
||||
<input id="password" type="password" placeholder="Password" />
|
||||
<button id="loginBtn">Admin Login</button>
|
||||
<button id="spectatorBtn">Spectate</button>
|
||||
<span id="roleStatus">Role: user</span>
|
||||
</div>
|
||||
<div id="layout">
|
||||
<div id="roverList">
|
||||
<label for="roverSelect">Rovers</label>
|
||||
@@ -41,6 +51,7 @@
|
||||
</div>
|
||||
<div style="flex: 1">
|
||||
<h3>Sensor Frames</h3>
|
||||
<div id="activeDriver">Active driver: --</div>
|
||||
<pre id="sensorOutput"></pre>
|
||||
<p>Use WASD keys to drive the selected rover. Shift increases speed.</p>
|
||||
<div id="alerts"></div>
|
||||
@@ -52,6 +63,7 @@
|
||||
<script src="src/helpers/formatters.js"></script>
|
||||
<script src="src/services/state.js"></script>
|
||||
<script src="src/services/alertFeed.js"></script>
|
||||
<script src="src/services/authControls.js"></script>
|
||||
<script src="src/services/roverUI.js"></script>
|
||||
<script src="src/services/driveControls.js"></script>
|
||||
<script src="src/main.js"></script>
|
||||
|
||||
@@ -2,5 +2,6 @@ requireModule('globals/socket');
|
||||
requireModule('helpers/formatters');
|
||||
requireModule('services/state');
|
||||
requireModule('services/alertFeed');
|
||||
requireModule('services/authControls');
|
||||
requireModule('services/roverUI');
|
||||
requireModule('services/driveControls');
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
registerModule('services/authControls', (require, exports) => {
|
||||
const { socket } = require('globals/socket');
|
||||
const state = require('services/state');
|
||||
|
||||
const usernameInput = document.getElementById('username');
|
||||
const passwordInput = document.getElementById('password');
|
||||
const loginBtn = document.getElementById('loginBtn');
|
||||
const roleStatus = document.getElementById('roleStatus');
|
||||
const spectatorBtn = document.getElementById('spectatorBtn');
|
||||
|
||||
function updateRole(role) {
|
||||
if (roleStatus) {
|
||||
roleStatus.textContent = `Role: ${role}`;
|
||||
}
|
||||
state.setRole(role);
|
||||
}
|
||||
|
||||
loginBtn?.addEventListener('click', () => {
|
||||
const username = usernameInput.value.trim();
|
||||
const password = passwordInput.value;
|
||||
socket.emit('auth:login', { username, password }, (resp = {}) => {
|
||||
if (!resp.success) {
|
||||
alert(resp.error || 'Login failed');
|
||||
} else {
|
||||
updateRole(resp.role);
|
||||
}
|
||||
passwordInput.value = '';
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('auth:role', ({ role }) => {
|
||||
updateRole(role);
|
||||
});
|
||||
// initialize from default role
|
||||
updateRole(state.getRole());
|
||||
|
||||
spectatorBtn?.addEventListener('click', () => {
|
||||
socket.emit('role:set', { role: 'spectator' });
|
||||
updateRole('spectator');
|
||||
});
|
||||
});
|
||||
@@ -8,9 +8,16 @@ registerModule('services/roverUI', (require, exports) => {
|
||||
const sensorOutput = document.getElementById('sensorOutput');
|
||||
const requestBtn = document.getElementById('requestControl');
|
||||
const lockBtn = document.getElementById('lockToggle');
|
||||
const activeDriverEl = document.getElementById('activeDriver');
|
||||
|
||||
let roster = [];
|
||||
|
||||
state.onRoleChange((role) => {
|
||||
const isAdmin = role === 'admin' || role === 'lockdown';
|
||||
if (requestBtn) requestBtn.disabled = !isAdmin;
|
||||
if (lockBtn) lockBtn.disabled = !isAdmin;
|
||||
});
|
||||
|
||||
socket.on('rovers', (list) => {
|
||||
roster = list;
|
||||
roverSelect.innerHTML = '';
|
||||
@@ -48,6 +55,13 @@ registerModule('services/roverUI', (require, exports) => {
|
||||
sensorOutput.textContent = lines.join('\n');
|
||||
});
|
||||
|
||||
socket.on('activeDriver', ({ roverId, socketId }) => {
|
||||
if (roverId !== state.getSelected()) return;
|
||||
if (activeDriverEl) {
|
||||
activeDriverEl.textContent = `Active driver: ${socketId || 'none'}`;
|
||||
}
|
||||
});
|
||||
|
||||
requestBtn?.addEventListener('click', () => {
|
||||
socket.emit('requestControl', { roverId: state.getSelected() });
|
||||
});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
registerModule('services/state', (require, exports) => {
|
||||
let selectedRover = null;
|
||||
let role = 'user';
|
||||
const roleListeners = new Set();
|
||||
|
||||
function setSelected(roverId) {
|
||||
selectedRover = roverId;
|
||||
@@ -9,6 +11,24 @@ registerModule('services/state', (require, exports) => {
|
||||
return selectedRover;
|
||||
}
|
||||
|
||||
function setRole(nextRole) {
|
||||
role = nextRole;
|
||||
roleListeners.forEach((cb) => cb(role));
|
||||
}
|
||||
|
||||
function getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
function onRoleChange(cb) {
|
||||
roleListeners.add(cb);
|
||||
cb(role);
|
||||
return () => roleListeners.delete(cb);
|
||||
}
|
||||
|
||||
exports.setSelected = setSelected;
|
||||
exports.getSelected = getSelected;
|
||||
exports.setRole = setRole;
|
||||
exports.getRole = getRole;
|
||||
exports.onRoleChange = onRoleChange;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user