3 Commits

Author SHA1 Message Date
ARCG Admin (Claude)
487c801bab feat(ui): add Impressum/Datenschutz footer links
remote.arcg.at has the same Medieninhaber (ARCG) as the homepage, so link the
legal pages there: Impressum -> amateurradioclubgraz.at/imprint/, Datenschutz ->
amateurradioclubgraz.at/datenschutz/ (the homepage DSE now covers the remote
station processing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-23 11:19:52 +02:00
dxd
1acbb569dd Merge pull request 'feat(wavelog): link to the Wavelog instance next to the API key field' (#3) from feat/wavelog-instance-link into main
Reviewed-on: #3
2026-10-22 21:46:20 +02:00
ARCG Admin (Claude)
9862f751a2 feat(wavelog): link to the Wavelog instance next to the API key field
Show an "Open Wavelog" link beside the Wavelog API Key heading in the
OpenWebRX panel. The URL comes from the runtime WAVELOG_BASE_URL (exposed
via GET /v1/me and the OpenWebRX session response), so the private hostname
is never hardcoded in this public repo. The link is hidden when no base URL
is configured.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-22 21:21:27 +02:00
6 changed files with 60 additions and 3 deletions

View File

@@ -138,6 +138,7 @@ const els = {
wavelogKeyInput: document.getElementById("wavelogKeyInput"),
wavelogKeySaveBtn: document.getElementById("wavelogKeySaveBtn"),
wavelogKeyMessage: document.getElementById("wavelogKeyMessage"),
wavelogInstanceLink: document.getElementById("wavelogInstanceLink"),
openwebrxTxStatePill: document.getElementById("openwebrxTxStatePill"),
rotorCurrent: document.getElementById("rotorCurrent"),
rotorCompass: document.getElementById("rotorCompass"),
@@ -1505,6 +1506,7 @@ async function refreshCurrentUser() {
const result = await api("/v1/me", { authRequired: true });
state.user = result.user;
state.wavelogApiKey = typeof result.wavelogApiKey === "string" ? result.wavelogApiKey : "";
state.wavelogBaseUrl = typeof result.wavelogBaseUrl === "string" ? result.wavelogBaseUrl : "";
applyWavelogKeyToInput();
renderUserSettingsAuthMethods();
await ensureLanguageFromUserPreference();
@@ -1698,6 +1700,16 @@ function applyWavelogKeyToInput() {
if (els.wavelogKeyInput) {
els.wavelogKeyInput.value = String(state.wavelogApiKey || "");
}
if (els.wavelogInstanceLink) {
const url = String(state.wavelogBaseUrl || "").trim();
if (url) {
els.wavelogInstanceLink.href = url;
els.wavelogInstanceLink.hidden = false;
} else {
els.wavelogInstanceLink.removeAttribute("href");
els.wavelogInstanceLink.hidden = true;
}
}
}
async function saveWavelogKey() {
@@ -1723,6 +1735,9 @@ async function openOpenWebRxSession() {
const session = result && result.session ? result.session : null;
if (result && typeof result.wavelogApiKey === "string") {
state.wavelogApiKey = result.wavelogApiKey;
if (typeof result.wavelogBaseUrl === "string") {
state.wavelogBaseUrl = result.wavelogBaseUrl;
}
applyWavelogKeyToInput();
}
const sessionTicket = session && session.ticket ? String(session.ticket) : "";
@@ -1752,6 +1767,9 @@ async function openOpenWebRxExternal() {
const session = result && result.session ? result.session : null;
if (result && typeof result.wavelogApiKey === "string") {
state.wavelogApiKey = result.wavelogApiKey;
if (typeof result.wavelogBaseUrl === "string") {
state.wavelogBaseUrl = result.wavelogBaseUrl;
}
applyWavelogKeyToInput();
}
const sessionTicket = session && session.ticket ? String(session.ticket) : "";

View File

@@ -56,6 +56,7 @@
"Key speichern": "Key speichern",
"Frequenz und Mode der Station werden beim Bandwechsel an dein Wavelog-Logbuch gesendet.": "Frequenz und Mode der Station werden beim Bandwechsel an dein Wavelog-Logbuch gesendet.",
"Wavelog API Key gespeichert.": "Wavelog API Key gespeichert.",
"Wavelog öffnen": "Wavelog öffnen",
"Reservierungen": "Reservierungen",
"Naechsten Slot reservieren": "Naechsten Slot reservieren",
"SWR Uebersicht": "SWR Uebersicht",

View File

@@ -56,6 +56,7 @@
"Key speichern": "Save key",
"Frequenz und Mode der Station werden beim Bandwechsel an dein Wavelog-Logbuch gesendet.": "The station's frequency and mode are sent to your Wavelog logbook on band change.",
"Wavelog API Key gespeichert.": "Wavelog API key saved.",
"Wavelog öffnen": "Open Wavelog",
"Reservierungen": "Reservations",
"Naechsten Slot reservieren": "Reserve next slot",
"SWR Uebersicht": "SWR Overview",

View File

@@ -167,7 +167,10 @@
<p class="muted">Session Key (Ticket): <code id="openwebrxSessionTicket">-</code></p>
</div>
<div id="wavelogKeyBox" class="stack">
<label for="wavelogKeyInput">Wavelog API Key (Rig-Key)</label>
<div class="section-head">
<label for="wavelogKeyInput">Wavelog API Key (Rig-Key)</label>
<a id="wavelogInstanceLink" target="_blank" rel="noopener noreferrer" hidden>Wavelog öffnen</a>
</div>
<input id="wavelogKeyInput" type="text" autocomplete="off" spellcheck="false" placeholder="Wavelog API Key" />
<div class="actions">
<button id="wavelogKeySaveBtn" type="button" class="ghost-btn">Key speichern</button>
@@ -548,6 +551,12 @@
</nav>
</main>
<footer class="site-footer">
<a href="https://amateurradioclubgraz.at/imprint/" target="_blank" rel="noopener noreferrer">Impressum</a>
<span class="site-footer-sep" aria-hidden="true">·</span>
<a href="https://amateurradioclubgraz.at/datenschutz/" target="_blank" rel="noopener noreferrer">Datenschutz</a>
</footer>
<script src="/app.js" defer></script>
</body>
</html>

View File

@@ -885,3 +885,24 @@ html[data-theme="light"] .message.domain-notice {
display: grid;
}
}
/* Legal footer links (Impressum / Datenschutz -> homepage) */
.site-footer {
margin: 2rem auto 1.25rem;
padding: 1rem;
text-align: center;
font-size: 0.85rem;
opacity: 0.8;
}
.site-footer a {
color: inherit;
text-decoration: underline;
}
.site-footer a:hover,
.site-footer a:focus-visible {
opacity: 1;
}
.site-footer-sep {
margin: 0 0.5rem;
opacity: 0.6;
}

View File

@@ -360,7 +360,7 @@ async function routeRequest(req, res) {
if (method === "GET" && url.pathname === "/v1/me") {
const auth = requireAuth(req, res);
if (!auth) return;
return sendJson(res, 200, { user: sanitizeUser(auth.user), wavelogApiKey: auth.user.wavelogApiKey || "", capabilities: userCapabilities(auth.user) });
return sendJson(res, 200, { user: sanitizeUser(auth.user), wavelogApiKey: auth.user.wavelogApiKey || "", wavelogBaseUrl: wavelogBaseUrlPublic(), capabilities: userCapabilities(auth.user) });
}
if (method === "GET" && url.pathname === "/v1/auth/session/diag") {
@@ -3641,7 +3641,8 @@ async function handleOpenWebRxSessionIssue(res, user) {
return sendJson(res, 200, {
ok: true,
session: result,
wavelogApiKey: user.wavelogApiKey || ""
wavelogApiKey: user.wavelogApiKey || "",
wavelogBaseUrl: wavelogBaseUrlPublic()
});
}
@@ -3719,6 +3720,12 @@ async function handleOpenWebRxBandSelect(res, user, body) {
}
}
// Public Wavelog base URL (for the UI link). Comes from runtime env only, so the
// private hostname is never baked into this (public) repo.
function wavelogBaseUrlPublic() {
return String(process.env.WAVELOG_BASE_URL || "").trim().replace(/\/+$/, "");
}
// Push a frequency/mode to the active operator's Wavelog logbook (CAT API).
// Best-effort: never throws into the caller's flow.
async function sendWavelogCat(user, frequencyHz, mode) {