mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	Merge pull request #391 from SiriusXT/revisions_number_limit
Revisions number limit
This commit is contained in:
		| @@ -3,6 +3,8 @@ | |||||||
| import protectedSessionService from "../../services/protected_session.js"; | import protectedSessionService from "../../services/protected_session.js"; | ||||||
| import log from "../../services/log.js"; | import log from "../../services/log.js"; | ||||||
| import sql from "../../services/sql.js"; | import sql from "../../services/sql.js"; | ||||||
|  | import optionService from "../../services/options.js"; | ||||||
|  | import eraseService from "../../services/erase.js"; | ||||||
| import utils from "../../services/utils.js"; | import utils from "../../services/utils.js"; | ||||||
| import dateUtils from "../../services/date_utils.js"; | import dateUtils from "../../services/date_utils.js"; | ||||||
| import AbstractBeccaEntity from "./abstract_becca_entity.js"; | import AbstractBeccaEntity from "./abstract_becca_entity.js"; | ||||||
| @@ -1107,7 +1109,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     getRevisions(): BRevision[] { |     getRevisions(): BRevision[] { | ||||||
|         return sql.getRows<RevisionRow>("SELECT * FROM revisions WHERE noteId = ?", [this.noteId]) |         return sql.getRows<RevisionRow>("SELECT * FROM revisions WHERE noteId = ? ORDER BY revisions.utcDateCreated ASC", [this.noteId]) | ||||||
|             .map(row => new BRevision(row)); |             .map(row => new BRevision(row)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1612,10 +1614,31 @@ class BNote extends AbstractBeccaEntity<BNote> { | |||||||
|  |  | ||||||
|             revision.setContent(noteContent); |             revision.setContent(noteContent); | ||||||
|  |  | ||||||
|  |             this.eraseExcessRevisionSnapshots() | ||||||
|             return revision; |             return revision; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Limit the number of Snapshots to revisionSnapshotNumberLimit | ||||||
|  |     // Delete older Snapshots that exceed the limit | ||||||
|  |     eraseExcessRevisionSnapshots() { | ||||||
|  |         // lable has a higher priority | ||||||
|  |         let revisionSnapshotNumberLimit = parseInt(this.getLabelValue("versioningLimit") ?? ""); | ||||||
|  |         if (!Number.isInteger(revisionSnapshotNumberLimit)) { | ||||||
|  |             revisionSnapshotNumberLimit = parseInt(optionService.getOption('revisionSnapshotNumberLimit')); | ||||||
|  |         } | ||||||
|  |         if (revisionSnapshotNumberLimit >= 0) { | ||||||
|  |             const revisions = this.getRevisions(); | ||||||
|  |             if (revisions.length - revisionSnapshotNumberLimit > 0) { | ||||||
|  |                 const revisionIds = revisions | ||||||
|  |                     .slice(0, revisions.length - revisionSnapshotNumberLimit) | ||||||
|  |                     .map(revision => revision.revisionId) | ||||||
|  |                     .filter((id): id is string => id !== undefined); | ||||||
|  |                 eraseService.eraseRevisions(revisionIds); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param matchBy - choose by which property we detect if to update an existing attachment. |      * @param matchBy - choose by which property we detect if to update an existing attachment. | ||||||
|  *                      Supported values are either 'attachmentId' (default) or 'title' |  *                      Supported values are either 'attachmentId' (default) or 'title' | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import openService from "../../services/open.js"; | |||||||
| import protectedSessionHolder from "../../services/protected_session_holder.js"; | import protectedSessionHolder from "../../services/protected_session_holder.js"; | ||||||
| import BasicWidget from "../basic_widget.js"; | import BasicWidget from "../basic_widget.js"; | ||||||
| import dialogService from "../../services/dialog.js"; | import dialogService from "../../services/dialog.js"; | ||||||
|  | import options from "../../services/options.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="revisions-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | <div class="revisions-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | ||||||
| @@ -66,6 +67,11 @@ const TPL = ` | |||||||
|                     <div class="revision-content"></div> |                     <div class="revision-content"></div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  |             <div class="modal-footer py-0"> | ||||||
|  |                 <span class="revisions-snapshot-interval flex-grow-1 my-0 py-0"></span> | ||||||
|  |                 <span class="maximum-revisions-for-current-note flex-grow-1 my-0 py-0"></span> | ||||||
|  |                 <button class="revision-settings-button icon-action bx bx-cog my-0 py-0" title="${t("revisions.settings")}"></button> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </div>`; | </div>`; | ||||||
| @@ -85,20 +91,29 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|  |  | ||||||
|         this.$list = this.$widget.find(".revision-list"); |         this.$list = this.$widget.find(".revision-list"); | ||||||
|         this.$listDropdown = this.$widget.find(".revision-list-dropdown"); |         this.$listDropdown = this.$widget.find(".revision-list-dropdown"); | ||||||
|  |         this.listDropdown = bootstrap.Dropdown.getOrCreateInstance(this.$listDropdown); | ||||||
|         this.$content = this.$widget.find(".revision-content"); |         this.$content = this.$widget.find(".revision-content"); | ||||||
|         this.$title = this.$widget.find(".revision-title"); |         this.$title = this.$widget.find(".revision-title"); | ||||||
|         this.$titleButtons = this.$widget.find(".revision-title-buttons"); |         this.$titleButtons = this.$widget.find(".revision-title-buttons"); | ||||||
|         this.$eraseAllRevisionsButton = this.$widget.find(".revisions-erase-all-revisions-button"); |         this.$eraseAllRevisionsButton = this.$widget.find(".revisions-erase-all-revisions-button"); | ||||||
|  |         this.$snapshotInterval = this.$widget.find(".revisions-snapshot-interval"); | ||||||
|         this.$listDropdown.dropdown(); |         this.$maximumRevisions = this.$widget.find(".maximum-revisions-for-current-note"); | ||||||
|  |         this.$revisionSettingsButton = this.$widget.find(".revision-settings-button") | ||||||
|  |         this.listDropdown.show(); | ||||||
|  |  | ||||||
|         this.$listDropdown.parent().on('hide.bs.dropdown', e => { |         this.$listDropdown.parent().on('hide.bs.dropdown', e => { | ||||||
|             // prevent closing dropdown by clicking outside |             // Prevent closing dropdown by pressing ESC and clicking outside | ||||||
|             if (e.clickEvent) { |  | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|             } |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         document.addEventListener('keydown', e => { | ||||||
|  |             // Close the revision dialog when revision element is focused and ESC is pressed | ||||||
|  |             if (e.key === 'Escape' || | ||||||
|  |                 e.target.classList.contains(['dropdown-item', 'active'])) { | ||||||
|  |                 this.modal.hide(); | ||||||
|  |             } | ||||||
|  |         }, true) | ||||||
|  |  | ||||||
|         this.$widget.on('shown.bs.modal', () => { |         this.$widget.on('shown.bs.modal', () => { | ||||||
|             this.$list.find(`[data-revision-id="${this.revisionId}"]`) |             this.$list.find(`[data-revision-id="${this.revisionId}"]`) | ||||||
|                 .trigger('focus'); |                 .trigger('focus'); | ||||||
| @@ -116,11 +131,6 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         this.$list.on('click', '.dropdown-item', e => { |  | ||||||
|             e.preventDefault(); |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         this.$list.on('focus', '.dropdown-item', e => { |         this.$list.on('focus', '.dropdown-item', e => { | ||||||
|             this.$list.find('.dropdown-item').each((i, el) => { |             this.$list.find('.dropdown-item').each((i, el) => { | ||||||
|                 $(el).toggleClass('active', el === e.target); |                 $(el).toggleClass('active', el === e.target); | ||||||
| @@ -128,6 +138,10 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|  |  | ||||||
|             this.setContentPane(); |             this.setContentPane(); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         this.$revisionSettingsButton.on('click', async () => { | ||||||
|  |             appContext.tabManager.openContextWithNote('_optionsOther', { activate: true }); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async showRevisionsEvent({ noteId = appContext.tabManager.getActiveContextNoteId() }) { |     async showRevisionsEvent({ noteId = appContext.tabManager.getActiveContextNoteId() }) { | ||||||
| @@ -153,7 +167,7 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.$listDropdown.dropdown('show'); |         this.listDropdown.show(); | ||||||
|  |  | ||||||
|         if (this.revisionItems.length > 0) { |         if (this.revisionItems.length > 0) { | ||||||
|             if (!this.revisionId) { |             if (!this.revisionId) { | ||||||
| @@ -165,6 +179,17 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0); |         this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0); | ||||||
|  |  | ||||||
|  |         // Show the footer of the revisions dialog | ||||||
|  |         this.$snapshotInterval.text(t("revisions.snapshot_interval", { seconds: options.getInt('revisionSnapshotTimeInterval') })) | ||||||
|  |         let revisionsNumberLimit = parseInt(this.note.getLabelValue("versioningLimit") ?? ""); | ||||||
|  |         if (!Number.isInteger(revisionsNumberLimit)) { | ||||||
|  |             revisionsNumberLimit = parseInt(options.getInt('revisionSnapshotNumberLimit')); | ||||||
|  |         } | ||||||
|  |         if (revisionsNumberLimit === -1) { | ||||||
|  |             revisionsNumberLimit = "∞" | ||||||
|  |         } | ||||||
|  |         this.$maximumRevisions.text(t("revisions.maximum_revisions", { number: revisionsNumberLimit })) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async setContentPane() { |     async setContentPane() { | ||||||
| @@ -245,12 +270,20 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|         } else if (revisionItem.type === 'code') { |         } else if (revisionItem.type === 'code') { | ||||||
|             this.$content.html($("<pre>").text(fullRevision.content)); |             this.$content.html($("<pre>").text(fullRevision.content)); | ||||||
|         } else if (revisionItem.type === 'image') { |         } else if (revisionItem.type === 'image') { | ||||||
|  |             if (fullRevision.mime === "image/svg+xml") { | ||||||
|  |                 let encodedSVG = encodeURIComponent(fullRevision.content); //Base64 of other format images may be embedded in svg | ||||||
|  |                 this.$content.html($("<img>") | ||||||
|  |                     .attr("src", `data:${fullRevision.mime};utf8,${encodedSVG}`) | ||||||
|  |                     .css("max-width", "100%") | ||||||
|  |                     .css("max-height", "100%")); | ||||||
|  |             } else { | ||||||
|                 this.$content.html($("<img>") |                 this.$content.html($("<img>") | ||||||
|                     // the reason why we put this inline as base64 is that we do not want to let user copy this |                     // the reason why we put this inline as base64 is that we do not want to let user copy this | ||||||
|                     // as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be uploaded as a new note |                     // as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be uploaded as a new note | ||||||
|                     .attr("src", `data:${fullRevision.mime};base64,${fullRevision.content}`) |                     .attr("src", `data:${fullRevision.mime};base64,${fullRevision.content}`) | ||||||
|                     .css("max-width", "100%") |                     .css("max-width", "100%") | ||||||
|                     .css("max-height", "100%")); |                     .css("max-height", "100%")); | ||||||
|  |             } | ||||||
|         } else if (revisionItem.type === 'file') { |         } else if (revisionItem.type === 'file') { | ||||||
|             const $table = $("<table cellpadding='10'>") |             const $table = $("<table cellpadding='10'>") | ||||||
|                 .append($("<tr>").append( |                 .append($("<tr>").append( | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ import SearchEngineOptions from "./options/other/search_engine.js"; | |||||||
| import TrayOptions from "./options/other/tray.js"; | import TrayOptions from "./options/other/tray.js"; | ||||||
| import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | ||||||
| import RevisionsSnapshotIntervalOptions from "./options/other/revisions_snapshot_interval.js"; | import RevisionsSnapshotIntervalOptions from "./options/other/revisions_snapshot_interval.js"; | ||||||
|  | import RevisionSnapshotsLimitOptions from "./options/other/revision_snapshots_limit.js"; | ||||||
| import NetworkConnectionsOptions from "./options/other/network_connections.js"; | import NetworkConnectionsOptions from "./options/other/network_connections.js"; | ||||||
| import AdvancedSyncOptions from "./options/advanced/sync.js"; | import AdvancedSyncOptions from "./options/advanced/sync.js"; | ||||||
| import DatabaseIntegrityCheckOptions from "./options/advanced/database_integrity_check.js"; | import DatabaseIntegrityCheckOptions from "./options/advanced/database_integrity_check.js"; | ||||||
| @@ -88,6 +89,7 @@ const CONTENT_WIDGETS = { | |||||||
|         NoteErasureTimeoutOptions, |         NoteErasureTimeoutOptions, | ||||||
|         AttachmentErasureTimeoutOptions, |         AttachmentErasureTimeoutOptions, | ||||||
|         RevisionsSnapshotIntervalOptions, |         RevisionsSnapshotIntervalOptions, | ||||||
|  |         RevisionSnapshotsLimitOptions, | ||||||
|         NetworkConnectionsOptions |         NetworkConnectionsOptions | ||||||
|     ], |     ], | ||||||
|     _optionsAdvanced: [ |     _optionsAdvanced: [ | ||||||
|   | |||||||
| @@ -0,0 +1,42 @@ | |||||||
|  | import OptionsWidget from "../options_widget.js"; | ||||||
|  | import { t } from "../../../../services/i18n.js"; | ||||||
|  | import server from "../../../../services/server.js"; | ||||||
|  | import toastService from "../../../../services/toast.js"; | ||||||
|  |  | ||||||
|  | const TPL = ` | ||||||
|  | <div class="options-section"> | ||||||
|  |     <h4>${t("revisions_snapshot_limit.note_revisions_snapshot_limit_title")}</h4> | ||||||
|  |  | ||||||
|  |     <p>${t("revisions_snapshot_limit.note_revisions_snapshot_limit_description")}</p> | ||||||
|  |  | ||||||
|  |     <div class="form-group"> | ||||||
|  |         <label>${t("revisions_snapshot_limit.snapshot_number_limit_label")}</label> | ||||||
|  |         <input class="revision-snapshot-number-limit form-control options-number-input" type="number" min="-1"> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <button class="erase-excess-revision-snapshots-now-button btn btn-sm" style="padding: 0 10px"> | ||||||
|  |                     ${t('revisions_snapshot_limit.erase_excess_revision_snapshots')}</button> | ||||||
|  | </div>`; | ||||||
|  |  | ||||||
|  | export default class RevisionSnapshotsLimitOptions extends OptionsWidget { | ||||||
|  |     doRender() { | ||||||
|  |         this.$widget = $(TPL); | ||||||
|  |         this.$revisionSnapshotsNumberLimit = this.$widget.find(".revision-snapshot-number-limit"); | ||||||
|  |         this.$revisionSnapshotsNumberLimit.on('change', () => { | ||||||
|  |             let revisionSnapshotNumberLimit = this.$revisionSnapshotsNumberLimit.val(); | ||||||
|  |             if (!isNaN(revisionSnapshotNumberLimit) && revisionSnapshotNumberLimit >= -1) { | ||||||
|  |                 this.updateOption('revisionSnapshotNumberLimit', revisionSnapshotNumberLimit) | ||||||
|  |             }  | ||||||
|  |         }); | ||||||
|  |         this.$eraseExcessRevisionSnapshotsButton = this.$widget.find(".erase-excess-revision-snapshots-now-button"); | ||||||
|  |         this.$eraseExcessRevisionSnapshotsButton.on('click', () => { | ||||||
|  |             server.post('revisions/erase-all-excess-revisions').then(() => { | ||||||
|  |                 toastService.showMessage(t("revisions_snapshot_limit.erase_excess_revision_snapshots_prompt")); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async optionsLoaded(options) { | ||||||
|  |         this.$revisionSnapshotsNumberLimit.val(options.revisionSnapshotNumberLimit); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -247,6 +247,9 @@ | |||||||
|     "revisions_deleted": "Note revisions has been deleted.", |     "revisions_deleted": "Note revisions has been deleted.", | ||||||
|     "revision_restored": "Note revision has been restored.", |     "revision_restored": "Note revision has been restored.", | ||||||
|     "revision_deleted": "Note revision has been deleted.", |     "revision_deleted": "Note revision has been deleted.", | ||||||
|  |     "snapshot_interval":"Note Revisions Snapshot Interval: {{seconds}}s.", | ||||||
|  |     "maximum_revisions":"Maximum revisions for current note: {{number}}.", | ||||||
|  |     "settings":"Settings for Note revisions.", | ||||||
|     "download_button": "Download", |     "download_button": "Download", | ||||||
|     "mime": "MIME: ", |     "mime": "MIME: ", | ||||||
|     "file_size": "File size:", |     "file_size": "File size:", | ||||||
| @@ -1088,7 +1091,14 @@ | |||||||
|   "revisions_snapshot_interval": { |   "revisions_snapshot_interval": { | ||||||
|     "note_revisions_snapshot_interval_title": "Note Revisions Snapshot Interval", |     "note_revisions_snapshot_interval_title": "Note Revisions Snapshot Interval", | ||||||
|     "note_revisions_snapshot_description": "Note revision snapshot time interval is time in seconds after which a new note revision will be created for the note. See <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki</a> for more info.", |     "note_revisions_snapshot_description": "Note revision snapshot time interval is time in seconds after which a new note revision will be created for the note. See <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki</a> for more info.", | ||||||
|     "snapshot_time_interval_label": "Note revision snapshot time interval (in seconds)" |     "snapshot_time_interval_label": "Note revision snapshot time interval (in seconds):" | ||||||
|  |   }, | ||||||
|  |   "revisions_snapshot_limit": { | ||||||
|  |     "note_revisions_snapshot_limit_title": "Note Revision Snapshots Limit", | ||||||
|  |     "note_revisions_snapshot_limit_description": "The note revision snapshot number limit refers to the maximum number of revisions that can be saved for each note. Where -1 means no limit, 0 means delete all revisions. You can set the maximum revisions for a single note through the #versioningLimit label.", | ||||||
|  |     "snapshot_number_limit_label": "Note revision snapshot number limit:", | ||||||
|  |     "erase_excess_revision_snapshots": "Erase excess revision snapshots now", | ||||||
|  |     "erase_excess_revision_snapshots_prompt": "Excess revision snapshots have been erased." | ||||||
|   }, |   }, | ||||||
|   "search_engine": { |   "search_engine": { | ||||||
|     "title": "Search Engine", |     "title": "Search Engine", | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ const ALLOWED_OPTIONS = new Set([ | |||||||
|     'eraseEntitiesAfterTimeInSeconds', |     'eraseEntitiesAfterTimeInSeconds', | ||||||
|     'protectedSessionTimeout', |     'protectedSessionTimeout', | ||||||
|     'revisionSnapshotTimeInterval', |     'revisionSnapshotTimeInterval', | ||||||
|  |     'revisionSnapshotNumberLimit', | ||||||
|     'zoomFactor', |     'zoomFactor', | ||||||
|     'theme', |     'theme', | ||||||
|     'syncServerHost', |     'syncServerHost', | ||||||
|   | |||||||
| @@ -112,6 +112,13 @@ function eraseRevision(req: Request) { | |||||||
|     eraseService.eraseRevisions([req.params.revisionId]); |     eraseService.eraseRevisions([req.params.revisionId]); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function eraseAllExcessRevisions() { | ||||||
|  |     let allNoteIds = sql.getRows("SELECT noteId FROM notes WHERE SUBSTRING(noteId, 1, 1) != '_'") as { noteId: string }[]; | ||||||
|  |     allNoteIds.forEach(row => { | ||||||
|  |         becca.getNote(row.noteId)?.eraseExcessRevisionSnapshots() | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
| function restoreRevision(req: Request) { | function restoreRevision(req: Request) { | ||||||
|     const revision = becca.getRevision(req.params.revisionId); |     const revision = becca.getRevision(req.params.revisionId); | ||||||
|  |  | ||||||
| @@ -139,6 +146,8 @@ function restoreRevision(req: Request) { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             note.title = revision.title; |             note.title = revision.title; | ||||||
|  |             note.mime = revision.mime; | ||||||
|  |             note.type = revision.type as any; | ||||||
|             note.setContent(revisionContent, { forceSave: true }); |             note.setContent(revisionContent, { forceSave: true }); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @@ -211,6 +220,7 @@ export default { | |||||||
|     downloadRevision, |     downloadRevision, | ||||||
|     getEditedNotesOnDate, |     getEditedNotesOnDate, | ||||||
|     eraseAllRevisions, |     eraseAllRevisions, | ||||||
|  |     eraseAllExcessRevisions, | ||||||
|     eraseRevision, |     eraseRevision, | ||||||
|     restoreRevision |     restoreRevision | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -184,6 +184,7 @@ function register(app: express.Application) { | |||||||
|  |  | ||||||
|     apiRoute(GET, '/api/notes/:noteId/revisions', revisionsApiRoute.getRevisions); |     apiRoute(GET, '/api/notes/:noteId/revisions', revisionsApiRoute.getRevisions); | ||||||
|     apiRoute(DEL, '/api/notes/:noteId/revisions', revisionsApiRoute.eraseAllRevisions); |     apiRoute(DEL, '/api/notes/:noteId/revisions', revisionsApiRoute.eraseAllRevisions); | ||||||
|  |     apiRoute(PST, '/api/revisions/erase-all-excess-revisions', revisionsApiRoute.eraseAllExcessRevisions); | ||||||
|     apiRoute(GET, '/api/revisions/:revisionId', revisionsApiRoute.getRevision); |     apiRoute(GET, '/api/revisions/:revisionId', revisionsApiRoute.getRevision); | ||||||
|     apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob); |     apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob); | ||||||
|     apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision); |     apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision); | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ async function initNotSyncedOptions(initialized: boolean, theme: string, opts: N | |||||||
|  |  | ||||||
| const defaultOptions: DefaultOption[] = [ | const defaultOptions: DefaultOption[] = [ | ||||||
|     { name: 'revisionSnapshotTimeInterval', value: '600', isSynced: true }, |     { name: 'revisionSnapshotTimeInterval', value: '600', isSynced: true }, | ||||||
|  |     { name: 'revisionSnapshotNumberLimit', value: '-1', isSynced: true }, | ||||||
|     { name: 'protectedSessionTimeout', value: '600', isSynced: true }, |     { name: 'protectedSessionTimeout', value: '600', isSynced: true }, | ||||||
|     { name: 'zoomFactor', value: process.platform === "win32" ? '0.9' : '1.0', isSynced: false }, |     { name: 'zoomFactor', value: process.platform === "win32" ? '0.9' : '1.0', isSynced: false }, | ||||||
|     { name: 'overrideThemeFonts', value: 'false', isSynced: false }, |     { name: 'overrideThemeFonts', value: 'false', isSynced: false }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user