1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-04-01 21:24:45 +02:00

Desktop: Allow restoring a delete note from note history using command palette

This commit is contained in:
Laurent Cozic 2021-06-10 11:49:20 +02:00
parent 00dc1d881b
commit 5fd6571bf1
6 changed files with 48 additions and 4 deletions

View File

@ -140,6 +140,9 @@ packages/app-desktop/commands/openProfileDirectory.js.map
packages/app-desktop/commands/replaceMisspelling.d.ts packages/app-desktop/commands/replaceMisspelling.d.ts
packages/app-desktop/commands/replaceMisspelling.js packages/app-desktop/commands/replaceMisspelling.js
packages/app-desktop/commands/replaceMisspelling.js.map packages/app-desktop/commands/replaceMisspelling.js.map
packages/app-desktop/commands/restoreNoteRevision.d.ts
packages/app-desktop/commands/restoreNoteRevision.js
packages/app-desktop/commands/restoreNoteRevision.js.map
packages/app-desktop/commands/startExternalEditing.d.ts packages/app-desktop/commands/startExternalEditing.d.ts
packages/app-desktop/commands/startExternalEditing.js packages/app-desktop/commands/startExternalEditing.js
packages/app-desktop/commands/startExternalEditing.js.map packages/app-desktop/commands/startExternalEditing.js.map

3
.gitignore vendored
View File

@ -126,6 +126,9 @@ packages/app-desktop/commands/openProfileDirectory.js.map
packages/app-desktop/commands/replaceMisspelling.d.ts packages/app-desktop/commands/replaceMisspelling.d.ts
packages/app-desktop/commands/replaceMisspelling.js packages/app-desktop/commands/replaceMisspelling.js
packages/app-desktop/commands/replaceMisspelling.js.map packages/app-desktop/commands/replaceMisspelling.js.map
packages/app-desktop/commands/restoreNoteRevision.d.ts
packages/app-desktop/commands/restoreNoteRevision.js
packages/app-desktop/commands/restoreNoteRevision.js.map
packages/app-desktop/commands/startExternalEditing.d.ts packages/app-desktop/commands/startExternalEditing.d.ts
packages/app-desktop/commands/startExternalEditing.js packages/app-desktop/commands/startExternalEditing.js
packages/app-desktop/commands/startExternalEditing.js.map packages/app-desktop/commands/startExternalEditing.js.map

View File

@ -96,6 +96,7 @@ const globalCommands = [
require('./commands/stopExternalEditing'), require('./commands/stopExternalEditing'),
require('./commands/toggleExternalEditing'), require('./commands/toggleExternalEditing'),
require('./commands/toggleSafeMode'), require('./commands/toggleSafeMode'),
require('./commands/restoreNoteRevision'),
require('@joplin/lib/commands/historyBackward'), require('@joplin/lib/commands/historyBackward'),
require('@joplin/lib/commands/historyForward'), require('@joplin/lib/commands/historyForward'),
require('@joplin/lib/commands/synchronize'), require('@joplin/lib/commands/synchronize'),

View File

@ -0,0 +1,20 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import RevisionService from '@joplin/lib/services/RevisionService';
export const declaration: CommandDeclaration = {
name: 'restoreNoteRevision',
label: 'Restore a note from history',
};
export const runtime = (): CommandRuntime => {
return {
execute: async (_context: CommandContext, noteId: string, reverseRevIndex: number = 0) => {
try {
const note = await RevisionService.instance().restoreNoteById(noteId, reverseRevIndex);
alert(RevisionService.instance().restoreSuccessMessage(note));
} catch (error) {
alert(error.message);
}
},
};
};

View File

@ -13,7 +13,7 @@ const shared = require('@joplin/lib/components/shared/note-screen-shared.js');
const { MarkupToHtml } = require('@joplin/renderer'); const { MarkupToHtml } = require('@joplin/renderer');
const time = require('@joplin/lib/time').default; const time = require('@joplin/lib/time').default;
const ReactTooltip = require('react-tooltip'); const ReactTooltip = require('react-tooltip');
const { urlDecode, substrWithEllipsis } = require('@joplin/lib/string-utils'); const { urlDecode } = require('@joplin/lib/string-utils');
const bridge = require('electron').remote.require('./bridge').default; const bridge = require('electron').remote.require('./bridge').default;
const markupLanguageUtils = require('../utils/markupLanguageUtils').default; const markupLanguageUtils = require('../utils/markupLanguageUtils').default;
@ -75,7 +75,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
this.setState({ restoring: true }); this.setState({ restoring: true });
await RevisionService.instance().importRevisionNote(this.state.note); await RevisionService.instance().importRevisionNote(this.state.note);
this.setState({ restoring: false }); this.setState({ restoring: false });
alert(_('The note "%s" has been successfully restored to the notebook "%s".', substrWithEllipsis(this.state.note.title, 0, 32), RevisionService.instance().restoreFolderTitle())); alert(RevisionService.instance().restoreSuccessMessage(this.state.note));
} }
backButton_click() { backButton_click() {

View File

@ -9,6 +9,7 @@ import shim from '../shim';
import BaseService from './BaseService'; import BaseService from './BaseService';
import { _ } from '../locale'; import { _ } from '../locale';
import { ItemChangeEntity, NoteEntity, RevisionEntity } from './database/types'; import { ItemChangeEntity, NoteEntity, RevisionEntity } from './database/types';
const { substrWithEllipsis } = require('../string-utils');
const { sprintf } = require('sprintf-js'); const { sprintf } = require('sprintf-js');
const { wrapError } = require('../errorUtils'); const { wrapError } = require('../errorUtils');
@ -230,7 +231,23 @@ export default class RevisionService extends BaseService {
return folder; return folder;
} }
async importRevisionNote(note: NoteEntity) { // reverseRevIndex = 0 means restoring the latest version. reverseRevIndex =
// 1 means the version before that, etc.
public async restoreNoteById(noteId: string, reverseRevIndex: number): Promise<NoteEntity> {
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, noteId);
if (!revisions.length) throw new Error(`No revision for note "${noteId}"`);
const revIndex = revisions.length - 1 - reverseRevIndex;
const note = await this.revisionNote(revisions, revIndex);
return this.importRevisionNote(note);
}
public restoreSuccessMessage(note: NoteEntity): string {
return _('The note "%s" has been successfully restored to the notebook "%s".', substrWithEllipsis(note.title, 0, 32), this.restoreFolderTitle());
}
async importRevisionNote(note: NoteEntity): Promise<NoteEntity> {
const toImport = Object.assign({}, note); const toImport = Object.assign({}, note);
delete toImport.id; delete toImport.id;
delete toImport.updated_time; delete toImport.updated_time;
@ -242,7 +259,7 @@ export default class RevisionService extends BaseService {
toImport.parent_id = folder.id; toImport.parent_id = folder.id;
await Note.save(toImport); return Note.save(toImport);
} }
async maintenance() { async maintenance() {