disappearing interface after link safe

This commit is contained in:
2026-08-26 16:30:25 +02:00
parent 01a4ed42bd
commit 94997752b6
11 changed files with 74 additions and 7 deletions
+12
View File
@@ -861,6 +861,18 @@ When the plugin is activated and the link already exists, show “This link alre
### Assistant outcome ### Assistant outcome
Added an authenticated duplicate-check request when the popup opens after loading the active page. Existing links now show the requested warning before submission; comment and tag editing plus plugin retriggering remain available. Added an authenticated duplicate-check request when the popup opens after loading the active page. Existing links now show the requested warning before submission; comment and tag editing plus plugin retriggering remain available.
### User
Display any errors that occur during posting.
### Assistant outcome
Save responses now include sanitized plugin failure details, and the popup displays publishing errors alongside the save confirmation, including Mastodon HTTP or connection failures.
### User
When pressing Save link, display “Link saved to <LinkLog server URL>” and hide all other information. Refresh only when the plugin is opened again.
### Assistant outcome
Added a terminal save state to the popup. After a successful save it displays the localized LinkLog server URL, hides the form, session, warnings, and header information, and performs no refresh until the popup is opened again.
### User ### User
The plugin settings still show `emailLabel`; make that `email` as the title for the email field. The plugin settings still show `emailLabel`; make that `email` as the title for the email field.
+2
View File
@@ -149,7 +149,9 @@
140. Change the title of the field "One-time password" to "One-time password (when configured)". 140. Change the title of the field "One-time password" to "One-time password (when configured)".
157. The plugin settings still show 'emailLabel'; make that 'email' as title for the email field. 157. The plugin settings still show 'emailLabel'; make that 'email' as title for the email field.
163. When a URL with the same title is already in the database, warn the user, allow comment and hashtag changes, and retrigger plugins such as Mastodon reposting. 163. When a URL with the same title is already in the database, warn the user, allow comment and hashtag changes, and retrigger plugins such as Mastodon reposting.
166. Display any errors that occur during posting.
164. When the plugin is activated and the link already exists, show "This link already exists. Comment and tags can be updated, and by submitting publishing will be retriggered." 164. When the plugin is activated and the link already exists, show "This link already exists. Comment and tags can be updated, and by submitting publishing will be retriggered."
165. When pressing save link the plugin should display "Link saved to <url of linklog server>" and hide all other information. It should only refresh when the plugin is opened again
141. Remove any leading and trailing spaces when entering fields in the settings page of the plugin. 141. Remove any leading and trailing spaces when entering fields in the settings page of the plugin.
142. Do a full security audit document in what you have done in detail in Security-audit.md 142. Do a full security audit document in what you have done in detail in Security-audit.md
143. Address issue 1. and improve password storage 143. Address issue 1. and improve password storage
Binary file not shown.
+6 -1
View File
@@ -76,7 +76,12 @@ def create_link_endpoint(payload: LinkCreate, response: Response, authorization:
mark_mastodon_posted(record['id'], info['user_id'], mastodon_result.get('post_id')) mark_mastodon_posted(record['id'], info['user_id'], mastodon_result.get('post_id'))
if any(result.get('status') == 'failed' for result in plugin_results): if any(result.get('status') == 'failed' for result in plugin_results):
logger.warning('One or more plugins failed for link_id=%s results=%s', record['id'], plugin_results) logger.warning('One or more plugins failed for link_id=%s results=%s', record['id'], plugin_results)
return {**record, 'duplicate': duplicate} plugin_errors = [
{'plugin': result.get('plugin', 'unknown'), 'reason': result.get('reason', 'Plugin failed')}
for result in plugin_results
if result.get('status') == 'failed'
]
return {**record, 'duplicate': duplicate, 'plugin_errors': plugin_errors}
@router.put('/links/{link_id}') @router.put('/links/{link_id}')
+12
View File
@@ -454,6 +454,18 @@ def test_duplicate_link_check_is_authenticated_and_detects_existing_entry():
assert check.json()['exists'] is True assert check.json()['exists'] is True
def test_link_save_reports_plugin_posting_errors():
with patch('backend.app.api.links.plugin_manager.dispatch', return_value=[
{'status': 'failed', 'plugin': 'mastodon', 'reason': 'HTTP 503: unavailable'},
]):
response = client.post('/api/links', headers=login_headers(), json={
'title': 'Plugin error report',
'url': 'https://example.com/plugin-error-report',
})
assert response.status_code == 201
assert response.json()['plugin_errors'] == [{'plugin': 'mastodon', 'reason': 'HTTP 503: unavailable'}]
def test_links_support_tags_and_tag_filtering(): def test_links_support_tags_and_tag_filtering():
headers = login_headers() headers = login_headers()
response = client.post('/api/links', headers=headers, json={ response = client.post('/api/links', headers=headers, json={
+2 -1
View File
@@ -40,9 +40,10 @@
"configureAndLogIn": {"message": "Konfiguriere die Backend-URL und melde dich zuerst an."}, "configureAndLogIn": {"message": "Konfiguriere die Backend-URL und melde dich zuerst an."},
"sessionExpired": {"message": "Sitzung abgelaufen. Authentifiziere dich in den Einstellungen erneut."}, "sessionExpired": {"message": "Sitzung abgelaufen. Authentifiziere dich in den Einstellungen erneut."},
"submissionFailed": {"message": "Senden fehlgeschlagen"}, "submissionFailed": {"message": "Senden fehlgeschlagen"},
"linkSaved": {"message": "Link erfolgreich gespeichert"}, "linkSaved": {"message": "Link auf $URL$ gespeichert.", "placeholders": {"url": {"content": "$1"}}},
"linkAlreadyExists": {"message": "Dieser Link existiert bereits. Kommentar und Tags wurden aktualisiert und die Veröffentlichung erneut ausgelöst."}, "linkAlreadyExists": {"message": "Dieser Link existiert bereits. Kommentar und Tags wurden aktualisiert und die Veröffentlichung erneut ausgelöst."},
"duplicateLinkWarning": {"message": "Dieser Link existiert bereits. Kommentar und Tags können aktualisiert werden; beim Absenden wird die Veröffentlichung erneut ausgelöst."}, "duplicateLinkWarning": {"message": "Dieser Link existiert bereits. Kommentar und Tags können aktualisiert werden; beim Absenden wird die Veröffentlichung erneut ausgelöst."},
"publishingErrors": {"message": "Fehler bei der Veröffentlichung: $ERRORS$", "placeholders": {"errors": {"content": "$1"}}},
"submissionFailedConnection": {"message": "Senden fehlgeschlagen. Überprüfe die Verbindung zum Backend."}, "submissionFailedConnection": {"message": "Senden fehlgeschlagen. Überprüfe die Verbindung zum Backend."},
"loggedInAt": {"message": "$USERNAME$ ist bei $BACKEND$ angemeldet", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}}, "loggedInAt": {"message": "$USERNAME$ ist bei $BACKEND$ angemeldet", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}},
"fillAllFields": {"message": "Fülle alle Felder aus"}, "fillAllFields": {"message": "Fülle alle Felder aus"},
+14 -1
View File
@@ -123,7 +123,12 @@
"message": "Submission failed" "message": "Submission failed"
}, },
"linkSaved": { "linkSaved": {
"message": "Link saved successfully" "message": "Link saved to $URL$.",
"placeholders": {
"url": {
"content": "$1"
}
}
}, },
"linkAlreadyExists": { "linkAlreadyExists": {
"message": "This link already exists. Comment and tags were updated, and publishing was retriggered." "message": "This link already exists. Comment and tags were updated, and publishing was retriggered."
@@ -131,6 +136,14 @@
"duplicateLinkWarning": { "duplicateLinkWarning": {
"message": "This link already exists. Comment and tags can be updated, and by submitting publishing will be retriggered." "message": "This link already exists. Comment and tags can be updated, and by submitting publishing will be retriggered."
}, },
"publishingErrors": {
"message": "Publishing errors: $ERRORS$",
"placeholders": {
"errors": {
"content": "$1"
}
}
},
"submissionFailedConnection": { "submissionFailedConnection": {
"message": "Submission failed. Check your backend connection." "message": "Submission failed. Check your backend connection."
}, },
+2 -1
View File
@@ -40,9 +40,10 @@
"configureAndLogIn": {"message": "Configura la URL del servidor e inicia sesión primero."}, "configureAndLogIn": {"message": "Configura la URL del servidor e inicia sesión primero."},
"sessionExpired": {"message": "La sesión ha caducado. Vuelve a autenticarte en la configuración."}, "sessionExpired": {"message": "La sesión ha caducado. Vuelve a autenticarte en la configuración."},
"submissionFailed": {"message": "Error al enviar"}, "submissionFailed": {"message": "Error al enviar"},
"linkSaved": {"message": "Enlace guardado correctamente"}, "linkSaved": {"message": "Enlace guardado en $URL$.", "placeholders": {"url": {"content": "$1"}}},
"linkAlreadyExists": {"message": "Este enlace ya existe. Se actualizaron el comentario y las etiquetas, y se volvió a activar la publicación."}, "linkAlreadyExists": {"message": "Este enlace ya existe. Se actualizaron el comentario y las etiquetas, y se volvió a activar la publicación."},
"duplicateLinkWarning": {"message": "Este enlace ya existe. Puedes actualizar el comentario y las etiquetas; al enviarlo se volverá a activar la publicación."}, "duplicateLinkWarning": {"message": "Este enlace ya existe. Puedes actualizar el comentario y las etiquetas; al enviarlo se volverá a activar la publicación."},
"publishingErrors": {"message": "Errores de publicación: $ERRORS$", "placeholders": {"errors": {"content": "$1"}}},
"submissionFailedConnection": {"message": "Error al enviar. Comprueba la conexión con el servidor."}, "submissionFailedConnection": {"message": "Error al enviar. Comprueba la conexión con el servidor."},
"loggedInAt": {"message": "$USERNAME$ ha iniciado sesión en $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}}, "loggedInAt": {"message": "$USERNAME$ ha iniciado sesión en $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}},
"fillAllFields": {"message": "Rellena todos los campos"}, "fillAllFields": {"message": "Rellena todos los campos"},
+2 -1
View File
@@ -40,9 +40,10 @@
"configureAndLogIn": {"message": "Configurez lURL du serveur et connectez-vous dabord."}, "configureAndLogIn": {"message": "Configurez lURL du serveur et connectez-vous dabord."},
"sessionExpired": {"message": "Session expirée. Reconnectez-vous dans les paramètres."}, "sessionExpired": {"message": "Session expirée. Reconnectez-vous dans les paramètres."},
"submissionFailed": {"message": "Échec de lenvoi"}, "submissionFailed": {"message": "Échec de lenvoi"},
"linkSaved": {"message": "Lien enregistré"}, "linkSaved": {"message": "Lien enregistré sur $URL$.", "placeholders": {"url": {"content": "$1"}}},
"linkAlreadyExists": {"message": "Ce lien existe déjà. Le commentaire et les étiquettes ont été mis à jour et la publication a été relancée."}, "linkAlreadyExists": {"message": "Ce lien existe déjà. Le commentaire et les étiquettes ont été mis à jour et la publication a été relancée."},
"duplicateLinkWarning": {"message": "Ce lien existe déjà. Le commentaire et les étiquettes peuvent être mis à jour ; lenvoi relancera la publication."}, "duplicateLinkWarning": {"message": "Ce lien existe déjà. Le commentaire et les étiquettes peuvent être mis à jour ; lenvoi relancera la publication."},
"publishingErrors": {"message": "Erreurs de publication : $ERRORS$", "placeholders": {"errors": {"content": "$1"}}},
"submissionFailedConnection": {"message": "Échec de lenvoi. Vérifiez la connexion au serveur."}, "submissionFailedConnection": {"message": "Échec de lenvoi. Vérifiez la connexion au serveur."},
"loggedInAt": {"message": "$USERNAME$ est connecté à $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}}, "loggedInAt": {"message": "$USERNAME$ est connecté à $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}},
"fillAllFields": {"message": "Veuillez remplir tous les champs"}, "fillAllFields": {"message": "Veuillez remplir tous les champs"},
+2 -1
View File
@@ -40,9 +40,10 @@
"configureAndLogIn": {"message": "Configureer de backend-URL en log eerst in."}, "configureAndLogIn": {"message": "Configureer de backend-URL en log eerst in."},
"sessionExpired": {"message": "Sessie verlopen. Verifieer opnieuw in de instellingen."}, "sessionExpired": {"message": "Sessie verlopen. Verifieer opnieuw in de instellingen."},
"submissionFailed": {"message": "Verzenden mislukt"}, "submissionFailed": {"message": "Verzenden mislukt"},
"linkSaved": {"message": "Koppeling opgeslagen"}, "linkSaved": {"message": "Koppeling opgeslagen op $URL$.", "placeholders": {"url": {"content": "$1"}}},
"linkAlreadyExists": {"message": "Deze koppeling bestaat al. De opmerking en tags zijn bijgewerkt en publiceren is opnieuw gestart."}, "linkAlreadyExists": {"message": "Deze koppeling bestaat al. De opmerking en tags zijn bijgewerkt en publiceren is opnieuw gestart."},
"duplicateLinkWarning": {"message": "Deze koppeling bestaat al. De opmerking en tags kunnen worden bijgewerkt; na verzenden wordt publiceren opnieuw gestart."}, "duplicateLinkWarning": {"message": "Deze koppeling bestaat al. De opmerking en tags kunnen worden bijgewerkt; na verzenden wordt publiceren opnieuw gestart."},
"publishingErrors": {"message": "Publicatiefouten: $ERRORS$", "placeholders": {"errors": {"content": "$1"}}},
"submissionFailedConnection": {"message": "Verzenden mislukt. Controleer de verbinding met de backend."}, "submissionFailedConnection": {"message": "Verzenden mislukt. Controleer de verbinding met de backend."},
"loggedInAt": {"message": "$USERNAME$ is ingelogd op $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}}, "loggedInAt": {"message": "$USERNAME$ is ingelogd op $BACKEND$", "placeholders": {"username": {"content": "$1"}, "backend": {"content": "$2"}}},
"fillAllFields": {"message": "Vul alle velden in"}, "fillAllFields": {"message": "Vul alle velden in"},
+20 -1
View File
@@ -65,6 +65,19 @@ function showSignedInState(user, backendUrl) {
form.classList.remove('hidden'); form.classList.remove('hidden');
} }
function showSavedState(message) {
document.querySelector('header').classList.add('hidden');
document.querySelector('.extension-footer').classList.add('hidden');
authSession.hidden = true;
authSession.classList.add('hidden');
authWarning.hidden = true;
authWarning.classList.add('hidden');
form.classList.add('hidden');
statusEl.textContent = message;
statusEl.classList.remove('hidden', 'error');
statusEl.classList.add('success');
}
async function updateFeedLink() { async function updateFeedLink() {
const settings = await browser.storage.local.get(['backendUrl', 'username', 'accessToken']); const settings = await browser.storage.local.get(['backendUrl', 'username', 'accessToken']);
if (!settings.backendUrl || !settings.username || !settings.accessToken) return; if (!settings.backendUrl || !settings.username || !settings.accessToken) return;
@@ -209,7 +222,13 @@ async function handleSubmit(event) {
} }
const result = await response.json(); const result = await response.json();
setStatus(result.duplicate ? t('linkAlreadyExists') : t('linkSaved'), Boolean(result.duplicate)); const saveMessage = result.duplicate ? t('linkAlreadyExists') : t('linkSaved', backendUrl);
if (result.plugin_errors?.length) {
const errors = result.plugin_errors.map((error) => `${error.plugin}: ${error.reason}`).join(' ');
showSavedState(`${saveMessage} ${t('publishingErrors', errors)}`);
return;
}
showSavedState(saveMessage);
} catch (error) { } catch (error) {
setStatus(t('submissionFailedConnection'), true); setStatus(t('submissionFailedConnection'), true);
} }