mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(account): show the deletion grace window and its undo
The deletion dialogs, the managed-profile delete dialog and the Data & Privacy page read the window from the privacy summary and say what happens: the account is locked at once, erased after the stated number of days, and an admin of the server can undo it until then; a wipe keeps a copy an admin can restore for the same time. Copies in the server's backups age out after their retention period, and the text says that too. With the window set to 0 they keep the immediate wording. The sign-in page names the erasure date when a sign-in, a passkey or the single sign-on callback is refused for an account pending deletion. The admin users list shows a pending account with its date and an "Undo deletion" action, and the backups list labels the copy taken before a wipe. Every new string is translated in all nine languages.
This commit is contained in:
1 parent
a69666fa16
commit
63574b98a6
21 files changed
+573
-141
No files matched your search
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Einladung ungültig",
|
||||
"description": "Dieser Einladungslink ist unvollständig oder falsch kopiert. Bitte die Person, die dich eingeladen hat, um einen neuen Link.",
|
||||
"toLogin": "Zur Anmeldung"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Dieses Konto wird am {date} gelöscht und ist bis dahin gesperrt. Ein Admin dieses Servers kann die Löschung vor diesem Datum rückgängig machen.",
|
||||
"deletionPendingNoDate": "Dieses Konto ist zur Löschung vorgemerkt und gesperrt. Ein Admin dieses Servers kann die Löschung rückgängig machen, bis sie abgeschlossen ist."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Löscht dein Konto inklusive Passkeys, Audit-Log und Sessions.",
|
||||
"deleteAccountCta": "Konto löschen",
|
||||
"deleteAccountConfirmTitle": "Konto endgültig löschen?",
|
||||
"deleteAccountConfirmDescription": "Dein Konto, alle Gesundheitsdaten, Passkeys, Sessions und Audit-Einträge werden unwiderruflich gelöscht. Du wirst danach automatisch abgemeldet.",
|
||||
"deleteAccountConfirmDescription": "Dein Konto, alle Gesundheitsdaten, Passkeys, Sessions und Audit-Einträge werden unwiderruflich gelöscht. Du wirst danach automatisch abgemeldet. Kopien in den Sicherungen dieses Servers verfallen nach ihrer Aufbewahrungsfrist.",
|
||||
"deleteAccountSuccess": "Konto wurde gelöscht. Du wirst abgemeldet.",
|
||||
"deleteAccountFailed": "Konto konnte nicht gelöscht werden",
|
||||
"deleteAccountFinal": "Endgültig löschen",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Coach-Unterhaltungen: {days} Tage",
|
||||
"audit": "Sicherheitsprotokoll: {days} Tage",
|
||||
"delivery": "Benachrichtigungsprotokoll: {days} Tage",
|
||||
"unavailable": "Aufbewahrungsdetails sind derzeit nicht verfügbar."
|
||||
"unavailable": "Aufbewahrungsdetails sind derzeit nicht verfügbar.",
|
||||
"accountDeletion": "Löschen deines Kontos, eines verwalteten Profils oder aller Daten: abgeschlossen nach {days} Tagen",
|
||||
"accountDeletionImmediate": "Löschen deines Kontos, eines verwalteten Profils oder aller Daten: sofort abgeschlossen"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Löschen oder zurücksetzen",
|
||||
"description": "Lösche dein Konto vollständig oder lösche deine Gesundheitsdaten und behalte das Konto.",
|
||||
"backupLag": "Die Löschung entfernt deine Daten sofort. Wenn dieser Server verschlüsselte externe Sicherungen anlegt, werden die Kopien deiner Daten gleich danach aus diesem Speicher gelöscht, oder in der nächsten Nacht, falls der Speicher nicht erreichbar ist.",
|
||||
"openAdvanced": "Löschen oder zurücksetzen"
|
||||
"openAdvanced": "Löschen oder zurücksetzen",
|
||||
"immediateNotice": "Die Löschung entfernt deine Daten sofort. Wenn dieser Server verschlüsselte externe Sicherungen anlegt, werden die Kopien deiner Daten gleich danach aus diesem Speicher gelöscht, oder in der nächsten Nacht, falls der Speicher nicht erreichbar ist. Kopien in den Sicherungen dieses Servers verfallen nach ihrer Aufbewahrungsfrist.",
|
||||
"graceNotice": "Wenn du dein Konto löschst, wird es sofort gesperrt und nach {days} Tagen endgültig gelöscht, zusammen mit jeder Kopie, die dieser Server davon aufbewahrt, auch verschlüsselten Kopien außerhalb des Servers. Bis dahin kann ein Admin dieses Servers die Löschung rückgängig machen. Beim Löschen aller Daten gilt dasselbe: Eine Kopie der Akte bleibt {days} Tage erhalten, sodass ein Admin sie wiederherstellen kann. Kopien in den Sicherungen dieses Servers verfallen nach ihrer Aufbewahrungsfrist."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Datenschutz-Einstellung",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Aus",
|
||||
"change": "Unter Module ändern"
|
||||
},
|
||||
"timezoneUseDevice": "Zeitzone dieses Geräts übernehmen ({zone})"
|
||||
"timezoneUseDevice": "Zeitzone dieses Geräts übernehmen ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Dieser Vorgang löscht alles in deiner Akte: Messwerte, Medikamente, Stimmungseinträge, Laborwerte, Zykluseinträge, Dokumente, KI-Gespräche und jede Integrationsverbindung, dazu alles daraus Abgeleitete und alles, was du früher gelöscht hast. Freigabe-Links, die du an eine Praxis gegeben hast, funktionieren sofort nicht mehr. Dein Konto bleibt bestehen, ebenso deine Anmeldedaten und Anzeigeeinstellungen wie Sprache, Zeitzone und Einheiten. Eine Kopie deiner Akte wird {days} Tage aufbewahrt, sodass ein Admin dieses Servers sie bis dahin wiederherstellen kann. Danach ist die Löschung endgültig.",
|
||||
"deleteAccountCardDetailGrace": "Dein Konto wird sofort gesperrt und nach {days} Tagen endgültig gelöscht. Bis dahin kann ein Admin dieses Servers die Löschung rückgängig machen.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Du wirst abgemeldet und dein Konto wird sofort gesperrt. Nach {days} Tagen wird es endgültig gelöscht, mit allen Gesundheitsdaten, Passkeys, Sessions und Audit-Einträgen. Bis dahin kann ein Admin dieses Servers die Löschung rückgängig machen. Kopien in den Sicherungen dieses Servers verfallen nach ihrer Aufbewahrungsfrist.",
|
||||
"deleteAccountScheduled": "Dein Konto ist gesperrt und wird am {date} endgültig gelöscht. Du wirst abgemeldet.",
|
||||
"dangerZoneSuccessGrace": "Deine Gesundheitsakte wurde gelöscht. Ein Admin dieses Servers kann sie bis zum {date} wiederherstellen."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administration",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Eigene Sitzungen können nicht beendet werden",
|
||||
"emptyTitle": "Keine Nutzer in dieser Ansicht",
|
||||
"emptyDescription": "Es gibt keine Nutzer, die zum aktuellen Filter passen.",
|
||||
"emptyResetFilter": "Alle Nutzer anzeigen"
|
||||
"emptyResetFilter": "Alle Nutzer anzeigen",
|
||||
"deletionPending": "Löschung am {date}",
|
||||
"deletionPendingNoDate": "Löschung vorgemerkt",
|
||||
"undoDeletion": "Löschung rückgängig machen",
|
||||
"undoDeletionTitle": "Löschung von {name} rückgängig machen?",
|
||||
"undoDeletionBody": "{name} hat die Löschung dieses Kontos verlangt; es wird gelöscht, wenn die Frist endet. Rückgängig machen behält das Konto und alles darin so, wie es war. Seine Sessions und Tokens bleiben widerrufen, die Anmeldung ist also neu nötig.",
|
||||
"undoDeletionBodyGuardian": "Eine betreuende Person hat das verwaltete Profil {name} gelöscht; es wird gelöscht, wenn die Frist endet. Rückgängig machen behält das Profil und alles darin so, wie es war, und die betreuenden Personen erreichen es wieder.",
|
||||
"undoDeletionDone": "Löschung von {name} rückgängig gemacht",
|
||||
"undoDeletionFailed": "Löschung konnte nicht rückgängig gemacht werden"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Einladungen",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Name eines Stimmungs-Tags oder einer Gruppe mit einem Schlüssel verschlüsselt, den dieser Server nicht hat (ohne Namen behalten)",
|
||||
"restoreSkippedVisitCiphertext": "Text zu Arztbesuch oder Praxis mit einem Schlüssel verschlüsselt, den dieser Server nicht hat (ohne ihn behalten)",
|
||||
"restoreSkippedVaccinationCiphertext": "Impf-Notiz mit einem Schlüssel verschlüsselt, den dieser Server nicht hat (Impfung ohne sie behalten)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Ort eines Umweltzeitraums oder -tags mit einem Schlüssel verschlüsselt, den dieser Server nicht hat (verschlüsselt behalten, diese Tage werden nicht neu abgerufen)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Ort eines Umweltzeitraums oder -tags mit einem Schlüssel verschlüsselt, den dieser Server nicht hat (verschlüsselt behalten, diese Tage werden nicht neu abgerufen)",
|
||||
"typePreWipe": "Vor dem Löschen aller Daten"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Gefahrenzone",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Wenn {name} die Akte selbst führen möchte.",
|
||||
"methodSso": "{name} meldet sich beim Einlösen des Links über Single Sign-on an.",
|
||||
"methodBoth": "{name} kann ein Passwort festlegen oder sich über Single Sign-on anmelden."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Alles, was für {name} erfasst wurde, verschwindet mit dem Profil: Messwerte, Medikamente, Dokumente und Notizen. Das Profil wird sofort gesperrt und nach {days} Tagen endgültig gelöscht. Bis dahin kann ein Admin dieses Servers die Löschung rückgängig machen."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "In der Akte von {name} gespeichert"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Invitation invalid",
|
||||
"description": "This invitation link is incomplete or was copied wrongly. Ask the person who invited you for a new link.",
|
||||
"toLogin": "Go to sign in"
|
||||
}
|
||||
},
|
||||
"deletionPending": "This account is scheduled for deletion on {date} and is locked until then. An admin of this server can undo the deletion before that date.",
|
||||
"deletionPendingNoDate": "This account is scheduled for deletion and is locked. An admin of this server can undo the deletion until it completes."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Deletes your account along with passkeys, audit log, and sessions.",
|
||||
"deleteAccountCta": "Delete account",
|
||||
"deleteAccountConfirmTitle": "Delete account permanently?",
|
||||
"deleteAccountConfirmDescription": "Your account, all health data, passkeys, sessions, and audit entries will be permanently deleted. You will be signed out immediately after.",
|
||||
"deleteAccountConfirmDescription": "Your account, all health data, passkeys, sessions, and audit entries will be permanently deleted. You will be signed out immediately after. Copies in this server's backups age out after their retention period.",
|
||||
"deleteAccountSuccess": "Account deleted. Signing you out.",
|
||||
"deleteAccountFailed": "Account could not be deleted",
|
||||
"deleteAccountFinal": "Delete permanently",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Coach conversations: kept {days} days",
|
||||
"audit": "Security activity log: kept {days} days",
|
||||
"delivery": "Notification delivery log: kept {days} days",
|
||||
"unavailable": "Retention details are unavailable right now."
|
||||
"unavailable": "Retention details are unavailable right now.",
|
||||
"accountDeletion": "Deleting your account, a managed profile or all data: completed after {days} days",
|
||||
"accountDeletionImmediate": "Deleting your account, a managed profile or all data: completed immediately"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Delete or reset",
|
||||
"description": "Remove your account entirely, or wipe your health records while keeping the account.",
|
||||
"backupLag": "Deletion removes your data immediately. If this server keeps encrypted off-host backups, the copies of your data are deleted from that storage right after, or on the next nightly run if the storage is unreachable.",
|
||||
"openAdvanced": "Delete or reset"
|
||||
"openAdvanced": "Delete or reset",
|
||||
"immediateNotice": "Deletion removes your data immediately. If this server keeps encrypted off-host backups, the copies of your data are deleted from that storage right after, or on the next nightly run if the storage is unreachable. Copies in this server's backups age out after their retention period.",
|
||||
"graceNotice": "When you delete your account, it is locked immediately and erased after {days} days, together with every copy this server keeps of it, including encrypted off-host copies. Until then, an admin of this server can undo the deletion. Deleting all data works the same way: a copy of the record is kept for {days} days, so an admin can restore it. Copies in this server's backups age out after their retention period."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Privacy posture",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Off",
|
||||
"change": "Change in Modules"
|
||||
},
|
||||
"timezoneUseDevice": "Use this device's timezone ({zone})"
|
||||
"timezoneUseDevice": "Use this device's timezone ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "This deletes everything in your record: measurements, medications, mood entries, lab results, cycle entries, documents, AI conversations and every integration connection, together with everything derived from them and anything you deleted earlier. Share links you gave to a doctor stop working immediately. Your account stays, along with the credentials you sign in with and display settings such as language, timezone and units. A copy of your record is kept for {days} days, so an admin of this server can restore it until then. After that the deletion is final.",
|
||||
"deleteAccountCardDetailGrace": "Your account is locked right away and erased after {days} days. Until then, an admin of this server can undo the deletion.",
|
||||
"deleteAccountConfirmDescriptionGrace": "You are signed out and your account is locked right away. After {days} days it is erased for good, with all health data, passkeys, sessions and audit entries. Until then, an admin of this server can undo the deletion. Copies in this server's backups age out after their retention period.",
|
||||
"deleteAccountScheduled": "Your account is locked and will be erased on {date}. Signing you out.",
|
||||
"dangerZoneSuccessGrace": "Your health record has been deleted. An admin of this server can restore it until {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administration",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Cannot force-logout yourself",
|
||||
"emptyTitle": "No users in this view",
|
||||
"emptyDescription": "There are no users matching the current filter.",
|
||||
"emptyResetFilter": "Show all users"
|
||||
"emptyResetFilter": "Show all users",
|
||||
"deletionPending": "Deletion on {date}",
|
||||
"deletionPendingNoDate": "Deletion pending",
|
||||
"undoDeletion": "Undo deletion",
|
||||
"undoDeletionTitle": "Undo the deletion of {name}?",
|
||||
"undoDeletionBody": "{name} asked to delete this account, and it is erased when the grace window ends. Undoing keeps the account and everything in it as it was. Its sessions and tokens stay revoked, so {name} signs in again.",
|
||||
"undoDeletionBodyGuardian": "A guardian deleted the managed profile {name}, and it is erased when the grace window ends. Undoing keeps the profile and everything in it as it was, and its guardians can reach it again.",
|
||||
"undoDeletionDone": "Deletion undone for {name}",
|
||||
"undoDeletionFailed": "Could not undo the deletion"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invites",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Mood tag or group name sealed with a key this server does not hold (kept without its name)",
|
||||
"restoreSkippedVisitCiphertext": "Visit or practitioner text sealed with a key this server does not hold (kept without it)",
|
||||
"restoreSkippedVaccinationCiphertext": "Vaccination note sealed with a key this server does not hold (dose kept without it)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Location of an environment period or day sealed with a key this server does not hold (kept sealed, those days are not refreshed)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Location of an environment period or day sealed with a key this server does not hold (kept sealed, those days are not refreshed)",
|
||||
"typePreWipe": "Before all data was deleted"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Danger zone",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "When {name} is ready to look after this record themselves.",
|
||||
"methodSso": "{name} signs in through single sign-on when they use the link.",
|
||||
"methodBoth": "{name} can set a password or sign in through single sign-on."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Everything recorded for {name} goes with the profile: readings, medications, documents and notes. The profile is locked right away and erased after {days} days. Until then, an admin of this server can undo the deletion."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Saved to {name}'s record"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Invitación no válida",
|
||||
"description": "Este enlace de invitación está incompleto o se copió mal. Pide un enlace nuevo a la persona que te invitó.",
|
||||
"toLogin": "Ir a iniciar sesión"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Esta cuenta se eliminará el {date} y está bloqueada hasta entonces. Un administrador de este servidor puede deshacer la eliminación antes de esa fecha.",
|
||||
"deletionPendingNoDate": "Esta cuenta está programada para eliminarse y está bloqueada. Un administrador de este servidor puede deshacer la eliminación hasta que se complete."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Panel",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Elimina tu cuenta junto con las claves de acceso, el registro de auditoría y las sesiones.",
|
||||
"deleteAccountCta": "Eliminar cuenta",
|
||||
"deleteAccountConfirmTitle": "¿Eliminar la cuenta de forma permanente?",
|
||||
"deleteAccountConfirmDescription": "Tu cuenta, todos los datos de salud, las claves de acceso, las sesiones y las entradas de auditoría se eliminarán de forma permanente. Se cerrará tu sesión inmediatamente después.",
|
||||
"deleteAccountConfirmDescription": "Tu cuenta, todos los datos de salud, las claves de acceso, las sesiones y las entradas de auditoría se eliminarán de forma permanente. Se cerrará tu sesión inmediatamente después. Las copias en las copias de seguridad de este servidor caducan al terminar su periodo de conservación.",
|
||||
"deleteAccountSuccess": "Cuenta eliminada. Cerrando tu sesión.",
|
||||
"deleteAccountFailed": "No se pudo eliminar la cuenta",
|
||||
"deleteAccountFinal": "Eliminar permanentemente",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Conversaciones con el asistente: {days} días",
|
||||
"audit": "Registro de seguridad: {days} días",
|
||||
"delivery": "Registro de envío de notificaciones: {days} días",
|
||||
"unavailable": "Los detalles de retención no están disponibles en este momento."
|
||||
"unavailable": "Los detalles de retención no están disponibles en este momento.",
|
||||
"accountDeletion": "Eliminar tu cuenta, un perfil gestionado o todos los datos: se completa al cabo de {days} días",
|
||||
"accountDeletionImmediate": "Eliminar tu cuenta, un perfil gestionado o todos los datos: se completa de inmediato"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Eliminar o restablecer",
|
||||
"description": "Elimina tu cuenta por completo o borra tus registros de salud conservando la cuenta.",
|
||||
"backupLag": "La eliminación borra tus datos de inmediato. Si este servidor guarda copias de seguridad cifradas externas, las copias de tus datos se borran de ese almacenamiento justo después, o en la siguiente ejecución nocturna si no está disponible.",
|
||||
"openAdvanced": "Eliminar o restablecer"
|
||||
"openAdvanced": "Eliminar o restablecer",
|
||||
"immediateNotice": "La eliminación borra tus datos de inmediato. Si este servidor guarda copias de seguridad cifradas externas, las copias de tus datos se borran de ese almacenamiento justo después, o en la siguiente ejecución nocturna si no está disponible. Las copias en las copias de seguridad de este servidor caducan al terminar su periodo de conservación.",
|
||||
"graceNotice": "Cuando eliminas tu cuenta, se bloquea de inmediato y se borra al cabo de {days} días, junto con todas las copias que este servidor guarda de ella, incluidas las copias cifradas fuera del servidor. Hasta entonces, un administrador de este servidor puede deshacer la eliminación. Eliminar todos los datos funciona igual: se guarda una copia del historial durante {days} días, para que un administrador pueda restaurarla. Las copias en las copias de seguridad de este servidor caducan al terminar su periodo de conservación."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Configuración de privacidad",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Desactivado",
|
||||
"change": "Cambiar en Módulos"
|
||||
},
|
||||
"timezoneUseDevice": "Usar la zona horaria de este dispositivo ({zone})"
|
||||
"timezoneUseDevice": "Usar la zona horaria de este dispositivo ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Esto elimina todo lo que hay en tu historial: mediciones, medicamentos, entradas de ánimo, resultados de laboratorio, entradas de ciclo, documentos, conversaciones con la IA y todas las conexiones de integración, junto con todo lo derivado de ello y todo lo que eliminaste antes. Los enlaces compartidos que diste a una consulta dejan de funcionar de inmediato. Tu cuenta se mantiene, junto con las credenciales con las que inicias sesión y los ajustes de presentación como el idioma, la zona horaria y las unidades. Se guarda una copia de tu historial durante {days} días, para que un administrador de este servidor pueda restaurarla hasta entonces. Después, la eliminación es definitiva.",
|
||||
"deleteAccountCardDetailGrace": "Tu cuenta se bloquea de inmediato y se borra al cabo de {days} días. Hasta entonces, un administrador de este servidor puede deshacer la eliminación.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Se cierra tu sesión y tu cuenta se bloquea de inmediato. Al cabo de {days} días se borra para siempre, con todos tus datos de salud, llaves de acceso, sesiones y entradas de auditoría. Hasta entonces, un administrador de este servidor puede deshacer la eliminación. Las copias en las copias de seguridad de este servidor caducan al terminar su periodo de conservación.",
|
||||
"deleteAccountScheduled": "Tu cuenta está bloqueada y se borrará el {date}. Cerrando tu sesión.",
|
||||
"dangerZoneSuccessGrace": "Tu historial de salud se ha eliminado. Un administrador de este servidor puede restaurarlo hasta el {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administration",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "No puedes forzar tu propio cierre de sesión",
|
||||
"emptyTitle": "No hay usuarios en esta vista",
|
||||
"emptyDescription": "No hay usuarios que coincidan con el filtro actual.",
|
||||
"emptyResetFilter": "Mostrar todos los usuarios"
|
||||
"emptyResetFilter": "Mostrar todos los usuarios",
|
||||
"deletionPending": "Eliminación el {date}",
|
||||
"deletionPendingNoDate": "Eliminación pendiente",
|
||||
"undoDeletion": "Deshacer eliminación",
|
||||
"undoDeletionTitle": "¿Deshacer la eliminación de {name}?",
|
||||
"undoDeletionBody": "{name} pidió eliminar esta cuenta, y se borra cuando termina el plazo de gracia. Deshacerlo conserva la cuenta y todo su contenido tal como estaba. Sus sesiones y tokens siguen revocados, así que habrá que volver a iniciar sesión.",
|
||||
"undoDeletionBodyGuardian": "Una persona responsable eliminó el perfil gestionado {name}, y se borra cuando termina el plazo de gracia. Deshacerlo conserva el perfil y todo su contenido tal como estaba, y las personas responsables vuelven a tener acceso.",
|
||||
"undoDeletionDone": "Eliminación de {name} deshecha",
|
||||
"undoDeletionFailed": "No se pudo deshacer la eliminación"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invitaciones",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Nombre de etiqueta o grupo de ánimo cifrado con una clave que este servidor no tiene (se conserva sin el nombre)",
|
||||
"restoreSkippedVisitCiphertext": "Texto de visita o profesional cifrado con una clave que este servidor no tiene (se conserva sin él)",
|
||||
"restoreSkippedVaccinationCiphertext": "Nota de vacunación cifrada con una clave que este servidor no tiene (la dosis se conserva sin ella)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Ubicación de un periodo o día ambiental cifrada con una clave que este servidor no tiene (se conserva cifrada, esos días no se actualizan)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Ubicación de un periodo o día ambiental cifrada con una clave que este servidor no tiene (se conserva cifrada, esos días no se actualizan)",
|
||||
"typePreWipe": "Antes de eliminar todos los datos"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Zona de peligro",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Cuando {name} quiera llevar este historial por su cuenta.",
|
||||
"methodSso": "{name} inicia sesión con el inicio de sesión único cuando usa el enlace.",
|
||||
"methodBoth": "{name} puede elegir una contraseña o iniciar sesión con el inicio de sesión único."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Todo lo registrado para {name} desaparece con el perfil: mediciones, medicamentos, documentos y notas. El perfil se bloquea de inmediato y se borra al cabo de {days} días. Hasta entonces, un administrador de este servidor puede deshacer la eliminación."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Guardado en el historial de {name}"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Invitation invalide",
|
||||
"description": "Ce lien d’invitation est incomplet ou a été mal copié. Demandez un nouveau lien à la personne qui vous a invité.",
|
||||
"toLogin": "Aller à la connexion"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Ce compte sera supprimé le {date} et reste verrouillé d’ici là. Un administrateur de ce serveur peut annuler la suppression avant cette date.",
|
||||
"deletionPendingNoDate": "Ce compte est programmé pour suppression et il est verrouillé. Un administrateur de ce serveur peut annuler la suppression tant qu’elle n’est pas terminée."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Tableau de bord",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Supprime votre compte ainsi que les clés d’accès, le journal d’audit et les sessions.",
|
||||
"deleteAccountCta": "Supprimer le compte",
|
||||
"deleteAccountConfirmTitle": "Supprimer définitivement le compte ?",
|
||||
"deleteAccountConfirmDescription": "Votre compte, toutes vos données de santé, vos clés d’accès, vos sessions et vos entrées d’audit seront définitivement supprimés. Vous serez déconnecté immédiatement après.",
|
||||
"deleteAccountConfirmDescription": "Votre compte, toutes vos données de santé, vos clés d’accès, vos sessions et vos entrées d’audit seront définitivement supprimés. Vous serez déconnecté immédiatement après. Les copies dans les sauvegardes de ce serveur expirent à la fin de leur durée de conservation.",
|
||||
"deleteAccountSuccess": "Compte supprimé, déconnexion en cours.",
|
||||
"deleteAccountFailed": "Le compte n’a pas pu être supprimé",
|
||||
"deleteAccountFinal": "Supprimer définitivement",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Conversations avec le coach : {days} jours",
|
||||
"audit": "Journal de sécurité : {days} jours",
|
||||
"delivery": "Journal d'envoi des notifications : {days} jours",
|
||||
"unavailable": "Les détails de conservation sont indisponibles pour le moment."
|
||||
"unavailable": "Les détails de conservation sont indisponibles pour le moment.",
|
||||
"accountDeletion": "Suppression de votre compte, d’un profil géré ou de toutes les données : effective au bout de {days} jours",
|
||||
"accountDeletionImmediate": "Suppression de votre compte, d’un profil géré ou de toutes les données : effective immédiatement"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Supprimer ou réinitialiser",
|
||||
"description": "Supprimez complètement votre compte, ou effacez vos données de santé tout en conservant le compte.",
|
||||
"backupLag": "La suppression efface vos données immédiatement. Si ce serveur conserve des sauvegardes externes chiffrées, les copies de vos données sont supprimées de ce stockage juste après, ou lors du prochain passage nocturne s'il est injoignable.",
|
||||
"openAdvanced": "Supprimer ou réinitialiser"
|
||||
"openAdvanced": "Supprimer ou réinitialiser",
|
||||
"immediateNotice": "La suppression efface vos données immédiatement. Si ce serveur conserve des sauvegardes externes chiffrées, les copies de vos données sont supprimées de ce stockage juste après, ou lors du prochain passage nocturne s'il est injoignable. Les copies dans les sauvegardes de ce serveur expirent à la fin de leur durée de conservation.",
|
||||
"graceNotice": "Lorsque vous supprimez votre compte, il est verrouillé immédiatement et effacé au bout de {days} jours, avec chaque copie que ce serveur en conserve, y compris les copies chiffrées hors du serveur. D’ici là, un administrateur de ce serveur peut annuler la suppression. La suppression de toutes les données fonctionne de la même façon : une copie du dossier est conservée pendant {days} jours, afin qu’un administrateur puisse la restaurer. Les copies dans les sauvegardes de ce serveur expirent à la fin de leur durée de conservation."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Posture de confidentialité",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Désactivé",
|
||||
"change": "Modifier dans Modules"
|
||||
},
|
||||
"timezoneUseDevice": "Utiliser le fuseau horaire de cet appareil ({zone})"
|
||||
"timezoneUseDevice": "Utiliser le fuseau horaire de cet appareil ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Cette action supprime tout ce que contient votre dossier : mesures, médicaments, entrées d’humeur, résultats de laboratoire, entrées de cycle, documents, conversations avec l’IA et toutes les connexions d’intégration, ainsi que tout ce qui en découle et tout ce que vous aviez supprimé auparavant. Les liens de partage remis à un cabinet cessent aussitôt de fonctionner. Votre compte reste en place, de même que vos identifiants de connexion et vos réglages d’affichage comme la langue, le fuseau horaire et les unités. Une copie de votre dossier est conservée pendant {days} jours, afin qu’un administrateur de ce serveur puisse la restaurer d’ici là. Ensuite, la suppression est définitive.",
|
||||
"deleteAccountCardDetailGrace": "Votre compte est verrouillé immédiatement et effacé au bout de {days} jours. D’ici là, un administrateur de ce serveur peut annuler la suppression.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Vous êtes déconnecté et votre compte est verrouillé immédiatement. Au bout de {days} jours, il est effacé définitivement, avec toutes vos données de santé, vos clés d’accès, vos sessions et vos entrées d’audit. D’ici là, un administrateur de ce serveur peut annuler la suppression. Les copies dans les sauvegardes de ce serveur expirent à la fin de leur durée de conservation.",
|
||||
"deleteAccountScheduled": "Votre compte est verrouillé et sera effacé le {date}. Déconnexion en cours.",
|
||||
"dangerZoneSuccessGrace": "Votre dossier de santé a été supprimé. Un administrateur de ce serveur peut le restaurer jusqu’au {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administration",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Impossible de forcer votre propre déconnexion",
|
||||
"emptyTitle": "Aucun utilisateur dans cette vue",
|
||||
"emptyDescription": "Aucun utilisateur ne correspond au filtre actuel.",
|
||||
"emptyResetFilter": "Afficher tous les utilisateurs"
|
||||
"emptyResetFilter": "Afficher tous les utilisateurs",
|
||||
"deletionPending": "Suppression le {date}",
|
||||
"deletionPendingNoDate": "Suppression programmée",
|
||||
"undoDeletion": "Annuler la suppression",
|
||||
"undoDeletionTitle": "Annuler la suppression de {name} ?",
|
||||
"undoDeletionBody": "{name} a demandé la suppression de ce compte, qui sera effacé à la fin du délai de grâce. Annuler conserve le compte et tout son contenu tels quels. Ses sessions et jetons restent révoqués : il faudra se reconnecter.",
|
||||
"undoDeletionBodyGuardian": "Une personne responsable a supprimé le profil géré {name}, qui sera effacé à la fin du délai de grâce. Annuler conserve le profil et tout son contenu tels quels, et les personnes responsables y ont de nouveau accès.",
|
||||
"undoDeletionDone": "Suppression de {name} annulée",
|
||||
"undoDeletionFailed": "Impossible d’annuler la suppression"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invitations",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Nom d’étiquette ou de groupe d’humeur chiffré avec une clé que ce serveur ne possède pas (conservé sans son nom)",
|
||||
"restoreSkippedVisitCiphertext": "Texte de consultation ou de praticien chiffré avec une clé que ce serveur ne possède pas (conservé sans)",
|
||||
"restoreSkippedVaccinationCiphertext": "Note de vaccination chiffrée avec une clé que ce serveur ne possède pas (dose conservée sans)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Lieu d'une période ou d'un jour environnemental chiffré avec une clé que ce serveur ne possède pas (conservé chiffré, ces jours ne sont pas actualisés)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Lieu d'une période ou d'un jour environnemental chiffré avec une clé que ce serveur ne possède pas (conservé chiffré, ces jours ne sont pas actualisés)",
|
||||
"typePreWipe": "Avant la suppression de toutes les données"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Zone de danger",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Quand {name} souhaite tenir ce dossier de façon autonome.",
|
||||
"methodSso": "{name} se connecte par authentification unique en utilisant le lien.",
|
||||
"methodBoth": "{name} peut définir un mot de passe ou se connecter par authentification unique."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Tout ce qui a été enregistré pour {name} disparaît avec le profil : mesures, médicaments, documents et notes. Le profil est verrouillé immédiatement et effacé au bout de {days} jours. D’ici là, un administrateur de ce serveur peut annuler la suppression."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Enregistré dans le dossier de {name}"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Invito non valido",
|
||||
"description": "Questo link di invito è incompleto o è stato copiato male. Chiedi un nuovo link alla persona che ti ha invitato.",
|
||||
"toLogin": "Vai all’accesso"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Questo account verrà eliminato il {date} ed è bloccato fino ad allora. Un amministratore di questo server può annullare l’eliminazione prima di quella data.",
|
||||
"deletionPendingNoDate": "Questo account è in attesa di eliminazione ed è bloccato. Un amministratore di questo server può annullare l’eliminazione finché non è completata."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Cruscotto",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Elimina il tuo account insieme a passkey, registro di controllo e sessioni.",
|
||||
"deleteAccountCta": "Elimina account",
|
||||
"deleteAccountConfirmTitle": "Eliminare definitivamente l’account?",
|
||||
"deleteAccountConfirmDescription": "Il tuo account, tutti i dati sanitari, le passkey, le sessioni e le voci di audit verranno eliminati definitivamente. Verrai disconnesso subito dopo.",
|
||||
"deleteAccountConfirmDescription": "Il tuo account, tutti i dati sanitari, le passkey, le sessioni e le voci di audit verranno eliminati definitivamente. Verrai disconnesso subito dopo. Le copie nei backup di questo server scadono al termine del loro periodo di conservazione.",
|
||||
"deleteAccountSuccess": "Account eliminato, disconnessione in corso.",
|
||||
"deleteAccountFailed": "Impossibile eliminare l’account",
|
||||
"deleteAccountFinal": "Elimina definitivamente",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Conversazioni con il coach: {days} giorni",
|
||||
"audit": "Registro di sicurezza: {days} giorni",
|
||||
"delivery": "Registro di invio delle notifiche: {days} giorni",
|
||||
"unavailable": "I dettagli di conservazione non sono disponibili al momento."
|
||||
"unavailable": "I dettagli di conservazione non sono disponibili al momento.",
|
||||
"accountDeletion": "Eliminazione del tuo account, di un profilo gestito o di tutti i dati: completata dopo {days} giorni",
|
||||
"accountDeletionImmediate": "Eliminazione del tuo account, di un profilo gestito o di tutti i dati: completata subito"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Elimina o reimposta",
|
||||
"description": "Elimina completamente il tuo account oppure cancella i tuoi dati sanitari mantenendo l'account.",
|
||||
"backupLag": "L'eliminazione rimuove subito i tuoi dati. Se questo server conserva backup esterni cifrati, le copie dei tuoi dati vengono eliminate da quello spazio subito dopo, o alla successiva esecuzione notturna se non è raggiungibile.",
|
||||
"openAdvanced": "Elimina o reimposta"
|
||||
"openAdvanced": "Elimina o reimposta",
|
||||
"immediateNotice": "L'eliminazione rimuove subito i tuoi dati. Se questo server conserva backup esterni cifrati, le copie dei tuoi dati vengono eliminate da quello spazio subito dopo, o alla successiva esecuzione notturna se non è raggiungibile. Le copie nei backup di questo server scadono al termine del loro periodo di conservazione.",
|
||||
"graceNotice": "Quando elimini il tuo account, viene bloccato subito e cancellato dopo {days} giorni, insieme a ogni copia che questo server ne conserva, incluse le copie cifrate fuori dal server. Fino ad allora un amministratore di questo server può annullare l’eliminazione. Eliminare tutti i dati funziona allo stesso modo: una copia della cartella viene conservata per {days} giorni, così un amministratore può ripristinarla. Le copie nei backup di questo server scadono al termine del loro periodo di conservazione."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Impostazione privacy",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Disattivo",
|
||||
"change": "Cambia in Moduli"
|
||||
},
|
||||
"timezoneUseDevice": "Usa il fuso orario di questo dispositivo ({zone})"
|
||||
"timezoneUseDevice": "Usa il fuso orario di questo dispositivo ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Questa azione elimina tutto ciò che contiene la tua cartella: misurazioni, farmaci, voci dell’umore, risultati di laboratorio, voci del ciclo, documenti, conversazioni con l’IA e ogni connessione di integrazione, insieme a tutto ciò che ne deriva e a tutto quello che avevi eliminato prima. I link di condivisione consegnati a uno studio medico smettono subito di funzionare. Il tuo account resta, insieme alle credenziali con cui accedi e alle impostazioni di visualizzazione come lingua, fuso orario e unità. Una copia della tua cartella viene conservata per {days} giorni, così un amministratore di questo server può ripristinarla fino ad allora. Dopo, l’eliminazione è definitiva.",
|
||||
"deleteAccountCardDetailGrace": "Il tuo account viene bloccato subito e cancellato dopo {days} giorni. Fino ad allora un amministratore di questo server può annullare l’eliminazione.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Vieni disconnesso e il tuo account viene bloccato subito. Dopo {days} giorni viene cancellato definitivamente, con tutti i dati sanitari, le passkey, le sessioni e le voci di audit. Fino ad allora un amministratore di questo server può annullare l’eliminazione. Le copie nei backup di questo server scadono al termine del loro periodo di conservazione.",
|
||||
"deleteAccountScheduled": "Il tuo account è bloccato e verrà cancellato il {date}. Disconnessione in corso.",
|
||||
"dangerZoneSuccessGrace": "La tua cartella sanitaria è stata eliminata. Un amministratore di questo server può ripristinarla fino al {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administration",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Non puoi forzare la tua disconnessione",
|
||||
"emptyTitle": "Nessun utente in questa vista",
|
||||
"emptyDescription": "Nessun utente corrisponde al filtro attuale.",
|
||||
"emptyResetFilter": "Mostra tutti gli utenti"
|
||||
"emptyResetFilter": "Mostra tutti gli utenti",
|
||||
"deletionPending": "Eliminazione il {date}",
|
||||
"deletionPendingNoDate": "Eliminazione in attesa",
|
||||
"undoDeletion": "Annulla eliminazione",
|
||||
"undoDeletionTitle": "Annullare l’eliminazione di {name}?",
|
||||
"undoDeletionBody": "{name} ha chiesto di eliminare questo account, che viene cancellato alla fine del periodo di tolleranza. Annullare mantiene l’account e tutto il suo contenuto com’era. Sessioni e token restano revocati, quindi servirà un nuovo accesso.",
|
||||
"undoDeletionBodyGuardian": "Una persona responsabile ha eliminato il profilo gestito {name}, che viene cancellato alla fine del periodo di tolleranza. Annullare mantiene il profilo e tutto il suo contenuto com’era, e le persone responsabili possono di nuovo accedervi.",
|
||||
"undoDeletionDone": "Eliminazione di {name} annullata",
|
||||
"undoDeletionFailed": "Impossibile annullare l’eliminazione"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Inviti",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Nome di tag o gruppo dell’umore cifrato con una chiave che questo server non possiede (mantenuto senza nome)",
|
||||
"restoreSkippedVisitCiphertext": "Testo di visita o professionista cifrato con una chiave che questo server non possiede (mantenuto senza)",
|
||||
"restoreSkippedVaccinationCiphertext": "Nota di vaccinazione cifrata con una chiave che questo server non possiede (dose mantenuta senza)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Luogo di un periodo o giorno ambientale cifrato con una chiave che questo server non possiede (mantenuto cifrato, quei giorni non vengono aggiornati)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Luogo di un periodo o giorno ambientale cifrato con una chiave che questo server non possiede (mantenuto cifrato, quei giorni non vengono aggiornati)",
|
||||
"typePreWipe": "Prima dell’eliminazione di tutti i dati"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Zona pericolosa",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Quando {name} vuole tenere questa cartella in autonomia.",
|
||||
"methodSso": "{name} accede con il single sign-on quando usa il link.",
|
||||
"methodBoth": "{name} può impostare una password oppure accedere con il single sign-on."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Tutto ciò che è stato registrato per {name} sparisce insieme al profilo: misurazioni, farmaci, documenti e note. Il profilo viene bloccato subito e cancellato dopo {days} giorni. Fino ad allora un amministratore di questo server può annullare l’eliminazione."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Salvato nella cartella di {name}"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "유효하지 않은 초대예요",
|
||||
"description": "이 초대 링크가 불완전하거나 잘못 복사되었어요. 초대한 분께 새 링크를 요청해 주세요.",
|
||||
"toLogin": "로그인으로 이동"
|
||||
}
|
||||
},
|
||||
"deletionPending": "이 계정은 {date}에 삭제될 예정이며 그때까지 잠겨 있어요. 그 전에는 이 서버의 관리자가 삭제를 취소할 수 있어요.",
|
||||
"deletionPendingNoDate": "이 계정은 삭제 예정이라 잠겨 있어요. 삭제가 끝나기 전까지는 이 서버의 관리자가 취소할 수 있어요."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "대시보드",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "패스키, 감사 로그, 세션까지 함께 계정을 삭제해요.",
|
||||
"deleteAccountCta": "계정 삭제",
|
||||
"deleteAccountConfirmTitle": "계정을 영구히 삭제할까요?",
|
||||
"deleteAccountConfirmDescription": "계정과 모든 건강 데이터, 패스키, 세션, 감사 기록이 영구히 삭제돼요. 삭제 직후 로그아웃돼요.",
|
||||
"deleteAccountConfirmDescription": "계정과 모든 건강 데이터, 패스키, 세션, 감사 기록이 영구히 삭제돼요. 삭제 직후 로그아웃돼요. 이 서버 백업에 남은 사본은 보관 기간이 지나면 사라져요.",
|
||||
"deleteAccountSuccess": "계정을 삭제했어요. 로그아웃할게요.",
|
||||
"deleteAccountFailed": "계정을 삭제하지 못했어요",
|
||||
"deleteAccountFinal": "영구 삭제",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "코치 대화: {days}일 보관",
|
||||
"audit": "보안 활동 기록: {days}일 보관",
|
||||
"delivery": "알림 발송 기록: {days}일 보관",
|
||||
"unavailable": "지금은 보관 기간 정보를 볼 수 없어요."
|
||||
"unavailable": "지금은 보관 기간 정보를 볼 수 없어요.",
|
||||
"accountDeletion": "계정, 관리 프로필 또는 모든 데이터 삭제: {days}일 뒤에 완료",
|
||||
"accountDeletionImmediate": "계정, 관리 프로필 또는 모든 데이터 삭제: 즉시 완료"
|
||||
},
|
||||
"delete": {
|
||||
"title": "삭제 또는 초기화",
|
||||
"description": "계정을 완전히 없애거나, 계정은 두고 건강 기록만 지워요.",
|
||||
"backupLag": "삭제하면 데이터는 즉시 지워져요. 이 서버가 암호화된 외부 백업을 보관한다면 그 저장소에 있는 데이터 사본도 곧바로 삭제되고, 저장소에 연결할 수 없으면 다음 야간 실행 때 삭제돼요.",
|
||||
"openAdvanced": "삭제 또는 초기화"
|
||||
"openAdvanced": "삭제 또는 초기화",
|
||||
"immediateNotice": "삭제하면 데이터는 즉시 지워져요. 이 서버가 암호화된 외부 백업을 보관한다면 그 저장소에 있는 데이터 사본도 곧바로 삭제되고, 저장소에 연결할 수 없으면 다음 야간 실행 때 삭제돼요. 이 서버 백업에 남은 사본은 보관 기간이 지나면 사라져요.",
|
||||
"graceNotice": "계정을 삭제하면 바로 잠기고 {days}일 뒤에 이 서버가 보관하는 모든 사본, 서버 밖에 암호화해 둔 사본까지 함께 완전히 지워져요. 그때까지는 이 서버의 관리자가 삭제를 취소할 수 있어요. 모든 데이터 삭제도 같은 방식이에요. 기록의 사본이 {days}일 동안 보관되어 관리자가 복원할 수 있어요. 이 서버 백업에 남은 사본은 보관 기간이 지나면 사라져요."
|
||||
},
|
||||
"posture": {
|
||||
"title": "개인정보 보호 수준",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "꺼짐",
|
||||
"change": "모듈에서 변경"
|
||||
},
|
||||
"timezoneUseDevice": "이 기기의 시간대 사용 ({zone})"
|
||||
"timezoneUseDevice": "이 기기의 시간대 사용 ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "기록에 있는 모든 것이 삭제돼요: 측정값, 약, 기분 기록, 검사 결과, 주기 기록, 문서, AI 대화, 모든 연동 연결과 여기서 파생된 데이터, 앞서 삭제한 데이터까지 전부요. 의사에게 준 공유 링크도 바로 작동을 멈춰요. 계정은 그대로 남고, 로그인에 쓰는 자격 증명과 언어·시간대·단위 같은 표시 설정도 유지돼요. 기록의 사본은 {days}일 동안 보관되므로, 그때까지는 이 서버의 관리자가 복원할 수 있어요. 그 후에는 삭제가 최종적으로 확정돼요.",
|
||||
"deleteAccountCardDetailGrace": "계정은 바로 잠기고 {days}일 뒤에 완전히 지워져요. 그때까지는 이 서버의 관리자가 삭제를 취소할 수 있어요.",
|
||||
"deleteAccountConfirmDescriptionGrace": "바로 로그아웃되고 계정이 잠겨요. {days}일 뒤에는 모든 건강 데이터, 패스키, 세션, 감사 기록과 함께 완전히 지워져요. 그때까지는 이 서버의 관리자가 삭제를 취소할 수 있어요. 이 서버 백업에 남은 사본은 보관 기간이 지나면 사라져요.",
|
||||
"deleteAccountScheduled": "계정이 잠겼고 {date}에 완전히 지워져요. 로그아웃하는 중이에요.",
|
||||
"dangerZoneSuccessGrace": "건강 기록이 삭제됐어요. {date}까지는 이 서버의 관리자가 복원할 수 있어요."
|
||||
},
|
||||
"admin": {
|
||||
"title": "관리자",
|
||||
@@ -8055,7 +8065,15 @@
|
||||
"cannotLogoutSelf": "자기 자신은 강제 로그아웃할 수 없어요",
|
||||
"emptyTitle": "이 화면에 사용자가 없어요",
|
||||
"emptyDescription": "현재 필터에 맞는 사용자가 없어요.",
|
||||
"emptyResetFilter": "전체 사용자 보기"
|
||||
"emptyResetFilter": "전체 사용자 보기",
|
||||
"deletionPending": "{date} 삭제 예정",
|
||||
"deletionPendingNoDate": "삭제 예정",
|
||||
"undoDeletion": "삭제 취소",
|
||||
"undoDeletionTitle": "{name} 삭제를 취소할까요?",
|
||||
"undoDeletionBody": "{name} 님이 이 계정의 삭제를 요청했고, 유예 기간이 끝나면 지워져요. 취소하면 계정과 그 안의 모든 내용이 그대로 남아요. 세션과 토큰은 계속 취소된 상태라 다시 로그인해야 해요.",
|
||||
"undoDeletionBodyGuardian": "보호자가 관리 프로필 {name}을(를) 삭제했고, 유예 기간이 끝나면 지워져요. 취소하면 프로필과 그 안의 모든 내용이 그대로 남고, 보호자들이 다시 접근할 수 있어요.",
|
||||
"undoDeletionDone": "{name} 삭제를 취소했어요",
|
||||
"undoDeletionFailed": "삭제를 취소하지 못했어요"
|
||||
},
|
||||
"invites": {
|
||||
"title": "초대",
|
||||
@@ -8285,7 +8303,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "이 서버에 없는 키로 암호화된 기분 태그 또는 그룹 이름(이름 없이 유지됨)",
|
||||
"restoreSkippedVisitCiphertext": "이 서버에 없는 키로 암호화된 진료 또는 의료진 텍스트(해당 내용 없이 유지됨)",
|
||||
"restoreSkippedVaccinationCiphertext": "이 서버에 없는 키로 암호화된 예방접종 메모(접종 기록은 메모 없이 유지됨)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "이 서버에 없는 키로 암호화된 환경 기간 또는 날짜의 위치(암호화된 채 유지되며 해당 날짜는 새로 가져오지 않음)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "이 서버에 없는 키로 암호화된 환경 기간 또는 날짜의 위치(암호화된 채 유지되며 해당 날짜는 새로 가져오지 않음)",
|
||||
"typePreWipe": "모든 데이터 삭제 전"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "위험 구역",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "{name} 님이 이 기록을 직접 관리할 준비가 되었을 때.",
|
||||
"methodSso": "{name}님은 링크를 사용할 때 통합 로그인(SSO)으로 로그인합니다.",
|
||||
"methodBoth": "{name}님은 비밀번호를 정하거나 통합 로그인(SSO)으로 로그인할 수 있습니다."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "{name} 님에 대해 기록한 모든 것이 프로필과 함께 사라져요. 측정값, 약, 문서, 메모 전부요. 프로필은 바로 잠기고 {days}일 뒤에 완전히 지워져요. 그때까지는 이 서버의 관리자가 삭제를 취소할 수 있어요."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "{name} 님의 기록에 저장했어요"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Ongeldige uitnodiging",
|
||||
"description": "Deze uitnodigingslink is onvolledig of verkeerd gekopieerd. Vraag de persoon die je heeft uitgenodigd om een nieuwe link.",
|
||||
"toLogin": "Naar inloggen"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Dit account wordt op {date} verwijderd en is tot dan vergrendeld. Een beheerder van deze server kan de verwijdering vóór die datum ongedaan maken.",
|
||||
"deletionPendingNoDate": "Dit account staat gepland voor verwijdering en is vergrendeld. Een beheerder van deze server kan de verwijdering ongedaan maken tot die voltooid is."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Verwijdert je account samen met passkeys, auditlogboek en sessies.",
|
||||
"deleteAccountCta": "Account verwijderen",
|
||||
"deleteAccountConfirmTitle": "Account definitief verwijderen?",
|
||||
"deleteAccountConfirmDescription": "Je account, alle gezondheidsgegevens, passkeys, sessies en auditregistraties worden definitief verwijderd. Je wordt daarna direct uitgelogd.",
|
||||
"deleteAccountConfirmDescription": "Je account, alle gezondheidsgegevens, passkeys, sessies en auditregistraties worden definitief verwijderd. Je wordt daarna direct uitgelogd. Kopieën in de back-ups van deze server verlopen na hun bewaartermijn.",
|
||||
"deleteAccountSuccess": "Account verwijderd. Je wordt uitgelogd.",
|
||||
"deleteAccountFailed": "Account kon niet worden verwijderd",
|
||||
"deleteAccountFinal": "Definitief verwijderen",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Coach-gesprekken: {days} dagen bewaard",
|
||||
"audit": "Logboek van beveiligingsactiviteit: {days} dagen bewaard",
|
||||
"delivery": "Logboek van bezorgde meldingen: {days} dagen bewaard",
|
||||
"unavailable": "Details over de bewaartermijn zijn op dit moment niet beschikbaar."
|
||||
"unavailable": "Details over de bewaartermijn zijn op dit moment niet beschikbaar.",
|
||||
"accountDeletion": "Je account, een beheerd profiel of alle gegevens verwijderen: voltooid na {days} dagen",
|
||||
"accountDeletionImmediate": "Je account, een beheerd profiel of alle gegevens verwijderen: meteen voltooid"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Verwijderen of wissen",
|
||||
"description": "Verwijder je account volledig, of wis je gezondheidsgegevens en behoud je account.",
|
||||
"backupLag": "Bij verwijderen worden je gegevens direct gewist. Als deze server versleutelde back-ups buiten de host bewaart, worden de kopieën van je gegevens direct daarna uit die opslag verwijderd, of bij de volgende nachtelijke run als de opslag niet bereikbaar is.",
|
||||
"openAdvanced": "Verwijderen of wissen"
|
||||
"openAdvanced": "Verwijderen of wissen",
|
||||
"immediateNotice": "Bij verwijderen worden je gegevens direct gewist. Als deze server versleutelde back-ups buiten de host bewaart, worden de kopieën van je gegevens direct daarna uit die opslag verwijderd, of bij de volgende nachtelijke run als de opslag niet bereikbaar is. Kopieën in de back-ups van deze server verlopen na hun bewaartermijn.",
|
||||
"graceNotice": "Als je je account verwijdert, wordt het meteen vergrendeld en na {days} dagen gewist, samen met elke kopie die deze server ervan bewaart, ook versleutelde kopieën buiten de server. Tot dan kan een beheerder van deze server de verwijdering ongedaan maken. Alle gegevens verwijderen werkt net zo: een kopie van het dossier wordt {days} dagen bewaard, zodat een beheerder die kan terugzetten. Kopieën in de back-ups van deze server verlopen na hun bewaartermijn."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Privacyniveau",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Uit",
|
||||
"change": "Wijzigen in Modules"
|
||||
},
|
||||
"timezoneUseDevice": "Tijdzone van dit apparaat gebruiken ({zone})"
|
||||
"timezoneUseDevice": "Tijdzone van dit apparaat gebruiken ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Hiermee wordt alles in je dossier verwijderd: metingen, medicatie, stemmingsregistraties, labuitslagen, cyclusregistraties, documenten, AI-gesprekken en alle koppelingen, samen met alles wat daarvan is afgeleid en alles wat je eerder hebt verwijderd. Deellinks die je aan een arts hebt gegeven, werken direct niet meer. Je account blijft bestaan, net als de inloggegevens waarmee je inlogt en weergave-instellingen zoals taal, tijdzone en eenheden. Een kopie van je dossier wordt {days} dagen bewaard, zodat een beheerder van deze server die tot dan kan terugzetten. Daarna is de verwijdering definitief.",
|
||||
"deleteAccountCardDetailGrace": "Je account wordt meteen vergrendeld en na {days} dagen gewist. Tot dan kan een beheerder van deze server de verwijdering ongedaan maken.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Je wordt uitgelogd en je account wordt meteen vergrendeld. Na {days} dagen wordt het definitief gewist, met alle gezondheidsgegevens, passkeys, sessies en auditregels. Tot dan kan een beheerder van deze server de verwijdering ongedaan maken. Kopieën in de back-ups van deze server verlopen na hun bewaartermijn.",
|
||||
"deleteAccountScheduled": "Je account is vergrendeld en wordt op {date} gewist. Je wordt uitgelogd.",
|
||||
"dangerZoneSuccessGrace": "Je gezondheidsdossier is verwijderd. Een beheerder van deze server kan het tot {date} terugzetten."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Beheer",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Je kunt jezelf niet geforceerd uitloggen",
|
||||
"emptyTitle": "Geen gebruikers in deze weergave",
|
||||
"emptyDescription": "Er zijn geen gebruikers die aan het huidige filter voldoen.",
|
||||
"emptyResetFilter": "Alle gebruikers tonen"
|
||||
"emptyResetFilter": "Alle gebruikers tonen",
|
||||
"deletionPending": "Verwijdering op {date}",
|
||||
"deletionPendingNoDate": "Verwijdering gepland",
|
||||
"undoDeletion": "Verwijdering ongedaan maken",
|
||||
"undoDeletionTitle": "Verwijdering van {name} ongedaan maken?",
|
||||
"undoDeletionBody": "{name} heeft gevraagd dit account te verwijderen; het wordt gewist als de bedenktijd afloopt. Ongedaan maken houdt het account en alles erin zoals het was. Sessies en tokens blijven ingetrokken, dus opnieuw inloggen is nodig.",
|
||||
"undoDeletionBodyGuardian": "Een verzorger heeft het beheerde profiel {name} verwijderd; het wordt gewist als de bedenktijd afloopt. Ongedaan maken houdt het profiel en alles erin zoals het was, en de verzorgers kunnen het weer bereiken.",
|
||||
"undoDeletionDone": "Verwijdering van {name} ongedaan gemaakt",
|
||||
"undoDeletionFailed": "Verwijdering kon niet ongedaan worden gemaakt"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Uitnodigingen",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Stemmingslabel of groepsnaam versleuteld met een sleutel die deze server niet heeft (behouden zonder naam)",
|
||||
"restoreSkippedVisitCiphertext": "Tekst van bezoek of zorgverlener versleuteld met een sleutel die deze server niet heeft (behouden zonder)",
|
||||
"restoreSkippedVaccinationCiphertext": "Vaccinatienotitie versleuteld met een sleutel die deze server niet heeft (dosis behouden zonder)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Locatie van een omgevingsperiode of -dag versleuteld met een sleutel die deze server niet heeft (versleuteld behouden, die dagen worden niet bijgewerkt)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Locatie van een omgevingsperiode of -dag versleuteld met een sleutel die deze server niet heeft (versleuteld behouden, die dagen worden niet bijgewerkt)",
|
||||
"typePreWipe": "Voor het verwijderen van alle gegevens"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Gevarenzone",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Wanneer {name} er klaar voor is om zelf voor dit dossier te zorgen.",
|
||||
"methodSso": "{name} logt via single sign-on in bij het gebruiken van de link.",
|
||||
"methodBoth": "{name} kan een wachtwoord instellen of inloggen via single sign-on."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Alles wat voor {name} is vastgelegd, verdwijnt samen met het profiel: metingen, medicatie, documenten en notities. Het profiel wordt meteen vergrendeld en na {days} dagen gewist. Tot dan kan een beheerder van deze server de verwijdering ongedaan maken."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Opgeslagen in het dossier van {name}"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Nieprawidłowe zaproszenie",
|
||||
"description": "Ten link z zaproszeniem jest niekompletny lub został źle skopiowany. Poproś osobę, która cię zaprosiła, o nowy link.",
|
||||
"toLogin": "Przejdź do logowania"
|
||||
}
|
||||
},
|
||||
"deletionPending": "To konto zostanie usunięte {date} i do tego czasu jest zablokowane. Administrator tego serwera może cofnąć usunięcie przed tą datą.",
|
||||
"deletionPendingNoDate": "To konto czeka na usunięcie i jest zablokowane. Administrator tego serwera może cofnąć usunięcie, dopóki się nie zakończy."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Pulpit",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Usuwa Twoje konto wraz z kluczami dostępu, dziennikiem audytu i sesjami.",
|
||||
"deleteAccountCta": "Usuń konto",
|
||||
"deleteAccountConfirmTitle": "Trwale usunąć konto?",
|
||||
"deleteAccountConfirmDescription": "Twoje konto, wszystkie dane zdrowotne, klucze dostępu, sesje i wpisy audytu zostaną trwale usunięte. Zostaniesz wylogowany natychmiast po tym.",
|
||||
"deleteAccountConfirmDescription": "Twoje konto, wszystkie dane zdrowotne, klucze dostępu, sesje i wpisy audytu zostaną trwale usunięte. Zostaniesz wylogowany natychmiast po tym. Kopie w kopiach zapasowych tego serwera wygasają po upływie okresu przechowywania.",
|
||||
"deleteAccountSuccess": "Konto usunięte, trwa wylogowywanie.",
|
||||
"deleteAccountFailed": "Nie udało się usunąć konta",
|
||||
"deleteAccountFinal": "Usuń trwale",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Rozmowy z asystentem: {days} dni",
|
||||
"audit": "Dziennik zabezpieczeń: {days} dni",
|
||||
"delivery": "Dziennik wysyłki powiadomień: {days} dni",
|
||||
"unavailable": "Szczegóły przechowywania są obecnie niedostępne."
|
||||
"unavailable": "Szczegóły przechowywania są obecnie niedostępne.",
|
||||
"accountDeletion": "Usunięcie konta, profilu zarządzanego lub wszystkich danych: kończy się po {days} dniach",
|
||||
"accountDeletionImmediate": "Usunięcie konta, profilu zarządzanego lub wszystkich danych: kończy się od razu"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Usuń lub zresetuj",
|
||||
"description": "Usuń całe konto albo wyczyść dane zdrowotne, zachowując konto.",
|
||||
"backupLag": "Usunięcie natychmiast usuwa Twoje dane. Jeśli ten serwer przechowuje zaszyfrowane kopie zapasowe poza serwerem, kopie Twoich danych są usuwane z tego magazynu zaraz potem, a jeśli jest niedostępny, przy następnym nocnym przebiegu.",
|
||||
"openAdvanced": "Usuń lub zresetuj"
|
||||
"openAdvanced": "Usuń lub zresetuj",
|
||||
"immediateNotice": "Usunięcie natychmiast usuwa Twoje dane. Jeśli ten serwer przechowuje zaszyfrowane kopie zapasowe poza serwerem, kopie Twoich danych są usuwane z tego magazynu zaraz potem, a jeśli jest niedostępny, przy następnym nocnym przebiegu. Kopie w kopiach zapasowych tego serwera wygasają po upływie okresu przechowywania.",
|
||||
"graceNotice": "Gdy usuwasz konto, zostaje ono od razu zablokowane i usunięte po {days} dniach, razem z każdą kopią, którą przechowuje ten serwer, także zaszyfrowanymi kopiami poza serwerem. Do tego czasu administrator tego serwera może cofnąć usunięcie. Usunięcie wszystkich danych działa tak samo: kopia dokumentacji jest przechowywana przez {days} dni, więc administrator może ją przywrócić. Kopie w kopiach zapasowych tego serwera wygasają po upływie okresu przechowywania."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Ustawienia prywatności",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Wyłączone",
|
||||
"change": "Zmień w Modułach"
|
||||
},
|
||||
"timezoneUseDevice": "Użyj strefy czasowej tego urządzenia ({zone})"
|
||||
"timezoneUseDevice": "Użyj strefy czasowej tego urządzenia ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Ta czynność usuwa wszystko z Twojej dokumentacji: pomiary, leki, wpisy nastroju, wyniki badań, wpisy cyklu, dokumenty, rozmowy z SI oraz wszystkie połączenia integracji, a wraz z nimi wszystko, co z nich wyliczono, i wszystko, co usunięto wcześniej. Linki udostępnione poradni natychmiast przestają działać. Konto zostaje, razem z danymi logowania i ustawieniami wyświetlania, takimi jak język, strefa czasowa i jednostki. Kopia twojej dokumentacji jest przechowywana przez {days} dni, więc do tego czasu administrator tego serwera może ją przywrócić. Potem usunięcie jest ostateczne.",
|
||||
"deleteAccountCardDetailGrace": "Twoje konto zostaje od razu zablokowane i usunięte po {days} dniach. Do tego czasu administrator tego serwera może cofnąć usunięcie.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Zostaniesz wylogowany, a twoje konto od razu zablokowane. Po {days} dniach zostanie trwale usunięte, razem ze wszystkimi danymi zdrowotnymi, kluczami dostępu, sesjami i wpisami audytu. Do tego czasu administrator tego serwera może cofnąć usunięcie. Kopie w kopiach zapasowych tego serwera wygasają po upływie okresu przechowywania.",
|
||||
"deleteAccountScheduled": "Twoje konto jest zablokowane i zostanie usunięte {date}. Trwa wylogowywanie.",
|
||||
"dangerZoneSuccessGrace": "Twoja dokumentacja zdrowotna została usunięta. Administrator tego serwera może ją przywrócić do {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administracja",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Nie można wymusić wylogowania samego siebie",
|
||||
"emptyTitle": "Brak użytkowników w tym widoku",
|
||||
"emptyDescription": "Brak użytkowników pasujących do bieżącego filtra.",
|
||||
"emptyResetFilter": "Pokaż wszystkich użytkowników"
|
||||
"emptyResetFilter": "Pokaż wszystkich użytkowników",
|
||||
"deletionPending": "Usunięcie {date}",
|
||||
"deletionPendingNoDate": "Usunięcie zaplanowane",
|
||||
"undoDeletion": "Cofnij usunięcie",
|
||||
"undoDeletionTitle": "Cofnąć usunięcie {name}?",
|
||||
"undoDeletionBody": "{name} poprosił o usunięcie tego konta; zostanie ono usunięte po upływie okresu karencji. Cofnięcie zachowuje konto i całą jego zawartość bez zmian. Sesje i tokeny pozostają unieważnione, więc trzeba będzie zalogować się ponownie.",
|
||||
"undoDeletionBodyGuardian": "Osoba opiekująca się profilem usunęła profil zarządzany {name}; zostanie on usunięty po upływie okresu karencji. Cofnięcie zachowuje profil i całą jego zawartość bez zmian, a osoby opiekujące się nim znów mają do niego dostęp.",
|
||||
"undoDeletionDone": "Cofnięto usunięcie {name}",
|
||||
"undoDeletionFailed": "Nie udało się cofnąć usunięcia"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Zaproszenia",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Nazwa tagu lub grupy nastroju zaszyfrowana kluczem, którego ten serwer nie ma (zachowana bez nazwy)",
|
||||
"restoreSkippedVisitCiphertext": "Tekst wizyty lub lekarza zaszyfrowany kluczem, którego ten serwer nie ma (zachowany bez niego)",
|
||||
"restoreSkippedVaccinationCiphertext": "Notatka szczepienia zaszyfrowana kluczem, którego ten serwer nie ma (dawka zachowana bez niej)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Lokalizacja okresu lub dnia środowiskowego zaszyfrowana kluczem, którego ten serwer nie ma (zachowana w postaci zaszyfrowanej, te dni nie są odświeżane)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Lokalizacja okresu lub dnia środowiskowego zaszyfrowana kluczem, którego ten serwer nie ma (zachowana w postaci zaszyfrowanej, te dni nie są odświeżane)",
|
||||
"typePreWipe": "Przed usunięciem wszystkich danych"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Strefa zagrożenia",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Gdy {name} chce samodzielnie prowadzić tę kartę.",
|
||||
"methodSso": "{name} loguje się przez logowanie jednokrotne (SSO), gdy użyje linku.",
|
||||
"methodBoth": "{name} może ustawić hasło albo zalogować się przez logowanie jednokrotne (SSO)."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Wszystko, co zapisano dla {name}, znika razem z profilem: pomiary, leki, dokumenty i notatki. Profil zostaje od razu zablokowany i usunięty po {days} dniach. Do tego czasu administrator tego serwera może cofnąć usunięcie."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Zapisano w karcie użytkownika {name}"
|
||||
|
||||
+29
-9
@@ -629,7 +629,9 @@
|
||||
"title": "Convite inválido",
|
||||
"description": "Este link de convite está incompleto ou foi copiado errado. Peça um novo à pessoa que convidou você.",
|
||||
"toLogin": "Ir para o login"
|
||||
}
|
||||
},
|
||||
"deletionPending": "Esta conta será excluída em {date} e está bloqueada até lá. Um administrador deste servidor pode desfazer a exclusão antes dessa data.",
|
||||
"deletionPendingNoDate": "Esta conta está programada para exclusão e está bloqueada. Um administrador deste servidor pode desfazer a exclusão até que ela seja concluída."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Painel",
|
||||
@@ -6922,7 +6924,7 @@
|
||||
"deleteAccountCardDescription": "Exclui sua conta junto com chaves de acesso, log de auditoria e sessões.",
|
||||
"deleteAccountCta": "Excluir conta",
|
||||
"deleteAccountConfirmTitle": "Excluir conta permanentemente?",
|
||||
"deleteAccountConfirmDescription": "Sua conta, todos os dados de saúde, chaves de acesso, sessões e registros de auditoria serão excluídos permanentemente. Você será desconectado imediatamente depois.",
|
||||
"deleteAccountConfirmDescription": "Sua conta, todos os dados de saúde, chaves de acesso, sessões e registros de auditoria serão excluídos permanentemente. Você será desconectado imediatamente depois. As cópias nos backups deste servidor expiram depois do período de retenção.",
|
||||
"deleteAccountSuccess": "Conta excluída. Desconectando você.",
|
||||
"deleteAccountFailed": "Não foi possível excluir a conta",
|
||||
"deleteAccountFinal": "Excluir permanentemente",
|
||||
@@ -7332,13 +7334,16 @@
|
||||
"coach": "Conversas do Coach: mantidas por {days} dias",
|
||||
"audit": "Log de atividade de segurança: mantido por {days} dias",
|
||||
"delivery": "Log de entrega de notificações: mantido por {days} dias",
|
||||
"unavailable": "Os detalhes de retenção estão indisponíveis agora."
|
||||
"unavailable": "Os detalhes de retenção estão indisponíveis agora.",
|
||||
"accountDeletion": "Excluir sua conta, um perfil gerenciado ou todos os dados: concluído depois de {days} dias",
|
||||
"accountDeletionImmediate": "Excluir sua conta, um perfil gerenciado ou todos os dados: concluído na hora"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Excluir ou redefinir",
|
||||
"description": "Remova sua conta por completo ou apague seus registros de saúde mantendo a conta.",
|
||||
"backupLag": "A exclusão remove seus dados imediatamente. Se este servidor mantiver backups criptografados fora do host, as cópias dos seus dados são excluídas desse armazenamento logo depois, ou na próxima execução noturna se o armazenamento estiver inacessível.",
|
||||
"openAdvanced": "Excluir ou redefinir"
|
||||
"openAdvanced": "Excluir ou redefinir",
|
||||
"immediateNotice": "A exclusão remove seus dados imediatamente. Se este servidor mantiver backups criptografados fora do host, as cópias dos seus dados são excluídas desse armazenamento logo depois, ou na próxima execução noturna se o armazenamento estiver inacessível. As cópias nos backups deste servidor expiram depois do período de retenção.",
|
||||
"graceNotice": "Quando você exclui sua conta, ela é bloqueada na hora e apagada depois de {days} dias, junto com todas as cópias que este servidor guarda dela, inclusive as cópias criptografadas fora do servidor. Até lá, um administrador deste servidor pode desfazer a exclusão. Excluir todos os dados funciona do mesmo jeito: uma cópia do registro é mantida por {days} dias, para que um administrador possa restaurá-la. As cópias nos backups deste servidor expiram depois do período de retenção."
|
||||
},
|
||||
"posture": {
|
||||
"title": "Postura de privacidade",
|
||||
@@ -7644,7 +7649,12 @@
|
||||
"off": "Desligado",
|
||||
"change": "Alterar em Módulos"
|
||||
},
|
||||
"timezoneUseDevice": "Usar o fuso horário deste dispositivo ({zone})"
|
||||
"timezoneUseDevice": "Usar o fuso horário deste dispositivo ({zone})",
|
||||
"dangerZoneConfirmDescriptionGrace": "Isso exclui tudo no seu registro: medições, medicamentos, registros de humor, resultados de exames, registros de ciclo, documentos, conversas de IA e todas as conexões de integração, junto com tudo derivado deles e qualquer coisa que você tenha excluído antes. Os links de compartilhamento que você deu a um médico param de funcionar imediatamente. Sua conta permanece, junto com as credenciais que você usa para entrar e as configurações de exibição, como idioma, fuso horário e unidades. Uma cópia do seu registro é mantida por {days} dias, para que um administrador deste servidor possa restaurá-la até lá. Depois disso, a exclusão é definitiva.",
|
||||
"deleteAccountCardDetailGrace": "Sua conta é bloqueada na hora e apagada depois de {days} dias. Até lá, um administrador deste servidor pode desfazer a exclusão.",
|
||||
"deleteAccountConfirmDescriptionGrace": "Você sai da sessão e sua conta é bloqueada na hora. Depois de {days} dias, ela é apagada de vez, com todos os dados de saúde, chaves de acesso, sessões e registros de auditoria. Até lá, um administrador deste servidor pode desfazer a exclusão. As cópias nos backups deste servidor expiram depois do período de retenção.",
|
||||
"deleteAccountScheduled": "Sua conta está bloqueada e será apagada em {date}. Saindo da sessão.",
|
||||
"dangerZoneSuccessGrace": "Seu registro de saúde foi excluído. Um administrador deste servidor pode restaurá-lo até {date}."
|
||||
},
|
||||
"admin": {
|
||||
"title": "Administração",
|
||||
@@ -8080,7 +8090,15 @@
|
||||
"cannotLogoutSelf": "Não é possível forçar o próprio logout",
|
||||
"emptyTitle": "Nenhum usuário nesta visão",
|
||||
"emptyDescription": "Não há usuários correspondentes ao filtro atual.",
|
||||
"emptyResetFilter": "Mostrar todos os usuários"
|
||||
"emptyResetFilter": "Mostrar todos os usuários",
|
||||
"deletionPending": "Exclusão em {date}",
|
||||
"deletionPendingNoDate": "Exclusão pendente",
|
||||
"undoDeletion": "Desfazer exclusão",
|
||||
"undoDeletionTitle": "Desfazer a exclusão de {name}?",
|
||||
"undoDeletionBody": "{name} pediu para excluir esta conta, e ela é apagada quando o prazo de carência termina. Desfazer mantém a conta e tudo o que há nela como estava. As sessões e tokens continuam revogados, então será preciso entrar de novo.",
|
||||
"undoDeletionBodyGuardian": "Um guardião excluiu o perfil gerenciado {name}, e ele é apagado quando o prazo de carência termina. Desfazer mantém o perfil e tudo o que há nele como estava, e os guardiões voltam a ter acesso.",
|
||||
"undoDeletionDone": "Exclusão de {name} desfeita",
|
||||
"undoDeletionFailed": "Não foi possível desfazer a exclusão"
|
||||
},
|
||||
"invites": {
|
||||
"title": "Convites",
|
||||
@@ -8310,7 +8328,8 @@
|
||||
"restoreSkippedMoodLabelCiphertext": "Etiqueta ou nome de grupo de humor selado com uma chave que este servidor não possui (mantido sem o nome)",
|
||||
"restoreSkippedVisitCiphertext": "Texto de consulta ou profissional selado com uma chave que este servidor não possui (mantido sem ele)",
|
||||
"restoreSkippedVaccinationCiphertext": "Nota de vacinação selada com uma chave que este servidor não possui (dose mantida sem ela)",
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Local de um período ou dia de ambiente selado com uma chave que este servidor não possui (mantido selado, esses dias não são atualizados)"
|
||||
"restoreSkippedEnvironmentLocationCiphertext": "Local de um período ou dia de ambiente selado com uma chave que este servidor não possui (mantido selado, esses dias não são atualizados)",
|
||||
"typePreWipe": "Antes da exclusão de todos os dados"
|
||||
},
|
||||
"danger-zone": {
|
||||
"title": "Zona de perigo",
|
||||
@@ -12660,7 +12679,8 @@
|
||||
"entryHint": "Quando {name} estiver pronto para cuidar deste registro por conta própria.",
|
||||
"methodSso": "{name} entra por login único ao usar o link.",
|
||||
"methodBoth": "{name} pode definir uma senha ou entrar por login único."
|
||||
}
|
||||
},
|
||||
"deleteBodyGrace": "Tudo registrado para {name} vai com o perfil: leituras, medicamentos, documentos e notas. O perfil é bloqueado na hora e apagado depois de {days} dias. Até lá, um administrador deste servidor pode desfazer a exclusão."
|
||||
},
|
||||
"toast": {
|
||||
"savedTo": "Salvo no registro de {name}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$comment": "Production functions over 200 lines, keyed \"file :: name\", and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
|
||||
"count": 348,
|
||||
"total": 112749,
|
||||
"total": 112742,
|
||||
"entries": {
|
||||
"app/achievements/page.tsx :: AchievementsPage": 206,
|
||||
"app/api/admin/backups/upload/route.ts :: apiHandler(arg)": 286,
|
||||
@@ -39,7 +39,7 @@
|
||||
"app/api/record-settings/[family]/route.ts :: apiHandler(arg) #2": 262,
|
||||
"app/api/user/ai-provider/route.ts :: apiHandler(arg) #2": 248,
|
||||
"app/api/withings/callback/route.ts :: apiHandler(arg)": 247,
|
||||
"app/auth/login/page.tsx :: LoginPage": 576,
|
||||
"app/auth/login/page.tsx :: LoginPage": 569,
|
||||
"app/auth/register/page.tsx :: RegisterPage": 285,
|
||||
"app/coach/conversations/page.tsx :: CoachConversationsBody": 249,
|
||||
"app/coach/plans/page.tsx :: CoachPlansBody": 216,
|
||||
|
||||
@@ -149,6 +149,9 @@ const PINNED_AFFORDANCES: Record<
|
||||
"text-success": 2,
|
||||
"toast.success": 2,
|
||||
},
|
||||
// An undone account deletion: an account action with no row counts to
|
||||
// misreport.
|
||||
"src/components/admin/pending-deletion-controls.tsx": { "toast.success": 1 },
|
||||
"src/components/admin/version-tile-section.tsx": {
|
||||
CheckCircle2: 2,
|
||||
"text-success": 1,
|
||||
|
||||
+44
-14
@@ -25,6 +25,7 @@ import { isDashboardSnapshotEnabled } from "@/lib/dashboard/snapshot-flag";
|
||||
import { prefetchDashboardSnapshot } from "@/lib/queries/use-dashboard-snapshot";
|
||||
import { clearOfflineCachesForSessionEnd } from "@/lib/pwa/query-persister";
|
||||
import { sanitizeSameOriginPath } from "@/lib/url-safety";
|
||||
import { formatDate } from "@/lib/format";
|
||||
import {
|
||||
InsecureTransportBanner,
|
||||
useClientTransport,
|
||||
@@ -33,8 +34,44 @@ import { transportVerdict } from "@/lib/auth/client-transport";
|
||||
|
||||
/** The server's refusal for a page whose sign-in cookie cannot stick. */
|
||||
const INSECURE_TRANSPORT_CODE = "auth.session.insecure_transport";
|
||||
/** The server's refusal for an account pending deletion. */
|
||||
const DELETION_PENDING = "auth.account.deletion_pending";
|
||||
import { loadDocument } from "@/lib/navigation/load-document";
|
||||
|
||||
type Translate = (key: string, params?: Record<string, string>) => string;
|
||||
|
||||
/**
|
||||
* An account pending deletion: the date it is erased, when the server named
|
||||
* one, and who can still stop it.
|
||||
*/
|
||||
function deletionPendingMessage(t: Translate, purgeAt: unknown): string {
|
||||
return typeof purgeAt === "string" && !Number.isNaN(Date.parse(purgeAt))
|
||||
? t("auth.deletionPending", { date: formatDate(purgeAt) })
|
||||
: t("auth.deletionPendingNoDate");
|
||||
}
|
||||
|
||||
/** The message for the `?error=` a sign-in redirect (the SSO callback) set. */
|
||||
function signInRedirectError(
|
||||
searchParams: URLSearchParams,
|
||||
t: Translate,
|
||||
): string | null {
|
||||
const oidcError = searchParams.get("error");
|
||||
// The SSO start refused a page on plain http://; the banner says why.
|
||||
if (!oidcError || oidcError === "insecure_transport") return null;
|
||||
if (oidcError === "account_deletion_pending") {
|
||||
return deletionPendingMessage(t, searchParams.get("purgeAt"));
|
||||
}
|
||||
const key: Record<string, string> = {
|
||||
oidc_denied: "auth.oidc.errorDenied",
|
||||
oidc_no_email: "auth.oidc.errorNoEmail",
|
||||
oidc_email_unverified: "auth.oidc.errorEmailUnverified",
|
||||
oidc_identity_conflict: "auth.oidc.errorIdentityConflict",
|
||||
oidc_link_required: "auth.oidc.errorLinkRequired",
|
||||
oidc_registration_disabled: "auth.oidc.errorRegistrationDisabled",
|
||||
};
|
||||
return t(key[oidcError] ?? "auth.oidc.errorFailed");
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -50,20 +87,9 @@ export default function LoginPage() {
|
||||
);
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(() => {
|
||||
const oidcError = searchParams.get("error");
|
||||
// The SSO start refused a page on plain http://; the banner says why.
|
||||
if (!oidcError || oidcError === "insecure_transport") return null;
|
||||
const key: Record<string, string> = {
|
||||
oidc_denied: "auth.oidc.errorDenied",
|
||||
oidc_no_email: "auth.oidc.errorNoEmail",
|
||||
oidc_email_unverified: "auth.oidc.errorEmailUnverified",
|
||||
oidc_identity_conflict: "auth.oidc.errorIdentityConflict",
|
||||
oidc_link_required: "auth.oidc.errorLinkRequired",
|
||||
oidc_registration_disabled: "auth.oidc.errorRegistrationDisabled",
|
||||
};
|
||||
return t(key[oidcError] ?? "auth.oidc.errorFailed");
|
||||
});
|
||||
const [error, setError] = useState<string | null>(() =>
|
||||
signInRedirectError(searchParams, t),
|
||||
);
|
||||
const [loading, setLoading] = useState(false);
|
||||
// v1.23 — second step of login when the password response carries
|
||||
// `meta.mfaRequired`. Holds the opaque ticket + the factors the account can
|
||||
@@ -127,6 +153,10 @@ export default function LoginPage() {
|
||||
setTransportRefused(true);
|
||||
return true;
|
||||
}
|
||||
if (err instanceof ApiError && err.meta?.errorCode === DELETION_PENDING) {
|
||||
setError(deletionPendingMessage(t, err.meta?.purgeAt));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,16 @@ export interface AdminUser {
|
||||
// the instance-wide default applies.
|
||||
documentQuotaBytes: number | null;
|
||||
passkeyCount: number;
|
||||
/**
|
||||
* Set while the account is pending deletion: when the purge job
|
||||
* erases it, and whether the account asked itself or a Guardian deleted
|
||||
* the managed profile. The row offers "Undo deletion" until then.
|
||||
*/
|
||||
deletion: {
|
||||
requestedAt: string;
|
||||
purgeAt: string | null;
|
||||
requestedBy: "self" | "guardian";
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface WorkerStatus {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useFormatters, useTranslations } from "@/lib/i18n/context";
|
||||
import type { BackupRow } from "@/types/backups";
|
||||
|
||||
import { RestoreRowDialog } from "./restore-dialog";
|
||||
import { isPreWipeBackupType } from "@/lib/account-deletion/pre-wipe-type";
|
||||
|
||||
/** What a row's Download and Restore controls act through. */
|
||||
export type BackupRowActionProps = {
|
||||
@@ -31,6 +32,9 @@ function formatBackupType(
|
||||
) {
|
||||
if (type === "WEEKLY_AUTO") return t("admin.section.backups.typeWeeklyAuto");
|
||||
if (type === "MANUAL") return t("admin.section.backups.typeManual");
|
||||
// The copy "Delete all entries" takes first; restorable until the deletion
|
||||
// grace window ends, when the purge job deletes it.
|
||||
if (isPreWipeBackupType(type)) return t("admin.section.backups.typePreWipe");
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
"use client";
|
||||
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { Undo2 } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ConfirmButton } from "@/components/ui/confirm-button";
|
||||
import { showErrorToast } from "@/lib/errors/error-toast";
|
||||
import { apiPost } from "@/lib/api/api-fetch";
|
||||
import { formatDate } from "@/lib/format";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import type { AdminUser } from "./_shared";
|
||||
|
||||
/**
|
||||
* An account pending deletion, in the admin users list: the date the purge
|
||||
* job erases it, and the one action that stops it.
|
||||
*
|
||||
* The account, its stored copies and its off-host objects are untouched
|
||||
* until that date, so "Undo deletion" (`POST /api/admin/users/{id}/undo-deletion`)
|
||||
* gives it back exactly as it was. Renders nothing for any other account.
|
||||
*/
|
||||
export function PendingDeletionControls({ user }: { user: AdminUser }) {
|
||||
const { t } = useTranslations();
|
||||
const queryClient = useQueryClient();
|
||||
const undo = useMutation({
|
||||
mutationFn: () => apiPost(`/api/admin/users/${user.id}/undo-deletion`),
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({ queryKey: queryKeys.adminUsers() });
|
||||
toast.success(
|
||||
t("admin.section.users.undoDeletionDone", { name: user.username }),
|
||||
);
|
||||
},
|
||||
onError: (err) => {
|
||||
showErrorToast(
|
||||
err instanceof Error && err.message
|
||||
? err.message
|
||||
: t("admin.section.users.undoDeletionFailed"),
|
||||
{ cause: err },
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
if (!user.deletion) return null;
|
||||
return (
|
||||
<span
|
||||
className="flex flex-wrap items-center gap-1"
|
||||
data-slot="admin-user-deletion-pending"
|
||||
>
|
||||
<Badge variant="destructive" className="text-xs">
|
||||
{user.deletion.purgeAt
|
||||
? t("admin.section.users.deletionPending", {
|
||||
date: formatDate(user.deletion.purgeAt),
|
||||
})
|
||||
: t("admin.section.users.deletionPendingNoDate")}
|
||||
</Badge>
|
||||
<ConfirmButton
|
||||
slot="admin-user-undo-deletion"
|
||||
size="sm"
|
||||
className="min-h-11 text-xs"
|
||||
icon={<Undo2 className="h-3 w-3" aria-hidden="true" />}
|
||||
label={t("admin.section.users.undoDeletion")}
|
||||
title={t("admin.section.users.undoDeletionTitle", {
|
||||
name: user.username,
|
||||
})}
|
||||
body={t(
|
||||
user.deletion.requestedBy === "guardian"
|
||||
? "admin.section.users.undoDeletionBodyGuardian"
|
||||
: "admin.section.users.undoDeletionBody",
|
||||
{ name: user.username },
|
||||
)}
|
||||
confirmLabel={t("admin.section.users.undoDeletion")}
|
||||
pending={undo.isPending}
|
||||
onConfirm={() => undo.mutate()}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import { ListRow } from "@/components/ui/list-row";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { type AdminUser, PasswordInput } from "./_shared";
|
||||
import { PendingDeletionControls } from "./pending-deletion-controls";
|
||||
import { apiGet, apiPost, apiPut } from "@/lib/api/api-fetch";
|
||||
import {
|
||||
recentProofErrorMessage,
|
||||
@@ -56,8 +57,7 @@ type UserFilter = "all" | "admin" | "user";
|
||||
|
||||
export function UserManagementSection() {
|
||||
const { t } = useTranslations();
|
||||
const { user } = useAuth();
|
||||
const currentUserId = user?.id ?? "";
|
||||
const currentUserId = useAuth().user?.id ?? "";
|
||||
const queryClient = useQueryClient();
|
||||
const [editingUser, setEditingUser] = useState<AdminUser | null>(null);
|
||||
const [editUsername, setEditUsername] = useState("");
|
||||
@@ -182,6 +182,7 @@ export function UserManagementSection() {
|
||||
*/
|
||||
const renderUserActions = (u: AdminUser) => (
|
||||
<>
|
||||
<PendingDeletionControls user={u} />
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
||||
@@ -153,6 +153,13 @@ vi.mock("@/hooks/use-account-switch", () => ({
|
||||
useAccountSwitch: () => ({ mutate: vi.fn(), isPending: false }),
|
||||
}));
|
||||
|
||||
// The deletion grace window the delete dialog states. 0 here, the immediate
|
||||
// erasure these tests were written against; the grace wording is pinned on
|
||||
// `deleteProfileBody` below.
|
||||
vi.mock("@/lib/queries/use-privacy-summary", () => ({
|
||||
useAccountDeletionGrace: () => ({ days: 0, pending: false }),
|
||||
}));
|
||||
|
||||
interface FakeMutation {
|
||||
mutate: ReturnType<typeof vi.fn>;
|
||||
isPending: boolean;
|
||||
@@ -662,6 +669,20 @@ describe("what the confirmation says before it deletes", () => {
|
||||
expect(body).toContain("recordSharing.managed.deleteFloorNote");
|
||||
});
|
||||
|
||||
it("says the profile is locked, erased after the window, and undoable", () => {
|
||||
const body = deleteProfileBody({
|
||||
t,
|
||||
tCount,
|
||||
name: "Managed record",
|
||||
activeGuardians: 1,
|
||||
graceDays: 14,
|
||||
});
|
||||
expect(body).toContain(
|
||||
'recordSharing.managed.deleteBodyGrace({"name":"Managed record","days":14})',
|
||||
);
|
||||
expect(body).not.toContain("recordSharing.managed.deleteBody(");
|
||||
});
|
||||
|
||||
it("counts the guardians who actually hold the record", () => {
|
||||
// A pending invitation confers nothing, and the server counts the same
|
||||
// way. Counting it would tell somebody two people lose the record when
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
accountLabel,
|
||||
type AccountAccessEntry,
|
||||
} from "@/lib/sharing/account-access-view";
|
||||
import { useAccountDeletionGrace } from "@/lib/queries/use-privacy-summary";
|
||||
|
||||
/**
|
||||
* v1.37.0 — the records this account looks after.
|
||||
@@ -140,6 +141,7 @@ function ManagedProfileRow({
|
||||
}) {
|
||||
const { t, tCount } = useTranslations();
|
||||
const guardians = useManagedProfileGuardians(profile.accountId);
|
||||
const grace = useAccountDeletionGrace();
|
||||
const name = accountLabel(profile);
|
||||
const failed =
|
||||
remove.isError &&
|
||||
@@ -185,7 +187,7 @@ function ManagedProfileRow({
|
||||
>
|
||||
{t("recordSharing.managed.edit")}
|
||||
</Button>
|
||||
{guardians.data && (
|
||||
{guardians.data && !grace.pending && (
|
||||
<ConfirmButton
|
||||
slot="managed-profile-delete"
|
||||
destructive
|
||||
@@ -198,6 +200,7 @@ function ManagedProfileRow({
|
||||
tCount,
|
||||
name,
|
||||
activeGuardians: activeGuardianCount(guardians.data),
|
||||
graceDays: grace.days ?? 0,
|
||||
})}
|
||||
confirmLabel={t("recordSharing.managed.deleteConfirm")}
|
||||
pending={remove.isPending}
|
||||
@@ -335,6 +338,7 @@ export function deleteProfileBody({
|
||||
tCount,
|
||||
name,
|
||||
activeGuardians,
|
||||
graceDays = 0,
|
||||
}: {
|
||||
t: (key: string, params?: Record<string, string | number>) => string;
|
||||
tCount: (
|
||||
@@ -345,9 +349,17 @@ export function deleteProfileBody({
|
||||
name: string;
|
||||
/** Taken from the roster read, never from a local counter. */
|
||||
activeGuardians: number;
|
||||
/**
|
||||
* The deletion grace window (`GET /api/settings/privacy-summary`). Above 0
|
||||
* the profile is locked and erased when it ends, and an admin can undo it
|
||||
* until then; 0 erases it at once.
|
||||
*/
|
||||
graceDays?: number;
|
||||
}): string {
|
||||
return [
|
||||
t("recordSharing.managed.deleteBody", { name }),
|
||||
graceDays > 0
|
||||
? t("recordSharing.managed.deleteBodyGrace", { name, days: graceDays })
|
||||
: t("recordSharing.managed.deleteBody", { name }),
|
||||
tCount("recordSharing.managed.deleteGuardians", activeGuardians, {
|
||||
count: activeGuardians,
|
||||
}),
|
||||
|
||||
@@ -17,15 +17,18 @@ import {
|
||||
useRecentProof,
|
||||
} from "@/components/settings/security-section/use-recent-proof";
|
||||
import { loadDocument } from "@/lib/navigation/load-document";
|
||||
import { useAccountDeletionGrace } from "@/lib/queries/use-privacy-summary";
|
||||
import { formatDate } from "@/lib/format";
|
||||
|
||||
/**
|
||||
* Settings → Advanced.
|
||||
*
|
||||
* v1.4.16: every export path (CSV, JSON, doctor-report PDF)
|
||||
* moved out into the dedicated `<ExportSection>` under `/settings/export`.
|
||||
* What stays here is the irreversible danger-zone — the "wipe all my
|
||||
* data" surface that should never live next to a single-click export
|
||||
* button.
|
||||
* What stays here is the danger-zone — the "wipe all my data" and
|
||||
* "delete my account" surfaces that should never live next to a
|
||||
* single-click export button. Both complete after the deletion grace
|
||||
* window (`ACCOUNT_DELETION_GRACE_DAYS`), which the dialogs state.
|
||||
*
|
||||
* v1.4.25 added a Research Mode opt-in here, gating the estimated GLP-1
|
||||
* drug-level curve behind an acknowledged disclaimer version. The chart
|
||||
@@ -52,6 +55,10 @@ export function AdvancedSection() {
|
||||
function DataResetCard() {
|
||||
const { t } = useTranslations();
|
||||
const queryClient = useQueryClient();
|
||||
// With a grace window the wipe keeps a copy an admin can restore until the
|
||||
// window ends; the dialog says so only once it knows the number.
|
||||
const grace = useAccountDeletionGrace();
|
||||
const graceDays = grace.days ?? 0;
|
||||
const recentProof = useRecentProof({
|
||||
description: t("settings.reproof.descriptionChange"),
|
||||
});
|
||||
@@ -86,7 +93,14 @@ function DataResetCard() {
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries();
|
||||
setMsg(t("settings.dangerZoneSuccess"));
|
||||
const restorableUntil: unknown = json?.data?.restorableUntil;
|
||||
setMsg(
|
||||
typeof restorableUntil === "string"
|
||||
? t("settings.dangerZoneSuccessGrace", {
|
||||
date: formatDate(restorableUntil),
|
||||
})
|
||||
: t("settings.dangerZoneSuccess"),
|
||||
);
|
||||
setMsgType("success");
|
||||
setConfirmOpen(false);
|
||||
} catch (err) {
|
||||
@@ -132,7 +146,7 @@ function DataResetCard() {
|
||||
onClick={() => setConfirmOpen(true)}
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
disabled={deleting}
|
||||
disabled={deleting || grace.pending}
|
||||
className="min-h-11 w-full shrink-0 sm:min-h-9 sm:w-auto"
|
||||
>
|
||||
{deleting ? (
|
||||
@@ -151,7 +165,13 @@ function DataResetCard() {
|
||||
setConfirmOpen(open);
|
||||
}}
|
||||
title={t("settings.dangerZoneConfirm")}
|
||||
body={t("settings.dangerZoneConfirmDescription")}
|
||||
body={
|
||||
graceDays > 0
|
||||
? t("settings.dangerZoneConfirmDescriptionGrace", {
|
||||
days: graceDays,
|
||||
})
|
||||
: t("settings.dangerZoneConfirmDescription")
|
||||
}
|
||||
confirmLabel={t("settings.finalDelete")}
|
||||
onConfirm={() => void handleDeleteAllData()}
|
||||
pending={deleting}
|
||||
@@ -180,6 +200,10 @@ function DataResetCard() {
|
||||
*/
|
||||
function AccountDeleteCard() {
|
||||
const { t } = useTranslations();
|
||||
// With a grace window the account is locked at once and erased when the
|
||||
// window ends; until then an admin can undo it. Stated only once known.
|
||||
const grace = useAccountDeletionGrace();
|
||||
const graceDays = grace.days ?? 0;
|
||||
const recentProof = useRecentProof({
|
||||
description: t("settings.reproof.descriptionChange"),
|
||||
});
|
||||
@@ -216,12 +240,24 @@ function AccountDeleteCard() {
|
||||
setDeleting(false);
|
||||
return;
|
||||
}
|
||||
setMsg(t("settings.deleteAccountSuccess"));
|
||||
let scheduledPurgeAt: unknown = null;
|
||||
try {
|
||||
scheduledPurgeAt = (await res.json())?.data?.scheduledPurgeAt;
|
||||
} catch {
|
||||
scheduledPurgeAt = null;
|
||||
}
|
||||
setMsg(
|
||||
typeof scheduledPurgeAt === "string"
|
||||
? t("settings.deleteAccountScheduled", {
|
||||
date: formatDate(scheduledPurgeAt),
|
||||
})
|
||||
: t("settings.deleteAccountSuccess"),
|
||||
);
|
||||
setMsgType("success");
|
||||
// The route destroyed every session before deleting the row;
|
||||
// give the toast a beat to paint, then bounce to the login page.
|
||||
// Leave `deleting` set so the confirm button keeps its pending
|
||||
// state through the redirect — the row is gone, nothing to undo.
|
||||
// The route revoked every session (and, without a grace window,
|
||||
// deleted the row); give the toast a beat to paint, then bounce to the
|
||||
// login page. Leave `deleting` set so the confirm button keeps its
|
||||
// pending state through the redirect: only an admin can undo it now.
|
||||
setTimeout(() => {
|
||||
loadDocument("/auth/login");
|
||||
}, 1_500);
|
||||
@@ -246,7 +282,11 @@ function AccountDeleteCard() {
|
||||
title={t("settings.deleteAccountCardTitle")}
|
||||
description={t("settings.deleteAccountCardDescription")}
|
||||
/>
|
||||
<p className="text-sm">{t("settings.deleteAccountCardDetail")}</p>
|
||||
<p className="text-sm">
|
||||
{graceDays > 0
|
||||
? t("settings.deleteAccountCardDetailGrace", { days: graceDays })
|
||||
: t("settings.deleteAccountCardDetail")}
|
||||
</p>
|
||||
|
||||
{msg && (
|
||||
<p
|
||||
@@ -262,7 +302,7 @@ function AccountDeleteCard() {
|
||||
onClick={() => setConfirmOpen(true)}
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
disabled={deleting}
|
||||
disabled={deleting || grace.pending}
|
||||
className="min-h-11 w-full shrink-0 sm:min-h-9 sm:w-auto"
|
||||
data-slot="settings-account-delete-trigger"
|
||||
>
|
||||
@@ -282,7 +322,13 @@ function AccountDeleteCard() {
|
||||
setConfirmOpen(open);
|
||||
}}
|
||||
title={t("settings.deleteAccountConfirmTitle")}
|
||||
body={t("settings.deleteAccountConfirmDescription")}
|
||||
body={
|
||||
graceDays > 0
|
||||
? t("settings.deleteAccountConfirmDescriptionGrace", {
|
||||
days: graceDays,
|
||||
})
|
||||
: t("settings.deleteAccountConfirmDescription")
|
||||
}
|
||||
confirmLabel={t("settings.deleteAccountFinal")}
|
||||
onConfirm={() => void handleDeleteAccount()}
|
||||
pending={deleting}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* left: Export & import and the Health record sit next to this page in the
|
||||
* Data group. The old anchors forward (`settings-anchor-forward.tsx`).
|
||||
*/
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Database,
|
||||
@@ -33,26 +32,11 @@ import { SettingsCard } from "@/components/settings/settings-card";
|
||||
import { SettingsCardHeader } from "@/components/settings/_card-header";
|
||||
import { SettingsInfoTile } from "@/components/settings/_info-tile";
|
||||
import { WorkoutRoutesCard } from "@/components/settings/workout-routes-card";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { MODULE_KEYS, MODULE_REGISTRY } from "@/lib/modules/registry";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { usePrivacySummary } from "@/lib/queries/use-privacy-summary";
|
||||
import { QueryErrorRow } from "@/components/ui/query-error-row";
|
||||
|
||||
interface PrivacySummary {
|
||||
retention: {
|
||||
coachMessagesDays: number;
|
||||
auditLogDays: number;
|
||||
deliveryLogDays: number;
|
||||
};
|
||||
encryption: {
|
||||
algorithm: string;
|
||||
columnCount: number;
|
||||
modelCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The modules that keep records of their own, read off the module registry
|
||||
* so a new module joins the "What's stored" list without anyone editing it.
|
||||
@@ -69,7 +53,6 @@ export function storedModuleLabelKeys(): string[] {
|
||||
|
||||
export function PrivacySection() {
|
||||
const { t, locale } = useTranslations();
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
const {
|
||||
data: summary,
|
||||
@@ -77,11 +60,7 @@ export function PrivacySection() {
|
||||
isError: summaryError,
|
||||
error: summaryFailure,
|
||||
refetch: refetchSummary,
|
||||
} = useQuery({
|
||||
queryKey: queryKeys.privacySummary(),
|
||||
queryFn: () => apiGet<PrivacySummary>("/api/settings/privacy-summary"),
|
||||
enabled: isAuthenticated,
|
||||
});
|
||||
} = usePrivacySummary();
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -177,6 +156,13 @@ export function PrivacySection() {
|
||||
days: summary.retention.deliveryLogDays,
|
||||
})}
|
||||
</li>
|
||||
<li>
|
||||
{summary.retention.accountDeletionGraceDays > 0
|
||||
? t("settings.privacy.retention.accountDeletion", {
|
||||
days: summary.retention.accountDeletionGraceDays,
|
||||
})
|
||||
: t("settings.privacy.retention.accountDeletionImmediate")}
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</SettingsCard>
|
||||
@@ -208,9 +194,15 @@ export function PrivacySection() {
|
||||
title={t("settings.privacy.delete.title")}
|
||||
description={t("settings.privacy.delete.description")}
|
||||
/>
|
||||
<SettingsInfoTile icon={Info} tone="warning">
|
||||
{t("settings.privacy.delete.backupLag")}
|
||||
</SettingsInfoTile>
|
||||
{summary && (
|
||||
<SettingsInfoTile icon={Info} tone="warning">
|
||||
{summary.retention.accountDeletionGraceDays > 0
|
||||
? t("settings.privacy.delete.graceNotice", {
|
||||
days: summary.retention.accountDeletionGraceDays,
|
||||
})
|
||||
: t("settings.privacy.delete.immediateNotice")}
|
||||
</SettingsInfoTile>
|
||||
)}
|
||||
<SettingsCardActions align="start">
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link href="/settings/advanced">
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* The privacy facts the server states (`GET /api/settings/privacy-summary`):
|
||||
* the retention windows, the deletion grace window and the encryption-at-rest
|
||||
* summary. One reader for every surface that quotes them, so the privacy page
|
||||
* and the deletion dialogs share one cache entry with one shape.
|
||||
*/
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
|
||||
export interface PrivacySummary {
|
||||
retention: {
|
||||
coachMessagesDays: number;
|
||||
auditLogDays: number;
|
||||
deliveryLogDays: number;
|
||||
/** Days until an account, profile or wipe deletion completes; 0: at once. */
|
||||
accountDeletionGraceDays: number;
|
||||
};
|
||||
encryption: {
|
||||
algorithm: string;
|
||||
columnCount: number;
|
||||
modelCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function usePrivacySummary() {
|
||||
const { isAuthenticated } = useAuth();
|
||||
return useQuery({
|
||||
queryKey: queryKeys.privacySummary(),
|
||||
queryFn: () => apiGet<PrivacySummary>("/api/settings/privacy-summary"),
|
||||
enabled: isAuthenticated,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The deletion grace window in days, or null while it is not known (still
|
||||
* loading, or the read failed): a dialog that states it must not guess.
|
||||
* `pending` is true only while the first read is in flight, so a control can
|
||||
* wait for the number instead of showing a sentence it would then change.
|
||||
*/
|
||||
export function useAccountDeletionGrace(): {
|
||||
days: number | null;
|
||||
pending: boolean;
|
||||
} {
|
||||
const { data, isPending, isError } = usePrivacySummary();
|
||||
return {
|
||||
days: data?.retention.accountDeletionGraceDays ?? null,
|
||||
pending: isPending && !isError,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user