Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: friendly number handling for note erasure timeouts #1163

Merged
merged 6 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,68 @@ const TPL = `
<p>${t("note_erasure_timeout.note_erasure_description")}</p>

<div class="form-group">
<label>${t("note_erasure_timeout.erase_notes_after_x_seconds")}</label>
<input class="erase-entities-after-time-in-seconds form-control options-number-input" type="number" min="0">
<label for="erase-entities-after-time">${t("note_erasure_timeout.erase_notes_after")}</label>
<div class="d-flex gap-2">
<input id="erase-entities-after-time" class="form-control options-number-input" type="number" min="0" steps="1" required>
<!-- TriliumNextTODO: i18n the strings when refactoring this to a standalone widget -->
<select id="erase-entities-after-time-scale" class="form-select duration-selector" required>
<option value="1">${t("duration.seconds")}</option>
<option value="60">${t("duration.minutes")}</option>
<option value="3600">${t("duration.hours")}</option>
<option value="86400">${t("duration.days")}</option>
</select>
</div>
</div>

<p>${t("note_erasure_timeout.manual_erasing_description")}</p>

<button class="erase-deleted-notes-now-button btn btn-secondary">${t("note_erasure_timeout.erase_deleted_notes_now")}</button>
<button id="erase-deleted-notes-now-button" class="btn btn-secondary">${t("note_erasure_timeout.erase_deleted_notes_now")}</button>

<style>
.duration-selector {
width: auto;
}
</style>
</div>`;

export default class NoteErasureTimeoutOptions extends OptionsWidget {

private $eraseEntitiesAfterTimeInSeconds!: JQuery<HTMLElement>;
private $eraseDeletedNotesButton!: JQuery<HTMLElement>;
private $eraseEntitiesAfterTime!: JQuery<HTMLInputElement>;
private $eraseEntitiesAfterTimeScale!: JQuery<HTMLSelectElement>;
private $eraseDeletedNotesButton!: JQuery<HTMLButtonElement>;
private eraseEntitiesAfterTimeInSeconds!: string | number;

doRender() {
this.$widget = $(TPL);
this.$eraseEntitiesAfterTimeInSeconds = this.$widget.find(".erase-entities-after-time-in-seconds");
this.$eraseEntitiesAfterTimeInSeconds.on("change", () => this.updateOption("eraseEntitiesAfterTimeInSeconds", this.$eraseEntitiesAfterTimeInSeconds.val()));
this.$eraseEntitiesAfterTime = this.$widget.find("#erase-entities-after-time");
this.$eraseEntitiesAfterTimeScale = this.$widget.find("#erase-entities-after-time-scale");

this.$eraseEntitiesAfterTime.on("change", () => {
const time = this.$eraseEntitiesAfterTime.val();
const timeScale = this.$eraseEntitiesAfterTimeScale.val();

if (!this.handleTimeValidation() || typeof timeScale !== "string" || !time) return;

this.eraseEntitiesAfterTimeInSeconds = this.convertTime(time, timeScale).toOption();
this.updateOption("eraseEntitiesAfterTimeInSeconds", this.eraseEntitiesAfterTimeInSeconds);

});

this.$eraseEntitiesAfterTimeScale.on("change", () => {

const timeScale = this.$eraseEntitiesAfterTimeScale.val();

if (!this.handleTimeValidation() || typeof timeScale !== "string") return;

//calculate the new displayed value
const displayedTime = this.convertTime(this.eraseEntitiesAfterTimeInSeconds, timeScale).toDisplay();

this.updateOption("eraseEntitiesAfterTimeScale", timeScale);
this.$eraseEntitiesAfterTime.val(displayedTime).trigger("change");

});

this.$eraseDeletedNotesButton = this.$widget.find(".erase-deleted-notes-now-button");
this.$eraseDeletedNotesButton = this.$widget.find("#erase-deleted-notes-now-button");
this.$eraseDeletedNotesButton.on("click", () => {
server.post("notes/erase-deleted-notes-now").then(() => {
toastService.showMessage(t("note_erasure_timeout.deleted_notes_erased"));
Expand All @@ -39,6 +81,40 @@ export default class NoteErasureTimeoutOptions extends OptionsWidget {
}

async optionsLoaded(options: OptionMap) {
this.$eraseEntitiesAfterTimeInSeconds.val(options.eraseEntitiesAfterTimeInSeconds);
this.eraseEntitiesAfterTimeInSeconds = options.eraseEntitiesAfterTimeInSeconds;

const displayedTime = this.convertTime(options.eraseEntitiesAfterTimeInSeconds, options.eraseEntitiesAfterTimeScale).toDisplay();
this.$eraseEntitiesAfterTime.val(displayedTime);
this.$eraseEntitiesAfterTimeScale.val(options.eraseEntitiesAfterTimeScale);
}


convertTime(time: string | number, timeScale: string | number) {

const value = typeof time === "number" ? time : parseInt(time);
if (Number.isNaN(value)) {
throw new Error(`Time needs to be a valid integer, but received: ${time}`);
}

const operand = typeof timeScale === "number" ? timeScale : parseInt(timeScale);
if (Number.isNaN(operand) || operand < 1) {
throw new Error(`TimeScale needs to be a valid integer >= 1, but received: ${timeScale}`);
}

return {
toOption: () => Math.ceil(value * operand),
toDisplay: () => Math.ceil(value / operand),
}

}

handleTimeValidation() {
if (this.$eraseEntitiesAfterTime.is(":invalid")) {
// TriliumNextTODO: i18n
toastService.showMessage("The entered time value is not a valid number.");
return false
}
return true;
}

}
2 changes: 1 addition & 1 deletion src/public/stylesheets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1643,4 +1643,4 @@ body.electron.platform-darwin:not(.native-titlebar) .tab-row-container {
background: var(--main-background-color);
box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
border-radius: 4px;
}
}
2 changes: 1 addition & 1 deletion src/public/translations/cn/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "笔记清理超时",
"note_erasure_description": "被删除的笔记(以及属性、历史版本等)最初仅被标记为“删除”,可以从“最近修改”对话框中恢复它们。经过一段时间后,已删除的笔记会被“清理”,这意味着它们的内容将无法恢复。此设置允许您配置从删除到清除笔记之间的时间长度。",
"erase_notes_after_x_seconds": "在笔记删除 X 秒后清理",
"erase_notes_after": "Erase notes after",
"manual_erasing_description": "您还可以手动触发清理(不考虑上述定义的超时):",
"erase_deleted_notes_now": "立即清理已删除的笔记",
"deleted_notes_erased": "已删除的笔记已被清理。"
Expand Down
2 changes: 1 addition & 1 deletion src/public/translations/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1102,7 +1102,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "Beachte das Zeitlimit für die Löschung",
"note_erasure_description": "Deleted notes (and attributes, revisions...) are at first only marked as deleted and it is possible to recover them from Recent Notes dialog. After a period of time, deleted notes are \"erased\" which means their content is not recoverable anymore. This setting allows you to configure the length of the period between deleting and erasing the note.",
"erase_notes_after_x_seconds": "Notizen nach X Sekunden löschen",
"erase_notes_after": "Notizen löschen nach",
"manual_erasing_description": "Du kannst das Löschen auch manuell auslösen (ohne Berücksichtigung des oben definierten Timeouts):",
"erase_deleted_notes_now": "Jetzt gelöschte Notizen löschen",
"deleted_notes_erased": "Gelöschte Notizen wurden gelöscht."
Expand Down
8 changes: 7 additions & 1 deletion src/public/translations/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "Note Erasure Timeout",
"note_erasure_description": "Deleted notes (and attributes, revisions...) are at first only marked as deleted and it is possible to recover them from Recent Notes dialog. After a period of time, deleted notes are \"erased\" which means their content is not recoverable anymore. This setting allows you to configure the length of the period between deleting and erasing the note.",
"erase_notes_after_x_seconds": "Erase notes after X seconds",
"erase_notes_after": "Erase notes after",
"manual_erasing_description": "You can also trigger erasing manually (without considering the timeout defined above):",
"erase_deleted_notes_now": "Erase deleted notes now",
"deleted_notes_erased": "Deleted notes have been erased."
Expand Down Expand Up @@ -1648,5 +1648,11 @@
},
"help-button": {
"title": "Open the relevant help page"
},
"duration": {
"seconds": "Seconds",
"minutes": "Minutes",
"hours": "Hours",
"days": "Days"
}
}
2 changes: 1 addition & 1 deletion src/public/translations/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "Tiempo de espera de borrado de notas",
"note_erasure_description": "Las notas eliminadas (y los atributos, las revisiones ...) en principio solo están marcadas como eliminadas y es posible recuperarlas del diálogo de Notas recientes. Después de un período de tiempo, las notas eliminadas son \" borradas\", lo que significa que su contenido ya no es recuperable. Esta configuración le permite configurar la longitud del período entre eliminar y borrar la nota.",
"erase_notes_after_x_seconds": "Borrar notas después de X segundos",
"erase_notes_after": "Borrar notas después de",
"manual_erasing_description": "También puede activar el borrado manualmente (sin considerar el tiempo de espera definido anteriormente):",
"erase_deleted_notes_now": "Borrar notas eliminadas ahora",
"deleted_notes_erased": "Las notas eliminadas han sido borradas."
Expand Down
2 changes: 1 addition & 1 deletion src/public/translations/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "Délai d'effacement des notes",
"note_erasure_description": "Les notes supprimées (et les attributs, versions...) sont seulement marquées comme supprimées et il est possible de les récupérer à partir de la boîte de dialogue Notes récentes. Après un certain temps, les notes supprimées sont « effacées », ce qui signifie que leur contenu n'est plus récupérable. Ce paramètre vous permet de configurer la durée entre la suppression et l'effacement de la note.",
"erase_notes_after_x_seconds": "Effacer les notes après X secondes",
"erase_notes_after": "Effacer les notes après",
"manual_erasing_description": "Vous pouvez également déclencher l'effacement manuellement (sans tenir compte de la durée définie ci-dessus) :",
"erase_deleted_notes_now": "Effacer les notes supprimées maintenant",
"deleted_notes_erased": "Les notes supprimées ont été effacées."
Expand Down
8 changes: 7 additions & 1 deletion src/public/translations/ro/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@
"note_erasure_timeout": {
"deleted_notes_erased": "Notițele șterse au fost eliminate permanent.",
"erase_deleted_notes_now": "Elimină notițele șterse acum",
"erase_notes_after_x_seconds": "Elimină notițele șterse după X secunde",
"erase_notes_after": "Elimină notițele șterse după",
"manual_erasing_description": "Se poate rula o eliminare manuală (fără a lua în considerare timpul definit mai sus):",
"note_erasure_description": "Notițele șterse (precum și atributele, reviziile) sunt prima oară doar marcate drept șterse și este posibil să fie recuperate din ecranul Notițe recente. După o perioadă de timp, notițele șterse vor fi „eliminate”, caz în care conținutul lor nu se poate recupera. Această setare permite configurarea duratei de timp dintre ștergerea și eliminarea notițelor.",
"note_erasure_timeout_title": "Timpul de eliminare automată a notițelor șterse"
Expand Down Expand Up @@ -1649,6 +1649,12 @@
"create-child-note-title": "Crează o notiță nouă și adaug-o pe hartă",
"unable-to-load-map": "Nu s-a putut încărca harta."
},
"duration": {
"days": "zile",
"hours": "ore",
"minutes": "minute",
"seconds": "secunde"
},
"help-button": {
"title": "Deschide ghidul relevant"
}
Expand Down
2 changes: 1 addition & 1 deletion src/public/translations/tw/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "筆記清理超時",
"note_erasure_description": "被刪除的筆記(以及屬性、歷史版本等)最初僅被標記為「刪除」,可以從「最近修改」對話框中恢復它們。經過一段時間後,已刪除的筆記會被「清理」,這意味著它們的內容將無法恢復。此設定允許您設定從刪除到清除筆記之間的時間長度。",
"erase_notes_after_x_seconds": "在筆記刪除 X 秒後清理",
"erase_notes_after": "Erase notes after",
"manual_erasing_description": "您還可以手動觸發清理(不考慮上述定義的超時):",
"erase_deleted_notes_now": "立即清理已刪除的筆記",
"deleted_notes_erased": "已刪除的筆記已被清理。"
Expand Down
1 change: 1 addition & 0 deletions src/routes/api/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { OptionNames } from "../../services/options_interface.js";
// options allowed to be updated directly in the Options dialog
const ALLOWED_OPTIONS = new Set([
"eraseEntitiesAfterTimeInSeconds",
"eraseEntitiesAfterTimeScale",
"protectedSessionTimeout",
"revisionSnapshotTimeInterval",
"revisionSnapshotNumberLimit",
Expand Down
1 change: 1 addition & 0 deletions src/services/options_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ const defaultOptions: DefaultOption[] = [
{ name: "rightPaneVisible", value: "true", isSynced: false },
{ name: "nativeTitleBarVisible", value: "false", isSynced: false },
{ name: "eraseEntitiesAfterTimeInSeconds", value: "604800", isSynced: true }, // default is 7 days
{ name: "eraseEntitiesAfterTimeScale", value: "86400", isSynced: true }, // default 86400 seconds = Day
{ name: "hideArchivedNotes_main", value: "false", isSynced: false },
{ name: "debugModeEnabled", value: "false", isSynced: false },
{ name: "headingStyle", value: "underline", isSynced: true },
Expand Down
1 change: 1 addition & 0 deletions src/services/options_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi
leftPaneWidth: number;
rightPaneWidth: number;
eraseEntitiesAfterTimeInSeconds: number;
eraseEntitiesAfterTimeScale: number;
autoReadonlySizeText: number;
autoReadonlySizeCode: number;
maxContentWidth: number;
Expand Down