diff --git a/README.md b/README.md
index 4d9058b..a98e875 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ Jeden kontener buildera buduje z jednego commita RustProxy:
## Panel repozytorium (RustProxy Package Registry)
+The dashboard interface defaults to **English (`en-GB`)**, including its dates, navigation, notifications, and installation instructions. The **Docker discovery agent** installation card is shown only for **Linux (DEB/RPM)**, never for OPNsense or native FreeBSD. Package listings/API also omit any stray agent PKG files for the FreeBSD channels.
+
Strony startowe wszystkich trzech repozytoriów działają teraz jako **lekka aplikacja Python** (`dashboard/`) za istniejącym Nginx. Wygląd nawiązuje do panelu RustProxy 0.34.6 (ciemny, jasny i kremowy motyw). **APT, RPM i pkg są nadal obsługiwane bezpośrednio przez Nginx**, więc mechanizm aktualizacji paczek, ścieżki plików, podpisy GPG i atomowe przełączanie `current` nie zmieniają się.
Panel udostępnia:
diff --git a/SHA256SUMS b/SHA256SUMS
index 57da09f..7841750 100644
--- a/SHA256SUMS
+++ b/SHA256SUMS
@@ -1,13 +1,13 @@
516d7009f920efa26f60acbd859fa62cd3c7e23953c805173150145b1428a033 .env.example
17298e7669ed82b4c98abfce803e1a3f0a265b0abdc2567bf1316aa15e98aad3 Dockerfile
-ef47c4a3fad51d17ad690b0d6aa440d6ef3e355c5e9bd1824368f5450b4b7957 README.md
+0a6ca99db70dafd639ff677e68c4ca28109d29b718229c40c7d0b14622c8011a README.md
862263fa1f46c20f0d1e4dac5ffcc75abd55c08211b2c3864c5f8764b9d87793 dashboard/.dockerignore
ced0339cb93478c2faf7b7b74215fe03375086e11ca957bd8892b52802fbbd3a dashboard/Dockerfile
-4bd84a56b756d6109a4fde23c6fcb2fef1b290302312a55046b8487cb9c36d74 dashboard/app.py
-345dbb2c4293405092445e159ce23053894d0c2335457f7299622ca42382dc05 dashboard/web/app.js
+bd2ba3a11ee715ba41a94f3301bec4ce83d7177489190a755e165112df50f112 dashboard/app.py
+a86070f70fe5fe159ac5b3e3c7643724f40761af3eb3a6fd40d584652e230c80 dashboard/web/app.js
f1ac0fb5c4da97db09ff328cb86f4bc763fbdd84d7310d6e8e713be1c8707bb9 dashboard/web/favicon.svg
-c7427bf31438cbbec9152c93674088bb2a16ea1d9a499b3c5c85beee2c543dda dashboard/web/index.html
-a3834770bcc9c0548bf387fb52795f3f6cb15b253f7d3819df9be147b04ebb8e dashboard/web/style.css
+37a6c0a8f6d10cca3147ed19043cd801eb76f4506e6fb94702a1841fc971e242 dashboard/web/index.html
+4ea25df28ed237a616085ac183aaf760cdbed3bf957e8f21859274513da14d0d dashboard/web/style.css
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/.gitkeep
328b8b8075208e0c92793cf70c6d8999775faf94abf5d839101e6d3ba35597cf docker-compose.yml
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 gpg/.gitkeep
@@ -70,5 +70,5 @@ e82c52ef15183a539e96909a39e44db68c8301543950e145008b563524b0b9b9 tests/freebsd-
c5781dd2335cc85e72daffe807c7ba24481b6c2e8bc95f4012be4ea1baeac9a8 tests/log-rotation.sh
aab57cd66dc157dc2359d8d57612c174570a7ea09fe753428dce8faad231ba3c tests/opnsense-plugin.sh
1227d503f784f7765c5950b603e4258ea155c2fdc3779886a7b0c403320be2a8 tests/static.sh
-ff0fe09dcd33124644a9babdf951193ebb358015997b302c7e3775a6c7a4d762 tests/test_dashboard.py
+9d33b7053024dee7b241d87182a895a7b2ee81c7094a97a3428a9b6036a5052a tests/test_dashboard.py
c8de9ebbf51e017643d0735f27b960a6cf3c9b7122f6de32858f6b7dcc7ba9e9 tests/toolchains.sh
diff --git a/dashboard/app.py b/dashboard/app.py
index 9861e19..2651721 100644
--- a/dashboard/app.py
+++ b/dashboard/app.py
@@ -138,6 +138,9 @@ def package_entry(path: Path, current: Path, site: str, kind: str, channel: str,
if not parsed or not path.is_file():
return None
name, version, arch = parsed
+ # Discovery agent is packaged for Linux DEB/RPM only; never advertise it as FreeBSD pkg.
+ if channel in ('opnsense', 'freebsd') and name == 'rustproxy-docker-agent':
+ return None
try:
stat = path.stat()
except OSError:
diff --git a/dashboard/web/app.js b/dashboard/web/app.js
index 703b705..fcf3fc5 100644
--- a/dashboard/web/app.js
+++ b/dashboard/web/app.js
@@ -5,10 +5,10 @@
const el = (id) => document.getElementById(id);
const CHANNEL_LABELS = {linux:'Linux',opnsense:'OPNsense',freebsd:'FreeBSD'};
const INSTALL_NAMES = {deb:'Debian / Ubuntu',rpm:'RHEL / Rocky / Alma / Fedora',opnsense:'OPNsense',freebsd:'FreeBSD native'};
- const SECTION_LABELS = {overview:'Przegląd',packages:'Paczki i wersje',install:'Instalacja',repository:'Repozytoria'};
+ const SECTION_LABELS = {overview:'Overview',packages:'Packages & versions',install:'Installation',repository:'Repositories'};
const esc = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char]));
- const collator = new Intl.Collator('pl', {numeric:true,sensitivity:'base'});
- const formatNumber = new Intl.NumberFormat('pl-PL');
+ const collator = new Intl.Collator('en', {numeric:true,sensitivity:'base'});
+ const formatNumber = new Intl.NumberFormat('en-GB');
const site = ['linux','opnsense','freebsd'].includes(document.body.dataset.site) ? document.body.dataset.site : 'linux';
const state = {
site, catalog:null, section:'overview', installing:site === 'linux' ? 'deb' : site,
@@ -20,13 +20,13 @@
if (!value) return '—';
const time = new Date(value);
if (Number.isNaN(time.valueOf())) return '—';
- return new Intl.DateTimeFormat('pl-PL', {year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}).format(time);
+ return new Intl.DateTimeFormat('en-GB', {year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'}).format(time);
};
const formatShortDate = (value) => {
if (!value) return '—';
const time = new Date(value);
if (Number.isNaN(time.valueOf())) return '—';
- return new Intl.DateTimeFormat('pl-PL', {day:'2-digit',month:'short',year:'numeric'}).format(time);
+ return new Intl.DateTimeFormat('en-GB', {day:'2-digit',month:'short',year:'numeric'}).format(time);
};
const formatSize = (value) => {
const size = Number(value);
@@ -43,7 +43,7 @@
return '#';
};
const origin = (url) => typeof url === 'string' ? url.replace(/\/$/, '') : '';
- const dateLabel = (kind) => kind === 'build' ? 'Data zapisana przez builder' : 'Data pliku (starsze buildy bez znacznika czasu)';
+ const dateLabel = (kind) => kind === 'build' ? 'Build timestamp recorded by the builder' : 'File modification time (older builds without a build timestamp)';
const setText = (id, value) => {const node = el(id);if (node) node.textContent = value;};
const versionText = (b) => b?.app_version ? `v${b.app_version}` : '—';
@@ -82,7 +82,7 @@
? `PKG · ${build?.opnsense_series || 'FreeBSD'}` : `PKG · ${build?.freebsd_abi || 'Native'}`;
const version = build?.package_version || (live ? build?.app_version : '') || '—';
return `
- ${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${channel === 'linux' ? 'SIGNED' : 'PKG'}${live ? 'PUBLISHED' : 'BRAK BUILDU'}
+ ${esc(CHANNEL_LABELS[channel].toUpperCase())} / ${channel === 'linux' ? 'SIGNED' : 'PKG'}${live ? 'PUBLISHED' : 'NOT BUILT'}
${esc(version)}
${esc(subtitle)}
BUILD DATE${esc(formatDate(build?.built_at))}
COMMIT${esc(commit)}
`;
@@ -92,7 +92,7 @@
return `${esc(pkg.format)}`;
}
function tableRow(pkg, compact = false) {
- const download = `${compact ? 'Pobierz' : 'Pobierz plik'} ↗`;
+ const download = `${compact ? 'Download' : 'Download file'} ↗`;
const first = `${esc(pkg.name)}${esc(pkg.architecture)}`;
const format = `${formatBadge(pkg)}${esc(CHANNEL_LABELS[pkg.channel] || pkg.channel)}`;
const date = `${esc(formatDate(pkg.built_at))}`;
@@ -112,29 +112,29 @@
setText('stat-channels', `${data.summary?.channels_published || 0} / 3`);
setText('stat-date', formatShortDate(data.summary?.latest_build_at));
setText('stat-version', heroVersion);
- setText('stat-release', main?.package_version ? `Pakiet: ${main.package_version}` : 'Brak opublikowanej wersji');
- setText('stat-date-sub', 'Data ostatniej publikacji');
+ setText('stat-release', main?.package_version ? `Package: ${main.package_version}` : 'No release published yet');
+ setText('stat-date-sub', 'Latest publication date');
setText('pipeline-updated', formatDate(data.generated_at));
const ready = !!data.ready;
- el('hero-status').innerHTML = ` ${ready ? 'REPOZYTORIUM AKTYWNE' : 'OCZEKIWANIE NA BUILD'}`;
+ el('hero-status').innerHTML = ` ${ready ? 'REPOSITORY ONLINE' : 'WAITING FOR BUILD'}`;
el('hero-status').classList.toggle('waiting', !ready);
el('sidebar-status').classList.toggle('waiting', !ready);
- el('sidebar-status').querySelector('span').textContent = ready ? 'REPOSITORY ONLINE' : 'OCZEKIWANIE NA DANE';
+ el('sidebar-status').querySelector('span').textContent = ready ? 'REPOSITORY ONLINE' : 'WAITING FOR DATA';
const side = el('side-channels');
side.innerHTML = ['linux','opnsense','freebsd'].map((channel) => `${esc(CHANNEL_LABELS[channel])}${channel === 'linux' ? 'APT / DNF' : 'PKG'}`).join('');
el('build-grid').innerHTML = ['linux','opnsense','freebsd'].map((channel) => buildCard(data.builds[channel],channel)).join('');
- const recent = data.packages.slice(0,6);
- el('recent-rows').innerHTML = recent.length ? recent.map((pkg) => tableRow(pkg,true)).join('') : '
| Nie opublikowano jeszcze żadnych paczek. Katalog zapełni się po pierwszym buildzie. |
';
+ const recent = data.packages.filter((pkg) => state.site === 'linux' || pkg.channel === state.site).slice(0,6);
+ el('recent-rows').innerHTML = recent.length ? recent.map((pkg) => tableRow(pkg,true)).join('') : '| No packages published yet. The catalog will populate after the first build. |
';
}
function filteredPackages() {
const arr = state.catalog?.packages || [];
- const search = state.search.trim().toLocaleLowerCase('pl-PL');
+ const search = state.search.trim().toLocaleLowerCase('en-GB');
const filtered = arr.filter((pkg) => {
if (state.channel !== 'all' && pkg.channel !== state.channel) return false;
if (state.format !== 'all' && pkg.format !== state.format) return false;
if (!search) return true;
- return [pkg.name,pkg.version,pkg.channel,pkg.format,pkg.architecture].some((field) => String(field ?? '').toLocaleLowerCase('pl-PL').includes(search));
+ return [pkg.name,pkg.version,pkg.channel,pkg.format,pkg.architecture].some((field) => String(field ?? '').toLocaleLowerCase('en-GB').includes(search));
});
if (state.sort === 'name') filtered.sort((a,b) => collator.compare(a.name,b.name) || collator.compare(b.version,a.version));
if (state.sort === 'version') filtered.sort((a,b) => collator.compare(b.version,a.version) || collator.compare(a.name,b.name));
@@ -147,10 +147,10 @@
if (!data) return;
const all = filteredPackages();
const shown = all.slice(0,state.rows);
- setText('packages-total', `${formatNumber.format(data.summary.packages_count)} paczek`);
- setText('filter-count', `${formatNumber.format(all.length)} ${all.length === 1 ? 'wynik' : 'wyników'}`);
- setText('result-range', all.length ? `Wyświetlono ${shown.length} z ${all.length}` : 'Brak pasujących paczek');
- el('catalog-rows').innerHTML = shown.length ? shown.map((pkg) => tableRow(pkg)).join('') : '| Brak paczek spełniających kryteria. Zmień filtry lub poczekaj na publikację. |
';
+ setText('packages-total', `${formatNumber.format(data.summary.packages_count)} packages`);
+ setText('filter-count', `${formatNumber.format(all.length)} ${all.length === 1 ? 'result' : 'results'}`);
+ setText('result-range', all.length ? `Showing ${shown.length} of ${all.length}` : 'No matching packages');
+ el('catalog-rows').innerHTML = shown.length ? shown.map((pkg) => tableRow(pkg)).join('') : '| No packages match these filters. Adjust your search or check back after a new release. |
';
el('show-more').hidden = shown.length >= all.length;
}
@@ -163,9 +163,9 @@
const component = data.apt_component || 'main';
if (kind === 'deb') {
return {
- description:'Dodaj podpisane repozytorium APT, odśwież listę pakietów i zainstaluj RustProxy.',
+ description:'Add the signed APT repository, update the package list, and install RustProxy.',
signature:'GPG SIGNED',
- note:'Obsługiwane: Debian / Ubuntu · architektura amd64.',
+ note:'Supported: Debian / Ubuntu · amd64 architecture.',
reference:`${linux}/apt/dists/${encodeURIComponent(distribution)}/InRelease`,
agent:'sudo apt install rustproxy-docker-agent',
code:[
@@ -182,9 +182,9 @@
}
if (kind === 'rpm') {
return {
- description:'Dodaj podpisane repozytorium DNF/YUM i zainstaluj serwer RustProxy.',
+ description:'Add the signed DNF/YUM repository and install the RustProxy server.',
signature:'GPG SIGNED',
- note:'Obsługiwane: RHEL / Rocky / Alma / Fedora · architektura x86_64.',
+ note:'Supported: RHEL / Rocky / Alma / Fedora · x86_64 architecture.',
reference:`${linux}/rpm/x86_64/repodata/repomd.xml`,
agent:'sudo dnf install rustproxy-docker-agent',
code:[
@@ -206,11 +206,11 @@
}
if (kind === 'opnsense') {
return {
- description:'Pobierz konfigurację repozytorium pkg i zainstaluj plugin os-rustproxy.',
+ description:'Fetch the pkg repository configuration and install the os-rustproxy plugin.',
signature:'UNSIGNED PKG',
- note:'Repozytorium pkg nie ma podpisanego katalogu. Korzystaj tylko z zaufanego hosta HTTPS.',
+ note:'The pkg repository index is unsigned. Only use a trusted HTTPS host.',
reference:`${opnsense}/RustProxy.conf`,
- agent:'sudo apt install rustproxy-docker-agent',
+ agent:null,
code:[
'mkdir -p /usr/local/etc/pkg/repos',
`fetch -o /usr/local/etc/pkg/repos/RustProxy.conf ${opnsense}/RustProxy.conf`,
@@ -220,11 +220,11 @@
};
}
return {
- description:'Zainstaluj natywny pakiet rustproxy i włącz usługę rc.d.',
+ description:'Install the native rustproxy package and enable its rc.d service.',
signature:'UNSIGNED PKG',
- note:'Dostępne po ustawieniu FREEBSD_NATIVE_ENABLED=1. Katalog pkg jest niesygnowany.',
+ note:'Requires FREEBSD_NATIVE_ENABLED=1. The pkg index is unsigned.',
reference:`${freebsd}/RustProxy-FreeBSD.conf`,
- agent:'sudo dnf install rustproxy-docker-agent',
+ agent:null,
code:[
'mkdir -p /usr/local/etc/pkg/repos',
`fetch -o /usr/local/etc/pkg/repos/RustProxy-FreeBSD.conf ${freebsd}/RustProxy-FreeBSD.conf`,
@@ -251,7 +251,12 @@
el('install-signature').classList.toggle('live', instructionsData.signature === 'GPG SIGNED');
setText('install-command', instructionsData.code);
setText('install-note', instructionsData.note);
- setText('agent-command', instructionsData.agent);
+ // Docker discovery agent is only built for Linux DEB/RPM.
+ const hasDockerAgent = (kind === 'deb' || kind === 'rpm') && !!instructionsData.agent;
+ el('agent-card').hidden = !hasDockerAgent;
+ el('install-extra-grid').classList.toggle('single-card', !hasDockerAgent);
+ setText('trust-index', hasDockerAgent ? '02' : '01');
+ setText('agent-command', hasDockerAgent ? instructionsData.agent : '');
el('install-reference').href = safeLink(instructionsData.reference);
}
@@ -269,7 +274,7 @@
const distribution = encodeURIComponent(data.apt_distribution || 'stable');
el('endpoints-grid').innerHTML = [
endpointsCard('Linux','GPG SIGNED',url.linux,[
- {name:'Klucz publiczny GPG',url:`${url.linux}/repo-key.gpg`},
+ {name:'GPG public key',url:`${url.linux}/repo-key.gpg`},
{name:'APT InRelease',url:`${url.linux}/apt/dists/${distribution}/InRelease`},
{name:'RPM repomd.xml',url:`${url.linux}/rpm/x86_64/repodata/repomd.xml`},
{name:'Build info',url:`${url.linux}/LINUX-BUILD-INFO.txt`},
@@ -290,13 +295,13 @@
el('metadata-table').innerHTML = ['linux','opnsense','freebsd'].map((channel) => {
const b = data.builds[channel] || {};
const rows = [
- ['WERSJA APLIKACJI',b.app_version || '—','latest-value'],
- ['WERSJA PACZKI',b.package_version || '—',''],
- ['DATA BUILDU',formatDate(b.built_at),''],
+ ['APPLICATION VERSION',b.app_version || '—','latest-value'],
+ ['PACKAGE VERSION',b.package_version || '—',''],
+ ['BUILD DATE',formatDate(b.built_at),''],
['SOURCE COMMIT',b.source_commit || '—',''],
- ['REWIZJA PAKOWANIA',b.packaging_revision || '—',''],
+ ['PACKAGING REVISION',b.packaging_revision || '—',''],
];
- return ``;
+ return ``;
}).join('');
}
@@ -325,7 +330,7 @@
el('error-banner').hidden = true;
} catch (err) {
el('error-banner').hidden = false;
- setText('last-sync','Błąd odczytu');
+ setText('last-sync','Load failed');
console.error('RustProxy repository:',err);
} finally {
state.refreshing = false;
@@ -349,8 +354,8 @@
input.remove();
if (!copied) throw new Error('Clipboard unsupported');
}
- toast('Skopiowano do schowka');
- } catch (_) { toast('Nie udało się skopiować — zaznacz polecenia ręcznie'); }
+ toast('Copied to clipboard');
+ } catch (_) { toast('Copy failed. Select and copy the command manually.'); }
}
function init() {
diff --git a/dashboard/web/index.html b/dashboard/web/index.html
index 6dad979..ed8ed23 100644
--- a/dashboard/web/index.html
+++ b/dashboard/web/index.html
@@ -1,5 +1,5 @@
-
+
@@ -19,13 +19,13 @@
INDEPENDENT BY DESIGN BUILD DISTRIBUTION
-