diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f6906e..10ed5d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@ Version numbers follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html
## [Unreleased]
+### Changed
+
+- **Share modal no longer leaves a stale link in the create box** — after clicking "Create", the generated-link preview row ("Copy link:") stayed visible at the top of the modal even though the new link was already listed under Active links with its own Copy button — so it looked like the form hadn't cleared. The redundant preview row is removed; creating a link now resets the form and briefly highlights the new entry in the Active links list, where it can be copied. (The 1.7.4 fix cleared the input fields but not this preview row.)
+
### Added
- **Reverse-proxy / HTTPS setup guide** — new `docs/setup/ZORAXY_SETUP.md` walks through putting the scanner behind Zoraxy with a Let's Encrypt certificate on a LAN-only deployment: DNS A-record to a private IP, ACME via DNS-01 challenge (HTTP-01 cannot reach a LAN-only host), proxy rule to `127.0.0.1:5100`, binding the app to loopback with `--host 127.0.0.1`, and scanner-specific verification (SSE streaming, HTTPS share links, self-update). Linked from the README (new "HTTPS / reverse proxy" section) and SECURITY.md.
diff --git a/static/js/viewer.js b/static/js/viewer.js
index 3e5871c..26bffe8 100644
--- a/static/js/viewer.js
+++ b/static/js/viewer.js
@@ -154,7 +154,6 @@ function _resetShareForm() {
function openShareModal() {
document.getElementById('shareBackdrop').classList.add('open');
- document.getElementById('shareNewLinkRow').style.display = 'none';
_resetShareForm();
_renderTokenList();
fetch('/api/viewer/pin').then(function(r){ return r.json(); }).then(function(d) {
@@ -167,7 +166,7 @@ function closeShareModal() {
document.getElementById('shareBackdrop').classList.remove('open');
}
-async function _renderTokenList() {
+async function _renderTokenList(highlightToken) {
const list = document.getElementById('shareTokenList');
list.innerHTML = '
' + t('lbl_loading', 'Loading…') + '
';
try {
@@ -222,6 +221,17 @@ async function _renderTokenList() {
'';
list.appendChild(row);
+ // Briefly highlight a freshly created link so it is easy to find and copy.
+ if (highlightToken && tok.token === highlightToken) {
+ row.style.transition = 'border-color .3s, background .3s';
+ row.style.borderColor = 'var(--accent)';
+ row.style.background = 'rgba(80,160,80,.18)';
+ setTimeout(function() { row.scrollIntoView({block: 'nearest'}); }, 0);
+ setTimeout(function() {
+ row.style.borderColor = 'var(--border)';
+ row.style.background = 'var(--bg)';
+ }, 2500);
+ }
});
} catch(e) {
list.innerHTML = '
' + t('share_load_error', 'Failed to load links.') + '
';
@@ -264,23 +274,16 @@ async function createShareLink() {
});
if (!r.ok) throw new Error('Server error ' + r.status);
const entry = await r.json();
- const url = (await _getShareBaseUrl()) + '/view?token=' + encodeURIComponent(entry.token);
- const urlInput = document.getElementById('shareNewLinkUrl');
- urlInput.value = url;
- document.getElementById('shareNewLinkRow').style.display = 'block';
- document.getElementById('shareCopyBtn').textContent = t('log_copy', 'Copy');
+ // The new link appears in the active-links list below (each row has its
+ // own Copy button) — reset the form and highlight the just-created row
+ // rather than leaving a stale link preview in the create box.
_resetShareForm();
- _renderTokenList();
+ _renderTokenList(entry.token);
} catch(e) {
alert(t('share_create_error', 'Failed to create link:') + ' ' + e.message);
}
}
-function copyShareLink() {
- const url = document.getElementById('shareNewLinkUrl').value;
- _copyText(url, document.getElementById('shareCopyBtn'));
-}
-
async function copyTokenLink(token, btn) {
const url = (await _getShareBaseUrl()) + '/view?token=' + encodeURIComponent(token);
_copyText(url, btn);
@@ -328,12 +331,6 @@ async function revokeToken(token, rowEl) {
if (!list.children.length) {
list.innerHTML = '
' + t('share_no_links', 'No active links.') + '
';
}
- // Hide the copy row if the just-revoked token was the last created
- const newRow = document.getElementById('shareNewLinkRow');
- if (newRow) {
- const shownUrl = document.getElementById('shareNewLinkUrl')?.value || '';
- if (shownUrl.includes(token)) newRow.style.display = 'none';
- }
} catch(e) {
alert(t('share_revoke_error', 'Failed to revoke:') + ' ' + e.message);
}
@@ -502,7 +499,6 @@ window._shareScopeTypeChanged = _shareScopeTypeChanged;
window.openShareModal = openShareModal;
window.closeShareModal = closeShareModal;
window.createShareLink = createShareLink;
-window.copyShareLink = copyShareLink;
window._copyText = _copyText;
window.copyTokenLink = copyTokenLink;
window.revokeToken = revokeToken;
diff --git a/templates/index.html b/templates/index.html
index dc2cf81..329888a 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1094,13 +1094,6 @@ document.addEventListener('DOMContentLoaded', applyI18n);
-