Feat v0.7.6 code hygiene (#60)
All checks were successful
CI/CD / e2e-smoke (push) Has been skipped
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-go-pg (push) Successful in 2m48s
CI/CD / build-and-deploy (push) Successful in 25s
CI/CD / test-sqlite (push) Successful in 2m55s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #60.
This commit is contained in:
2026-04-02 17:39:41 +00:00
committed by xcaliber
parent 5e830c04de
commit e02b13dc12
22 changed files with 850 additions and 144 deletions

View File

@@ -30,12 +30,12 @@ export default function BackupSection() {
sw.toast('Backup created', 'success');
load();
} else {
// Stream download
// Stream download — use _getToken() for raw bearer token
const url = '/api/v1/admin/backup';
const token = sw.auth.token();
const token = sw.auth._getToken();
const resp = await fetch(url, {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token },
headers: token ? { 'Authorization': 'Bearer ' + token } : {},
});
if (!resp.ok) throw new Error('Backup failed');
const blob = await resp.blob();
@@ -54,9 +54,9 @@ export default function BackupSection() {
}
async function downloadBackup(name) {
const token = sw.auth.token();
const token = sw.auth._getToken();
const resp = await fetch(sw.api.admin.backup.download(name), {
headers: { 'Authorization': 'Bearer ' + token },
headers: token ? { 'Authorization': 'Bearer ' + token } : {},
});
if (!resp.ok) { sw.toast('Download failed', 'error'); return; }
const blob = await resp.blob();

View File

@@ -20,14 +20,14 @@ import { DialogStack } from '../../shell/dialog-stack.js';
const ADMIN_SECTIONS = {
people: ['users', 'teams', 'groups'],
workflows: ['workflows'],
system: ['settings', 'storage', 'packages', 'connections', 'broadcast', 'backup'],
system: ['settings', 'packages', 'connections', 'broadcast', 'backup'],
monitoring: ['health', 'audit'],
};
const ADMIN_LABELS = {
users: 'Users', teams: 'Teams', groups: 'Groups',
workflows: 'Workflows',
settings: 'Settings', storage: 'Storage', packages: 'Packages',
settings: 'Settings', packages: 'Packages',
connections: 'Connections', broadcast: 'Broadcast',
backup: 'Backup',
health: 'Health', audit: 'Audit',
@@ -63,7 +63,6 @@ const sectionModules = {
groups: () => import(`./groups.js${_v}`),
workflows: () => import(`./workflows.js${_v}`),
settings: () => import(`./settings.js${_v}`),
storage: () => import(`./storage.js${_v}`),
packages: () => import(`./packages.js${_v}`),
connections: () => import(`./connections.js${_v}`),
broadcast: () => import(`./broadcast.js${_v}`),

View File

@@ -1,76 +0,0 @@
/**
* Admin > System > Storage
*/
const { html } = window;
const { useState, useEffect, useCallback } = hooks;
export default function StorageSection() {
const [status, setStatus] = useState(null);
const [orphans, setOrphans] = useState(null);
const [extraction, setExtraction] = useState(null);
const [loading, setLoading] = useState(true);
const load = useCallback(async () => {
try {
const [s, o, e] = await Promise.all([
sw.api.admin.storage.status(),
sw.api.admin.storage.orphans(),
sw.api.admin.storage.extraction().catch(() => null),
]);
setStatus(s);
setOrphans(o);
setExtraction(e);
} catch (e) { sw.toast(e.message, 'error'); }
finally { setLoading(false); }
}, []);
useEffect(() => { load(); }, []);
async function cleanup() {
const ok = await sw.confirm('Remove orphaned blobs?');
if (!ok) return;
try {
await sw.api.admin.storage.cleanup();
sw.toast('Cleanup complete', 'success');
load();
} catch (e) { sw.toast(e.message, 'error'); }
}
function formatBytes(b) {
if (!b) return '0 B';
if (b < 1024) return b + ' B';
if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
if (b < 1073741824) return (b / 1048576).toFixed(1) + ' MB';
return (b / 1073741824).toFixed(2) + ' GB';
}
if (loading) return html`<div class="settings-placeholder">Loading\u2026</div>`;
return html`
<div>
${status && html`
<div class="stat-cards-grid" style="margin-bottom:16px;">
<div class="stat-card"><div class="stat-value">${status.backend || '\u2014'}</div><div class="stat-label">Backend</div></div>
<div class="stat-card"><div class="stat-value"><span class="badge ${status.healthy ? 'badge-active' : 'badge-inactive'}">${status.healthy ? 'Healthy' : 'Unhealthy'}</span></div><div class="stat-label">Status</div></div>
<div class="stat-card"><div class="stat-value">${status.file_count ?? '\u2014'}</div><div class="stat-label">Files</div></div>
<div class="stat-card"><div class="stat-value">${formatBytes(status.total_bytes)}</div><div class="stat-label">Total Size</div></div>
</div>
`}
${orphans && html`
<div class="settings-section" style="margin-bottom:16px;">
<h4>Orphaned Blobs</h4>
<p class="text-muted" style="font-size:12px;">${orphans.count || 0} orphans found</p>
${(orphans.count || 0) > 0 && html`<button class="sw-btn sw-btn--primary sw-btn--sm" onClick=${cleanup}>Clean Up</button>`}
</div>
`}
${extraction && html`
<div class="settings-section">
<h4>Extraction Queue</h4>
<pre class="code-block" style="font-size:12px;max-height:200px;overflow:auto;">${JSON.stringify(extraction, null, 2)}</pre>
</div>
`}
</div>
`;
}