feat(deploy): reliability API routes, atomic releases, version single-source

This commit is contained in:
2026-08-22 15:20:39 -06:00
parent aba08e36c7
commit 1bb15de258
10 changed files with 586 additions and 40 deletions
@@ -269,7 +269,7 @@
<script src="js/xterm-addon-fit.min.js"></script>
<script src="js/terminal.js?v=20260820-4"></script>
<script src="js/pager.js?v=20260820-4"></script>
<script src="js/views.js?v=20260822-1"></script>
<script src="js/views.js?v=20260822-2"></script>
<script src="js/app.js?v=20260822-1"></script>
</body>
</html>
@@ -3920,6 +3920,43 @@ views.settings = (root) => {
overlay.appendChild(restoreBtn);
loadOverlay();
const profiles = settingsCard(box, 'Reliability Profiles',
'Snapshots of the PineAP, wireless, and network UCI config. Save one before risky changes; restoring rolls the config back and reloads the radios.');
const profBody = h('div', { class: 'settings-table-wrap', text: 'Loading…' });
profiles.appendChild(profBody);
function loadProfiles() {
PagerAPI.get('/api/reliability/profiles').then((r) => {
const names = (r.data || {}).profiles || [];
profBody.innerHTML = '';
if (!names.length) {
profBody.appendChild(h('div', { class: 'empty', text: 'No saved profiles yet.' }));
return;
}
profBody.appendChild(table([
{ label: 'Profile', key: 'name' },
{ label: '', render: (row) => {
const doRestore = btn('Restore', () => runAction(doRestore,
() => PagerAPI.post('/api/reliability/restore', { name: row.name })
.then(() => App.toast('Profile restored; radios reloaded')), 'Restoring…'), 'ghost');
return doRestore;
} }
], names.map((name) => ({ name }))));
}).catch(() => { profBody.textContent = 'Unable to load profiles.'; });
}
const profName = h('input', { placeholder: 'e.g. pre-evilwpa', maxlength: '64',
autocomplete: 'off' });
const profSave = btn('Save Profile', () => {
const name = profName.value.trim();
if (!name) { App.toast('Profile name is required', 'error'); return; }
return runAction(profSave, () => PagerAPI.post('/api/reliability/profile', { name })
.then(() => { profName.value = ''; App.toast('Config profile saved'); loadProfiles(); }), 'Saving…');
});
profiles.appendChild(h('div', { class: 'settings-form-grid' },
h('label', {}, 'Profile Name', profName)));
profiles.appendChild(h('div', { class: 'settings-actions' }, profSave,
btn('Refresh', () => { loadProfiles(); }, 'ghost')));
loadProfiles();
settingsCard(box, 'Button Script', 'The Mark VII button script has no safe Pager equivalent. Pager buttons remain managed by the native input and payload-launcher system.');
const resources = settingsCard(box, 'Resources');