v2
This commit is contained in:
1 parent
c1a2a8cc30
commit
3fb3418e89
4 files changed
+19
-7
No files matched your search
@@ -16,8 +16,8 @@
|
||||
function repoCard(title,url,links){return `<article class="repo-card"><h3>${esc(title)}</h3><a href="${esc(url)}">${esc(url)}</a><div class="repo-links">${links.map(([n,u])=>`<a href="${esc(u)}"><span>${esc(n)}</span></a>`).join('')}</div></article>`}
|
||||
function renderRepositories(){const d=state.data;if(!d)return;const u=d.repository_url,dist=encodeURIComponent(d.apt_distribution);$('repo-cards').innerHTML=repoCard('Debian / Ubuntu',`${u}/apt`,[['GPG public key',`${u}/repo-key.gpg`],['APT InRelease',`${u}/apt/dists/${dist}/InRelease`],['Build info',`${u}/DEBIAN-BUILD-INFO.txt`]])+repoCard('RHEL / AlmaLinux / Rocky Linux',`${u}/rpm/x86_64`,[['GPG public key',`${u}/repo-key.gpg`],['RPM repomd.xml',`${u}/rpm/x86_64/repodata/repomd.xml`],['Metadata signature',`${u}/rpm/x86_64/repodata/repomd.xml.asc`],['Build info',`${u}/RHEL-BUILD-INFO.txt`]])+repoCard('SUSE / openSUSE',`${u}/suse/x86_64`,[['GPG public key',`${u}/repo-key.gpg`],['RPM repomd.xml',`${u}/suse/x86_64/repodata/repomd.xml`],['Metadata signature',`${u}/suse/x86_64/repodata/repomd.xml.asc`],['Build info',`${u}/SUSE-BUILD-INFO.txt`]]);$('metadata').innerHTML=['debian','rhel','suse'].map(ch=>{const b=d.builds[ch]||{};return `<div class="meta-block"><h3>${esc(channelNames[ch])}</h3>${[['Version',b.app_version],['Package release',b.package_release],['Build time',fmtDate(b.built_at)],['Commit',b.source_commit?b.source_commit.slice(0,12):'-'],['Packaging revision',b.packaging_revision]].map(([a,v])=>`<div class="meta-row"><span>${esc(a)}</span><strong>${esc(v||'-')}</strong></div>`).join('')}</div>`}).join('')}
|
||||
function renderAll(){renderOverview();renderPackages();renderInstall();renderRepositories()}
|
||||
async function refresh(){const btn=$('refresh');btn.disabled=true;try{const r=await fetch('/api/v1/packages',{cache:'no-store'});if(!r.ok)throw new Error(`HTTP ${r.status}`);state.data=await r.json();renderAll();$('last-sync').textContent=`Last refresh: ${fmtDate(state.data.generated_at)}`;$('status-text').textContent=state.data.ready?'Repository ready':'Waiting for first build'}catch(e){$('status-text').textContent='Repository unavailable';console.error(e)}finally{btn.disabled=false}}
|
||||
function setTheme(theme){document.documentElement.dataset.theme=theme;localStorage.setItem('rustbox-repo-theme',theme)}
|
||||
async function refresh(){const btn=$('refresh'),icon=btn.querySelector('.refresh-icon');btn.disabled=true;icon?.classList.add('spinning');try{const r=await fetch('/api/v1/packages',{cache:'no-store'});if(!r.ok)throw new Error(`HTTP ${r.status}`);state.data=await r.json();renderAll();$('last-sync').textContent=`Last refresh: ${fmtDate(state.data.generated_at)}`;$('status-text').textContent=state.data.ready?'Repository ready':'Waiting for first build'}catch(e){$('status-text').textContent='Repository unavailable';console.error(e)}finally{btn.disabled=false;icon?.classList.remove('spinning')}}
|
||||
function setTheme(theme){document.documentElement.dataset.theme=theme;const next=theme==='dark'?'light':'dark';const btn=$('theme-toggle');btn.setAttribute('aria-label',`Switch to ${next} theme`);btn.title=`Switch to ${next} theme`;localStorage.setItem('rustbox-repo-theme',theme)}
|
||||
document.querySelectorAll('[data-view]').forEach(b=>b.addEventListener('click',()=>navigate(b.dataset.view)));
|
||||
document.querySelectorAll('[data-go]').forEach(b=>b.addEventListener('click',()=>navigate(b.dataset.go)));
|
||||
document.querySelectorAll('[data-install]').forEach(b=>b.addEventListener('click',()=>{state.install=b.dataset.install;renderInstall()}));
|
||||
|
||||
@@ -22,7 +22,15 @@
|
||||
<main>
|
||||
<header class="topbar">
|
||||
<div><h1 id="view-title">Overview</h1><p id="last-sync">-</p></div>
|
||||
<div class="toolbar"><button id="theme-toggle" type="button">Theme</button><button id="refresh" type="button">Refresh</button></div>
|
||||
<div class="toolbar">
|
||||
<button id="theme-toggle" class="icon-button" type="button" aria-label="Switch to light theme" title="Switch to light theme">
|
||||
<svg class="theme-icon theme-icon-sun" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41"></path></svg>
|
||||
<svg class="theme-icon theme-icon-moon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20.25 15.12A8.5 8.5 0 0 1 8.88 3.75 8.5 8.5 0 1 0 20.25 15.12Z"></path></svg>
|
||||
</button>
|
||||
<button id="refresh" class="icon-button" type="button" aria-label="Refresh repository" title="Refresh repository">
|
||||
<svg class="refresh-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6v5h-5"></path><path d="M4 18v-5h5"></path><path d="M18.49 9A7 7 0 0 0 6.2 6.2L4 11"></path><path d="M5.51 15A7 7 0 0 0 17.8 17.8L20 13"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="overview" class="view active">
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
:root{color-scheme:dark;--bg:#121513;--panel:#181c19;--panel2:#1e231f;--panel3:#242a25;--sidebar:#101310;--line:#313832;--line2:#485149;--text:#edf0ec;--muted:#9da79f;--subtle:#7c877f;--accent:#8fb9a4;--accent2:#a4c9b6;--good:#a7c892;--field:#121713;--hover:#202621;--shadow:rgba(0,0,0,.32);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
|
||||
html[data-theme="light"]{color-scheme:light;--bg:#f2f4f1;--panel:#fff;--panel2:#f7f8f6;--panel3:#edf1ec;--sidebar:#e9eee9;--line:#cbd2cb;--line2:#aeb8af;--text:#202622;--muted:#647068;--subtle:#7a847d;--accent:#507b67;--accent2:#416b58;--good:#587a49;--field:#fff;--hover:#e8ede8;--shadow:rgba(31,39,33,.16)}
|
||||
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-size:14px}.shell{min-height:100vh;display:grid;grid-template-columns:228px minmax(0,1fr)}.sidebar{position:sticky;top:0;height:100vh;background:var(--sidebar);border-right:1px solid var(--line);padding:18px 12px;display:flex;flex-direction:column}.brand{display:flex;align-items:center;padding:7px 8px 24px}.brand strong,.brand span{display:block}.brand span{color:var(--muted);font-size:11px;margin-top:2px}.sidebar nav{display:grid;gap:3px}.nav{border:0;background:transparent;color:var(--muted);text-align:left;padding:10px 12px;border-radius:5px;cursor:pointer;font-weight:600}.nav:hover{background:var(--hover);color:var(--text)}.nav.active{background:var(--panel3);color:var(--text);box-shadow:inset 2px 0 var(--accent)}.sidebar-foot{margin-top:auto;border-top:1px solid var(--line);padding:15px 8px 2px;color:var(--muted);display:flex;align-items:center;gap:8px;font-size:12px}main{min-width:0}.topbar{height:72px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 24px;background:color-mix(in srgb,var(--bg) 84%,transparent);backdrop-filter:blur(10px);position:sticky;top:0;z-index:5}.topbar h1{font-size:18px;margin:0}.topbar p{margin:3px 0 0;color:var(--subtle);font-size:11px}.toolbar{display:flex;gap:7px}.toolbar button,.panel button,.install-tabs button{border:1px solid var(--line);background:var(--panel);color:var(--text);min-height:32px;padding:0 11px;border-radius:5px;cursor:pointer}.toolbar button:hover,.panel button:hover,.install-tabs button:hover{border-color:var(--line2);background:var(--hover)}.view{display:none;padding:24px;max-width:1320px;margin:0 auto}.view.active{display:block}.hero{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:18px;background:linear-gradient(135deg,var(--panel),var(--panel2));border:1px solid var(--line);border-radius:7px;padding:28px}.hero h2{font-size:30px;margin:7px 0 8px}.hero p{color:var(--muted);max-width:700px;margin:0;line-height:1.55}.eyebrow{color:var(--accent2);font-size:11px;font-weight:800;letter-spacing:.14em}.version-box{background:var(--field);border:1px solid var(--line);border-radius:6px;padding:18px;display:flex;flex-direction:column;justify-content:center}.version-box span{color:var(--subtle);font-size:10px;letter-spacing:.1em}.version-box strong{font-size:27px;margin:5px 0}.version-box small{color:var(--muted)}.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:12px 0}.cards article{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:17px}.cards span,.cards small{display:block;color:var(--muted)}.cards strong{display:block;font-size:22px;margin:5px 0}.panel{background:var(--panel);border:1px solid var(--line);border-radius:6px;margin-top:12px;overflow:hidden}.panel-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--line)}.panel-head h3{margin:0;font-size:14px}.panel-head p{margin:4px 0 0;color:var(--muted)}.package-row,.table-row{display:grid;grid-template-columns:minmax(220px,1fr) 150px 90px 110px 150px;gap:12px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--line)}.package-row:last-child,.table-row:last-child{border-bottom:0}.package-row:hover,.table-row:hover{background:var(--hover)}.pkg-name{font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.muted{color:var(--muted)}.pill{display:inline-flex;align-items:center;border:1px solid var(--line2);border-radius:99px;padding:3px 7px;font-size:10px;color:var(--muted);width:max-content}.download{color:var(--accent2);text-decoration:none;font-weight:650}.filters{display:grid;grid-template-columns:minmax(240px,1fr) 190px 170px;gap:8px;padding:12px;border-bottom:1px solid var(--line)}input,select{width:100%;height:34px;background:var(--field);color:var(--text);border:1px solid var(--line);border-radius:5px;padding:0 10px;outline:none}input:focus,select:focus{border-color:var(--accent)}.install-tabs{display:flex;gap:7px;flex-wrap:wrap}.install-tabs button.active{background:var(--accent);border-color:var(--accent);color:#102018;font-weight:700}.command-panel pre{margin:0;background:#0c0f0d;color:#e8efe9;padding:18px;overflow:auto;font:12px/1.6 ui-monospace,SFMono-Regular,Consolas,monospace}.note{margin-top:12px;border:1px solid var(--line);background:var(--panel2);padding:14px;border-radius:6px;color:var(--muted)}code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace}.repo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.repo-card{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:16px}.repo-card h3{margin:0 0 8px}.repo-card>a{color:var(--accent2);word-break:break-all}.repo-links{display:grid;margin-top:12px;border-top:1px solid var(--line)}.repo-links a{padding:9px 0;color:var(--muted);text-decoration:none;border-bottom:1px solid var(--line)}.metadata{display:grid;grid-Line truncated
|
||||
:root{color-scheme:dark;--bg:#101724;--panel:#172133;--panel2:#1c2940;--panel3:#23344e;--sidebar:#0d1522;--line:#2c3c55;--line2:#425673;--text:#f1f5fa;--muted:#aab6c8;--subtle:#8291a8;--accent:#62c9bd;--accent2:#7dd8ce;--accent-ink:#0b2a27;--good:#8bd5a0;--field:#111b2b;--hover:#202f46;--code-bg:#0b1220;--code-text:#e7eef8;--shadow:rgba(3,8,18,.34);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
|
||||
html[data-theme="light"]{color-scheme:light;--bg:#f4f8fc;--panel:#fff;--panel2:#f7fafc;--panel3:#eaf2f8;--sidebar:#edf4f9;--line:#d6e1eb;--line2:#b5c6d5;--text:#243247;--muted:#66778d;--subtle:#8290a3;--accent:#2f8078;--accent2:#236f69;--accent-ink:#fff;--good:#43875c;--field:#fff;--hover:#e8f1f7;--code-bg:#172235;--code-text:#f1f5fa;--shadow:rgba(42,64,84,.14)}
|
||||
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-size:14px}.shell{min-height:100vh;display:grid;grid-template-columns:228px minmax(0,1fr)}.sidebar{position:sticky;top:0;height:100vh;background:var(--sidebar);border-right:1px solid var(--line);padding:18px 12px;display:flex;flex-direction:column}.brand{display:flex;align-items:center;padding:7px 8px 24px}.brand strong,.brand span{display:block}.brand span{color:var(--muted);font-size:11px;margin-top:2px}.sidebar nav{display:grid;gap:3px}.nav{border:0;background:transparent;color:var(--muted);text-align:left;padding:10px 12px;border-radius:5px;cursor:pointer;font-weight:600}.nav:hover{background:var(--hover);color:var(--text)}.nav.active{background:var(--panel3);color:var(--text);box-shadow:inset 2px 0 var(--accent)}.sidebar-foot{margin-top:auto;border-top:1px solid var(--line);padding:15px 8px 2px;color:var(--muted);display:flex;align-items:center;gap:8px;font-size:12px}main{min-width:0}.topbar{height:72px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 24px;background:color-mix(in srgb,var(--bg) 84%,transparent);backdrop-filter:blur(10px);position:sticky;top:0;z-index:5}.topbar h1{font-size:18px;margin:0}.topbar p{margin:3px 0 0;color:var(--subtle);font-size:11px}.toolbar{display:flex;gap:7px}.toolbar button,.panel button,.install-tabs button{border:1px solid var(--line);background:var(--panel);color:var(--text);min-height:32px;padding:0 11px;border-radius:5px;cursor:pointer}.toolbar button:hover,.panel button:hover,.install-tabs button:hover{border-color:var(--line2);background:var(--hover)}.toolbar .icon-button{width:34px;height:34px;min-height:34px;padding:0;display:inline-flex;align-items:center;justify-content:center}.icon-button svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.theme-icon-moon{display:none}html[data-theme="light"] .theme-icon-sun{display:none}html[data-theme="light"] .theme-icon-moon{display:block}.refresh-icon.spinning{animation:repo-spin .65s linear infinite}@keyframes repo-spin{to{transform:rotate(360deg)}}.view{display:none;padding:24px;max-width:1320px;margin:0 auto}.view.active{display:block}.hero{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:18px;background:linear-gradient(135deg,var(--panel),color-mix(in srgb,var(--panel2) 86%,var(--accent) 14%));border:1px solid var(--line);border-radius:7px;padding:28px}.hero h2{font-size:30px;margin:7px 0 8px}.hero p{color:var(--muted);max-width:700px;margin:0;line-height:1.55}.eyebrow{color:var(--accent2);font-size:11px;font-weight:800;letter-spacing:.14em}.version-box{background:var(--field);border:1px solid var(--line);border-radius:6px;padding:18px;display:flex;flex-direction:column;justify-content:center}.version-box span{color:var(--subtle);font-size:10px;letter-spacing:.1em}.version-box strong{font-size:27px;margin:5px 0}.version-box small{color:var(--muted)}.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:12px 0}.cards article{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:17px}.cards span,.cards small{display:block;color:var(--muted)}.cards strong{display:block;font-size:22px;margin:5px 0}.panel{background:var(--panel);border:1px solid var(--line);border-radius:6px;margin-top:12px;overflow:hidden}.panel-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--line)}.panel-head h3{margin:0;font-size:14px}.panel-head p{margin:4px 0 0;color:var(--muted)}.package-row,.table-row{display:grid;grid-template-columns:minmax(220px,1fr) 150px 90px 110px 150px;gap:12px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--line)}.package-row:last-child,.table-row:last-child{border-bottom:0}.package-row:hover,.table-row:hover{background:var(--hover)}.pkg-name{font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.muted{color:var(--muted)}.pill{display:inline-flex;align-items:center;border:1px solid var(--line2);border-radius:99px;padding:3px 7px;font-size:10px;color:var(--muted);width:max-content}.download{color:var(--accent2);text-decoration:none;font-weight:650}.filters{display:grid;grid-template-columns:minmax(240px,1fr) 190px 170px;gap:8px;padding:12px;border-bottom:1px solid var(--line)}input,select{width:100%;height:34px;background:var(--field);color:var(--text);border:1px solid var(--line);border-radius:5px;padding:0 10px;outline:none}input:focus,select:focus{border-color:var(--accent)}.install-tabs{display:flex;gap:7px;flex-wrap:wrap}.install-tabs button.active{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:700}.command-panel pre{margin:0;background:var(--code-bg);color:var(--code-text);padding:18px;overflow:auto;font:12px/1.6 ui-monospace,SFMono-Regular,Consolas,monospace}.note{margin-top:12px;border:1px solid var(--line);backgrounLine truncated
|
||||
@@ -38,12 +38,16 @@ def test_catalog_uses_three_linux_distribution_families():
|
||||
assert len(catalog["packages"]) == 3
|
||||
|
||||
|
||||
def test_dashboard_is_english_text_only():
|
||||
def test_dashboard_is_english_with_utility_svg_icons_only():
|
||||
html = (ROOT / "dashboard/web/index.html").read_text()
|
||||
js = (ROOT / "dashboard/web/app.js").read_text()
|
||||
assert 'lang="en"' in html
|
||||
assert "brand-icon" not in html
|
||||
assert "favicon" not in html
|
||||
assert "status-dot" not in html
|
||||
assert "theme-icon-sun" in html
|
||||
assert "theme-icon-moon" in html
|
||||
assert "refresh-icon" in html
|
||||
assert html.count("<svg") == 3
|
||||
for label in ("Overview", "Packages", "Installation", "Repositories", "Debian / Ubuntu", "RHEL / AlmaLinux / Rocky Linux", "SUSE / openSUSE"):
|
||||
assert label in html or label in js
|
||||
Reference in new issue
Block a user