You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Merge branch 'release-3.0' into dev
This commit is contained in:
		| @@ -204,7 +204,7 @@ class Application extends BaseApplication { | ||||
| 	public updateEditorFont() { | ||||
| 		const fontFamilies = []; | ||||
| 		if (Setting.value('style.editor.fontFamily')) fontFamilies.push(`"${Setting.value('style.editor.fontFamily')}"`); | ||||
| 		fontFamilies.push('Avenir, Arial, sans-serif'); | ||||
| 		fontFamilies.push('\'Avenir Next\', Avenir, Arial, sans-serif'); | ||||
|  | ||||
| 		// The '*' and '!important' parts are necessary to make sure Russian text is displayed properly | ||||
| 		// https://github.com/laurent22/joplin/issues/155 | ||||
|   | ||||
| @@ -104,10 +104,17 @@ const useOnKeyDown = ( | ||||
| 			event.preventDefault(); | ||||
| 		} | ||||
|  | ||||
| 		if (noteIds.length && (key === 'Delete' || (key === 'Backspace' && event.metaKey))) { | ||||
| 			event.preventDefault(); | ||||
| 			if (CommandService.instance().isEnabled('deleteNote')) { | ||||
| 				void CommandService.instance().execute('deleteNote', noteIds); | ||||
| 		if (noteIds.length) { | ||||
| 			if (key === 'Delete' && event.shiftKey) { | ||||
| 				event.preventDefault(); | ||||
| 				if (CommandService.instance().isEnabled('permanentlyDeleteNote')) { | ||||
| 					void CommandService.instance().execute('permanentlyDeleteNote', noteIds); | ||||
| 				} | ||||
| 			} else if (key === 'Delete' || (key === 'Backspace' && event.metaKey)) { | ||||
| 				event.preventDefault(); | ||||
| 				if (CommandService.instance().isEnabled('deleteNote')) { | ||||
| 					void CommandService.instance().execute('deleteNote', noteIds); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { useMemo } from 'react'; | ||||
| import { FolderListItem, HeaderId, HeaderListItem, ListItem, ListItemType, TagListItem } from '../types'; | ||||
| import { FolderEntity, TagsWithNoteCountEntity } from '@joplin/lib/services/database/types'; | ||||
| import { renderFolders, renderTags } from '@joplin/lib/components/shared/side-menu-shared'; | ||||
| import { buildFolderTree, renderFolders, renderTags } from '@joplin/lib/components/shared/side-menu-shared'; | ||||
| import { _ } from '@joplin/lib/locale'; | ||||
| import CommandService from '@joplin/lib/services/CommandService'; | ||||
| import Setting from '@joplin/lib/models/Setting'; | ||||
| @@ -35,10 +35,13 @@ const useSidebarListData = (props: Props): ListItem[] => { | ||||
| 		}); | ||||
| 	}, [props.tags]); | ||||
|  | ||||
| 	const folderTree = useMemo(() => { | ||||
| 		return buildFolderTree(props.folders); | ||||
| 	}, [props.folders]); | ||||
|  | ||||
| 	const folderItems = useMemo(() => { | ||||
| 		const renderProps = { | ||||
| 			folders: props.folders, | ||||
| 			folderTree, | ||||
| 			collapsedFolderIds: props.collapsedFolderIds, | ||||
| 		}; | ||||
| 		return renderFolders<ListItem>(renderProps, (folder, hasChildren, depth): FolderListItem => { | ||||
| @@ -50,7 +53,7 @@ const useSidebarListData = (props: Props): ListItem[] => { | ||||
| 				key: folder.id, | ||||
| 			}; | ||||
| 		}); | ||||
| 	}, [props.folders, props.collapsedFolderIds]); | ||||
| 	}, [folderTree, props.collapsedFolderIds]); | ||||
|  | ||||
| 	return useMemo(() => { | ||||
| 		const foldersHeader: HeaderListItem = { | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import { test, expect } from './util/test'; | ||||
| import MainScreen from './models/MainScreen'; | ||||
| import activateMainMenuItem from './util/activateMainMenuItem'; | ||||
| import setMessageBoxResponse from './util/setMessageBoxResponse'; | ||||
|  | ||||
| test.describe('noteList', () => { | ||||
| 	test('should be possible to edit notes in a different notebook when searching', async ({ mainWindow }) => { | ||||
| @@ -35,4 +37,42 @@ test.describe('noteList', () => { | ||||
| 		// Updating the title should force the sidebar to update sooner | ||||
| 		await expect(editor.noteTitleInput).toHaveValue('note-1'); | ||||
| 	}); | ||||
|  | ||||
| 	test('shift-delete should ask to permanently delete notes, but only when the note list is focused', async ({ electronApp, mainWindow }) => { | ||||
| 		const mainScreen = new MainScreen(mainWindow); | ||||
| 		const sidebar = mainScreen.sidebar; | ||||
|  | ||||
| 		const folderBHeader = await sidebar.createNewFolder('Folder B'); | ||||
| 		const folderAHeader = await sidebar.createNewFolder('Folder A'); | ||||
| 		await expect(folderAHeader).toBeVisible(); | ||||
|  | ||||
| 		await mainScreen.createNewNote('test note 1'); | ||||
| 		await mainScreen.createNewNote('test note 2'); | ||||
|  | ||||
| 		await activateMainMenuItem(electronApp, 'Note list', 'Focus'); | ||||
| 		await expect(mainScreen.noteListContainer.getByText('test note 1')).toBeVisible(); | ||||
|  | ||||
| 		await setMessageBoxResponse(electronApp, /^Delete/i); | ||||
|  | ||||
| 		const pressShiftDelete = async () => { | ||||
| 			await mainWindow.keyboard.press('Shift'); | ||||
| 			await mainWindow.keyboard.press('Delete'); | ||||
| 			await mainWindow.keyboard.up('Delete'); | ||||
| 			await mainWindow.keyboard.up('Shift'); | ||||
| 		}; | ||||
| 		await pressShiftDelete(); | ||||
|  | ||||
| 		await folderBHeader.click(); | ||||
| 		await folderAHeader.click(); | ||||
| 		await expect(mainScreen.noteListContainer.getByText('test note 2')).not.toBeVisible(); | ||||
|  | ||||
| 		// Should not delete when the editor is focused | ||||
| 		await mainScreen.noteEditor.focusCodeMirrorEditor(); | ||||
| 		await mainWindow.keyboard.type('test'); | ||||
| 		await pressShiftDelete(); | ||||
|  | ||||
| 		await folderBHeader.click(); | ||||
| 		await folderAHeader.click(); | ||||
| 		await expect(mainScreen.noteListContainer.getByText('test note 1')).toBeVisible(); | ||||
| 	}); | ||||
| }); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@joplin/app-desktop", | ||||
|   "version": "3.0.12", | ||||
|   "version": "3.0.13", | ||||
|   "description": "Joplin for Desktop", | ||||
|   "main": "main.js", | ||||
|   "private": true, | ||||
|   | ||||
| @@ -79,8 +79,8 @@ android { | ||||
|         applicationId "net.cozic.joplin" | ||||
|         minSdkVersion rootProject.ext.minSdkVersion | ||||
|         targetSdkVersion rootProject.ext.targetSdkVersion | ||||
| 		versionCode 2097746 | ||||
| 		versionName "3.0.7" | ||||
| 		versionCode 2097747 | ||||
| 		versionName "3.0.8" | ||||
| 		ndk { | ||||
| 			abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" | ||||
| 		} | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import Synchronizer from '@joplin/lib/Synchronizer'; | ||||
| import NavService from '@joplin/lib/services/NavService'; | ||||
| import { _ } from '@joplin/lib/locale'; | ||||
| import { ThemeStyle, themeStyle } from './global-style'; | ||||
| import { isFolderSelected, renderFolders } from '@joplin/lib/components/shared/side-menu-shared'; | ||||
| import { buildFolderTree, isFolderSelected, renderFolders } from '@joplin/lib/components/shared/side-menu-shared'; | ||||
| import { FolderEntity, FolderIcon, FolderIconType } from '@joplin/lib/services/database/types'; | ||||
| import { AppState } from '../utils/types'; | ||||
| import Setting from '@joplin/lib/models/Setting'; | ||||
| @@ -560,8 +560,16 @@ const SideMenuContentComponent = (props: Props) => { | ||||
|  | ||||
| 	items.push(renderSidebarButton('folder_header', _('Notebooks'), 'folder')); | ||||
|  | ||||
| 	const folderTree = useMemo(() => { | ||||
| 		return buildFolderTree(props.folders); | ||||
| 	}, [props.folders]); | ||||
|  | ||||
| 	if (props.folders.length) { | ||||
| 		const result = renderFolders(props, renderFolderItem); | ||||
| 		const result = renderFolders({ | ||||
| 			folderTree, | ||||
| 			collapsedFolderIds: props.collapsedFolderIds, | ||||
| 		}, renderFolderItem); | ||||
|  | ||||
| 		const folderItems = result.items; | ||||
| 		items = items.concat(folderItems); | ||||
| 	} | ||||
|   | ||||
| @@ -503,13 +503,13 @@ | ||||
| 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
| 				CLANG_ENABLE_MODULES = YES; | ||||
| 				CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; | ||||
| 				CURRENT_PROJECT_VERSION = 119; | ||||
| 				CURRENT_PROJECT_VERSION = 120; | ||||
| 				DEVELOPMENT_TEAM = A9BXAFS6CT; | ||||
| 				ENABLE_BITCODE = NO; | ||||
| 				INFOPLIST_FILE = Joplin/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 13.4; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | ||||
| 				MARKETING_VERSION = 13.0.5; | ||||
| 				MARKETING_VERSION = 13.0.6; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"$(inherited)", | ||||
| 					"-ObjC", | ||||
| @@ -534,12 +534,12 @@ | ||||
| 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
| 				CLANG_ENABLE_MODULES = YES; | ||||
| 				CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; | ||||
| 				CURRENT_PROJECT_VERSION = 119; | ||||
| 				CURRENT_PROJECT_VERSION = 120; | ||||
| 				DEVELOPMENT_TEAM = A9BXAFS6CT; | ||||
| 				INFOPLIST_FILE = Joplin/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 13.4; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | ||||
| 				MARKETING_VERSION = 13.0.5; | ||||
| 				MARKETING_VERSION = 13.0.6; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"$(inherited)", | ||||
| 					"-ObjC", | ||||
| @@ -724,14 +724,14 @@ | ||||
| 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; | ||||
| 				CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; | ||||
| 				CODE_SIGN_STYLE = Automatic; | ||||
| 				CURRENT_PROJECT_VERSION = 119; | ||||
| 				CURRENT_PROJECT_VERSION = 120; | ||||
| 				DEBUG_INFORMATION_FORMAT = dwarf; | ||||
| 				DEVELOPMENT_TEAM = A9BXAFS6CT; | ||||
| 				GCC_C_LANGUAGE_STANDARD = gnu11; | ||||
| 				INFOPLIST_FILE = ShareExtension/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 13.4; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; | ||||
| 				MARKETING_VERSION = 13.0.5; | ||||
| 				MARKETING_VERSION = 13.0.6; | ||||
| 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; | ||||
| 				MTL_FAST_MATH = YES; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| @@ -762,14 +762,14 @@ | ||||
| 				CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; | ||||
| 				CODE_SIGN_STYLE = Automatic; | ||||
| 				COPY_PHASE_STRIP = NO; | ||||
| 				CURRENT_PROJECT_VERSION = 119; | ||||
| 				CURRENT_PROJECT_VERSION = 120; | ||||
| 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||||
| 				DEVELOPMENT_TEAM = A9BXAFS6CT; | ||||
| 				GCC_C_LANGUAGE_STANDARD = gnu11; | ||||
| 				INFOPLIST_FILE = ShareExtension/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 13.4; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; | ||||
| 				MARKETING_VERSION = 13.0.5; | ||||
| 				MARKETING_VERSION = 13.0.6; | ||||
| 				MTL_FAST_MATH = YES; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"$(inherited)", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { FolderEntity } from '../../services/database/types'; | ||||
| import { getTrashFolder, getTrashFolderId } from '../../services/trash'; | ||||
| import { renderFolders } from './side-menu-shared'; | ||||
| import { buildFolderTree, renderFolders } from './side-menu-shared'; | ||||
|  | ||||
| const renderItem = (folder: FolderEntity, hasChildren: boolean, depth: number) => { | ||||
| 	return [folder.id, hasChildren, depth]; | ||||
| @@ -86,8 +86,52 @@ describe('side-menu-shared', () => { | ||||
| 				order: ['1', getTrashFolderId(), '2'], | ||||
| 			}, | ||||
| 		], | ||||
| 	])('should render folders', (props, expected) => { | ||||
| 		const actual = renderFolders(props, renderItem); | ||||
|  | ||||
| 		// Should not render id: 4 because it's contained within the child of a collapsed folder. | ||||
| 		[ | ||||
| 			{ | ||||
| 				collapsedFolderIds: ['2'], | ||||
| 				folders: [ | ||||
| 					{ | ||||
| 						id: '1', | ||||
| 						parent_id: '', | ||||
| 						deleted_time: 0, | ||||
| 					}, | ||||
| 					{ | ||||
| 						id: '2', | ||||
| 						parent_id: '', | ||||
| 						deleted_time: 0, | ||||
| 					}, | ||||
| 					{ | ||||
| 						id: '3', | ||||
| 						parent_id: '2', | ||||
| 						deleted_time: 0, | ||||
| 					}, | ||||
| 					{ | ||||
| 						id: '4', | ||||
| 						parent_id: '3', | ||||
| 						deleted_time: 0, | ||||
| 					}, | ||||
| 					getTrashFolder(), | ||||
| 				], | ||||
| 				notesParentType: 'Folder', | ||||
| 				selectedFolderId: '', | ||||
| 				selectedTagId: '', | ||||
| 			}, | ||||
| 			{ | ||||
| 				items: [ | ||||
| 					['1', false, 0], | ||||
| 					['2', true, 0], | ||||
| 					[getTrashFolderId(), false, 0], | ||||
| 				], | ||||
| 				order: ['1', '2', getTrashFolderId()], | ||||
| 			}, | ||||
| 		], | ||||
| 	])('should render folders (case %#)', (props, expected) => { | ||||
| 		const actual = renderFolders({ | ||||
| 			folderTree: buildFolderTree(props.folders), | ||||
| 			collapsedFolderIds: props.collapsedFolderIds, | ||||
| 		}, renderItem); | ||||
| 		expect(actual).toEqual(expected); | ||||
| 	}); | ||||
|  | ||||
|   | ||||
| @@ -1,39 +1,10 @@ | ||||
| import Folder from '../../models/Folder'; | ||||
| import BaseModel from '../../BaseModel'; | ||||
| import { FolderEntity, TagEntity, TagsWithNoteCountEntity } from '../../services/database/types'; | ||||
| import { getDisplayParentId, getTrashFolderId } from '../../services/trash'; | ||||
| import { getDisplayParentId } from '../../services/trash'; | ||||
| import { getCollator } from '../../models/utils/getCollator'; | ||||
|  | ||||
| export type RenderFolderItem<T> = (folder: FolderEntity, hasChildren: boolean, depth: number)=> T; | ||||
| export type RenderTagItem<T> = (tag: TagsWithNoteCountEntity)=> T; | ||||
|  | ||||
| function folderHasChildren_(folders: FolderEntity[], folderId: string) { | ||||
| 	if (folderId === getTrashFolderId()) { | ||||
| 		return !!folders.find(f => !!f.deleted_time); | ||||
| 	} | ||||
|  | ||||
| 	for (let i = 0; i < folders.length; i++) { | ||||
| 		const folder = folders[i]; | ||||
| 		const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id)); | ||||
| 		if (folderParentId === folderId) return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| function folderIsCollapsed(folders: FolderEntity[], folderId: string, collapsedFolderIds: string[]) { | ||||
| 	if (!collapsedFolderIds || !collapsedFolderIds.length) return false; | ||||
|  | ||||
| 	while (true) { | ||||
| 		const folder: FolderEntity = BaseModel.byId(folders, folderId); | ||||
| 		if (!folder) throw new Error(`No folder with id ${folder.id}`); | ||||
| 		const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id)); | ||||
| 		if (!folderParentId) return false; | ||||
| 		if (collapsedFolderIds.indexOf(folderParentId) >= 0) return true; | ||||
| 		folderId = folderParentId; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| interface FolderSelectedContext { | ||||
| 	selectedFolderId: string; | ||||
| 	notesParentType: string; | ||||
| @@ -48,21 +19,36 @@ type ItemsWithOrder<ItemType> = { | ||||
| 	order: string[]; | ||||
| }; | ||||
|  | ||||
| interface RenderFoldersProps { | ||||
| interface FolderTree { | ||||
| 	folders: FolderEntity[]; | ||||
| 	parentIdToChildren: Map<string, FolderEntity[]>; | ||||
| 	idToItem: Map<string, FolderEntity>; | ||||
| } | ||||
|  | ||||
| interface RenderFoldersProps { | ||||
| 	folderTree: FolderTree; | ||||
| 	collapsedFolderIds: string[]; | ||||
| } | ||||
|  | ||||
| function folderIsCollapsed(context: RenderFoldersProps, folderId: string) { | ||||
| 	if (!context.collapsedFolderIds || !context.collapsedFolderIds.length) return false; | ||||
|  | ||||
| 	while (true) { | ||||
| 		const folder = context.folderTree.idToItem.get(folderId); | ||||
| 		const folderParentId = getDisplayParentId(folder, context.folderTree.idToItem.get(folder.parent_id)); | ||||
| 		if (!folderParentId) return false; | ||||
| 		if (context.collapsedFolderIds.includes(folderParentId)) return true; | ||||
| 		folderId = folderParentId; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| function renderFoldersRecursive_<T>(props: RenderFoldersProps, renderItem: RenderFolderItem<T>, items: T[], parentId: string, depth: number, order: string[]): ItemsWithOrder<T> { | ||||
| 	const folders = props.folders; | ||||
| 	for (let i = 0; i < folders.length; i++) { | ||||
| 		const folder = folders[i]; | ||||
| 	const folders = props.folderTree.parentIdToChildren.get(parentId ?? '') ?? []; | ||||
| 	const parentIdToChildren = props.folderTree.parentIdToChildren; | ||||
| 	for (const folder of folders) { | ||||
| 		if (folderIsCollapsed(props, folder.id)) continue; | ||||
|  | ||||
| 		const folderParentId = getDisplayParentId(folder, props.folders.find(f => f.id === folder.parent_id)); | ||||
|  | ||||
| 		if (!Folder.idsEqual(folderParentId, parentId)) continue; | ||||
| 		if (folderIsCollapsed(props.folders, folder.id, props.collapsedFolderIds)) continue; | ||||
| 		const hasChildren = folderHasChildren_(folders, folder.id); | ||||
| 		const hasChildren = parentIdToChildren.has(folder.id); | ||||
| 		order.push(folder.id); | ||||
| 		items.push(renderItem(folder, hasChildren, depth)); | ||||
| 		if (hasChildren) { | ||||
| @@ -81,6 +67,24 @@ export const renderFolders = <T> (props: RenderFoldersProps, renderItem: RenderF | ||||
| 	return renderFoldersRecursive_(props, renderItem, [], '', 0, []); | ||||
| }; | ||||
|  | ||||
| export const buildFolderTree = (folders: FolderEntity[]): FolderTree => { | ||||
| 	const idToItem = new Map<string, FolderEntity>(); | ||||
| 	for (const folder of folders) { | ||||
| 		idToItem.set(folder.id, folder); | ||||
| 	} | ||||
|  | ||||
| 	const parentIdToChildren = new Map<string, FolderEntity[]>(); | ||||
| 	for (const folder of folders) { | ||||
| 		const displayParentId = getDisplayParentId(folder, idToItem.get(folder.parent_id)) ?? ''; | ||||
| 		if (!parentIdToChildren.has(displayParentId)) { | ||||
| 			parentIdToChildren.set(displayParentId, []); | ||||
| 		} | ||||
| 		parentIdToChildren.get(displayParentId).push(folder); | ||||
| 	} | ||||
|  | ||||
| 	return { folders, parentIdToChildren, idToItem }; | ||||
| }; | ||||
|  | ||||
| const sortTags = (tags: TagEntity[]) => { | ||||
| 	tags = tags.slice(); | ||||
| 	const collator = getCollator(); | ||||
|   | ||||
| @@ -108,7 +108,6 @@ const defaultKeymapItems = { | ||||
| 		{ accelerator: 'Ctrl+Alt+1', command: 'switchProfile1' }, | ||||
| 		{ accelerator: 'Ctrl+Alt+2', command: 'switchProfile2' }, | ||||
| 		{ accelerator: 'Ctrl+Alt+3', command: 'switchProfile3' }, | ||||
| 		{ accelerator: 'Shift+Delete', command: 'permanentlyDeleteNote' }, | ||||
| 	], | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -58,7 +58,7 @@ export default function(theme: any, options: Options = null) { | ||||
|  | ||||
| 	theme = theme ? theme : {}; | ||||
|  | ||||
| 	const fontFamily = '\'Avenir\', \'Arial\', sans-serif'; | ||||
| 	const fontFamily = '\'Avenir Next\', \'Avenir\', \'Arial\', sans-serif'; | ||||
|  | ||||
| 	const maxWidthTarget = options.contentMaxWidthTarget ? options.contentMaxWidthTarget : '#rendered-md'; | ||||
| 	const maxWidthCss = options.contentMaxWidth ? ` | ||||
|   | ||||
| @@ -269,7 +269,9 @@ function filterLogs(logs: LogEntry[], platform: Platform) { | ||||
| 		// but that's not useful in a changelog especially since most people | ||||
| 		// don't know country and language codes. So we catch all these and | ||||
| 		// bundle them all up in a single "Updated translations" at the end. | ||||
| 		if (log.message.match(/Translation:\sUpdate\s.*?(\.po|[a-zA-Z][a-zA-Z]|[a-zA-Z][a-zA-Z]_[a-zA-Z][a-zA-Z])/)) { | ||||
| 		if (log.message.match(/Translation:\sUpdate\s.*?(\.po|[a-zA-Z][a-zA-Z]|[a-zA-Z][a-zA-Z]_[a-zA-Z][a-zA-Z])/) | ||||
| 			|| log.message.match(/Update.+\.po/) | ||||
| 		) { | ||||
| 			// updatedTranslations = true; | ||||
| 			addIt = false; | ||||
| 		} | ||||
|   | ||||
| @@ -7,6 +7,8 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: Joplin-CLI 1.0.0\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: \n" | ||||
| "PO-Revision-Date: \n" | ||||
| "Last-Translator: cedecode <christoph.eder@phsalzburg.at>\n" | ||||
| "Language-Team: \n" | ||||
| "Language: de_DE\n" | ||||
| @@ -484,7 +486,7 @@ msgid "" | ||||
| "Any email sent to this address will be converted into a note and added to " | ||||
| "your collection. The note will be saved into the Inbox notebook" | ||||
| msgstr "" | ||||
| "Jede an diese Adresse gerichtete E-Mail wird zu einer Notiz konvertiert und " | ||||
| "Jedes an diese Adresse gerichtete Email wird zu einer Notiz umgewandelt und " | ||||
| "deiner Kollektion hinzugefügt. Die Notiz wird im Inbox-Notizbuch gespeichert" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2804 | ||||
| @@ -1208,7 +1210,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Es konnte keine Verbindung zum Joplin-Server hergestellt werden. Bitte " | ||||
| "überprüfe die Synchronisationsoptionen in der Konfigurationsmaske. " | ||||
| "Vollständiger Fehler war:\n" | ||||
| "Vollständiger Fehler:\n" | ||||
| "\n" | ||||
| "%s" | ||||
|  | ||||
| @@ -1250,12 +1252,12 @@ msgid "" | ||||
| "again when you are connected to the internet." | ||||
| msgstr "" | ||||
| "Der Freigabestatus dieses Notizbuchs konnte nicht überprüft werden - Vorgang " | ||||
| "wird abgebrochen. Bitte versuche es erneut, wenn eine Internetverbindung " | ||||
| "abgebrochen. Bitte versuche es erneut, sobald eine Internetverbindung " | ||||
| "besteht." | ||||
|  | ||||
| #: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:20 | ||||
| msgid "Could not verify your identity: %s" | ||||
| msgstr "Konnte deine Identität nicht verifizieren: %s" | ||||
| msgstr "Konnte deine Identität nicht überprüfen: %s" | ||||
|  | ||||
| #: packages/app-desktop/gui/PromptDialog.tsx:301 | ||||
| msgid "Create" | ||||
| @@ -1492,7 +1494,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Das Inbox-Notizbuch löschen?\n" | ||||
| "\n" | ||||
| "Wenn du das Inbox-Notizbuch löschst, gehen in ihm gespeicherte E-Mails " | ||||
| "Wenn du das Inbox-Notizbuch löschst, gehen kürzlich dort eingegangene Emails " | ||||
| "möglicherweise verloren." | ||||
|  | ||||
| #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:245 | ||||
| @@ -1854,25 +1856,25 @@ msgstr "Emacs" | ||||
| #: packages/server/src/routes/admin/emails.ts:127 | ||||
| #: packages/server/src/routes/admin/users.ts:140 | ||||
| msgid "Email" | ||||
| msgstr "E-Mail" | ||||
| msgstr "Email" | ||||
|  | ||||
| #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:47 | ||||
| #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:23 | ||||
| msgid "Email to note" | ||||
| msgstr "E-Mail zu Notiz" | ||||
| msgstr "Email zu Notiz" | ||||
|  | ||||
| #: packages/lib/utils/joplinCloud/index.ts:187 | ||||
| msgid "Email to Note" | ||||
| msgstr "E-Mail zu Notiz" | ||||
| msgstr "Email zu Notiz" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2843 | ||||
| msgid "Email To Note, login information" | ||||
| msgstr "E-Mail zu Notiz, Login-Informationen" | ||||
| msgstr "Email zu Notiz, Login-Informationen" | ||||
|  | ||||
| #: packages/server/src/routes/admin/emails.ts:111 | ||||
| #: packages/server/src/services/MustacheService.ts:133 | ||||
| msgid "Emails" | ||||
| msgstr "E-Mails" | ||||
| msgstr "Emails" | ||||
|  | ||||
| #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:191 | ||||
| msgid "emphasised text" | ||||
| @@ -1983,7 +1985,7 @@ msgstr "Weiche Zeilenumbrüche aktivieren" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1110 | ||||
| msgid "Enable spellcheck in the text editor" | ||||
| msgstr "Aktiviere die Rechtschreibprüfung im Text-Editor" | ||||
| msgstr "Aktiviere die Rechtschreibprüfung im Texteditor" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1276 | ||||
| msgid "Enable table of contents extension" | ||||
| @@ -2017,8 +2019,8 @@ msgid "" | ||||
| "Enabling encryption means *all* your notes and attachments are going to be " | ||||
| "re-synchronised and sent encrypted to the sync target." | ||||
| msgstr "" | ||||
| "Durch die Aktivierung der Verschlüsselung werden *alle* Notizen und Anhänge " | ||||
| "neu synchronisiert und verschlüsselt an das Synchronisationsziel gesendet." | ||||
| "Durch Aktivierung der Verschlüsselung werden *alle* Notizen und Anhänge neu " | ||||
| "synchronisiert und verschlüsselt an das Synchronisationsziel gesendet." | ||||
|  | ||||
| #: packages/lib/models/BaseItem.ts:913 | ||||
| msgid "Encrypted" | ||||
| @@ -2849,7 +2851,7 @@ msgstr "Joplin Server" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:709 | ||||
| msgid "Joplin Server email" | ||||
| msgstr "Joplin Server E-Mail" | ||||
| msgstr "Joplin Server-Email" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:721 | ||||
| msgid "Joplin Server password" | ||||
| @@ -2864,7 +2866,7 @@ msgid "" | ||||
| "Joplin Web Clipper allows saving web pages and screenshots from your browser " | ||||
| "to Joplin." | ||||
| msgstr "" | ||||
| "Joplin Web-Clipper ermöglicht das Speichern von Webseiten und Screenshots " | ||||
| "Joplin Web Clipper ermöglicht das Speichern von Webseiten und Screenshots " | ||||
| "aus deinem Browser in Joplin." | ||||
|  | ||||
| #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:612 | ||||
| @@ -3052,9 +3054,8 @@ msgid "Log" | ||||
| msgstr "Protokoll" | ||||
|  | ||||
| #: packages/app-desktop/gui/MainScreen/MainScreen.tsx:698 | ||||
| #, fuzzy | ||||
| msgid "Login to Joplin Cloud." | ||||
| msgstr "Mit Joplin Cloud verbinden" | ||||
| msgstr "Mit Joplin Cloud verbinden." | ||||
|  | ||||
| #: packages/app-mobile/components/screens/dropbox-login.js:55 | ||||
| msgid "Login with Dropbox" | ||||
| @@ -3202,7 +3203,7 @@ msgstr "Mobile Daten - Auto-Synchronisierung deaktiviert" | ||||
|  | ||||
| #: packages/app-desktop/gui/MainScreen/MainScreen.tsx:667 | ||||
| msgid "More info" | ||||
| msgstr "Weitere Information" | ||||
| msgstr "Weitere Infos" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2817 | ||||
| msgid "More information" | ||||
| @@ -3211,7 +3212,8 @@ msgstr "Weitere Informationen" | ||||
| #: packages/app-cli/app/app.ts:67 | ||||
| msgid "More than one item match \"%s\". Please narrow down your query." | ||||
| msgstr "" | ||||
| "Mehr als ein Element stimmt mit „%s“ überein. Bitte schränke deine Suche ein." | ||||
| "Mehr als ein Element stimmt mit „%s“ überein. Bitte schränke deine " | ||||
| "Suchabfrage ein." | ||||
|  | ||||
| #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:115 | ||||
| msgid "" | ||||
| @@ -3266,7 +3268,7 @@ msgstr "N" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1189 | ||||
| msgid "Never resize" | ||||
| msgstr "Größe niemals anpassen" | ||||
| msgstr "Größe nie anpassen" | ||||
|  | ||||
| #: packages/app-desktop/gui/Sidebar/listItemComponents/HeaderItem.tsx:46 | ||||
| msgid "New" | ||||
| @@ -3341,7 +3343,7 @@ msgstr "Nextcloud-WebDAV-URL" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:418 | ||||
| msgid "no" | ||||
| msgstr "Nein" | ||||
| msgstr "nein" | ||||
|  | ||||
| #: packages/app-desktop/services/plugins/UserWebviewDialogButtonBar.tsx:32 | ||||
| #: packages/app-mobile/components/screens/Note.tsx:747 | ||||
| @@ -3402,8 +3404,8 @@ msgstr "Kein Tab ausgewählt" | ||||
| msgid "" | ||||
| "No text editor is defined. Please set it using `config editor <editor-path>`" | ||||
| msgstr "" | ||||
| "Kein Texteditor festgelegt. Bitte stelle einen mit `config editor <Pfad-Zum-" | ||||
| "Texteditor>` ein" | ||||
| "Kein Texteditor festgelegt. Bitte wähle einen mit `config editor <Pfad-Zum-" | ||||
| "Texteditor>`" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:435 | ||||
| msgid "Nord" | ||||
| @@ -3440,11 +3442,11 @@ msgstr "Notiz" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1805 | ||||
| msgid "Note area growth factor" | ||||
| msgstr "Notiz-Flächenwachstumsfaktor" | ||||
| msgstr "Notizbereich-Wachstumsfaktor" | ||||
|  | ||||
| #: packages/app-desktop/gui/Root.tsx:233 | ||||
| msgid "Note attachments" | ||||
| msgstr "Anhänge" | ||||
| msgstr "Notiz-Anhänge" | ||||
|  | ||||
| #: packages/app-desktop/gui/MenuBar.tsx:561 | ||||
| msgid "Note attachments..." | ||||
| @@ -3481,7 +3483,7 @@ msgstr "Notizliste" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1790 | ||||
| msgid "Note list growth factor" | ||||
| msgstr "Notiz-Listenwachstumsfaktor" | ||||
| msgstr "Notizlisten-Wachstumsfaktor" | ||||
|  | ||||
| #: packages/app-desktop/gui/MenuBar.tsx:781 | ||||
| msgid "Note list style" | ||||
| @@ -3498,18 +3500,18 @@ msgstr "Notiz-Titel" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1297 | ||||
| msgid "Note: Does not work in all desktop environments." | ||||
| msgstr "Hinweis: Funktioniert nicht in allen Desktopumgebungen." | ||||
| msgstr "Hinweis: Funktioniert nicht in allen Desktop-Umgebungen." | ||||
|  | ||||
| #: packages/app-desktop/gui/ShareNoteDialog.tsx:192 | ||||
| msgid "" | ||||
| "Note: When a note is shared, it will no longer be encrypted on the server." | ||||
| msgstr "" | ||||
| "Achtung: Wenn eine Notiz geteilt wird, wird sie auf dem Server nicht mehr " | ||||
| "Hinweis: Wenn eine Notiz geteilt wird, wird sie auf dem Server nicht länger " | ||||
| "verschlüsselt sein." | ||||
|  | ||||
| #: packages/app-desktop/gui/MenuBar.tsx:860 | ||||
| msgid "Note&book" | ||||
| msgstr "Notizbücher" | ||||
| msgstr "Notiz&bücher" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2806 | ||||
| msgid "Notebook" | ||||
| @@ -3898,8 +3900,8 @@ msgid "" | ||||
| "can extend Joplin's editor, viewer, and more." | ||||
| msgstr "" | ||||
| "Mit Erweiterungen lassen sich in Joplin zusätzliche Funktionen hinzufügen, " | ||||
| "die standardmäßig nicht verfügbar sind. Sie können den Editor, die Ansicht " | ||||
| "und vieles mehr erweitern." | ||||
| "die standardmäßig nicht verfügbar sind. Erweiterungen können den Editor, die " | ||||
| "Ansicht und vieles mehr ergänzen." | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1543 | ||||
| msgid "Portrait" | ||||
| @@ -4570,11 +4572,11 @@ msgstr "Mehr Aktionen anzeigen" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:952 | ||||
| msgid "Show note counts" | ||||
| msgstr "Notizanzahl anzeigen" | ||||
| msgstr "Anzahl der Notizen anzeigen" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1020 | ||||
| msgid "Show sort order buttons" | ||||
| msgstr "Knöpfe zur Einstellung der Sortierreihenfolge anzeigen" | ||||
| msgstr "Buttons für die Sortierreihenfolge anzeigen" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1295 | ||||
| msgid "Show tray icon" | ||||
| @@ -4747,8 +4749,8 @@ msgstr "Synchronisation starten..." | ||||
| #: packages/app-cli/app/command-edit.ts:76 | ||||
| msgid "Starting to edit note. Close the editor to get back to the prompt." | ||||
| msgstr "" | ||||
| "Beginne die Notiz zu bearbeiten. Schließe das Textverarbeitungsprogramm, um " | ||||
| "zurück zum Terminal zu gelangen." | ||||
| "Bearbeite die Notiz jetzt. Schließe den Editor, um zurück zum Terminal zu " | ||||
| "gelangen." | ||||
|  | ||||
| #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:164 | ||||
| msgid "Statistics" | ||||
| @@ -5151,8 +5153,8 @@ msgid "" | ||||
| "The Joplin team has vetted this plugin and it meets our standards for " | ||||
| "security and performance." | ||||
| msgstr "" | ||||
| "Das Joplin-Team hat dieses Plugin auf unsere Standards für Sicherheit und " | ||||
| "Leistung überprüft." | ||||
| "Das Joplin-Team hat dieses Plugin überprüft und es erfüllt unsere Standards " | ||||
| "für Sicherheit und Leistung." | ||||
|  | ||||
| #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:321 | ||||
| msgid "" | ||||
| @@ -5655,7 +5657,7 @@ msgstr "Menüleiste umschalten" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2846 | ||||
| msgid "Toggle note history, keep notes for" | ||||
| msgstr "Notizverlauf umschalten, Notizen aufbewahren für" | ||||
| msgstr "Notizenverlauf umschalten, Notizen aufbewahren für" | ||||
|  | ||||
| #: packages/app-desktop/gui/MainScreen/commands/toggleNoteList.ts:9 | ||||
| msgid "Toggle note list" | ||||
| @@ -5927,8 +5929,8 @@ msgid "" | ||||
| "Use this to rebuild the search index if there is a problem with search. It " | ||||
| "may take a long time depending on the number of notes." | ||||
| msgstr "" | ||||
| "Verwende dies, um den Suchindex neu aufzubauen, wenn es ein Problem mit der " | ||||
| "Suche gibt. Dies kann je nach Anzahl der Notizen eine lange Zeit dauern." | ||||
| "Verwende dies zum Neuaufbau des Suchindex, falls es ein Problem mit der " | ||||
| "Suche gibt. Dies kann je nach Anzahl der Notizen etwas länger dauern." | ||||
|  | ||||
| #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:83 | ||||
| msgid "" | ||||
| @@ -5973,7 +5975,7 @@ msgstr "Gültig" | ||||
|  | ||||
| #: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:10 | ||||
| msgid "Verify your identity" | ||||
| msgstr "Verifiziere deine Identität" | ||||
| msgstr "Überprüfe deine Identität" | ||||
|  | ||||
| #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:10 | ||||
| msgid "View" | ||||
| @@ -6024,7 +6026,7 @@ msgstr "Warnung" | ||||
| #: packages/app-desktop/gui/ResourceScreen.tsx:302 | ||||
| msgid "Warning: not all resources shown for performance reasons (limit: %s)." | ||||
| msgstr "" | ||||
| "Warnung: Aus Leistungsgründen werden nicht alle Anhänge angezeigt " | ||||
| "Warnung: Aus Kapazitätsgründen werden nicht alle Anhänge angezeigt " | ||||
| "(Obergrenze: %s)." | ||||
|  | ||||
| #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:116 | ||||
| @@ -6038,7 +6040,7 @@ msgid "" | ||||
| "We mark plugins developed by trusted Joplin community members as " | ||||
| "\"recommended\"." | ||||
| msgstr "" | ||||
| "Wir kennzeichen Erweiterungen, die von vertrauenswürdigen Mitgliedern der " | ||||
| "Wir kennzeichnen Erweiterungen, die von vertrauenswürdigen Mitgliedern der " | ||||
| "Joplin-Community entwickelt wurden, als „empfohlen“." | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:2812 | ||||
| @@ -6086,8 +6088,8 @@ msgid "" | ||||
| msgstr "" | ||||
| "Willkommen bei Joplin!\n" | ||||
| "\n" | ||||
| "Tippe `:help shortcuts` für eine Liste der Shortcuts oder `:help` für " | ||||
| "Informationen zur Benutzung ein.\n" | ||||
| "Gib `:help shortcuts` für eine Liste der Shortcuts oder `:help` für Infos " | ||||
| "zur Benutzung ein.\n" | ||||
| "\n" | ||||
| "Um zum Beispiel ein Notizbuch zu erstellen, drücke `mb`; um eine Notiz zu " | ||||
| "erstellen drücke `mn`." | ||||
| @@ -6102,11 +6104,11 @@ msgstr "Was sind Erweiterungen?" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1166 | ||||
| msgid "When creating a new note:" | ||||
| msgstr "Wenn eine neue Notiz erstellt wird:" | ||||
| msgstr "Beim Erstellen einer neuen Notiz:" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:1149 | ||||
| msgid "When creating a new to-do:" | ||||
| msgstr "Wenn eine neue Aufgabe erstellt wird:" | ||||
| msgstr "Beim Erstellen einer neuen Aufgabe:" | ||||
|  | ||||
| #: packages/lib/models/Setting.ts:882 | ||||
| msgid "" | ||||
| @@ -6114,8 +6116,7 @@ msgid "" | ||||
| "text from it. This will allow you to search for text in these attachments." | ||||
| msgstr "" | ||||
| "Wenn aktiviert, wird die Anwendung deine Anhänge einlesen und Text aus ihnen " | ||||
| "extrahieren. Dies wird dir ermöglichen, nach Text innerhalb dieser Anhänge " | ||||
| "zu suchen." | ||||
| "extrahieren. Damit kannst du innerhalb dieser Anhänge nach Text suchen." | ||||
|  | ||||
| #: packages/app-desktop/ElectronAppWrapper.ts:184 | ||||
| msgid "Window unresponsive." | ||||
| @@ -6197,7 +6198,7 @@ msgstr "Dein Konto hat keinen Zugriff auf diese Funktion" | ||||
|  | ||||
| #: packages/app-cli/app/cli-utils.js:160 | ||||
| msgid "Your choice: " | ||||
| msgstr "Deine Auswahl: " | ||||
| msgstr "Deine Wahl: " | ||||
|  | ||||
| #: packages/lib/components/EncryptionConfigScreen/utils.ts:70 | ||||
| msgid "Your data is going to be re-encrypted and synced again." | ||||
| @@ -6206,7 +6207,7 @@ msgstr "Deine Daten werden neu verschlüsselt und erneut synchronisiert." | ||||
| #: packages/app-desktop/gui/MainScreen/MainScreen.tsx:697 | ||||
| #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:55 | ||||
| msgid "Your Joplin Cloud credentials are invalid, please login." | ||||
| msgstr "" | ||||
| msgstr "Deine Zugangsdaten für Joplin Cloud sind ungültig, bitte einloggen." | ||||
|  | ||||
| #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:259 | ||||
| msgid "Your password is needed to decrypt some of your data." | ||||
| @@ -6808,7 +6809,7 @@ msgstr "Herauszoomen" | ||||
| #~ msgstr "\"%s\": \"%s\"" | ||||
|  | ||||
| #~ msgid "File system synchronisation target directory" | ||||
| #~ msgstr "Dateisystem-Synchronisation Zielpfad" | ||||
| #~ msgstr "Dateisystem-Zielpfad für Synchronisation" | ||||
|  | ||||
| #~ msgid "Set or clear alarm:" | ||||
| #~ msgstr "Erstelle oder entferne Alarm:" | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| # Joplin Android Changelog | ||||
|  | ||||
| ## [android-v3.0.8](https://github.com/laurent22/joplin/releases/tag/android-v3.0.8) (Pre-release) - 2024-07-06T10:26:06Z | ||||
|  | ||||
| - Fixed: Fix sidebar performance regression with many nested notebooks (#10676) (#10674 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) | ||||
|  | ||||
| ## [android-v3.0.7](https://github.com/laurent22/joplin/releases/tag/android-v3.0.7) (Pre-release) - 2024-07-01T15:47:15Z | ||||
|  | ||||
| - Improved: Set min version for synchronising to 3.0.0 (e4b8976) | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| # Joplin iOS Changelog | ||||
|  | ||||
| ## [ios-v13.0.6](https://github.com/laurent22/joplin/releases/tag/ios-v13.0.6) - 2024-07-06T11:22:58Z | ||||
|  | ||||
| - Fixed: Fix sidebar performance regression with many nested notebooks (#10676) (#10674 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) | ||||
|  | ||||
| ## [ios-v13.0.5](https://github.com/laurent22/joplin/releases/tag/ios-v13.0.5) - 2024-07-01T15:47:53Z | ||||
|  | ||||
| - Improved: Set min version for synchronising to 3.0.0 (e4b8976) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user