You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	This commit is contained in:
		| @@ -209,7 +209,6 @@ packages/app-desktop/gui/MainScreen/MainScreen.js | |||||||
| packages/app-desktop/gui/MainScreen/commands/addProfile.js | packages/app-desktop/gui/MainScreen/commands/addProfile.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/commandPalette.js | packages/app-desktop/gui/MainScreen/commands/commandPalette.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/deleteFolder.js | packages/app-desktop/gui/MainScreen/commands/deleteFolder.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/deleteNote.js |  | ||||||
| packages/app-desktop/gui/MainScreen/commands/duplicateNote.js | packages/app-desktop/gui/MainScreen/commands/duplicateNote.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/editAlarm.js | packages/app-desktop/gui/MainScreen/commands/editAlarm.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/exportPdf.js | packages/app-desktop/gui/MainScreen/commands/exportPdf.js | ||||||
| @@ -228,7 +227,6 @@ packages/app-desktop/gui/MainScreen/commands/openItem.js | |||||||
| packages/app-desktop/gui/MainScreen/commands/openNote.js | packages/app-desktop/gui/MainScreen/commands/openNote.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/openPdfViewer.js | packages/app-desktop/gui/MainScreen/commands/openPdfViewer.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/openTag.js | packages/app-desktop/gui/MainScreen/commands/openTag.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/permanentlyDeleteNote.js |  | ||||||
| packages/app-desktop/gui/MainScreen/commands/print.js | packages/app-desktop/gui/MainScreen/commands/print.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/renameFolder.js | packages/app-desktop/gui/MainScreen/commands/renameFolder.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/renameTag.js | packages/app-desktop/gui/MainScreen/commands/renameTag.js | ||||||
| @@ -921,10 +919,12 @@ packages/lib/array.js | |||||||
| packages/lib/callbackUrlUtils.test.js | packages/lib/callbackUrlUtils.test.js | ||||||
| packages/lib/callbackUrlUtils.js | packages/lib/callbackUrlUtils.js | ||||||
| packages/lib/clipperUtils.js | packages/lib/clipperUtils.js | ||||||
|  | packages/lib/commands/deleteNote.js | ||||||
| packages/lib/commands/historyBackward.js | packages/lib/commands/historyBackward.js | ||||||
| packages/lib/commands/historyForward.js | packages/lib/commands/historyForward.js | ||||||
| packages/lib/commands/index.js | packages/lib/commands/index.js | ||||||
| packages/lib/commands/openMasterPasswordDialog.js | packages/lib/commands/openMasterPasswordDialog.js | ||||||
|  | packages/lib/commands/permanentlyDeleteNote.js | ||||||
| packages/lib/commands/synchronize.js | packages/lib/commands/synchronize.js | ||||||
| packages/lib/components/EncryptionConfigScreen/utils.test.js | packages/lib/components/EncryptionConfigScreen/utils.test.js | ||||||
| packages/lib/components/EncryptionConfigScreen/utils.js | packages/lib/components/EncryptionConfigScreen/utils.js | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -186,7 +186,6 @@ packages/app-desktop/gui/MainScreen/MainScreen.js | |||||||
| packages/app-desktop/gui/MainScreen/commands/addProfile.js | packages/app-desktop/gui/MainScreen/commands/addProfile.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/commandPalette.js | packages/app-desktop/gui/MainScreen/commands/commandPalette.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/deleteFolder.js | packages/app-desktop/gui/MainScreen/commands/deleteFolder.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/deleteNote.js |  | ||||||
| packages/app-desktop/gui/MainScreen/commands/duplicateNote.js | packages/app-desktop/gui/MainScreen/commands/duplicateNote.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/editAlarm.js | packages/app-desktop/gui/MainScreen/commands/editAlarm.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/exportPdf.js | packages/app-desktop/gui/MainScreen/commands/exportPdf.js | ||||||
| @@ -205,7 +204,6 @@ packages/app-desktop/gui/MainScreen/commands/openItem.js | |||||||
| packages/app-desktop/gui/MainScreen/commands/openNote.js | packages/app-desktop/gui/MainScreen/commands/openNote.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/openPdfViewer.js | packages/app-desktop/gui/MainScreen/commands/openPdfViewer.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/openTag.js | packages/app-desktop/gui/MainScreen/commands/openTag.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/permanentlyDeleteNote.js |  | ||||||
| packages/app-desktop/gui/MainScreen/commands/print.js | packages/app-desktop/gui/MainScreen/commands/print.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/renameFolder.js | packages/app-desktop/gui/MainScreen/commands/renameFolder.js | ||||||
| packages/app-desktop/gui/MainScreen/commands/renameTag.js | packages/app-desktop/gui/MainScreen/commands/renameTag.js | ||||||
| @@ -898,10 +896,12 @@ packages/lib/array.js | |||||||
| packages/lib/callbackUrlUtils.test.js | packages/lib/callbackUrlUtils.test.js | ||||||
| packages/lib/callbackUrlUtils.js | packages/lib/callbackUrlUtils.js | ||||||
| packages/lib/clipperUtils.js | packages/lib/clipperUtils.js | ||||||
|  | packages/lib/commands/deleteNote.js | ||||||
| packages/lib/commands/historyBackward.js | packages/lib/commands/historyBackward.js | ||||||
| packages/lib/commands/historyForward.js | packages/lib/commands/historyForward.js | ||||||
| packages/lib/commands/index.js | packages/lib/commands/index.js | ||||||
| packages/lib/commands/openMasterPasswordDialog.js | packages/lib/commands/openMasterPasswordDialog.js | ||||||
|  | packages/lib/commands/permanentlyDeleteNote.js | ||||||
| packages/lib/commands/synchronize.js | packages/lib/commands/synchronize.js | ||||||
| packages/lib/components/EncryptionConfigScreen/utils.test.js | packages/lib/components/EncryptionConfigScreen/utils.test.js | ||||||
| packages/lib/components/EncryptionConfigScreen/utils.js | packages/lib/components/EncryptionConfigScreen/utils.js | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| import * as addProfile from './addProfile'; | import * as addProfile from './addProfile'; | ||||||
| import * as commandPalette from './commandPalette'; | import * as commandPalette from './commandPalette'; | ||||||
| import * as deleteFolder from './deleteFolder'; | import * as deleteFolder from './deleteFolder'; | ||||||
| import * as deleteNote from './deleteNote'; |  | ||||||
| import * as duplicateNote from './duplicateNote'; | import * as duplicateNote from './duplicateNote'; | ||||||
| import * as editAlarm from './editAlarm'; | import * as editAlarm from './editAlarm'; | ||||||
| import * as exportPdf from './exportPdf'; | import * as exportPdf from './exportPdf'; | ||||||
| @@ -20,7 +19,6 @@ import * as openItem from './openItem'; | |||||||
| import * as openNote from './openNote'; | import * as openNote from './openNote'; | ||||||
| import * as openPdfViewer from './openPdfViewer'; | import * as openPdfViewer from './openPdfViewer'; | ||||||
| import * as openTag from './openTag'; | import * as openTag from './openTag'; | ||||||
| import * as permanentlyDeleteNote from './permanentlyDeleteNote'; |  | ||||||
| import * as print from './print'; | import * as print from './print'; | ||||||
| import * as renameFolder from './renameFolder'; | import * as renameFolder from './renameFolder'; | ||||||
| import * as renameTag from './renameTag'; | import * as renameTag from './renameTag'; | ||||||
| @@ -52,7 +50,6 @@ const index: any[] = [ | |||||||
| 	addProfile, | 	addProfile, | ||||||
| 	commandPalette, | 	commandPalette, | ||||||
| 	deleteFolder, | 	deleteFolder, | ||||||
| 	deleteNote, |  | ||||||
| 	duplicateNote, | 	duplicateNote, | ||||||
| 	editAlarm, | 	editAlarm, | ||||||
| 	exportPdf, | 	exportPdf, | ||||||
| @@ -70,7 +67,6 @@ const index: any[] = [ | |||||||
| 	openNote, | 	openNote, | ||||||
| 	openPdfViewer, | 	openPdfViewer, | ||||||
| 	openTag, | 	openTag, | ||||||
| 	permanentlyDeleteNote, |  | ||||||
| 	print, | 	print, | ||||||
| 	renameFolder, | 	renameFolder, | ||||||
| 	renameTag, | 	renameTag, | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ import ItemChange from '@joplin/lib/models/ItemChange'; | |||||||
| import { getDisplayParentId } from '@joplin/lib/services/trash'; | import { getDisplayParentId } from '@joplin/lib/services/trash'; | ||||||
| import { itemIsReadOnlySync, ItemSlice } from '@joplin/lib/models/utils/readOnly'; | import { itemIsReadOnlySync, ItemSlice } from '@joplin/lib/models/utils/readOnly'; | ||||||
| import { LayoutChangeEvent } from 'react-native'; | import { LayoutChangeEvent } from 'react-native'; | ||||||
|  | import shim from '@joplin/lib/shim'; | ||||||
|  |  | ||||||
| interface WrapperProps { | interface WrapperProps { | ||||||
| } | } | ||||||
| @@ -140,6 +141,24 @@ describe('Note', () => { | |||||||
| 		}); | 		}); | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
|  | 	it('pressing "delete permanently" should permanently delete a note', async () => { | ||||||
|  | 		const noteId = await openNewNote({ title: 'To be deleted', body: '...', deleted_time: Date.now() }); | ||||||
|  | 		render(<WrappedNoteScreen />); | ||||||
|  |  | ||||||
|  | 		// Permanently delete note shows a confirmation dialog -- mock it. | ||||||
|  | 		const deleteId = 0; | ||||||
|  | 		shim.showMessageBox = jest.fn(async () => deleteId); | ||||||
|  |  | ||||||
|  | 		await openNoteActionsMenu(); | ||||||
|  | 		const deleteButton = await screen.findByText('Permanently delete note'); | ||||||
|  | 		fireEvent.press(deleteButton); | ||||||
|  |  | ||||||
|  | 		await waitFor(async () => { | ||||||
|  | 			expect(await Note.load(noteId)).toBeUndefined(); | ||||||
|  | 		}); | ||||||
|  | 		expect(shim.showMessageBox).toHaveBeenCalled(); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
| 	it('delete should be disabled in a read-only note', async () => { | 	it('delete should be disabled in a read-only note', async () => { | ||||||
| 		const shareId = 'testShare'; | 		const shareId = 'testShare'; | ||||||
| 		const noteId = await openNewNote({ | 		const noteId = await openNewNote({ | ||||||
|   | |||||||
| @@ -627,21 +627,6 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | |||||||
| 		await shared.saveOneProperty(this, name, value); | 		await shared.saveOneProperty(this, name, value); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private async deleteNote_onPress() { |  | ||||||
| 		const note = this.state.note; |  | ||||||
| 		if (!note.id) return; |  | ||||||
|  |  | ||||||
| 		const folderId = note.parent_id; |  | ||||||
|  |  | ||||||
| 		await Note.delete(note.id, { toTrash: true, sourceDescription: 'Delete note button' }); |  | ||||||
|  |  | ||||||
| 		this.props.dispatch({ |  | ||||||
| 			type: 'NAV_GO', |  | ||||||
| 			routeName: 'Notes', |  | ||||||
| 			folderId: folderId, |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private async pickDocuments() { | 	private async pickDocuments() { | ||||||
| 		const result = await pickDocument({ multiple: true }); | 		const result = await pickDocument({ multiple: true }); | ||||||
| 		return result; | 		return result; | ||||||
| @@ -1283,30 +1268,33 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | |||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		output.push({ | 		const commandService = CommandService.instance(); | ||||||
| 			title: _('Delete'), | 		const whenContext = commandService.currentWhenClauseContext(); | ||||||
| 			onPress: () => { | 		const addButtonFromCommand = (commandName: string, title?: string) => { | ||||||
| 				void this.deleteNote_onPress(); | 			if (commandName === '-') { | ||||||
| 			}, | 				output.push({ isDivider: true }); | ||||||
| 			disabled: readOnly, | 			} else { | ||||||
| 		}); | 				output.push({ | ||||||
|  | 					title: title ?? commandService.description(commandName), | ||||||
|  | 					onPress: async () => { | ||||||
|  | 						void commandService.execute(commandName); | ||||||
|  | 					}, | ||||||
|  | 					disabled: !commandService.isEnabled(commandName, whenContext), | ||||||
|  | 				}); | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		if (whenContext.inTrash) { | ||||||
|  | 			addButtonFromCommand('permanentlyDeleteNote'); | ||||||
|  | 		} else { | ||||||
|  | 			addButtonFromCommand('deleteNote', _('Delete')); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (pluginCommands.length) { | 		if (pluginCommands.length) { | ||||||
| 			output.push({ isDivider: true }); | 			output.push({ isDivider: true }); | ||||||
|  |  | ||||||
| 			const commandService = CommandService.instance(); |  | ||||||
| 			for (const commandName of pluginCommands) { | 			for (const commandName of pluginCommands) { | ||||||
| 				if (commandName === '-') { | 				addButtonFromCommand(commandName); | ||||||
| 					output.push({ isDivider: true }); |  | ||||||
| 				} else { |  | ||||||
| 					output.push({ |  | ||||||
| 						title: commandService.description(commandName), |  | ||||||
| 						onPress: async () => { |  | ||||||
| 							void commandService.execute(commandName); |  | ||||||
| 						}, |  | ||||||
| 						disabled: !commandService.isEnabled(commandName), |  | ||||||
| 					}); |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; | import { CommandRuntime, CommandDeclaration, CommandContext } from '../services/CommandService'; | ||||||
| import { _ } from '@joplin/lib/locale'; | import { _ } from '../locale'; | ||||||
| import Note from '@joplin/lib/models/Note'; | import Note from '../models/Note'; | ||||||
| 
 | 
 | ||||||
| export const declaration: CommandDeclaration = { | export const declaration: CommandDeclaration = { | ||||||
| 	name: 'deleteNote', | 	name: 'deleteNote', | ||||||
| @@ -1,13 +1,17 @@ | |||||||
| // AUTO-GENERATED using `gulp buildScriptIndexes` | // AUTO-GENERATED using `gulp buildScriptIndexes` | ||||||
|  | import * as deleteNote from './deleteNote'; | ||||||
| import * as historyBackward from './historyBackward'; | import * as historyBackward from './historyBackward'; | ||||||
| import * as historyForward from './historyForward'; | import * as historyForward from './historyForward'; | ||||||
| import * as openMasterPasswordDialog from './openMasterPasswordDialog'; | import * as openMasterPasswordDialog from './openMasterPasswordDialog'; | ||||||
|  | import * as permanentlyDeleteNote from './permanentlyDeleteNote'; | ||||||
| import * as synchronize from './synchronize'; | import * as synchronize from './synchronize'; | ||||||
|  |  | ||||||
| const index: any[] = [ | const index: any[] = [ | ||||||
|  | 	deleteNote, | ||||||
| 	historyBackward, | 	historyBackward, | ||||||
| 	historyForward, | 	historyForward, | ||||||
| 	openMasterPasswordDialog, | 	openMasterPasswordDialog, | ||||||
|  | 	permanentlyDeleteNote, | ||||||
| 	synchronize, | 	synchronize, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; | import { CommandRuntime, CommandDeclaration, CommandContext } from '../services/CommandService'; | ||||||
| import { _ } from '@joplin/lib/locale'; | import { _ } from '../locale'; | ||||||
| import Note from '@joplin/lib/models/Note'; | import Note from '../models/Note'; | ||||||
| import bridge from '../../../services/bridge'; | import shim from '../shim'; | ||||||
| 
 | 
 | ||||||
| export const declaration: CommandDeclaration = { | export const declaration: CommandDeclaration = { | ||||||
| 	name: 'permanentlyDeleteNote', | 	name: 'permanentlyDeleteNote', | ||||||
| @@ -16,12 +16,15 @@ export const runtime = (): CommandRuntime => { | |||||||
| 			if (!noteIds.length) return; | 			if (!noteIds.length) return; | ||||||
| 			const msg = await Note.permanentlyDeleteMessage(noteIds); | 			const msg = await Note.permanentlyDeleteMessage(noteIds); | ||||||
| 
 | 
 | ||||||
| 			const ok = bridge().showConfirmMessageBox(msg, { | 			const deleteIndex = 0; | ||||||
|  | 			const result = await shim.showMessageBox(msg, { | ||||||
| 				buttons: [_('Delete'), _('Cancel')], | 				buttons: [_('Delete'), _('Cancel')], | ||||||
| 				defaultId: 1, | 				defaultId: 1, | ||||||
|  | 				cancelId: 1, | ||||||
|  | 				type: 'question', | ||||||
| 			}); | 			}); | ||||||
| 
 | 
 | ||||||
| 			if (ok) { | 			if (result === deleteIndex) { | ||||||
| 				await Note.batchDelete(noteIds, { toTrash: false, sourceDescription: 'permanentlyDeleteNote command' }); | 				await Note.batchDelete(noteIds, { toTrash: false, sourceDescription: 'permanentlyDeleteNote command' }); | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -280,19 +280,32 @@ shared.initState = async function(comp: BaseNoteScreenComponent) { | |||||||
| 		comp.scheduleFocusUpdate(); | 		comp.scheduleFocusUpdate(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	const folder = Folder.byId(comp.props.folders, note.parent_id); | 	const fromShare = !!comp.props.sharedData; | ||||||
|  | 	if (note) { | ||||||
| 	comp.setState({ | 		const folder = Folder.byId(comp.props.folders, note.parent_id); | ||||||
| 		lastSavedNote: { ...note }, | 		comp.setState({ | ||||||
| 		note: note, | 			lastSavedNote: { ...note }, | ||||||
| 		mode: mode, | 			note: note, | ||||||
| 		folder: folder, | 			mode: mode, | ||||||
| 		isLoading: false, | 			folder: folder, | ||||||
| 		fromShare: !!comp.props.sharedData, | 			isLoading: false, | ||||||
| 		noteResources: await shared.attachedResources(note ? note.body : ''), | 			fromShare: !!comp.props.sharedData, | ||||||
| 		readOnly: itemIsReadOnlySync(ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note as ItemSlice, Setting.value('sync.userId'), BaseItem.syncShareCache), | 			noteResources: await shared.attachedResources(note ? note.body : ''), | ||||||
| 	}); | 			readOnly: itemIsReadOnlySync(ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note as ItemSlice, Setting.value('sync.userId'), BaseItem.syncShareCache), | ||||||
|  | 		}); | ||||||
|  | 	} else { | ||||||
|  | 		// Handle the case where a non-existent note is loaded. This can happen briefly after deleting a note. | ||||||
|  | 		comp.setState({ | ||||||
|  | 			lastSavedNote: {}, | ||||||
|  | 			note: {}, | ||||||
|  | 			mode, | ||||||
|  | 			folder: null, | ||||||
|  | 			isLoading: true, | ||||||
|  | 			fromShare, | ||||||
|  | 			noteResources: [], | ||||||
|  | 			readOnly: true, | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (comp.props.sharedData) { | 	if (comp.props.sharedData) { | ||||||
| 		if (comp.props.sharedData.title) { | 		if (comp.props.sharedData.title) { | ||||||
| @@ -315,7 +328,7 @@ shared.initState = async function(comp: BaseNoteScreenComponent) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// eslint-disable-next-line require-atomic-updates | 	// eslint-disable-next-line require-atomic-updates | ||||||
| 	comp.lastLoadedNoteId_ = note.id; | 	comp.lastLoadedNoteId_ = note?.id; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| shared.toggleIsTodo_onPress = function(comp: BaseNoteScreenComponent) { | shared.toggleIsTodo_onPress = function(comp: BaseNoteScreenComponent) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user