feat: release passwordless hierarchical APT v1.2.5
APT build checks / build-checks (push) Successful in 37s
APT build checks / build-checks (pull_request) Successful in 37s

This commit is contained in:
2026-08-22 16:20:12 +00:00
parent c08d2ad381
commit ace4568f81
27 changed files with 209 additions and 145 deletions
+42 -9
View File
@@ -10,7 +10,6 @@ const statusIndicator = document.getElementById('statusIndicator');
const deviceSearch = document.getElementById('deviceSearch');
const disconnectBtn = document.getElementById('disconnectBtn');
const selectedDeviceId = document.getElementById('selectedDeviceId');
const altaUsername = document.getElementById('altaUsername');
const startProxyBtn = document.getElementById('startProxyBtn');
const stopProxyBtn = document.getElementById('stopProxyBtn');
const checkUpdateBtn = document.getElementById('checkUpdateBtn');
@@ -18,11 +17,14 @@ const updateNotice = document.getElementById('updateNotice');
const updateMessage = document.getElementById('updateMessage');
const openReleasesBtn = document.getElementById('openReleasesBtn');
const dismissUpdateBtn = document.getElementById('dismissUpdateBtn');
const pairingSection = document.getElementById('pairingSection');
const managePairingBtn = document.getElementById('managePairingBtn');
const pairingState = document.getElementById('pairingState');
const pairingSecret = document.getElementById('pairingSecret');
const pairingSecretRow = document.getElementById('pairingSecretRow');
const rotatePairingBtn = document.getElementById('rotatePairingBtn');
const revokePairingBtn = document.getElementById('revokePairingBtn');
const hidePairingBtn = document.getElementById('hidePairingBtn');
const ROW_HEIGHT = window.AptSidebarView.ROW_HEIGHT;
let connection = { connected: false, origin: null, activeProxies: [] };
@@ -32,6 +34,17 @@ let sidebarController = null;
let loadGeneration = 0;
let searchTimer = null;
let scrollFrame = null;
let pairingView = { paired: false, secretVisible: false, manuallyOpen: false };
function renderPairingVisibility() {
const visible = window.AptRendererController.shouldShowPairingOnboarding({
...pairingView,
connected: connection.connected,
});
pairingSection.hidden = !visible;
managePairingBtn.hidden = visible || !pairingView.paired;
hidePairingBtn.hidden = !pairingView.paired;
}
function showStatus(element, message, type) {
element.textContent = message;
@@ -51,8 +64,7 @@ function deviceStatusFor(device) {
function updateProxyButtons() {
const id = selectedDevice && selectedDevice.id;
const active = id ? activeDeviceIds().has(id.toLowerCase()) : false;
const hasUsername = altaUsername.value.trim().length > 0;
startProxyBtn.disabled = !connection.connected || !id || !hasUsername || active;
startProxyBtn.disabled = !connection.connected || !id || active;
stopProxyBtn.disabled = !id || !active;
}
@@ -67,6 +79,13 @@ function renderConnectionState(state) {
dot.className = `status-dot ${connection.connected ? 'online' : 'offline'}`;
text.textContent = connection.connected ? 'Connected' : 'Disconnected';
disconnectBtn.disabled = !connection.connected;
if (connection.connected) {
pairingView.secretVisible = false;
pairingView.manuallyOpen = false;
pairingSecret.value = '';
pairingSecretRow.style.display = 'none';
}
renderPairingVisibility();
updateProxyButtons();
if (sidebarController) sidebarController.refresh();
}
@@ -145,10 +164,9 @@ function installHierarchy(hierarchy) {
const count = snapshot.state.searchQuery && snapshot.state.searchCameraKeys
? snapshot.state.searchCameraKeys.size
: hierarchyModel.cameraCount;
const hidden = snapshot.rows.hiddenSelected ? ' Selected camera is hidden by the current view.' : '';
deviceResults.textContent = snapshot.state.searchQuery
? `${count} exact search result${count === 1 ? '' : 's'}.${hidden}`
: `${count} camera${count === 1 ? '' : 's'}.${hidden}`;
? `${count} exact search result${count === 1 ? '' : 's'}.`
: `${count} camera${count === 1 ? '' : 's'}.`;
},
});
sidebarController = window.AptSidebarController.createSidebarController({
@@ -201,7 +219,6 @@ const rendererController = window.AptRendererController.createRendererController
disconnect: () => window.electronAPI.disconnect(),
renderConnectionState,
clearDisconnectedState: () => {
altaUsername.value = '';
clearHierarchy();
},
showConnectionStatus: (message, type) => showStatus(connectionStatus, message, type),
@@ -216,7 +233,7 @@ async function handleStartProxy() {
if (!id) return;
startProxyBtn.disabled = true;
showStatus(connectionStatus, `Starting proxy for ${selectedDevice.name || 'selected device'}...`, 'info');
const result = await window.electronAPI.launchProxy(id, altaUsername.value);
const result = await window.electronAPI.launchProxy(id);
if (result.success) {
renderConnectionState(await window.electronAPI.getConnectionState());
showStatus(connectionStatus, 'Camera proxy started.', 'success');
@@ -259,6 +276,11 @@ async function checkForUpdates(showCurrent = true) {
}
function renderPairingStatus(result) {
pairingView = {
paired: result.paired === true,
secretVisible: Boolean(result.secret),
manuallyOpen: Boolean(result.secret) || result.paired !== true,
};
pairingState.textContent = result.paired ? 'Paired' : 'Revoked / not paired';
pairingState.className = result.paired ? 'paired' : 'unpaired';
revokePairingBtn.disabled = !result.paired;
@@ -270,6 +292,7 @@ function renderPairingStatus(result) {
pairingSecret.value = '';
pairingSecretRow.style.display = 'none';
}
renderPairingVisibility();
}
async function runSearch(query) {
@@ -340,10 +363,20 @@ deviceSearch.addEventListener('keydown', (event) => {
disconnectBtn.addEventListener('click', handleDisconnect);
startProxyBtn.addEventListener('click', handleStartProxy);
stopProxyBtn.addEventListener('click', handleStopProxy);
altaUsername.addEventListener('input', updateProxyButtons);
checkUpdateBtn.addEventListener('click', () => checkForUpdates(true));
openReleasesBtn.addEventListener('click', () => window.electronAPI.openFixedReleasesPage());
dismissUpdateBtn.addEventListener('click', () => { updateNotice.style.display = 'none'; });
rotatePairingBtn.addEventListener('click', async () => renderPairingStatus(await window.electronAPI.rotatePairing()));
revokePairingBtn.addEventListener('click', async () => renderPairingStatus(await window.electronAPI.revokePairing()));
managePairingBtn.addEventListener('click', () => {
pairingView.manuallyOpen = true;
renderPairingVisibility();
});
hidePairingBtn.addEventListener('click', () => {
pairingView.manuallyOpen = false;
pairingView.secretVisible = false;
pairingSecret.value = '';
pairingSecretRow.style.display = 'none';
renderPairingVisibility();
});
document.addEventListener('DOMContentLoaded', () => { initialize().catch(() => showStatus(connectionStatus, 'Application initialization failed.', 'error')); });