mirror of
https://github.com/laurent22/joplin.git
synced 2026-11-06 08:42:24 +00:00
Compare commits
72
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99b5847244 | ||
|
|
4ad7e1b245 | ||
|
|
b6f889baca | ||
|
|
54fb4b0946 | ||
|
|
80762572cf | ||
|
|
8e5d209d3c | ||
|
|
f71dad6d09 | ||
|
|
f5891dfae8 | ||
|
|
736bbbd8ed | ||
|
|
973121addd | ||
|
|
95ad4c3177 | ||
|
|
71c470f59d | ||
|
|
c529b972e3 | ||
|
|
e6bff3f2e0 | ||
|
|
1bc674a1f9 | ||
|
|
f371bb8e59 | ||
|
|
7c85889c1f | ||
|
|
ab134807ea | ||
|
|
a5b3bb6058 | ||
|
|
8ab1cd984c | ||
|
|
e387d9a91b | ||
|
|
0793b1be59 | ||
|
|
19225abbcf | ||
|
|
85fa3288ab | ||
|
|
17f82c426a | ||
|
|
82331c9b93 | ||
|
|
886b6d1126 | ||
|
|
1a703c4ecd | ||
|
|
1126899769 | ||
|
|
a571d38862 | ||
|
|
4ab2fb73b7 | ||
|
|
78c7b79299 | ||
|
|
d97ba57dda | ||
|
|
9c44133bd0 | ||
|
|
dc008ecf64 | ||
|
|
93a4ad09bb | ||
|
|
9c1dc7898a | ||
|
|
6520a481ca | ||
|
|
5805a41249 | ||
|
|
b88b747ba6 | ||
|
|
ce89ee5bab | ||
|
|
596f679b1f | ||
|
|
78d5fd1385 | ||
|
|
0a98854e43 | ||
|
|
a8a0dd2dd6 | ||
|
|
ad931a738f | ||
|
|
3b6e6e45cf | ||
|
|
dec0a08954 | ||
|
|
b269c2fdb9 | ||
|
|
ad51090cdb | ||
|
|
bd4714037c | ||
|
|
f42fd0ecce | ||
|
|
62c5f433d7 | ||
|
|
e73a4b7286 | ||
|
|
6c18c6ddc7 | ||
|
|
20d1f74ee4 | ||
|
|
2386abea3e | ||
|
|
90621a8417 | ||
|
|
b02baa6891 | ||
|
|
ee46978389 | ||
|
|
2b6b4dd916 | ||
|
|
f0361bf80d | ||
|
|
ecf718005d | ||
|
|
305d0ffc49 | ||
|
|
f454c4e33b | ||
|
|
047883bd27 | ||
|
|
f118f5250f | ||
|
|
61161039c8 | ||
|
|
00504898f2 | ||
|
|
0a6390ed96 | ||
|
|
f909fe6670 | ||
|
|
b17d8bc533 |
No files matched your search
+82
-3
@@ -64,6 +64,7 @@ packages/tools/PortableAppsLauncher
|
||||
packages/fork-*
|
||||
plugin_types/
|
||||
readme/
|
||||
**/commands/index.ts
|
||||
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.d.ts
|
||||
@@ -117,6 +118,12 @@ packages/app-desktop/InteropServiceHelper.js.map
|
||||
packages/app-desktop/app.d.ts
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/app.js.map
|
||||
packages/app-desktop/app.reducer.d.ts
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.reducer.js.map
|
||||
packages/app-desktop/app.reducer.test.d.ts
|
||||
packages/app-desktop/app.reducer.test.js
|
||||
packages/app-desktop/app.reducer.test.js.map
|
||||
packages/app-desktop/bridge.d.ts
|
||||
packages/app-desktop/bridge.js
|
||||
packages/app-desktop/bridge.js.map
|
||||
@@ -135,6 +142,9 @@ packages/app-desktop/commands/exportNotes.js.map
|
||||
packages/app-desktop/commands/focusElement.d.ts
|
||||
packages/app-desktop/commands/focusElement.js
|
||||
packages/app-desktop/commands/focusElement.js.map
|
||||
packages/app-desktop/commands/index.d.ts
|
||||
packages/app-desktop/commands/index.js
|
||||
packages/app-desktop/commands/index.js.map
|
||||
packages/app-desktop/commands/openProfileDirectory.d.ts
|
||||
packages/app-desktop/commands/openProfileDirectory.js
|
||||
packages/app-desktop/commands/openProfileDirectory.js.map
|
||||
@@ -240,6 +250,9 @@ packages/app-desktop/gui/MainScreen/commands/gotoAnything.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.js
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/index.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/index.js
|
||||
packages/app-desktop/gui/MainScreen/commands/index.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.js
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.js.map
|
||||
@@ -396,21 +409,24 @@ packages/app-desktop/gui/NoteEditor/NoteEditor.js.map
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js.map
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js.map
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js.map
|
||||
@@ -465,12 +481,18 @@ packages/app-desktop/gui/NoteList/NoteList.js.map
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js.map
|
||||
packages/app-desktop/gui/NoteList/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/index.js
|
||||
packages/app-desktop/gui/NoteList/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js.map
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js.map
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.js
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteListItem.d.ts
|
||||
packages/app-desktop/gui/NoteListItem.js
|
||||
packages/app-desktop/gui/NoteListItem.js.map
|
||||
@@ -567,12 +589,18 @@ packages/app-desktop/gui/Sidebar/Sidebar.js.map
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.d.ts
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js.map
|
||||
packages/app-desktop/gui/Sidebar/commands/index.d.ts
|
||||
packages/app-desktop/gui/Sidebar/commands/index.js
|
||||
packages/app-desktop/gui/Sidebar/commands/index.js.map
|
||||
packages/app-desktop/gui/Sidebar/styles/index.d.ts
|
||||
packages/app-desktop/gui/Sidebar/styles/index.js
|
||||
packages/app-desktop/gui/Sidebar/styles/index.js.map
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.d.ts
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.js
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.js.map
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.d.ts
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.js
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.js.map
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.d.ts
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.js
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.js.map
|
||||
@@ -861,6 +889,9 @@ packages/lib/JoplinServerApi.js.map
|
||||
packages/lib/Logger.d.ts
|
||||
packages/lib/Logger.js
|
||||
packages/lib/Logger.js.map
|
||||
packages/lib/ObjectUtils.d.ts
|
||||
packages/lib/ObjectUtils.js
|
||||
packages/lib/ObjectUtils.js.map
|
||||
packages/lib/PoorManIntervals.d.ts
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/PoorManIntervals.js.map
|
||||
@@ -894,6 +925,9 @@ packages/lib/commands/historyBackward.js.map
|
||||
packages/lib/commands/historyForward.d.ts
|
||||
packages/lib/commands/historyForward.js
|
||||
packages/lib/commands/historyForward.js.map
|
||||
packages/lib/commands/index.d.ts
|
||||
packages/lib/commands/index.js
|
||||
packages/lib/commands/index.js.map
|
||||
packages/lib/commands/synchronize.d.ts
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/commands/synchronize.js.map
|
||||
@@ -936,6 +970,9 @@ packages/lib/fs-driver-node.js.map
|
||||
packages/lib/fsDriver.test.d.ts
|
||||
packages/lib/fsDriver.test.js
|
||||
packages/lib/fsDriver.test.js.map
|
||||
packages/lib/hooks/useAsyncEffect.d.ts
|
||||
packages/lib/hooks/useAsyncEffect.js
|
||||
packages/lib/hooks/useAsyncEffect.js.map
|
||||
packages/lib/hooks/useElementSize.d.ts
|
||||
packages/lib/hooks/useElementSize.js
|
||||
packages/lib/hooks/useElementSize.js.map
|
||||
@@ -990,6 +1027,9 @@ packages/lib/models/Folder.test.js.map
|
||||
packages/lib/models/ItemChange.d.ts
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/ItemChange.js.map
|
||||
packages/lib/models/ItemChange.test.d.ts
|
||||
packages/lib/models/ItemChange.test.js
|
||||
packages/lib/models/ItemChange.test.js.map
|
||||
packages/lib/models/MasterKey.d.ts
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/MasterKey.js.map
|
||||
@@ -1404,6 +1444,12 @@ packages/lib/services/rest/actionApi.desktop.js.map
|
||||
packages/lib/services/rest/routes/auth.d.ts
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/auth.js.map
|
||||
packages/lib/services/rest/routes/events.d.ts
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/events.js.map
|
||||
packages/lib/services/rest/routes/events.test.d.ts
|
||||
packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.test.js.map
|
||||
packages/lib/services/rest/routes/folders.d.ts
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/folders.js.map
|
||||
@@ -1485,6 +1531,21 @@ packages/lib/services/spellChecker/SpellCheckerService.js.map
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.d.ts
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js.map
|
||||
packages/lib/services/style/cssToTheme.d.ts
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/cssToTheme.js.map
|
||||
packages/lib/services/style/cssToTheme.test.d.ts
|
||||
packages/lib/services/style/cssToTheme.test.js
|
||||
packages/lib/services/style/cssToTheme.test.js.map
|
||||
packages/lib/services/style/loadCssToTheme.d.ts
|
||||
packages/lib/services/style/loadCssToTheme.js
|
||||
packages/lib/services/style/loadCssToTheme.js.map
|
||||
packages/lib/services/style/themeToCss.d.ts
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/style/themeToCss.js.map
|
||||
packages/lib/services/style/themeToCss.test.d.ts
|
||||
packages/lib/services/style/themeToCss.test.js
|
||||
packages/lib/services/style/themeToCss.test.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js.map
|
||||
@@ -1635,6 +1696,12 @@ packages/plugin-repo-cli/lib/gitCompareUrl.js.map
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.d.ts
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js.map
|
||||
packages/plugin-repo-cli/lib/overrideUtils.d.ts
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js.map
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.d.ts
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js.map
|
||||
packages/plugin-repo-cli/lib/types.d.ts
|
||||
packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/types.js.map
|
||||
@@ -1644,6 +1711,9 @@ packages/plugin-repo-cli/lib/updateReadme.js.map
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.d.ts
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js.map
|
||||
packages/plugin-repo-cli/lib/utils.d.ts
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugin-repo-cli/lib/utils.js.map
|
||||
packages/plugins/ToggleSidebars/api/index.d.ts
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/index.js.map
|
||||
@@ -1716,6 +1786,9 @@ packages/renderer/MdToHtml/setupLinkify.js.map
|
||||
packages/renderer/MdToHtml/validateLinks.d.ts
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/MdToHtml/validateLinks.js.map
|
||||
packages/renderer/headerAnchor.d.ts
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/headerAnchor.js.map
|
||||
packages/renderer/htmlUtils.d.ts
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/htmlUtils.js.map
|
||||
@@ -1734,12 +1807,18 @@ packages/renderer/utils.js.map
|
||||
packages/tools/buildServerDocker.d.ts
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/buildServerDocker.js.map
|
||||
packages/tools/convertThemesToCss.d.ts
|
||||
packages/tools/convertThemesToCss.js
|
||||
packages/tools/convertThemesToCss.js.map
|
||||
packages/tools/generate-database-types.d.ts
|
||||
packages/tools/generate-database-types.js
|
||||
packages/tools/generate-database-types.js.map
|
||||
packages/tools/generate-images.d.ts
|
||||
packages/tools/generate-images.js
|
||||
packages/tools/generate-images.js.map
|
||||
packages/tools/git-changelog.d.ts
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/git-changelog.js.map
|
||||
packages/tools/lerna-add.d.ts
|
||||
packages/tools/lerna-add.js
|
||||
packages/tools/lerna-add.js.map
|
||||
|
||||
@@ -35,6 +35,14 @@ jobs:
|
||||
sudo apt-get update || true
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
|
||||
# the next line enables multi-architecture support for docker, it basically makes it use qemu for non native platforms
|
||||
# See https://hub.docker.com/r/tonistiigi/binfmt for more info
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
|
||||
# this just prints the info about what platforms are supported in the builder (can help debugging if something isn't working right)
|
||||
# and also proves the above worked properly
|
||||
sudo docker buildx ls
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: olegtarasov/get-tag@v2.1
|
||||
- uses: actions/setup-node@v2
|
||||
|
||||
+82
-3
@@ -49,6 +49,7 @@ packages/tools/commit_hook.txt
|
||||
packages/tools/github_oauth_token.txt
|
||||
lerna-debug.log
|
||||
.env
|
||||
docs/**/*.mustache
|
||||
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.d.ts
|
||||
@@ -102,6 +103,12 @@ packages/app-desktop/InteropServiceHelper.js.map
|
||||
packages/app-desktop/app.d.ts
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/app.js.map
|
||||
packages/app-desktop/app.reducer.d.ts
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.reducer.js.map
|
||||
packages/app-desktop/app.reducer.test.d.ts
|
||||
packages/app-desktop/app.reducer.test.js
|
||||
packages/app-desktop/app.reducer.test.js.map
|
||||
packages/app-desktop/bridge.d.ts
|
||||
packages/app-desktop/bridge.js
|
||||
packages/app-desktop/bridge.js.map
|
||||
@@ -120,6 +127,9 @@ packages/app-desktop/commands/exportNotes.js.map
|
||||
packages/app-desktop/commands/focusElement.d.ts
|
||||
packages/app-desktop/commands/focusElement.js
|
||||
packages/app-desktop/commands/focusElement.js.map
|
||||
packages/app-desktop/commands/index.d.ts
|
||||
packages/app-desktop/commands/index.js
|
||||
packages/app-desktop/commands/index.js.map
|
||||
packages/app-desktop/commands/openProfileDirectory.d.ts
|
||||
packages/app-desktop/commands/openProfileDirectory.js
|
||||
packages/app-desktop/commands/openProfileDirectory.js.map
|
||||
@@ -225,6 +235,9 @@ packages/app-desktop/gui/MainScreen/commands/gotoAnything.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.js
|
||||
packages/app-desktop/gui/MainScreen/commands/hideModalMessage.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/index.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/index.js
|
||||
packages/app-desktop/gui/MainScreen/commands/index.js.map
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.d.ts
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.js
|
||||
packages/app-desktop/gui/MainScreen/commands/moveToFolder.js.map
|
||||
@@ -381,21 +394,24 @@ packages/app-desktop/gui/NoteEditor/NoteEditor.js.map
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js.map
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js.map
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js.map
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.d.ts
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js.map
|
||||
@@ -450,12 +466,18 @@ packages/app-desktop/gui/NoteList/NoteList.js.map
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
|
||||
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js.map
|
||||
packages/app-desktop/gui/NoteList/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/index.js
|
||||
packages/app-desktop/gui/NoteList/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js.map
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js
|
||||
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js.map
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.js
|
||||
packages/app-desktop/gui/NoteListControls/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteListItem.d.ts
|
||||
packages/app-desktop/gui/NoteListItem.js
|
||||
packages/app-desktop/gui/NoteListItem.js.map
|
||||
@@ -552,12 +574,18 @@ packages/app-desktop/gui/Sidebar/Sidebar.js.map
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.d.ts
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
|
||||
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js.map
|
||||
packages/app-desktop/gui/Sidebar/commands/index.d.ts
|
||||
packages/app-desktop/gui/Sidebar/commands/index.js
|
||||
packages/app-desktop/gui/Sidebar/commands/index.js.map
|
||||
packages/app-desktop/gui/Sidebar/styles/index.d.ts
|
||||
packages/app-desktop/gui/Sidebar/styles/index.js
|
||||
packages/app-desktop/gui/Sidebar/styles/index.js.map
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.d.ts
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.js
|
||||
packages/app-desktop/gui/StatusScreen/StatusScreen.js.map
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.d.ts
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.js
|
||||
packages/app-desktop/gui/StyleSheets/StyleSheetContainer.js.map
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.d.ts
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.js
|
||||
packages/app-desktop/gui/SyncWizard/Dialog.js.map
|
||||
@@ -846,6 +874,9 @@ packages/lib/JoplinServerApi.js.map
|
||||
packages/lib/Logger.d.ts
|
||||
packages/lib/Logger.js
|
||||
packages/lib/Logger.js.map
|
||||
packages/lib/ObjectUtils.d.ts
|
||||
packages/lib/ObjectUtils.js
|
||||
packages/lib/ObjectUtils.js.map
|
||||
packages/lib/PoorManIntervals.d.ts
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/PoorManIntervals.js.map
|
||||
@@ -879,6 +910,9 @@ packages/lib/commands/historyBackward.js.map
|
||||
packages/lib/commands/historyForward.d.ts
|
||||
packages/lib/commands/historyForward.js
|
||||
packages/lib/commands/historyForward.js.map
|
||||
packages/lib/commands/index.d.ts
|
||||
packages/lib/commands/index.js
|
||||
packages/lib/commands/index.js.map
|
||||
packages/lib/commands/synchronize.d.ts
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/commands/synchronize.js.map
|
||||
@@ -921,6 +955,9 @@ packages/lib/fs-driver-node.js.map
|
||||
packages/lib/fsDriver.test.d.ts
|
||||
packages/lib/fsDriver.test.js
|
||||
packages/lib/fsDriver.test.js.map
|
||||
packages/lib/hooks/useAsyncEffect.d.ts
|
||||
packages/lib/hooks/useAsyncEffect.js
|
||||
packages/lib/hooks/useAsyncEffect.js.map
|
||||
packages/lib/hooks/useElementSize.d.ts
|
||||
packages/lib/hooks/useElementSize.js
|
||||
packages/lib/hooks/useElementSize.js.map
|
||||
@@ -975,6 +1012,9 @@ packages/lib/models/Folder.test.js.map
|
||||
packages/lib/models/ItemChange.d.ts
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/ItemChange.js.map
|
||||
packages/lib/models/ItemChange.test.d.ts
|
||||
packages/lib/models/ItemChange.test.js
|
||||
packages/lib/models/ItemChange.test.js.map
|
||||
packages/lib/models/MasterKey.d.ts
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/MasterKey.js.map
|
||||
@@ -1389,6 +1429,12 @@ packages/lib/services/rest/actionApi.desktop.js.map
|
||||
packages/lib/services/rest/routes/auth.d.ts
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/auth.js.map
|
||||
packages/lib/services/rest/routes/events.d.ts
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/events.js.map
|
||||
packages/lib/services/rest/routes/events.test.d.ts
|
||||
packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.test.js.map
|
||||
packages/lib/services/rest/routes/folders.d.ts
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/folders.js.map
|
||||
@@ -1470,6 +1516,21 @@ packages/lib/services/spellChecker/SpellCheckerService.js.map
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.d.ts
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js.map
|
||||
packages/lib/services/style/cssToTheme.d.ts
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/cssToTheme.js.map
|
||||
packages/lib/services/style/cssToTheme.test.d.ts
|
||||
packages/lib/services/style/cssToTheme.test.js
|
||||
packages/lib/services/style/cssToTheme.test.js.map
|
||||
packages/lib/services/style/loadCssToTheme.d.ts
|
||||
packages/lib/services/style/loadCssToTheme.js
|
||||
packages/lib/services/style/loadCssToTheme.js.map
|
||||
packages/lib/services/style/themeToCss.d.ts
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/style/themeToCss.js.map
|
||||
packages/lib/services/style/themeToCss.test.d.ts
|
||||
packages/lib/services/style/themeToCss.test.js
|
||||
packages/lib/services/style/themeToCss.test.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js.map
|
||||
@@ -1620,6 +1681,12 @@ packages/plugin-repo-cli/lib/gitCompareUrl.js.map
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.d.ts
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js.map
|
||||
packages/plugin-repo-cli/lib/overrideUtils.d.ts
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js.map
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.d.ts
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js.map
|
||||
packages/plugin-repo-cli/lib/types.d.ts
|
||||
packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/types.js.map
|
||||
@@ -1629,6 +1696,9 @@ packages/plugin-repo-cli/lib/updateReadme.js.map
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.d.ts
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js.map
|
||||
packages/plugin-repo-cli/lib/utils.d.ts
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugin-repo-cli/lib/utils.js.map
|
||||
packages/plugins/ToggleSidebars/api/index.d.ts
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/index.js.map
|
||||
@@ -1701,6 +1771,9 @@ packages/renderer/MdToHtml/setupLinkify.js.map
|
||||
packages/renderer/MdToHtml/validateLinks.d.ts
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/MdToHtml/validateLinks.js.map
|
||||
packages/renderer/headerAnchor.d.ts
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/headerAnchor.js.map
|
||||
packages/renderer/htmlUtils.d.ts
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/htmlUtils.js.map
|
||||
@@ -1719,12 +1792,18 @@ packages/renderer/utils.js.map
|
||||
packages/tools/buildServerDocker.d.ts
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/buildServerDocker.js.map
|
||||
packages/tools/convertThemesToCss.d.ts
|
||||
packages/tools/convertThemesToCss.js
|
||||
packages/tools/convertThemesToCss.js.map
|
||||
packages/tools/generate-database-types.d.ts
|
||||
packages/tools/generate-database-types.js
|
||||
packages/tools/generate-database-types.js.map
|
||||
packages/tools/generate-images.d.ts
|
||||
packages/tools/generate-images.js
|
||||
packages/tools/generate-images.js.map
|
||||
packages/tools/git-changelog.d.ts
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/git-changelog.js.map
|
||||
packages/tools/lerna-add.d.ts
|
||||
packages/tools/lerna-add.js
|
||||
packages/tools/lerna-add.js.map
|
||||
|
||||
@@ -29,7 +29,7 @@ ol, ul {
|
||||
#main-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 225px;
|
||||
padding-bottom: 127px; /* Needs to be the height of the footer */
|
||||
}
|
||||
|
||||
.help-page-container img {
|
||||
@@ -583,7 +583,7 @@ div.navbar-mobile-content a.sponsor-button {
|
||||
|
||||
/* footer section */
|
||||
footer {
|
||||
padding-top: 50px;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@@ -594,6 +594,7 @@ footer a,
|
||||
footer p {
|
||||
color: #90b1d9;
|
||||
text-decoration: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
@@ -617,6 +618,35 @@ footer .right-links a {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
footer .footer-right {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
footer .social-links {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #315885;
|
||||
}
|
||||
|
||||
footer .social-links a:hover {
|
||||
color: #e8f3ff;
|
||||
}
|
||||
|
||||
footer .social-links i {
|
||||
margin-left: 15px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
footer .bottom-links-row {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
footer .bottom-links-row p {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
IN THE PRESS
|
||||
The "In the press" section height needs to be adjusted as the
|
||||
@@ -679,7 +709,7 @@ footer .right-links a {
|
||||
#main-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 260px;
|
||||
padding-bottom: 130px;
|
||||
}
|
||||
|
||||
.front-page h1 {
|
||||
@@ -866,7 +896,7 @@ footer .right-links a {
|
||||
|
||||
.help-page-container {
|
||||
padding-top: 90px;
|
||||
padding-bottom: 50px;
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
.donate-links {
|
||||
@@ -880,7 +910,7 @@ footer .right-links a {
|
||||
border-radius: 20px;
|
||||
padding: 30px 20px;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: 50px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
@@ -923,6 +953,11 @@ footer .right-links a {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.plan-group .joplin-cloud-login-info {
|
||||
margin-bottom: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plan-group .plan-price-yearly-per-year {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -368,40 +368,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="darkblue-bg">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3 d-none d-md-block">
|
||||
<img src="{{imageBaseUrl}}/logo-text.svg" alt="" width="150" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<a href="{{baseUrl}}">
|
||||
<img
|
||||
src="{{imageBaseUrl}}/logo-text.svg"
|
||||
width="120"
|
||||
class="img-center d-block d-md-none"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<br class="d-block d-md-none" />
|
||||
<p class="text-center-sm">Copyright © 2016-{{yyyy}} Laurent Cozic</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p class="text-right text-center-sm right-links">
|
||||
<a href="https://github.com/laurent22/joplin/" class="github-link"><i class="fab fa-github"></i> GitHub Repository</a>
|
||||
<a href="{{baseUrl}}/privacy/">Privacy Policy</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
{{> footer}}
|
||||
</div>
|
||||
|
||||
<script
|
||||
|
||||
@@ -75,38 +75,8 @@ https://github.com/laurent22/joplin/blob/dev/{{{sourceMarkdownFile}}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="darkblue-bg">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3 d-none d-md-block">
|
||||
<img src="{{imageBaseUrl}}/logo-text.svg" alt="" width="150" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<img
|
||||
src="{{imageBaseUrl}}/logo-text.svg"
|
||||
width="120"
|
||||
class="img-center d-block d-md-none"
|
||||
alt=""
|
||||
/>
|
||||
<br class="d-block d-md-none" />
|
||||
<p class="text-center-sm">Copyright © 2016-{{yyyy}} Laurent Cozic</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 right-links">
|
||||
<p class="text-right text-center-sm">
|
||||
<a href="https://github.com/laurent22/joplin/" class="github-link"><i class="fab fa-github"></i> GitHub Repository</a>
|
||||
<a href="{{baseUrl}}/privacy/">Privacy Policy</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{{> footer}}
|
||||
</div>
|
||||
|
||||
<script src="{{jsBaseUrl}}/script.js?t={{buildTime}}"></script>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<footer class="darkblue-bg">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-12 social-links">
|
||||
<a href="https://twitter.com/joplinapp" title="Twitter feed"><i class="fab fa-twitter"></i></a>
|
||||
<a href="https://github.com/laurent22/joplin/" title="GitHub repository"><i class="fab fa-github"></i></a>
|
||||
<a href="https://www.patreon.com/joplin" title="Patreon blog"><i class="fab fa-patreon"></i></a>
|
||||
<a href="https://discordapp.com/invite/d2HMPwE" title="Discord chat"><i class="fab fa-discord"></i></a>
|
||||
<a href="https://www.reddit.com/r/joplinapp/" title="Subreddit"><i class="fab fa-reddit"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row bottom-links-row">
|
||||
<div class="col-12 col-md-6">
|
||||
<p class="text-center-sm">Copyright © 2016-{{yyyy}} Laurent Cozic</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p class="text-right text-center-sm right-links">
|
||||
<span class="footer-right">
|
||||
<a href="{{baseUrl}}/privacy/">Privacy Policy</a>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -6,7 +6,7 @@
|
||||
Joplin Cloud <span class="frame-bg frame-bg-yellow">plans</span>
|
||||
</h1>
|
||||
<p class="text-center sub-title">
|
||||
Joplin Cloud allows you to synchronise your notes across devices. It also lets you publish notes, and collaborate on notebooks with your friends, family or colleagues.
|
||||
<a href="https://joplincloud.com">Joplin Cloud</a> allows you to synchronise your notes across devices. It also lets you publish notes, and collaborate on notebooks with your friends, family or colleagues.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,6 +45,8 @@
|
||||
{{#plans.business}}
|
||||
{{> plan}}
|
||||
{{/plans.business}}
|
||||
|
||||
<p class="joplin-cloud-login-info">Already have a Joplin Cloud account? <a href="https://joplincloud.com">Login now</a></p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
@@ -184,7 +184,7 @@ if command -v lsb_release &> /dev/null; then
|
||||
# Check for "The SUID sandbox helper binary was found, but is not configured correctly" problem.
|
||||
# It is present in Debian 1X. A (temporary) patch will be applied at .desktop file
|
||||
# Linux Mint 4 Debbie is based on Debian 10 and requires the same param handling.
|
||||
if [ $DISTVER =~ Debian1. ] || [ "$DISTVER" = "Linuxmint4" ] && [ "$DISTCODENAME" = "debbie" ]
|
||||
if [[ $DISTVER =~ Debian1. ]] || [ "$DISTVER" = "Linuxmint4" ] && [ "$DISTCODENAME" = "debbie" ]
|
||||
then
|
||||
SANDBOXPARAM=" --no-sandbox"
|
||||
fi
|
||||
|
||||
@@ -511,7 +511,7 @@ Current translations:
|
||||
<img src="https://joplinapp.org/images/flags/es/catalonia.png" width="16px"/> | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | jmontane, 2019 | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/hr.png" width="16px"/> | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Milo Ivir](mailto:mail@milotype.de) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cz.png" width="16px"/> | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | [Michal Stanke](mailto:michal@stanke.cz) | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | Mustafa Al-Dailemi (dailemi@hotmail.com)Language-Team: | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | Mustafa Al-Dailemi (dailemi@hotmail.com)Language-Team: | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/de.png" width="16px"/> | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [Atalanttore](mailto:atalanttore@googlemail.com) | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ee.png" width="16px"/> | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 54%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/gb.png" width="16px"/> | English (United Kingdom) | [en_GB](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_GB.po) | | 100%
|
||||
@@ -527,7 +527,7 @@ Current translations:
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/be.png" width="16px"/> | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 87%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/nl.png" width="16px"/> | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MetBril](mailto:metbril@users.noreply.github.com) | 90%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/no.png" width="16px"/> | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | Alexander Dawson | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ir.png" width="16px"/> | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 68%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ir.png" width="16px"/> | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 67%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pl.png" width="16px"/> | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | [konhi](mailto:hello.konhi@gmail.com) | 90%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/br.png" width="16px"/> | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_BR.po) | [Nicolas Suzuki](mailto:nicolas.suzuki@pm.me) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pt.png" width="16px"/> | Português (Portugal) | [pt_PT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_PT.po) | [Diogo Caveiro](mailto:dcaveiro@yahoo.com) | 90%
|
||||
@@ -536,13 +536,13 @@ Current translations:
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/se.png" width="16px"/> | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/th.png" width="16px"/> | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 42%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/vi.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ua.png" width="16px"/> | Ukrainian (Україна) | [uk_UA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/uk_UA.po) | [Vyacheslav Andreykiv](mailto:vandreykiv@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/gr.png" width="16px"/> | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Sergey Segeda](mailto:thesermanarm@gmail.com) | 90%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Sergey Segeda](mailto:thesermanarm@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/rs.png" width="16px"/> | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 81%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cn.png" width="16px"/> | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [南宫小骏](mailto:jackytsu@vip.qq.com) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Po-Chiang Chao](mailto:BobChao%29%20%28bobchao@gmail.com) | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cn.png" width="16px"/> | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [南宫小骏](mailto:jackytsu@vip.qq.com) | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Po-Chiang Chao](mailto:BobChao%29%20%28bobchao@gmail.com) | 94%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/jp.png" width="16px"/> | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/kr.png" width="16px"/> | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 95%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
@@ -5,6 +5,7 @@ const tasks = {
|
||||
// copyLib: require('./packages/tools/gulp/tasks/copyLib'),
|
||||
// tsc: require('./packages/tools/gulp/tasks/tsc'),
|
||||
updateIgnoredTypeScriptBuild: require('./packages/tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
|
||||
buildCommandIndex: require('./packages/tools/gulp/tasks/buildCommandIndex'),
|
||||
// deleteBuildDirs: require('./packages/tools/gulp/tasks/deleteBuildDirs'),
|
||||
completePublishAll: {
|
||||
fn: async () => {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"bootstrapServerOnly": "lerna bootstrap --force-local --no-ci --include-dependents --include-dependencies --scope @joplin/server",
|
||||
"build": "lerna run build && npm run tsc",
|
||||
"buildApiDoc": "npm start --prefix=packages/app-cli -- apidoc ../../readme/api/references/rest_api.md",
|
||||
"buildCommandIndex": "gulp buildCommandIndex",
|
||||
"buildDoc": "./packages/tools/build-all.sh",
|
||||
"buildPluginDoc": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme './Assets/PluginDocTheme/' --readme './Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out docs/api/references/plugin_api packages/lib/services/plugins/api/",
|
||||
"buildSettingJsonSchema": "npm start --prefix=packages/app-cli -- settingschema ../../docs/schema/settings.json",
|
||||
|
||||
@@ -381,6 +381,30 @@ async function fetchAllNotes() {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const tableFields = reg.db().tableFields('item_changes', { includeDescription: true });
|
||||
|
||||
lines.push('# Events');
|
||||
lines.push('');
|
||||
lines.push('This end point can be used to retrieve the latest note changes. Currently only note changes are tracked.');
|
||||
lines.push('');
|
||||
lines.push('## Properties');
|
||||
lines.push('');
|
||||
lines.push(this.createPropertiesTable(tableFields));
|
||||
lines.push('');
|
||||
lines.push('## GET /events');
|
||||
lines.push('');
|
||||
lines.push('Returns a paginated list of recent events. A `cursor` property should be provided, which tells from what point in time the events should be returned. The API will return a `cursor` property, to tell from where to resume retrieving events, as well as an `has_more` (tells if more changes can be retrieved) and `items` property, which will contain the list of events. Events are kept for up to 90 days.');
|
||||
lines.push('');
|
||||
lines.push('If no `cursor` property is provided, the API will respond with the latest change ID. That can be used to retrieve future events later on.');
|
||||
lines.push('');
|
||||
lines.push('The results are paginated so will need to may multiple calls to retrieve all the events. Use the `has_more` property to know if more can be retrieved.');
|
||||
lines.push('');
|
||||
lines.push('## GET /events/:id');
|
||||
lines.push('');
|
||||
lines.push('Returns the event with the given ID.');
|
||||
}
|
||||
|
||||
const outFilePath = args['file'];
|
||||
|
||||
await shim.fsDriver().writeFile(outFilePath, lines.join('\n'), 'utf8');
|
||||
|
||||
@@ -237,7 +237,7 @@ export default class ElectronAppWrapper {
|
||||
const iid = setInterval(() => {
|
||||
if (this.electronApp().isReady()) {
|
||||
clearInterval(iid);
|
||||
resolve();
|
||||
resolve(null);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { AppState } from './app.reducer';
|
||||
import appReducer, { createAppDefaultState } from './app.reducer';
|
||||
|
||||
describe('app.reducer', function() {
|
||||
|
||||
it('DIALOG_OPEN', async () => {
|
||||
const state: AppState = createAppDefaultState({}, {});
|
||||
|
||||
let newState = appReducer(state, {
|
||||
type: 'DIALOG_OPEN',
|
||||
name: 'syncWizard',
|
||||
});
|
||||
|
||||
expect(newState.dialogs.length).toBe(1);
|
||||
expect(newState.dialogs[0].name).toBe('syncWizard');
|
||||
|
||||
expect(() => appReducer(newState, {
|
||||
type: 'DIALOG_OPEN',
|
||||
name: 'syncWizard',
|
||||
})).toThrow();
|
||||
|
||||
newState = appReducer(newState, {
|
||||
type: 'DIALOG_CLOSE',
|
||||
name: 'syncWizard',
|
||||
});
|
||||
|
||||
expect(newState.dialogs.length).toBe(0);
|
||||
|
||||
expect(() => appReducer(newState, {
|
||||
type: 'DIALOG_CLOSE',
|
||||
name: 'syncWizard',
|
||||
})).toThrow();
|
||||
|
||||
newState = appReducer(newState, {
|
||||
type: 'DIALOG_OPEN',
|
||||
name: 'syncWizard',
|
||||
});
|
||||
|
||||
newState = appReducer(newState, {
|
||||
type: 'DIALOG_OPEN',
|
||||
name: 'setPassword',
|
||||
});
|
||||
|
||||
expect(newState.dialogs).toEqual([{ name: 'syncWizard' }, { name: 'setPassword' }]);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,316 @@
|
||||
import produce from 'immer';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { defaultState, State } from '@joplin/lib/reducer';
|
||||
import iterateItems from './gui/ResizableLayout/utils/iterateItems';
|
||||
import { LayoutItem } from './gui/ResizableLayout/utils/types';
|
||||
import validateLayout from './gui/ResizableLayout/utils/validateLayout';
|
||||
|
||||
export interface AppStateRoute {
|
||||
type: string;
|
||||
routeName: string;
|
||||
props: any;
|
||||
}
|
||||
|
||||
export enum AppStateDialogName {
|
||||
SyncWizard = 'syncWizard',
|
||||
MasterPassword = 'masterPassword',
|
||||
}
|
||||
|
||||
export interface AppStateDialog {
|
||||
name: AppStateDialogName;
|
||||
}
|
||||
|
||||
export interface AppState extends State {
|
||||
route: AppStateRoute;
|
||||
navHistory: any[];
|
||||
noteVisiblePanes: string[];
|
||||
windowContentSize: any;
|
||||
watchedNoteFiles: string[];
|
||||
lastEditorScrollPercents: any;
|
||||
devToolsVisible: boolean;
|
||||
visibleDialogs: any; // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
focusedField: string;
|
||||
layoutMoveMode: boolean;
|
||||
startupPluginsLoaded: boolean;
|
||||
|
||||
// Extra reducer keys go here
|
||||
watchedResources: any;
|
||||
mainLayout: LayoutItem;
|
||||
dialogs: AppStateDialog[];
|
||||
}
|
||||
|
||||
export function createAppDefaultState(windowContentSize: any, resourceEditWatcherDefaultState: any): AppState {
|
||||
return {
|
||||
...defaultState,
|
||||
route: {
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Main',
|
||||
props: {},
|
||||
},
|
||||
navHistory: [],
|
||||
noteVisiblePanes: ['editor', 'viewer'],
|
||||
windowContentSize, // bridge().windowContentSize(),
|
||||
watchedNoteFiles: [],
|
||||
lastEditorScrollPercents: {},
|
||||
devToolsVisible: false,
|
||||
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
focusedField: null,
|
||||
layoutMoveMode: false,
|
||||
mainLayout: null,
|
||||
startupPluginsLoaded: false,
|
||||
dialogs: [],
|
||||
...resourceEditWatcherDefaultState,
|
||||
};
|
||||
}
|
||||
|
||||
export default function(state: AppState, action: any) {
|
||||
let newState = state;
|
||||
|
||||
try {
|
||||
switch (action.type) {
|
||||
|
||||
case 'NAV_BACK':
|
||||
case 'NAV_GO':
|
||||
|
||||
{
|
||||
const goingBack = action.type === 'NAV_BACK';
|
||||
|
||||
if (goingBack && !state.navHistory.length) break;
|
||||
|
||||
const currentRoute = state.route;
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
const newNavHistory = state.navHistory.slice();
|
||||
|
||||
if (goingBack) {
|
||||
let newAction = null;
|
||||
while (newNavHistory.length) {
|
||||
newAction = newNavHistory.pop();
|
||||
if (newAction.routeName !== state.route.routeName) break;
|
||||
}
|
||||
|
||||
if (!newAction) break;
|
||||
|
||||
action = newAction;
|
||||
}
|
||||
|
||||
if (!goingBack) newNavHistory.push(currentRoute);
|
||||
newState.navHistory = newNavHistory;
|
||||
newState.route = action;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STARTUP_PLUGINS_LOADED':
|
||||
|
||||
// When all startup plugins have loaded, we also recreate the
|
||||
// main layout to ensure that it is updated in the UI. There's
|
||||
// probably a cleaner way to do this, but for now that will do.
|
||||
if (state.startupPluginsLoaded !== action.value) {
|
||||
newState = {
|
||||
...newState,
|
||||
startupPluginsLoaded: action.value,
|
||||
mainLayout: JSON.parse(JSON.stringify(newState.mainLayout)),
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'WINDOW_CONTENT_SIZE_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.windowContentSize = action.size;
|
||||
break;
|
||||
|
||||
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
||||
|
||||
{
|
||||
const getNextLayout = (currentLayout: any) => {
|
||||
currentLayout = panes.length === 2 ? 'both' : currentLayout[0];
|
||||
|
||||
let paneOptions;
|
||||
if (state.settings.layoutButtonSequence === Setting.LAYOUT_EDITOR_VIEWER) {
|
||||
paneOptions = ['editor', 'viewer'];
|
||||
} else if (state.settings.layoutButtonSequence === Setting.LAYOUT_EDITOR_SPLIT) {
|
||||
paneOptions = ['editor', 'both'];
|
||||
} else if (state.settings.layoutButtonSequence === Setting.LAYOUT_VIEWER_SPLIT) {
|
||||
paneOptions = ['viewer', 'both'];
|
||||
} else {
|
||||
paneOptions = ['editor', 'viewer', 'both'];
|
||||
}
|
||||
|
||||
const currentLayoutIndex = paneOptions.indexOf(currentLayout);
|
||||
const nextLayoutIndex = currentLayoutIndex === paneOptions.length - 1 ? 0 : currentLayoutIndex + 1;
|
||||
|
||||
const nextLayout = paneOptions[nextLayoutIndex];
|
||||
return nextLayout === 'both' ? ['editor', 'viewer'] : [nextLayout];
|
||||
};
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
|
||||
const panes = state.noteVisiblePanes.slice();
|
||||
newState.noteVisiblePanes = getNextLayout(panes);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_VISIBLE_PANES_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.noteVisiblePanes = action.panes;
|
||||
break;
|
||||
|
||||
case 'MAIN_LAYOUT_SET':
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: action.value,
|
||||
};
|
||||
break;
|
||||
|
||||
case 'MAIN_LAYOUT_SET_ITEM_PROP':
|
||||
|
||||
{
|
||||
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
|
||||
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
|
||||
if (item.key === action.itemKey) {
|
||||
(item as any)[action.propName] = action.propValue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: newLayout,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_ADD':
|
||||
|
||||
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {
|
||||
newState = Object.assign({}, state);
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
watchedNoteFiles.push(action.id);
|
||||
newState.watchedNoteFiles = watchedNoteFiles;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_REMOVE':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const idx = newState.watchedNoteFiles.indexOf(action.id);
|
||||
if (idx >= 0) {
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
watchedNoteFiles.splice(idx, 1);
|
||||
newState.watchedNoteFiles = watchedNoteFiles;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_CLEAR':
|
||||
|
||||
if (state.watchedNoteFiles.length) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.watchedNoteFiles = [];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'EDITOR_SCROLL_PERCENT_SET':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
|
||||
newPercents[action.noteId] = action.percent;
|
||||
newState.lastEditorScrollPercents = newPercents;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_TOGGLE':
|
||||
newState = Object.assign({}, state);
|
||||
newState.devToolsVisible = !newState.devToolsVisible;
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_SET':
|
||||
newState = Object.assign({}, state);
|
||||
newState.devToolsVisible = action.value;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_ADD':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
newState.visibleDialogs[action.name] = true;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_REMOVE':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
delete newState.visibleDialogs[action.name];
|
||||
break;
|
||||
|
||||
case 'FOCUS_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = action.field;
|
||||
break;
|
||||
|
||||
case 'FOCUS_CLEAR':
|
||||
|
||||
// A field can only clear its own state
|
||||
if (action.field === state.focusedField) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DIALOG_OPEN':
|
||||
case 'DIALOG_CLOSE':
|
||||
|
||||
{
|
||||
let isOpen = true;
|
||||
|
||||
if (action.type === 'DIALOG_CLOSE') {
|
||||
isOpen = false;
|
||||
} else { // DIALOG_OPEN
|
||||
isOpen = action.isOpen !== false;
|
||||
}
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
|
||||
if (isOpen) {
|
||||
const newDialogs = newState.dialogs.slice();
|
||||
|
||||
if (newDialogs.find(d => d.name === action.name)) throw new Error(`Trying to open a dialog is already open: ${action.name}`);
|
||||
|
||||
newDialogs.push({
|
||||
name: action.name,
|
||||
});
|
||||
|
||||
newState.dialogs = newDialogs;
|
||||
} else {
|
||||
if (!newState.dialogs.find(d => d.name === action.name)) throw new Error(`Trying to close a dialog that is not open: ${action.name}`);
|
||||
const newDialogs = newState.dialogs.slice().filter(d => d.name !== action.name);
|
||||
newState.dialogs = newDialogs;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'LAYOUT_MOVE_MODE_SET':
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
layoutMoveMode: action.value,
|
||||
};
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
+31
-352
@@ -3,7 +3,6 @@ import CommandService from '@joplin/lib/services/CommandService';
|
||||
import KeymapService from '@joplin/lib/services/KeymapService';
|
||||
import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import resourceEditWatcherReducer, { defaultState as resourceEditWatcherDefaultState } from '@joplin/lib/services/ResourceEditWatcher/reducer';
|
||||
import { defaultState, State } from '@joplin/lib/reducer';
|
||||
import PluginRunner from './services/plugins/PluginRunner';
|
||||
import PlatformImplementation from './services/plugins/PlatformImplementation';
|
||||
import shim from '@joplin/lib/shim';
|
||||
@@ -19,13 +18,10 @@ import SpellCheckerService from '@joplin/lib/services/spellChecker/SpellCheckerS
|
||||
import SpellCheckerServiceDriverNative from './services/spellChecker/SpellCheckerServiceDriverNative';
|
||||
import bridge from './services/bridge';
|
||||
import menuCommandNames from './gui/menuCommandNames';
|
||||
import { LayoutItem } from './gui/ResizableLayout/utils/types';
|
||||
import stateToWhenClauseContext from './services/commands/stateToWhenClauseContext';
|
||||
import ResourceService from '@joplin/lib/services/ResourceService';
|
||||
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
|
||||
import produce from 'immer';
|
||||
import iterateItems from './gui/ResizableLayout/utils/iterateItems';
|
||||
import validateLayout from './gui/ResizableLayout/utils/validateLayout';
|
||||
import appReducer, { createAppDefaultState } from './app.reducer';
|
||||
const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js');
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
const fs = require('fs-extra');
|
||||
@@ -40,125 +36,38 @@ const PluginManager = require('@joplin/lib/services/PluginManager');
|
||||
import RevisionService from '@joplin/lib/services/RevisionService';
|
||||
import MigrationService from '@joplin/lib/services/MigrationService';
|
||||
import { loadCustomCss, injectCustomStyles } from '@joplin/lib/CssUtils';
|
||||
import mainScreenCommands from './gui/MainScreen/commands/index';
|
||||
import noteEditorCommands from './gui/NoteEditor/commands/index';
|
||||
import noteListCommands from './gui/NoteList/commands/index';
|
||||
import noteListControlsCommands from './gui/NoteListControls/commands/index';
|
||||
import sidebarCommands from './gui/Sidebar/commands/index';
|
||||
import appCommands from './commands/index';
|
||||
import libCommands from '@joplin/lib/commands/index';
|
||||
// import populateDatabase from '@joplin/lib/services/debug/populateDatabase';
|
||||
|
||||
const commands = [
|
||||
require('./gui/MainScreen/commands/editAlarm'),
|
||||
require('./gui/MainScreen/commands/exportPdf'),
|
||||
require('./gui/MainScreen/commands/gotoAnything'),
|
||||
require('./gui/MainScreen/commands/commandPalette'),
|
||||
require('./gui/MainScreen/commands/hideModalMessage'),
|
||||
require('./gui/MainScreen/commands/moveToFolder'),
|
||||
require('./gui/MainScreen/commands/newFolder'),
|
||||
require('./gui/MainScreen/commands/newNote'),
|
||||
require('./gui/MainScreen/commands/newSubFolder'),
|
||||
require('./gui/MainScreen/commands/newTodo'),
|
||||
require('./gui/MainScreen/commands/openFolder'),
|
||||
require('./gui/MainScreen/commands/openNote'),
|
||||
require('./gui/MainScreen/commands/openTag'),
|
||||
require('./gui/MainScreen/commands/print'),
|
||||
require('./gui/MainScreen/commands/renameFolder'),
|
||||
require('./gui/MainScreen/commands/renameTag'),
|
||||
require('./gui/MainScreen/commands/search'),
|
||||
require('./gui/MainScreen/commands/setTags'),
|
||||
require('./gui/MainScreen/commands/showModalMessage'),
|
||||
require('./gui/MainScreen/commands/showNoteContentProperties'),
|
||||
require('./gui/MainScreen/commands/showNoteProperties'),
|
||||
require('./gui/MainScreen/commands/showPrompt'),
|
||||
require('./gui/MainScreen/commands/showShareFolderDialog'),
|
||||
require('./gui/MainScreen/commands/showShareNoteDialog'),
|
||||
require('./gui/MainScreen/commands/showSpellCheckerMenu'),
|
||||
require('./gui/MainScreen/commands/toggleEditors'),
|
||||
require('./gui/MainScreen/commands/toggleLayoutMoveMode'),
|
||||
require('./gui/MainScreen/commands/toggleNoteList'),
|
||||
require('./gui/MainScreen/commands/toggleSideBar'),
|
||||
require('./gui/MainScreen/commands/toggleVisiblePanes'),
|
||||
require('./gui/NoteEditor/commands/focusElementNoteBody'),
|
||||
require('./gui/NoteEditor/commands/focusElementNoteTitle'),
|
||||
require('./gui/NoteEditor/commands/showLocalSearch'),
|
||||
require('./gui/NoteEditor/commands/showRevisions'),
|
||||
require('./gui/NoteList/commands/focusElementNoteList'),
|
||||
require('./gui/NoteListControls/commands/focusSearch'),
|
||||
require('./gui/Sidebar/commands/focusElementSideBar'),
|
||||
];
|
||||
const commands = mainScreenCommands
|
||||
.concat(noteEditorCommands)
|
||||
.concat(noteListCommands)
|
||||
.concat(noteListControlsCommands)
|
||||
.concat(sidebarCommands);
|
||||
|
||||
// Commands that are not tied to any particular component.
|
||||
// The runtime for these commands can be loaded when the app starts.
|
||||
const globalCommands = [
|
||||
require('./commands/copyDevCommand'),
|
||||
require('./commands/exportFolders'),
|
||||
require('./commands/exportNotes'),
|
||||
require('./commands/focusElement'),
|
||||
require('./commands/openProfileDirectory'),
|
||||
require('./commands/replaceMisspelling'),
|
||||
require('./commands/startExternalEditing'),
|
||||
require('./commands/stopExternalEditing'),
|
||||
require('./commands/toggleExternalEditing'),
|
||||
require('./commands/toggleSafeMode'),
|
||||
require('./commands/restoreNoteRevision'),
|
||||
require('@joplin/lib/commands/historyBackward'),
|
||||
require('@joplin/lib/commands/historyForward'),
|
||||
require('@joplin/lib/commands/synchronize'),
|
||||
];
|
||||
const globalCommands = appCommands.concat(libCommands);
|
||||
|
||||
import editorCommandDeclarations from './gui/NoteEditor/commands/editorCommandDeclarations';
|
||||
import editorCommandDeclarations from './gui/NoteEditor/editorCommandDeclarations';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import checkForUpdates from './checkForUpdates';
|
||||
import { AppState } from './app.reducer';
|
||||
|
||||
const pluginClasses = [
|
||||
require('./plugins/GotoAnything').default,
|
||||
];
|
||||
|
||||
interface AppStateRoute {
|
||||
type: string;
|
||||
routeName: string;
|
||||
props: any;
|
||||
}
|
||||
|
||||
export interface AppStateDialog {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AppState extends State {
|
||||
route: AppStateRoute;
|
||||
navHistory: any[];
|
||||
noteVisiblePanes: string[];
|
||||
windowContentSize: any;
|
||||
watchedNoteFiles: string[];
|
||||
lastEditorScrollPercents: any;
|
||||
devToolsVisible: boolean;
|
||||
visibleDialogs: any; // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
focusedField: string;
|
||||
layoutMoveMode: boolean;
|
||||
startupPluginsLoaded: boolean;
|
||||
|
||||
// Extra reducer keys go here
|
||||
watchedResources: any;
|
||||
mainLayout: LayoutItem;
|
||||
dialogs: AppStateDialog[];
|
||||
}
|
||||
|
||||
const appDefaultState: AppState = {
|
||||
...defaultState,
|
||||
route: {
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Main',
|
||||
props: {},
|
||||
},
|
||||
navHistory: [],
|
||||
noteVisiblePanes: ['editor', 'viewer'],
|
||||
windowContentSize: bridge().windowContentSize(),
|
||||
watchedNoteFiles: [],
|
||||
lastEditorScrollPercents: {},
|
||||
devToolsVisible: false,
|
||||
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
focusedField: null,
|
||||
layoutMoveMode: false,
|
||||
mainLayout: null,
|
||||
startupPluginsLoaded: false,
|
||||
dialogs: [],
|
||||
...resourceEditWatcherDefaultState,
|
||||
};
|
||||
const appDefaultState = createAppDefaultState(
|
||||
bridge().windowContentSize(),
|
||||
resourceEditWatcherDefaultState
|
||||
);
|
||||
|
||||
class Application extends BaseApplication {
|
||||
|
||||
@@ -175,249 +84,9 @@ class Application extends BaseApplication {
|
||||
}
|
||||
|
||||
reducer(state: AppState = appDefaultState, action: any) {
|
||||
let newState = state;
|
||||
|
||||
try {
|
||||
switch (action.type) {
|
||||
|
||||
case 'NAV_BACK':
|
||||
case 'NAV_GO':
|
||||
|
||||
{
|
||||
const goingBack = action.type === 'NAV_BACK';
|
||||
|
||||
if (goingBack && !state.navHistory.length) break;
|
||||
|
||||
const currentRoute = state.route;
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
const newNavHistory = state.navHistory.slice();
|
||||
|
||||
if (goingBack) {
|
||||
let newAction = null;
|
||||
while (newNavHistory.length) {
|
||||
newAction = newNavHistory.pop();
|
||||
if (newAction.routeName !== state.route.routeName) break;
|
||||
}
|
||||
|
||||
if (!newAction) break;
|
||||
|
||||
action = newAction;
|
||||
}
|
||||
|
||||
if (!goingBack) newNavHistory.push(currentRoute);
|
||||
newState.navHistory = newNavHistory;
|
||||
newState.route = action;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'STARTUP_PLUGINS_LOADED':
|
||||
|
||||
// When all startup plugins have loaded, we also recreate the
|
||||
// main layout to ensure that it is updated in the UI. There's
|
||||
// probably a cleaner way to do this, but for now that will do.
|
||||
if (state.startupPluginsLoaded !== action.value) {
|
||||
newState = {
|
||||
...newState,
|
||||
startupPluginsLoaded: action.value,
|
||||
mainLayout: JSON.parse(JSON.stringify(newState.mainLayout)),
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'WINDOW_CONTENT_SIZE_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.windowContentSize = action.size;
|
||||
break;
|
||||
|
||||
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
||||
|
||||
{
|
||||
const getNextLayout = (currentLayout: any) => {
|
||||
currentLayout = panes.length === 2 ? 'both' : currentLayout[0];
|
||||
|
||||
let paneOptions;
|
||||
if (state.settings.layoutButtonSequence === Setting.LAYOUT_EDITOR_VIEWER) {
|
||||
paneOptions = ['editor', 'viewer'];
|
||||
} else if (state.settings.layoutButtonSequence === Setting.LAYOUT_EDITOR_SPLIT) {
|
||||
paneOptions = ['editor', 'both'];
|
||||
} else if (state.settings.layoutButtonSequence === Setting.LAYOUT_VIEWER_SPLIT) {
|
||||
paneOptions = ['viewer', 'both'];
|
||||
} else {
|
||||
paneOptions = ['editor', 'viewer', 'both'];
|
||||
}
|
||||
|
||||
const currentLayoutIndex = paneOptions.indexOf(currentLayout);
|
||||
const nextLayoutIndex = currentLayoutIndex === paneOptions.length - 1 ? 0 : currentLayoutIndex + 1;
|
||||
|
||||
const nextLayout = paneOptions[nextLayoutIndex];
|
||||
return nextLayout === 'both' ? ['editor', 'viewer'] : [nextLayout];
|
||||
};
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
|
||||
const panes = state.noteVisiblePanes.slice();
|
||||
newState.noteVisiblePanes = getNextLayout(panes);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_VISIBLE_PANES_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.noteVisiblePanes = action.panes;
|
||||
break;
|
||||
|
||||
case 'MAIN_LAYOUT_SET':
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: action.value,
|
||||
};
|
||||
break;
|
||||
|
||||
case 'MAIN_LAYOUT_SET_ITEM_PROP':
|
||||
|
||||
{
|
||||
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
|
||||
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
|
||||
if (item.key === action.itemKey) {
|
||||
(item as any)[action.propName] = action.propValue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: newLayout,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_ADD':
|
||||
|
||||
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {
|
||||
newState = Object.assign({}, state);
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
watchedNoteFiles.push(action.id);
|
||||
newState.watchedNoteFiles = watchedNoteFiles;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_REMOVE':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const idx = newState.watchedNoteFiles.indexOf(action.id);
|
||||
if (idx >= 0) {
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
watchedNoteFiles.splice(idx, 1);
|
||||
newState.watchedNoteFiles = watchedNoteFiles;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_CLEAR':
|
||||
|
||||
if (state.watchedNoteFiles.length) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.watchedNoteFiles = [];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'EDITOR_SCROLL_PERCENT_SET':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
|
||||
newPercents[action.noteId] = action.percent;
|
||||
newState.lastEditorScrollPercents = newPercents;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_TOGGLE':
|
||||
newState = Object.assign({}, state);
|
||||
newState.devToolsVisible = !newState.devToolsVisible;
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_SET':
|
||||
newState = Object.assign({}, state);
|
||||
newState.devToolsVisible = action.value;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_ADD':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
newState.visibleDialogs[action.name] = true;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_REMOVE':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
delete newState.visibleDialogs[action.name];
|
||||
break;
|
||||
|
||||
case 'FOCUS_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = action.field;
|
||||
break;
|
||||
|
||||
case 'FOCUS_CLEAR':
|
||||
|
||||
// A field can only clear its own state
|
||||
if (action.field === state.focusedField) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DIALOG_OPEN':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const newDialogs = newState.dialogs.slice();
|
||||
|
||||
if (newDialogs.find(d => d.name === action.name)) throw new Error(`This dialog is already opened: ${action.name}`);
|
||||
|
||||
newDialogs.push({
|
||||
name: action.name,
|
||||
});
|
||||
newState.dialogs = newDialogs;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DIALOG_CLOSE':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const newDialogs = newState.dialogs.slice().filter(d => d.name !== action.name);
|
||||
newState.dialogs = newDialogs;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'LAYOUT_MOVE_MODE_SET':
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
layoutMoveMode: action.value,
|
||||
};
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
let newState = appReducer(state, action);
|
||||
newState = resourceEditWatcherReducer(newState, action);
|
||||
newState = super.reducer(newState, action);
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
@@ -873,6 +542,16 @@ class Application extends BaseApplication {
|
||||
// });
|
||||
// }, 2000);
|
||||
|
||||
// setTimeout(() => {
|
||||
// this.dispatch({
|
||||
// type: 'NAV_GO',
|
||||
// routeName: 'Config',
|
||||
// props: {
|
||||
// defaultSection: 'plugins',
|
||||
// },
|
||||
// });
|
||||
// }, 2000);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as copyDevCommand from './copyDevCommand';
|
||||
import * as exportFolders from './exportFolders';
|
||||
import * as exportNotes from './exportNotes';
|
||||
import * as focusElement from './focusElement';
|
||||
import * as openProfileDirectory from './openProfileDirectory';
|
||||
import * as replaceMisspelling from './replaceMisspelling';
|
||||
import * as restoreNoteRevision from './restoreNoteRevision';
|
||||
import * as startExternalEditing from './startExternalEditing';
|
||||
import * as stopExternalEditing from './stopExternalEditing';
|
||||
import * as toggleExternalEditing from './toggleExternalEditing';
|
||||
import * as toggleSafeMode from './toggleSafeMode';
|
||||
|
||||
const index:any[] = [
|
||||
copyDevCommand,
|
||||
exportFolders,
|
||||
exportNotes,
|
||||
focusElement,
|
||||
openProfileDirectory,
|
||||
replaceMisspelling,
|
||||
restoreNoteRevision,
|
||||
startExternalEditing,
|
||||
stopExternalEditing,
|
||||
toggleExternalEditing,
|
||||
toggleSafeMode,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -1,5 +1,5 @@
|
||||
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
import bridge from '../services/bridge';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { _ } from '@joplin/lib/locale';
|
||||
import ClipperServer from '@joplin/lib/ClipperServer';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import EncryptionService from '@joplin/lib/services/e2ee/EncryptionService';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
|
||||
class ClipperConfigScreenComponent extends React.Component {
|
||||
constructor() {
|
||||
|
||||
@@ -133,6 +133,20 @@ const StyledDescription = styled.div`
|
||||
line-height: 1.6em;
|
||||
`;
|
||||
|
||||
const RecommendedBadge = styled.a`
|
||||
font-family: ${props => props.theme.fontFamily};
|
||||
color: ${props => props.theme.colorWarn};
|
||||
font-size: ${props => props.theme.fontSize}px;
|
||||
border: 1px solid ${props => props.theme.colorWarn};
|
||||
padding: 5px;
|
||||
border-radius: 50px;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function(props: Props) {
|
||||
const item = useMemo(() => {
|
||||
return props.item ? props.item : manifestToItem(props.manifest);
|
||||
@@ -144,6 +158,10 @@ export default function(props: Props) {
|
||||
bridge().openExternal(manifest.homepage_url);
|
||||
}, [item]);
|
||||
|
||||
const onRecommendedClick = useCallback(() => {
|
||||
bridge().openExternal('https://github.com/joplin/plugins/blob/master/readme/recommended.md#recommended-plugins');
|
||||
}, []);
|
||||
|
||||
// For plugins in dev mode things like enabling/disabling or
|
||||
// uninstalling them doesn't make sense, as that should be done by
|
||||
// adding/removing them from wherever they were loaded from.
|
||||
@@ -222,11 +240,18 @@ export default function(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
function renderRecommendedBadge() {
|
||||
if (props.onToggle) return null;
|
||||
if (!item.manifest._recommended) return null;
|
||||
return <RecommendedBadge href="#" title={_('The Joplin team has vetted this plugin and it meets our standards for security and performance.')} onClick={onRecommendedClick}><i className="fas fa-crown"></i></RecommendedBadge>;
|
||||
}
|
||||
|
||||
return (
|
||||
<CellRoot isCompatible={props.isCompatible}>
|
||||
<CellTop>
|
||||
<StyledNameAndVersion mb={'5px'}><StyledName onClick={onNameClick} href="#" style={{ marginRight: 5 }}>{item.manifest.name} {item.deleted ? _('(%s)', 'Deleted') : ''}</StyledName><StyledVersion>v{item.manifest.version}</StyledVersion></StyledNameAndVersion>
|
||||
{renderToggleButton()}
|
||||
{renderRecommendedBadge()}
|
||||
</CellTop>
|
||||
<CellContent>
|
||||
<StyledDescription>{item.manifest.description}</StyledDescription>
|
||||
|
||||
@@ -299,7 +299,7 @@ export default function(props: Props) {
|
||||
function renderRepoApiError() {
|
||||
if (!repoApiError) return null;
|
||||
|
||||
return <RepoApiErrorMessage maxWidth={maxWidth} type="error">{_('Could not connect to plugin repository')} - <StyledLink href="#" onClick={() => { setFetchManifestTime(Date.now()); }}>{_('Try again')}</StyledLink></RepoApiErrorMessage>;
|
||||
return <RepoApiErrorMessage maxWidth={maxWidth} type="error">{_('Could not connect to plugin repository.')}<br/><br/>- <StyledLink href="#" onClick={() => { setFetchManifestTime(Date.now()); }}>{_('Try again')}</StyledLink><br/><br/>- <StyledLink href="#" onClick={onBrowsePlugins}>{_('Browse all plugins')}</StyledLink></RepoApiErrorMessage>;
|
||||
}
|
||||
|
||||
function renderBottomArea() {
|
||||
|
||||
@@ -30,6 +30,14 @@ interface Props {
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
function sortManifestResults(results: PluginManifest[]): PluginManifest[] {
|
||||
return results.sort((m1, m2) => {
|
||||
if (m1._recommended && !m2._recommended) return -1;
|
||||
if (!m1._recommended && m2._recommended) return +1;
|
||||
return m1.name.toLowerCase() < m2.name.toLowerCase() ? -1 : +1;
|
||||
});
|
||||
}
|
||||
|
||||
export default function(props: Props) {
|
||||
const [searchStarted, setSearchStarted] = useState(false);
|
||||
const [manifests, setManifests] = useState<PluginManifest[]>([]);
|
||||
@@ -47,7 +55,7 @@ export default function(props: Props) {
|
||||
setSearchResultCount(null);
|
||||
} else {
|
||||
const r = await props.repoApi().search(props.searchQuery);
|
||||
setManifests(r);
|
||||
setManifests(sortManifestResults(r));
|
||||
setSearchResultCount(r.length);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,8 +12,16 @@ import bridge from '../services/bridge';
|
||||
import shared from '@joplin/lib/components/shared/encryption-config-shared';
|
||||
import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types';
|
||||
import { getEncryptionEnabled, masterKeyEnabled, SyncInfo } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { toggleAndSetupEncryption } from '@joplin/lib/services/e2ee/utils';
|
||||
import { getDefaultMasterKey, toggleAndSetupEncryption } from '@joplin/lib/services/e2ee/utils';
|
||||
import MasterKey from '@joplin/lib/models/MasterKey';
|
||||
import StyledInput from './style/StyledInput';
|
||||
import Button, { ButtonLevel } from './Button/Button';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const MasterPasswordInput = styled(StyledInput)`
|
||||
min-width: 300px;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
interface Props {}
|
||||
|
||||
@@ -45,6 +53,10 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
private renderMasterKey(mk: MasterKeyEntity, isDefault: boolean) {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const onToggleEnabledClick = () => {
|
||||
return shared.onToggleEnabledClick(this, mk);
|
||||
};
|
||||
|
||||
const passwordStyle = {
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
@@ -60,8 +72,23 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
return shared.onPasswordChange(this, mk, event.target.value);
|
||||
};
|
||||
|
||||
const onToggleEnabledClick = () => {
|
||||
return shared.onToggleEnabledClick(this, mk);
|
||||
const renderPasswordInput = (masterKeyId: string) => {
|
||||
if (this.state.masterPasswordKeys[masterKeyId] || !this.state.passwordChecks['master']) {
|
||||
return (
|
||||
<td style={{ ...theme.textStyle, color: theme.colorFaded, fontStyle: 'italic' }}>
|
||||
({_('Master password')})
|
||||
</td>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<td style={theme.textStyle}>
|
||||
<input type="password" style={passwordStyle} value={password} onChange={event => onPasswordChange(event)} />{' '}
|
||||
<button style={theme.buttonStyle} onClick={() => onSaveClick()}>
|
||||
{_('Save')}
|
||||
</button>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const password = this.state.passwords[mk.id] ? this.state.passwords[mk.id] : '';
|
||||
@@ -74,12 +101,7 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
<td style={theme.textStyle}>{activeIcon}</td>
|
||||
<td style={theme.textStyle}>{mk.id}<br/>{_('Source: ')}{mk.source_application}</td>
|
||||
<td style={theme.textStyle}>{_('Created: ')}{time.formatMsToLocal(mk.created_time)}<br/>{_('Updated: ')}{time.formatMsToLocal(mk.updated_time)}</td>
|
||||
<td style={theme.textStyle}>
|
||||
<input type="password" style={passwordStyle} value={password} onChange={event => onPasswordChange(event)} />{' '}
|
||||
<button style={theme.buttonStyle} onClick={() => onSaveClick()}>
|
||||
{_('Save')}
|
||||
</button>
|
||||
</td>
|
||||
{renderPasswordInput(mk.id)}
|
||||
<td style={theme.textStyle}>{passwordOk}</td>
|
||||
<td style={theme.textStyle}>
|
||||
<button disabled={isActive || isDefault} style={theme.buttonStyle} onClick={() => onToggleEnabledClick()}>{masterKeyEnabled(mk) ? _('Disable') : _('Enable')}</button>
|
||||
@@ -165,7 +187,7 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
}
|
||||
|
||||
const headerComp = isEnabledMasterKeys ? <h1 style={theme.h1Style}>{_('Master Keys')}</h1> : <a onClick={() => shared.toggleShowDisabledMasterKeys(this) } style={{ ...theme.urlStyle, display: 'inline-block', marginBottom: 10 }} href="#">{showTable ? _('Hide disabled master keys') : _('Show disabled master keys')}</a>;
|
||||
const infoComp = isEnabledMasterKeys ? <p style={theme.textStyle}>{_('Note: Only one master key is going to be used for encryption (the one marked as "active"). Any of the keys might be used for decryption, depending on how the notes or notebooks were originally encrypted.')}</p> : null;
|
||||
const infoComp = isEnabledMasterKeys ? <p style={theme.textStyle}>{'Note: Only one master key is going to be used for encryption (the one marked as "active"). Any of the keys might be used for decryption, depending on how the notes or notebooks were originally encrypted.'}</p> : null;
|
||||
const tableComp = !showTable ? null : (
|
||||
<table>
|
||||
<tbody>
|
||||
@@ -195,6 +217,39 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
return null;
|
||||
}
|
||||
|
||||
private renderMasterPassword() {
|
||||
if (!this.props.encryptionEnabled && !this.props.masterKeys.length) return null;
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const onMasterPasswordSave = async () => {
|
||||
shared.onMasterPasswordSave(this);
|
||||
|
||||
if (!(await shared.masterPasswordIsValid(this, this.state.masterPasswordInput))) {
|
||||
alert('Password is invalid. Please try again.');
|
||||
}
|
||||
};
|
||||
|
||||
if (this.state.passwordChecks['master']) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<span style={theme.textStyle}>{_('Master password:')}</span>
|
||||
<span style={{ ...theme.textStyle, fontWeight: 'bold' }}>✔ {_('Loaded')}</span>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<span style={theme.textStyle}>❌ {'The master password is not set or is invalid. Please type it below:'}</span>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', marginTop: 10 }}>
|
||||
<MasterPasswordInput placeholder={_('Enter your master password')} type="password" value={this.state.masterPasswordInput} onChange={(event: any) => shared.onMasterPasswordChange(this, event.target.value)} />{' '}
|
||||
<Button ml="10px" level={ButtonLevel.Secondary} onClick={onMasterPasswordSave} title={_('Save')} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const masterKeys: MasterKeyEntity[] = this.props.masterKeys;
|
||||
@@ -215,7 +270,7 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
|
||||
const onToggleButtonClick = async () => {
|
||||
const isEnabled = getEncryptionEnabled();
|
||||
const masterKey = MasterKey.latest();
|
||||
const masterKey = getDefaultMasterKey();
|
||||
|
||||
let answer = null;
|
||||
if (isEnabled) {
|
||||
@@ -304,6 +359,7 @@ class EncryptionConfigScreenComponent extends React.Component<Props> {
|
||||
<p style={theme.textStyle}>
|
||||
{_('Encryption is:')} <strong>{this.props.encryptionEnabled ? _('Enabled') : _('Disabled')}</strong>
|
||||
</p>
|
||||
{this.renderMasterPassword()}
|
||||
{decryptedItemsInfo}
|
||||
{toggleButton}
|
||||
{needUpgradeSection}
|
||||
@@ -329,6 +385,7 @@ const mapStateToProps = (state: State) => {
|
||||
activeMasterKeyId: syncInfo.activeMasterKeyId,
|
||||
shouldReencrypt: state.settings['encryption.shouldReencrypt'] >= Setting.SHOULD_REENCRYPT_YES,
|
||||
notLoadedMasterKeys: state.notLoadedMasterKeys,
|
||||
masterPassword: state.settings['encryption.masterPassword'],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { stateUtils } from '@joplin/lib/reducer';
|
||||
import InteropServiceHelper from '../../InteropServiceHelper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import NoteListWrapper from '../NoteListWrapper/NoteListWrapper';
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { saveLayout, loadLayout } from '../ResizableLayout/utils/persist';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import produce from 'immer';
|
||||
@@ -37,6 +37,7 @@ import { reg } from '@joplin/lib/registry';
|
||||
import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems';
|
||||
import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils';
|
||||
import commands from './commands/index';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { PromptDialog } = require('../PromptDialog.min.js');
|
||||
@@ -110,39 +111,6 @@ const defaultLayout: LayoutItem = {
|
||||
],
|
||||
};
|
||||
|
||||
const commands = [
|
||||
require('./commands/editAlarm'),
|
||||
require('./commands/exportPdf'),
|
||||
require('./commands/gotoAnything'),
|
||||
require('./commands/commandPalette'),
|
||||
require('./commands/hideModalMessage'),
|
||||
require('./commands/moveToFolder'),
|
||||
require('./commands/newFolder'),
|
||||
require('./commands/newNote'),
|
||||
require('./commands/newSubFolder'),
|
||||
require('./commands/newTodo'),
|
||||
require('./commands/openFolder'),
|
||||
require('./commands/openNote'),
|
||||
require('./commands/openTag'),
|
||||
require('./commands/print'),
|
||||
require('./commands/renameFolder'),
|
||||
require('./commands/renameTag'),
|
||||
require('./commands/search'),
|
||||
require('./commands/setTags'),
|
||||
require('./commands/showModalMessage'),
|
||||
require('./commands/showNoteContentProperties'),
|
||||
require('./commands/showNoteProperties'),
|
||||
require('./commands/showPrompt'),
|
||||
require('./commands/showShareFolderDialog'),
|
||||
require('./commands/showShareNoteDialog'),
|
||||
require('./commands/showSpellCheckerMenu'),
|
||||
require('./commands/toggleEditors'),
|
||||
require('./commands/toggleLayoutMoveMode'),
|
||||
require('./commands/toggleNoteList'),
|
||||
require('./commands/toggleSideBar'),
|
||||
require('./commands/toggleVisiblePanes'),
|
||||
];
|
||||
|
||||
class MainScreenComponent extends React.Component<Props, State> {
|
||||
|
||||
private waitForNotesSavedIID_: any;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as commandPalette from './commandPalette';
|
||||
import * as editAlarm from './editAlarm';
|
||||
import * as exportPdf from './exportPdf';
|
||||
import * as gotoAnything from './gotoAnything';
|
||||
import * as hideModalMessage from './hideModalMessage';
|
||||
import * as moveToFolder from './moveToFolder';
|
||||
import * as newFolder from './newFolder';
|
||||
import * as newNote from './newNote';
|
||||
import * as newSubFolder from './newSubFolder';
|
||||
import * as newTodo from './newTodo';
|
||||
import * as openFolder from './openFolder';
|
||||
import * as openNote from './openNote';
|
||||
import * as openTag from './openTag';
|
||||
import * as print from './print';
|
||||
import * as renameFolder from './renameFolder';
|
||||
import * as renameTag from './renameTag';
|
||||
import * as search from './search';
|
||||
import * as setTags from './setTags';
|
||||
import * as showModalMessage from './showModalMessage';
|
||||
import * as showNoteContentProperties from './showNoteContentProperties';
|
||||
import * as showNoteProperties from './showNoteProperties';
|
||||
import * as showPrompt from './showPrompt';
|
||||
import * as showShareFolderDialog from './showShareFolderDialog';
|
||||
import * as showShareNoteDialog from './showShareNoteDialog';
|
||||
import * as showSpellCheckerMenu from './showSpellCheckerMenu';
|
||||
import * as toggleEditors from './toggleEditors';
|
||||
import * as toggleLayoutMoveMode from './toggleLayoutMoveMode';
|
||||
import * as toggleNoteList from './toggleNoteList';
|
||||
import * as toggleSideBar from './toggleSideBar';
|
||||
import * as toggleVisiblePanes from './toggleVisiblePanes';
|
||||
|
||||
const index:any[] = [
|
||||
commandPalette,
|
||||
editAlarm,
|
||||
exportPdf,
|
||||
gotoAnything,
|
||||
hideModalMessage,
|
||||
moveToFolder,
|
||||
newFolder,
|
||||
newNote,
|
||||
newSubFolder,
|
||||
newTodo,
|
||||
openFolder,
|
||||
openNote,
|
||||
openTag,
|
||||
print,
|
||||
renameFolder,
|
||||
renameTag,
|
||||
search,
|
||||
setTags,
|
||||
showModalMessage,
|
||||
showNoteContentProperties,
|
||||
showNoteProperties,
|
||||
showPrompt,
|
||||
showShareFolderDialog,
|
||||
showShareNoteDialog,
|
||||
showSpellCheckerMenu,
|
||||
toggleEditors,
|
||||
toggleLayoutMoveMode,
|
||||
toggleNoteList,
|
||||
toggleSideBar,
|
||||
toggleVisiblePanes,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -2,7 +2,7 @@ import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import bridge from '../../../services/bridge';
|
||||
import SpellCheckerService from '@joplin/lib/services/spellChecker/SpellCheckerService';
|
||||
import { AppState } from '../../../app';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
|
||||
const Menu = bridge().Menu;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { AppState } from '../../../app';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'toggleLayoutMoveMode',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import setLayoutItemProps from '../../ResizableLayout/utils/setLayoutItemProps';
|
||||
import layoutItemProp from '../../ResizableLayout/utils/layoutItemProp';
|
||||
import { AppState } from '../../../app';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'toggleNoteList',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import setLayoutItemProps from '../../ResizableLayout/utils/setLayoutItemProps';
|
||||
import layoutItemProp from '../../ResizableLayout/utils/layoutItemProp';
|
||||
import { AppState } from '../../../app';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'toggleSideBar',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState, useRef, useCallback } from 'react';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
import InteropService from '@joplin/lib/services/interop/InteropService';
|
||||
import { stateUtils } from '@joplin/lib/reducer';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
|
||||
@@ -3,7 +3,7 @@ import CommandService from '@joplin/lib/services/CommandService';
|
||||
import ToolbarBase from '../../../ToolbarBase';
|
||||
import { utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from '../../../../app';
|
||||
import { AppState } from '../../../../app.reducer';
|
||||
import ToolbarButtonUtils, { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
|
||||
import stateToWhenClauseContext from '../../../../services/commands/stateToWhenClauseContext';
|
||||
const { buildStyle } = require('@joplin/lib/theme');
|
||||
|
||||
@@ -20,7 +20,7 @@ import CommandService from '@joplin/lib/services/CommandService';
|
||||
import ToolbarButton from '../ToolbarButton/ToolbarButton';
|
||||
import Button, { ButtonLevel } from '../Button/Button';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import ToolbarButtonUtils from '@joplin/lib/services/commands/ToolbarButtonUtils';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import TagList from '../TagList';
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as focusElementNoteBody from './focusElementNoteBody';
|
||||
import * as focusElementNoteTitle from './focusElementNoteTitle';
|
||||
import * as showLocalSearch from './showLocalSearch';
|
||||
import * as showRevisions from './showRevisions';
|
||||
|
||||
const index:any[] = [
|
||||
focusElementNoteBody,
|
||||
focusElementNoteTitle,
|
||||
showLocalSearch,
|
||||
showRevisions,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
File renamed without changes.
@@ -1,6 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { FormNote, ScrollOptionTypes } from './types';
|
||||
import editorCommandDeclarations from '../commands/editorCommandDeclarations';
|
||||
import editorCommandDeclarations from '../editorCommandDeclarations';
|
||||
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import time from '@joplin/lib/time';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import NoteListUtils from '../utils/NoteListUtils';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as focusElementNoteList from './focusElementNoteList';
|
||||
|
||||
const index:any[] = [
|
||||
focusElementNoteList,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -0,0 +1,9 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as focusSearch from './focusSearch';
|
||||
|
||||
const index:any[] = [
|
||||
focusSearch,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -1,4 +1,5 @@
|
||||
import app, { AppState, AppStateDialog } from '../app';
|
||||
import app from '../app';
|
||||
import { AppState, AppStateDialog } from '../app.reducer';
|
||||
import MainScreen from './MainScreen/MainScreen';
|
||||
import ConfigScreen from './ConfigScreen/ConfigScreen';
|
||||
import StatusScreen from './StatusScreen/StatusScreen';
|
||||
@@ -19,6 +20,7 @@ import DialogTitle from './DialogTitle';
|
||||
import DialogButtonRow, { ButtonSpec, ClickEvent, ClickEventHandler } from './DialogButtonRow';
|
||||
import Dialog from './Dialog';
|
||||
import SyncWizardDialog from './SyncWizard/Dialog';
|
||||
import StyleSheetContainer from './StyleSheets/StyleSheetContainer';
|
||||
const { ImportScreen } = require('./ImportScreen.min.js');
|
||||
const { ResourceScreen } = require('./ResourceScreen.js');
|
||||
const { Navigator } = require('./Navigator.min.js');
|
||||
@@ -207,6 +209,7 @@ class RootComponent extends React.Component<Props, any> {
|
||||
return (
|
||||
<StyleSheetManager disableVendorPrefixes>
|
||||
<ThemeProvider theme={theme}>
|
||||
<StyleSheetContainer themeId={this.props.themeId}></StyleSheetContainer>
|
||||
<MenuBar/>
|
||||
<GlobalStyle/>
|
||||
<Navigator style={navigatorStyle} screens={screens} />
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ShareUserStatus, StateShare, StateShareUser } from '@joplin/lib/service
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
import { connect } from 'react-redux';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
||||
|
||||
const logger = Logger.create('ShareFolderDialog');
|
||||
|
||||
@@ -100,20 +101,6 @@ interface RecipientDeleteEvent {
|
||||
shareUserId: string;
|
||||
}
|
||||
|
||||
interface AsyncEffectEvent {
|
||||
cancelled: boolean;
|
||||
}
|
||||
|
||||
function useAsyncEffect(effect: Function, dependencies: any[]) {
|
||||
useEffect(() => {
|
||||
const event = { cancelled: false };
|
||||
effect(event);
|
||||
return () => {
|
||||
event.cancelled = true;
|
||||
};
|
||||
}, dependencies);
|
||||
}
|
||||
|
||||
enum ShareState {
|
||||
Idle = 0,
|
||||
Synchronizing = 1,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { StateShare } from '@joplin/lib/services/share/reducer';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import Button from './Button/Button';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
import { getEncryptionEnabled } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
const { clipboard } = require('electron');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import InteropServiceHelper from '../../InteropServiceHelper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import { MenuItemLocation } from '@joplin/lib/services/plugins/api/types';
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { ModelType } from '@joplin/lib/BaseModel';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import layoutItemProp from '../../ResizableLayout/utils/layoutItemProp';
|
||||
import { AppState } from '../../../app';
|
||||
import { AppState } from '../../../app.reducer';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'focusElementSideBar',
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as focusElementSideBar from './focusElementSideBar';
|
||||
|
||||
const index:any[] = [
|
||||
focusElementSideBar,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -0,0 +1,41 @@
|
||||
// This component is perhaps a bit of a hack but the approach should be
|
||||
// reliable. It converts the current (JS) theme to CSS, and add it to the HEAD
|
||||
// tag. The component itself doesn't render anything where it's located (just an
|
||||
// empty invisible DIV), so it means it could be put anywhere and would have the
|
||||
// same effect.
|
||||
//
|
||||
// It's still reliable because the lifecyle of adding the CSS and removing on
|
||||
// unmout is handled properly. There should only be one such component on the
|
||||
// page.
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
||||
import themeToCss from '@joplin/lib/services/style/themeToCss';
|
||||
import { themeById } from '@joplin/lib/theme';
|
||||
|
||||
interface Props {
|
||||
themeId: any;
|
||||
}
|
||||
|
||||
export default function(props: Props): any {
|
||||
const [styleSheetContent, setStyleSheetContent] = useState('');
|
||||
|
||||
useAsyncEffect(async (event: AsyncEffectEvent) => {
|
||||
const theme = themeById(props.themeId);
|
||||
const themeCss = themeToCss(theme);
|
||||
if (event.cancelled) return;
|
||||
setStyleSheetContent(themeCss);
|
||||
}, [props.themeId]);
|
||||
|
||||
useEffect(() => {
|
||||
const element = document.createElement('style');
|
||||
element.setAttribute('id', 'main-theme-stylesheet-container');
|
||||
document.head.appendChild(element);
|
||||
element.appendChild(document.createTextNode(styleSheetContent));
|
||||
return () => {
|
||||
document.head.removeChild(element);
|
||||
};
|
||||
}, [styleSheetContent]);
|
||||
|
||||
return <div style={{ display: 'none' }}></div>;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { themeStyle } = require('@joplin/lib/theme');
|
||||
|
||||
@@ -19,6 +19,7 @@ const tasks = {
|
||||
},
|
||||
tsc: require('@joplin/tools/gulp/tasks/tsc'),
|
||||
updateIgnoredTypeScriptBuild: require('@joplin/tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
|
||||
buildCommandIndex: require('@joplin/tools/gulp/tasks/buildCommandIndex'),
|
||||
};
|
||||
|
||||
utils.registerGulpTasks(gulp, tasks);
|
||||
@@ -28,7 +29,8 @@ const buildParallel = [
|
||||
'compilePackageInfo',
|
||||
'copyPluginAssets',
|
||||
'copyTinyMceLangs',
|
||||
// 'updateIgnoredTypeScriptBuild',
|
||||
'updateIgnoredTypeScriptBuild',
|
||||
'buildCommandIndex',
|
||||
];
|
||||
|
||||
gulp.task('build', gulp.parallel(...buildParallel));
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.4.2",
|
||||
"version": "2.4.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.4.2",
|
||||
"version": "2.4.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.4.2",
|
||||
"version": "2.4.4",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { AppState } from '../app';
|
||||
import { AppState } from '../app.reducer';
|
||||
import CommandService, { SearchResult as CommandSearchResult } from '@joplin/lib/services/CommandService';
|
||||
import KeymapService from '@joplin/lib/services/KeymapService';
|
||||
import shim from '@joplin/lib/shim';
|
||||
@@ -337,6 +337,10 @@ class Dialog extends React.PureComponent<Props, State> {
|
||||
// @ts-ignore
|
||||
const notesById = notes.reduce((obj, { id, body, markup_language }) => ((obj[[id]] = { id, body, markup_language }), obj), {});
|
||||
|
||||
// Filter out search results that are associated with non-existing notes.
|
||||
// https://github.com/laurent22/joplin/issues/5417
|
||||
results = results.filter(r => !!notesById[r.id]);
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const row = results[i];
|
||||
const path = Folder.folderPathString(this.props.folders, row.parent_id);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// general, any desktop component should import this file, and not the lib
|
||||
// one.
|
||||
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import libStateToWhenClauseContext, { WhenClauseContextOptions } from '@joplin/lib/services/commands/stateToWhenClauseContext';
|
||||
import layoutItemProp from '../../gui/ResizableLayout/utils/layoutItemProp';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppState } from '../../app';
|
||||
import { AppState } from '../../app.reducer';
|
||||
|
||||
export interface DesktopCommandContext {
|
||||
state: AppState;
|
||||
|
||||
@@ -64,28 +64,6 @@ a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
.note-list .list-item-container:hover {
|
||||
background-color: rgba(0,160,255,0.1) !important;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
.editor-toolbar .button:not(.disabled):hover,
|
||||
.header .button:not(.disabled):hover {
|
||||
background-color: rgba(0,160,255,0.1);
|
||||
border: 1px solid rgba(0,160,255,0.5);
|
||||
box-sizing: 'border-box';
|
||||
}
|
||||
|
||||
.editor-toolbar .button:not(.disabled):active,
|
||||
.header .button:not(.disabled):active {
|
||||
background-color: rgba(0,160,255,0.2);
|
||||
border: 1px solid rgba(0,160,255,0.7);
|
||||
box-sizing: 'border-box';
|
||||
}
|
||||
*/
|
||||
|
||||
.editor-toolbar .button,
|
||||
.header .button {
|
||||
border: 1px solid rgba(0,160,255,0);
|
||||
@@ -163,11 +141,6 @@ a {
|
||||
to {transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
/* .joplin-tinymce .tox-editor-header {
|
||||
padding-left: 88px;
|
||||
padding-right: 150px;
|
||||
} */
|
||||
|
||||
*:focus {
|
||||
outline: none;
|
||||
}
|
||||
@@ -141,8 +141,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097648
|
||||
versionName "2.4.0"
|
||||
versionCode 2097649
|
||||
versionName "2.4.1"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
||||
@@ -116,15 +116,29 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent<Props> {
|
||||
inputStyle.borderBottomWidth = 1;
|
||||
inputStyle.borderBottomColor = theme.dividerColor;
|
||||
|
||||
const renderPasswordInput = (masterKeyId: string) => {
|
||||
if (this.state.masterPasswordKeys[masterKeyId] || !this.state.passwordChecks['master']) {
|
||||
return (
|
||||
<Text style={{ ...this.styles().normalText, color: theme.colorFaded, fontStyle: 'italic' }}>({_('Master password')})</Text>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TextInput selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} secureTextEntry={true} value={password} onChangeText={(text: string) => onPasswordChange(text)} style={inputStyle}></TextInput>
|
||||
<Text style={{ fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{passwordOk}</Text>
|
||||
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View key={mk.id}>
|
||||
<Text style={this.styles().titleText}>{_('Master Key %s', mk.id.substr(0, 6))}</Text>
|
||||
<Text style={this.styles().normalText}>{_('Created: %s', time.formatMsToLocal(mk.created_time))}</Text>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Text style={{ flex: 0, fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{_('Password:')}</Text>
|
||||
<TextInput selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} secureTextEntry={true} value={password} onChangeText={(text: string) => onPasswordChange(text)} style={inputStyle}></TextInput>
|
||||
<Text style={{ fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{passwordOk}</Text>
|
||||
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
|
||||
{renderPasswordInput(mk.id)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -203,6 +217,43 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderMasterPassword() {
|
||||
if (!this.props.encryptionEnabled && !this.props.masterKeys.length) return null;
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const onMasterPasswordSave = async () => {
|
||||
shared.onMasterPasswordSave(this);
|
||||
|
||||
if (!(await shared.masterPasswordIsValid(this, this.state.masterPasswordInput))) {
|
||||
alert('Password is invalid. Please try again.');
|
||||
}
|
||||
};
|
||||
|
||||
const inputStyle: any = { flex: 1, marginRight: 10, color: theme.color };
|
||||
inputStyle.borderBottomWidth = 1;
|
||||
inputStyle.borderBottomColor = theme.dividerColor;
|
||||
|
||||
if (this.state.passwordChecks['master']) {
|
||||
return (
|
||||
<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Text style={{ ...this.styles().normalText, flex: 0, marginRight: 5 }}>{_('Master password:')}</Text>
|
||||
<Text style={{ ...this.styles().normalText, fontWeight: 'bold' }}>{_('Loaded')}</Text>
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ display: 'flex', flexDirection: 'column', marginTop: 10 }}>
|
||||
<Text style={this.styles().normalText}>{'The master password is not set or is invalid. Please type it below:'}</Text>
|
||||
<View style={{ display: 'flex', flexDirection: 'row', marginTop: 10 }}>
|
||||
<TextInput selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} secureTextEntry={true} value={this.state.masterPasswordInput} onChangeText={(text: string) => shared.onMasterPasswordChange(this, text)} style={inputStyle}></TextInput>
|
||||
<Button onPress={onMasterPasswordSave} title={_('Save')} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const masterKeys = this.props.masterKeys;
|
||||
@@ -289,6 +340,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent<Props> {
|
||||
<Text style={this.styles().titleText}>{_('Status')}</Text>
|
||||
<Text style={this.styles().normalText}>{_('Encryption is: %s', this.props.encryptionEnabled ? _('Enabled') : _('Disabled'))}</Text>
|
||||
{decryptedItemsInfo}
|
||||
{this.renderMasterPassword()}
|
||||
{toggleButton}
|
||||
{passwordPromptComp}
|
||||
{mkComps}
|
||||
@@ -315,6 +367,7 @@ const EncryptionConfigScreen = connect((state: State) => {
|
||||
encryptionEnabled: syncInfo.e2ee,
|
||||
activeMasterKeyId: syncInfo.activeMasterKeyId,
|
||||
notLoadedMasterKeys: state.notLoadedMasterKeys,
|
||||
masterPassword: state.settings['encryption.masterPassword'],
|
||||
};
|
||||
})(EncryptionConfigScreenComponent);
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>api.joplincloud.local</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
|
||||
@@ -14,7 +14,7 @@ import ResourceService from '@joplin/lib/services/ResourceService';
|
||||
import KvStore from '@joplin/lib/services/KvStore';
|
||||
import NoteScreen from './components/screens/Note';
|
||||
import UpgradeSyncTargetScreen from './components/screens/UpgradeSyncTargetScreen';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import Setting, { Env } from '@joplin/lib/models/Setting';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import PoorManIntervals from '@joplin/lib/PoorManIntervals';
|
||||
import reducer from '@joplin/lib/reducer';
|
||||
@@ -103,7 +103,7 @@ import { clearSharedFilesCache } from './utils/ShareUtils';
|
||||
import setIgnoreTlsErrors from './utils/TlsUtils';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import setupNotifications from './utils/setupNotifications';
|
||||
import { loadMasterKeysFromSettings } from '@joplin/lib/services/e2ee/utils';
|
||||
import { loadMasterKeysFromSettings, migrateMasterPassword } from '@joplin/lib/services/e2ee/utils';
|
||||
import SyncTargetNone from '../lib/SyncTargetNone';
|
||||
|
||||
let storeDispatch = function(_action: any) {};
|
||||
@@ -474,15 +474,24 @@ async function initialize(dispatch: Function) {
|
||||
if (Setting.value('env') == 'prod') {
|
||||
await db.open({ name: 'joplin.sqlite' });
|
||||
} else {
|
||||
await db.open({ name: 'joplin-101.sqlite' });
|
||||
await db.open({ name: 'joplin-104.sqlite' });
|
||||
|
||||
// await db.clearForTesting();
|
||||
}
|
||||
|
||||
reg.logger().info('Database is ready.');
|
||||
|
||||
reg.logger().info('Loading settings...');
|
||||
|
||||
await loadKeychainServiceAndSettings(KeychainServiceDriverMobile);
|
||||
await migrateMasterPassword();
|
||||
|
||||
if (Setting.value('env') === Env.Dev) {
|
||||
// Setting.setValue('sync.10.path', 'https://api.joplincloud.com');
|
||||
// Setting.setValue('sync.10.userContentPath', 'https://joplinusercontent.com');
|
||||
Setting.setValue('sync.10.path', 'http://api.joplincloud.local:22300');
|
||||
Setting.setValue('sync.10.userContentPath', 'http://joplinusercontent.local:22300');
|
||||
}
|
||||
|
||||
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
|
||||
|
||||
@@ -530,7 +539,6 @@ async function initialize(dispatch: Function) {
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
EncryptionService.fsDriver_ = fsDriver;
|
||||
EncryptionService.instance().setLogger(mainLogger);
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
BaseItem.encryptionService_ = EncryptionService.instance();
|
||||
BaseItem.shareService_ = ShareService.instance();
|
||||
@@ -634,7 +642,7 @@ async function initialize(dispatch: Function) {
|
||||
|
||||
class AppComponent extends React.Component {
|
||||
|
||||
constructor() {
|
||||
public constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
@@ -677,7 +685,7 @@ class AppComponent extends React.Component {
|
||||
// https://github.com/laurent22/joplin/issues/3807
|
||||
// https://discourse.joplinapp.org/t/webdav-config-encryption-config-randomly-lost-on-android/11364
|
||||
// https://discourse.joplinapp.org/t/android-keeps-on-resetting-my-sync-and-theme/11443
|
||||
async componentDidMount() {
|
||||
public async componentDidMount() {
|
||||
if (this.props.appState == 'starting') {
|
||||
this.props.dispatch({
|
||||
type: 'APP_STATE_SET',
|
||||
@@ -725,15 +733,18 @@ class AppComponent extends React.Component {
|
||||
setupQuickActions(this.props.dispatch, this.props.selectedFolderId);
|
||||
|
||||
await setupNotifications(this.props.dispatch);
|
||||
|
||||
// Setting.setValue('encryption.masterPassword', 'WRONG');
|
||||
// setTimeout(() => NavService.go('EncryptionConfig'), 2000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
public componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this.onAppStateChange_);
|
||||
Linking.removeEventListener('url', this.handleOpenURL_);
|
||||
if (this.unsubscribeNetInfoHandler_) this.unsubscribeNetInfoHandler_();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: any) {
|
||||
public componentDidUpdate(prevProps: any) {
|
||||
if (this.props.showSideMenu !== prevProps.showSideMenu) {
|
||||
Animated.timing(this.state.sideMenuContentOpacity, {
|
||||
toValue: this.props.showSideMenu ? 0.5 : 0,
|
||||
@@ -742,7 +753,7 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
async backButtonHandler() {
|
||||
private async backButtonHandler() {
|
||||
if (this.props.noteSelectionEnabled) {
|
||||
this.props.dispatch({ type: 'NOTE_SELECTION_END' });
|
||||
return true;
|
||||
@@ -763,7 +774,7 @@ class AppComponent extends React.Component {
|
||||
return false;
|
||||
}
|
||||
|
||||
async handleShareData() {
|
||||
private async handleShareData() {
|
||||
const sharedData = await ShareExtension.data();
|
||||
if (sharedData) {
|
||||
reg.logger().info('Received shared data');
|
||||
@@ -775,14 +786,14 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps: any) {
|
||||
public UNSAFE_componentWillReceiveProps(newProps: any) {
|
||||
if (newProps.syncStarted != this.lastSyncStarted_) {
|
||||
if (!newProps.syncStarted) FoldersScreenUtils.refreshFolders();
|
||||
this.lastSyncStarted_ = newProps.syncStarted;
|
||||
}
|
||||
}
|
||||
|
||||
sideMenu_change(isOpen: boolean) {
|
||||
private sideMenu_change(isOpen: boolean) {
|
||||
// Make sure showSideMenu property of state is updated
|
||||
// when the menu is open/closed.
|
||||
this.props.dispatch({
|
||||
@@ -790,7 +801,7 @@ class AppComponent extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
if (this.props.appState != 'ready') return null;
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"version": "4.1.33",
|
||||
"version": "4.1.34",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"description": "Fast & forgiving HTML/XML/RSS parser",
|
||||
"version": "4.1.33",
|
||||
"version": "4.1.34",
|
||||
"author": "Felix Boehm <me@feedic.com>",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-sax",
|
||||
"version": "1.2.37",
|
||||
"version": "1.2.38",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@joplin/fork-sax",
|
||||
"description": "An evented streaming XML parser in JavaScript",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"version": "1.2.37",
|
||||
"version": "1.2.38",
|
||||
"main": "lib/sax.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -43,7 +43,7 @@ import SearchEngine from './services/searchengine/SearchEngine';
|
||||
import RevisionService from './services/RevisionService';
|
||||
import ResourceService from './services/ResourceService';
|
||||
import DecryptionWorker from './services/DecryptionWorker';
|
||||
const { loadKeychainServiceAndSettings } = require('./services/SettingUtils');
|
||||
import { loadKeychainServiceAndSettings } from './services/SettingUtils';
|
||||
import MigrationService from './services/MigrationService';
|
||||
import ShareService from './services/share/ShareService';
|
||||
import handleSyncStartupOperation from './services/synchronizer/utils/handleSyncStartupOperation';
|
||||
@@ -51,7 +51,7 @@ import SyncTargetJoplinCloud from './SyncTargetJoplinCloud';
|
||||
const { toSystemSlashes } = require('./path-utils');
|
||||
const { setAutoFreeze } = require('immer');
|
||||
import { getEncryptionEnabled } from './services/synchronizer/syncInfoUtils';
|
||||
import { loadMasterKeysFromSettings } from './services/e2ee/utils';
|
||||
import { loadMasterKeysFromSettings, migrateMasterPassword } from './services/e2ee/utils';
|
||||
import SyncTargetNone from './SyncTargetNone';
|
||||
|
||||
const appLogger: LoggerWrapper = Logger.create('App');
|
||||
@@ -465,6 +465,7 @@ export default class BaseApplication {
|
||||
sideEffects['timeFormat'] = sideEffects['dateFormat'];
|
||||
sideEffects['locale'] = sideEffects['dateFormat'];
|
||||
sideEffects['encryption.passwordCache'] = sideEffects['syncInfoCache'];
|
||||
sideEffects['encryption.masterPassword'] = sideEffects['syncInfoCache'];
|
||||
|
||||
if (action) {
|
||||
const effect = sideEffects[action.key];
|
||||
@@ -768,6 +769,7 @@ export default class BaseApplication {
|
||||
BaseModel.setDb(this.database_);
|
||||
|
||||
await loadKeychainServiceAndSettings(options.keychainEnabled ? KeychainServiceDriver : KeychainServiceDriverDummy);
|
||||
await migrateMasterPassword();
|
||||
await handleSyncStartupOperation();
|
||||
|
||||
appLogger.info(`Client ID: ${Setting.value('clientId')}`);
|
||||
@@ -825,7 +827,6 @@ export default class BaseApplication {
|
||||
|
||||
KvStore.instance().setDb(reg.db());
|
||||
|
||||
EncryptionService.instance().setLogger(globalLogger);
|
||||
BaseItem.encryptionService_ = EncryptionService.instance();
|
||||
BaseItem.shareService_ = ShareService.instance();
|
||||
DecryptionWorker.instance().setLogger(globalLogger);
|
||||
|
||||
@@ -259,6 +259,14 @@ export default class JoplinDatabase extends Database {
|
||||
folders: {},
|
||||
resources: {},
|
||||
tags: {},
|
||||
item_changes: {
|
||||
type: 'The type of change - either 1 (created), 2 (updated) or 3 (deleted)',
|
||||
created_time: 'When the event was generated',
|
||||
item_type: 'The item type (see table above for the list of item types)',
|
||||
item_id: 'The item ID',
|
||||
before_change_item: 'Unused',
|
||||
source: 'Unused',
|
||||
},
|
||||
};
|
||||
|
||||
const baseItems = ['notes', 'folders', 'tags', 'resources'];
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
const ObjectUtils = {};
|
||||
|
||||
ObjectUtils.sortByValue = function(object) {
|
||||
export function sortByValue(object: any) {
|
||||
const temp = [];
|
||||
for (const k in object) {
|
||||
if (!object.hasOwnProperty(k)) continue;
|
||||
@@ -19,16 +17,16 @@ ObjectUtils.sortByValue = function(object) {
|
||||
return v1 < v2 ? -1 : +1;
|
||||
});
|
||||
|
||||
const output = {};
|
||||
const output: any = {};
|
||||
for (let i = 0; i < temp.length; i++) {
|
||||
const item = temp[i];
|
||||
output[item.key] = item.value;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
ObjectUtils.fieldsEqual = function(o1, o2) {
|
||||
export function fieldsEqual(o1: any, o2: any) {
|
||||
if ((!o1 || !o2) && o1 !== o2) return false;
|
||||
|
||||
for (const k in o1) {
|
||||
@@ -42,10 +40,10 @@ ObjectUtils.fieldsEqual = function(o1, o2) {
|
||||
if (c1.length !== c2.length) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
ObjectUtils.convertValuesToFunctions = function(o) {
|
||||
const output = {};
|
||||
export function convertValuesToFunctions(o: any) {
|
||||
const output: any = {};
|
||||
for (const n in o) {
|
||||
if (!o.hasOwnProperty(n)) continue;
|
||||
output[n] = () => {
|
||||
@@ -53,11 +51,26 @@ ObjectUtils.convertValuesToFunctions = function(o) {
|
||||
};
|
||||
}
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
ObjectUtils.isEmpty = function(o) {
|
||||
export function isEmpty(o: any) {
|
||||
if (!o) return true;
|
||||
return Object.keys(o).length === 0 && o.constructor === Object;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = ObjectUtils;
|
||||
// export function isStringifiable(o:any):boolean {
|
||||
// if (o === null || o === undefined) return true;
|
||||
|
||||
// if (Array.isArray(o)) {
|
||||
// for (const e of o) {
|
||||
// if (!isStringifiable(e)) return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (typeof o === 'object') {
|
||||
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
@@ -0,0 +1,13 @@
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
import * as historyBackward from './historyBackward';
|
||||
import * as historyForward from './historyForward';
|
||||
import * as synchronize from './synchronize';
|
||||
|
||||
const index:any[] = [
|
||||
historyBackward,
|
||||
historyForward,
|
||||
synchronize,
|
||||
];
|
||||
|
||||
export default index;
|
||||
// AUTO-GENERATED using `gulp buildCommandIndex`
|
||||
@@ -8,6 +8,7 @@ import shim from '../../shim';
|
||||
import { MasterKeyEntity } from '../../services/e2ee/types';
|
||||
import time from '../../time';
|
||||
import { masterKeyEnabled, setMasterKeyEnabled } from '../../services/synchronizer/syncInfoUtils';
|
||||
import { findMasterKeyPassword } from '../../services/e2ee/utils';
|
||||
|
||||
class Shared {
|
||||
|
||||
@@ -16,12 +17,16 @@ class Shared {
|
||||
public initialize(comp: any, props: any) {
|
||||
comp.state = {
|
||||
passwordChecks: {},
|
||||
// Master keys that can be decrypted with the master password
|
||||
// (normally all of them, but for legacy support we need this).
|
||||
masterPasswordKeys: {},
|
||||
stats: {
|
||||
encrypted: null,
|
||||
total: null,
|
||||
},
|
||||
passwords: Object.assign({}, props.passwords),
|
||||
showDisabledMasterKeys: false,
|
||||
masterPasswordInput: '',
|
||||
};
|
||||
comp.isMounted_ = false;
|
||||
|
||||
@@ -108,15 +113,37 @@ class Shared {
|
||||
}
|
||||
}
|
||||
|
||||
public async masterPasswordIsValid(comp: any, masterPassword: string = null) {
|
||||
const activeMasterKey = comp.props.masterKeys.find((mk: MasterKeyEntity) => mk.id === comp.props.activeMasterKeyId);
|
||||
masterPassword = masterPassword === null ? comp.props.masterPassword : masterPassword;
|
||||
if (activeMasterKey && masterPassword) {
|
||||
return EncryptionService.instance().checkMasterKeyPassword(activeMasterKey, masterPassword);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async checkPasswords(comp: any) {
|
||||
const passwordChecks = Object.assign({}, comp.state.passwordChecks);
|
||||
const masterPasswordKeys = Object.assign({}, comp.state.masterPasswordKeys);
|
||||
for (let i = 0; i < comp.props.masterKeys.length; i++) {
|
||||
const mk = comp.props.masterKeys[i];
|
||||
const password = comp.state.passwords[mk.id];
|
||||
const password = await findMasterKeyPassword(EncryptionService.instance(), mk);
|
||||
const ok = password ? await EncryptionService.instance().checkMasterKeyPassword(mk, password) : false;
|
||||
passwordChecks[mk.id] = ok;
|
||||
masterPasswordKeys[mk.id] = password === comp.props.masterPassword;
|
||||
}
|
||||
comp.setState({ passwordChecks: passwordChecks });
|
||||
|
||||
passwordChecks['master'] = await this.masterPasswordIsValid(comp);
|
||||
|
||||
comp.setState({ passwordChecks, masterPasswordKeys });
|
||||
}
|
||||
|
||||
public masterPasswordStatus(comp: any) {
|
||||
// Don't translate for now because that's temporary - later it should
|
||||
// always be set and the label should be replaced by a "Change master
|
||||
// password" button.
|
||||
return comp.props.masterPassword ? 'Master password is set' : 'Master password is not set';
|
||||
}
|
||||
|
||||
public decryptedStatText(comp: any) {
|
||||
@@ -138,6 +165,14 @@ class Shared {
|
||||
comp.checkPasswords();
|
||||
}
|
||||
|
||||
public onMasterPasswordChange(comp: any, value: string) {
|
||||
comp.setState({ masterPasswordInput: value });
|
||||
}
|
||||
|
||||
public onMasterPasswordSave(comp: any) {
|
||||
Setting.setValue('encryption.masterPassword', comp.state.masterPasswordInput);
|
||||
}
|
||||
|
||||
public onPasswordChange(comp: any, mk: MasterKeyEntity, password: string) {
|
||||
const passwords = Object.assign({}, comp.state.passwords);
|
||||
passwords[mk.id] = password;
|
||||
|
||||
@@ -77,7 +77,7 @@ export default class Database {
|
||||
throw new Error(`Invalid field format: ${field}`);
|
||||
}
|
||||
|
||||
escapeFields(fields: string[] | string): string[] | string {
|
||||
public escapeFields(fields: string[] | string): string[] | string {
|
||||
if (fields == '*') return '*';
|
||||
|
||||
const output = [];
|
||||
@@ -87,6 +87,16 @@ export default class Database {
|
||||
return output;
|
||||
}
|
||||
|
||||
public escapeFieldsToString(fields: string[] | string): string {
|
||||
if (fields === '*') return '*';
|
||||
|
||||
const output = [];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
output.push(this.escapeField(fields[i]));
|
||||
}
|
||||
return output.join(',');
|
||||
}
|
||||
|
||||
async tryCall(callName: string, inputSql: StringOrSqlQuery, inputParams: SqlParams) {
|
||||
let sql: string = null;
|
||||
let params: SqlParams = null;
|
||||
|
||||
@@ -21,6 +21,38 @@ export default class FsDriverBase {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async readFile(_path: string, _encoding: string = 'utf8'): Promise<any> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async copy(_source: string, _dest: string) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async mkdir(_path: string) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async unlink(_path: string) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async move(_source: string, _dest: string) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async readFileChunk(_handle: any, _length: number, _encoding: string = 'base64'): Promise<string> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async open(_path: string, _mode: any): Promise<any> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async close(_handle: any): Promise<any> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async readDirStats(_path: string, _options: ReadDirStatsOptions = null): Promise<Stat[]> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import shim from '../shim';
|
||||
const { useEffect } = shim.react();
|
||||
|
||||
export interface AsyncEffectEvent {
|
||||
cancelled: boolean;
|
||||
}
|
||||
|
||||
export type EffectFunction = (event: AsyncEffectEvent)=> Promise<void>;
|
||||
|
||||
export default function(effect: EffectFunction, dependencies: any[]) {
|
||||
useEffect(() => {
|
||||
const event: AsyncEffectEvent = { cancelled: false };
|
||||
void effect(event);
|
||||
return () => {
|
||||
event.cancelled = true;
|
||||
};
|
||||
}, dependencies);
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Per a suprimir una etiqueta, traieu l'etiqueta en les notes associades.","Please select the note or notebook to be deleted first.":"Primer seleccioneu la nota o el bloc de notes que vulgueu suprimir.","Press Ctrl+D or type \"exit\" to exit the application":"Premeu Ctrl+D o escriviu «exit» per a sortir de l'aplicació","More than one item match \"%s\". Please narrow down your query.":"Hi ha més d'un element que coincideix amb «%s». Restringiu la consulta.","No notebook selected.":"No heu seleccionat cap bloc de notes.","No notebook has been specified.":"No heu indicat cap bloc de notes.","Y":"S","n":"n","N":"N","y":"s","Cancelling background synchronisation... Please wait.":"S'està cancel·lant la sincronització en segon pla... Espereu.","No such command: %s":"No existeix l'ordre: %s","The command \"%s\" is only available in GUI mode":"L'ordre «%s» només és disponible en mode IGU","Cannot change encrypted item":"No es pot canviar un element xifrat","Missing required argument: %s":"Manca un argument requerit: %s","%s: %s":"%s: %s","Your choice: ":"La vostra tria: ","Invalid answer: %s":"La resposta no és vàlida: %s","Attaches the given file to the note.":"Adjunta el fitxer indicat a la nota.","Cannot find \"%s\".":"No es pot trobar «%s».","Runs the commands contained in the text file. There should be one command per line.":"Executa les ordres contingudes al fitxer de text. Hi ha d'haver una ordre per línia.","Displays the given note.":"Mostra la nota indicada.","Displays the complete information about note.":"Mostra la informació completa sobre la nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obté o estableix un valor de configuració. Si no s'indica [valor], mostrarà el valor de [nom]. Si no s'indica ni [nom] ni [valor], es mostrarà un llistat amb la configuració actual.","Also displays unset and hidden config variables.":"També mostra variables de configuració ocultes o sense definir.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica les notes que coincideixen amb <note> a [blocdenotes]. Si no indiqueu cap bloc de notes es dupliquen en el bloc de notes actual.","Marks a to-do as done.":"Marca un llistat de tasques pendents com a fet.","Note is not a to-do: \"%s\"":"La nota no és un llistat de tasques pendents: «%s»","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gestiona la configuració E2EE. Les ordres són «enable», «disable», «decrypt», «status» i «target-status».","Enter master password:":"Introduïu una contrasenya mestra:","Operation cancelled":"L'operació s'ha cancel·lat","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"S'està iniciant el desxifratge... Espereu perquè això pot durar alguns minuts, depenent de quanta informació calgui desxifrar.","Decrypted items: %d":"Elements desxifrats: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Elements omesos: %d (utilitza --retry-failed-items per tornar a intentar desxifrar-los)","Completed decryption.":"El desxifratge ha finalitzat.","Confirm password:":"Confirmeu la contrasenya:","Passwords do not match!":"Les contrasenyes no coincideixen!","Enabled":"Activat","Disabled":"Desactivat","Encryption is: %s":"El xifratge és: %s","Edit note.":"Edita la nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"No hi ha definit cap editor de text. Establiu-ne un usant `config editor <editor-path>`","No active notebook.":"No hi ha cap bloc de notes actiu.","Note does not exist: \"%s\". Create it?":"La nota «%s» no existeix. Voleu crear-la?","Starting to edit note. Close the editor to get back to the prompt.":"S'està iniciant l'edició del a nota. Tanqueu l'editor per a tornar a l'indicador.","Error opening note in editor: %s":"S'ha produït un error a l'obrir la nota amb l'editor: %s","Note has been saved.":"S'ha desat la nota.","Exits the application.":"Surt de l'aplicació.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta les dades del Joplin al camí indicat. Per defecte, exportarà tota la base de dades, incloent-hi blocs de notes, notes, etiquetes i recursos.","Destination format: %s":"Format destí: %s","Exports only the given note.":"Exporta només la nota indicada.","Exports only the given notebook.":"Exporta només el bloc de notes indicat.","Displays a geolocation URL for the note.":"Motra una URL de geolocalitzacio de la nota.","Displays usage information.":"Mostra la informació d'ús.","For infLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Per a suprimir una etiqueta, traieu l'etiqueta en les notes associades.","Please select the note or notebook to be deleted first.":"Primer seleccioneu la nota o el bloc de notes que vulgueu suprimir.","Press Ctrl+D or type \"exit\" to exit the application":"Premeu Ctrl+D o escriviu «exit» per a sortir de l'aplicació","More than one item match \"%s\". Please narrow down your query.":"Hi ha més d'un element que coincideix amb «%s». Restringiu la consulta.","No notebook selected.":"No heu seleccionat cap bloc de notes.","No notebook has been specified.":"No heu indicat cap bloc de notes.","Y":"S","n":"n","N":"N","y":"s","Cancelling background synchronisation... Please wait.":"S'està cancel·lant la sincronització en segon pla... Espereu.","No such command: %s":"No existeix l'ordre: %s","The command \"%s\" is only available in GUI mode":"L'ordre «%s» només és disponible en mode IGU","Cannot change encrypted item":"No es pot canviar un element xifrat","Missing required argument: %s":"Manca un argument requerit: %s","%s: %s":"%s: %s","Your choice: ":"La vostra tria: ","Invalid answer: %s":"La resposta no és vàlida: %s","Attaches the given file to the note.":"Adjunta el fitxer indicat a la nota.","Cannot find \"%s\".":"No es pot trobar «%s».","Runs the commands contained in the text file. There should be one command per line.":"Executa les ordres contingudes al fitxer de text. Hi ha d'haver una ordre per línia.","Displays the given note.":"Mostra la nota indicada.","Displays the complete information about note.":"Mostra la informació completa sobre la nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obté o estableix un valor de configuració. Si no s'indica [valor], mostrarà el valor de [nom]. Si no s'indica ni [nom] ni [valor], es mostrarà un llistat amb la configuració actual.","Also displays unset and hidden config variables.":"També mostra variables de configuració ocultes o sense definir.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica les notes que coincideixen amb <note> a [blocdenotes]. Si no indiqueu cap bloc de notes es dupliquen en el bloc de notes actual.","Marks a to-do as done.":"Marca un llistat de tasques pendents com a fet.","Note is not a to-do: \"%s\"":"La nota no és un llistat de tasques pendents: «%s»","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gestiona la configuració E2EE. Les ordres són «enable», «disable», «decrypt», «status» i «target-status».","Enter master password:":"Introduïu una contrasenya mestra:","Operation cancelled":"L'operació s'ha cancel·lat","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"S'està iniciant el desxifratge... Espereu perquè això pot durar alguns minuts, depenent de quanta informació calgui desxifrar.","Decrypted items: %d":"Elements desxifrats: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Elements omesos: %d (utilitza --retry-failed-items per tornar a intentar desxifrar-los)","Completed decryption.":"El desxifratge ha finalitzat.","Confirm password:":"Confirmeu la contrasenya:","Passwords do not match!":"Les contrasenyes no coincideixen!","Enabled":"Activat","Disabled":"Desactivat","Encryption is: %s":"El xifratge és: %s","Edit note.":"Edita la nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"No hi ha definit cap editor de text. Establiu-ne un usant `config editor <editor-path>`","No active notebook.":"No hi ha cap bloc de notes actiu.","Note does not exist: \"%s\". Create it?":"La nota «%s» no existeix. Voleu crear-la?","Starting to edit note. Close the editor to get back to the prompt.":"S'està iniciant l'edició del a nota. Tanqueu l'editor per a tornar a l'indicador.","Error opening note in editor: %s":"S'ha produït un error a l'obrir la nota amb l'editor: %s","Note has been saved.":"S'ha desat la nota.","Exits the application.":"Surt de l'aplicació.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta les dades del Joplin al camí indicat. Per defecte, exportarà tota la base de dades, incloent-hi blocs de notes, notes, etiquetes i recursos.","Destination format: %s":"Format destí: %s","Exports only the given note.":"Exporta només la nota indicada.","Exports only the given notebook.":"Exporta només el bloc de notes indicat.","Displays a geolocation URL for the note.":"Motra una URL de geolocalitzacio de la nota.","Displays usage information.":"Mostra la informació d'ús.","For infLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Před smazáním štítku ho odeberte od přiřazených poznámek.","Please select the note or notebook to be deleted first.":"Nejprve prosím vyberte poznámku či zápisník ke smazání.","Press Ctrl+D or type \"exit\" to exit the application":"Stiskněte Ctrl+D nebo napište \"exit\" pro ukončení aplikace","More than one item match \"%s\". Please narrow down your query.":"Výrazu \"%s\" odpovídá více než jedna položka, upřesněte prosím hledaný text.","No notebook selected.":"Není vybrán žádný zápisník.","No notebook has been specified.":"Nebyl vybrán žádný zápisník.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Zastavování synchronizace, počkejte prosím...","No such command: %s":"Příkaz neexistuje\" %s","The command \"%s\" is only available in GUI mode":"Příkaz \"%s\" je dostupný pouze v grafickém rozhraní","Cannot change encrypted item":"Nelze editovat zašifrovanou položku","Missing required argument: %s":"Chybí povinný parametr: %s","%s: %s":"%s: %s","Your choice: ":"Vaše volba: ","Invalid answer: %s":"Neplatná odpověď: %s","Attaches the given file to the note.":"Přiloží soubor k poznámce.","Cannot find \"%s\".":"Výraz \"%s\" nebyl nalezen.","Runs the commands contained in the text file. There should be one command per line.":"Spustí příkazy z textového souboru. Každý příkaz by měl být na vlastním řádku.","Displays the given note.":"Zobrazí vybranou poznámku.","Displays the complete information about note.":"Zobrazí veškeré informace o poznámce.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Získá nebo nastaví konfigurační hodnotu. Pokud není [hodnota] specifikována, zobrazí hodnotu položky [jméno]. Pokud není specifikována [hodnota] ani [jméno], je zobrazena současná konfigurace.","Also displays unset and hidden config variables.":"Zobrazí i nenastavené a schované konfigurační proměnné.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplikuje poznámky vyhovující <note> do [notebook]. Pokud není notebook (zápisník) specifikován, je poznámka duplikována v tom současném.","Marks a to-do as done.":"Označí úkol jako hotový.","Note is not a to-do: \"%s\"":"Poznámka není úkol: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Nastavuje šifrování. Příkazy jsou `enable` (zapnout), `disable` (vypnout), `decrypt` (dešifrovat), `status` (stav) a `target-status` (stav v cíli synchronizace).","Enter master password:":"Zadejte hlavní heslo:","Operation cancelled":"Operace zrušena","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Probíhá dešifrování... Počkejte prosím na jeho dokončení. Podle množství dat může zabrat i několik minut.","Decrypted items: %d":"Dešifrované položky: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Přeskočené položky: %d (použijte --retry-failed-items pro nový pokus o dešifrování)","Completed decryption.":"Dešifrování dokončeno.","Confirm password:":"Potvrďte heslo:","Passwords do not match!":"Hesla se neshodují!","Enabled":"Zapnuto","Disabled":"Vypnuto","Encryption is: %s":"Šifrování je: %s","Edit note.":"Upravit poznámku.","No text editor is defined. Please set it using `config editor <editor-path>`":"Nebyl vybrán textový editor. Prosím nastavte jej pomocí `config editor <editor-path>`","No active notebook.":"Není vybrán žádný zápisník.","Note does not exist: \"%s\". Create it?":"Poznámka \"%s\" neexistuje. Chcete ji vytvořit?","Starting to edit note. Close the editor to get back to the prompt.":"Začínám s úpravou poznámky. Pro návrat do příkazové řádky ukončete editor.","Error opening note in editor: %s":"Chyba při otevírání poznámky v editoru: %s","Note has been saved.":"Poznámka uložena.","Exits the application.":"Ukončí aplikaci.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exportuje data Joplinu do zadané cesty. Bez dalších voleb exportuje veškerý obsah databáze včetně zápisníků, poznámek, štítků a příloh.","Destination format: %s":"Cílový formát: %s","Exports only the given note.":"Exportuje pouze vybranou poznámku.","Exports only the given notebook.":"Exportuje pouze vybraný zápisník.","Displays a geolocation URL for the note.":"Zobrazí geolokační URL poznámky.","Displays usage information.":"Zobrazí informace o použití.","For information on how to custLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Před smazáním štítku ho odeberte od přiřazených poznámek.","Please select the note or notebook to be deleted first.":"Nejprve prosím vyberte poznámku či zápisník ke smazání.","Press Ctrl+D or type \"exit\" to exit the application":"Stiskněte Ctrl+D nebo napište \"exit\" pro ukončení aplikace","More than one item match \"%s\". Please narrow down your query.":"Výrazu \"%s\" odpovídá více než jedna položka, upřesněte prosím hledaný text.","No notebook selected.":"Není vybrán žádný zápisník.","No notebook has been specified.":"Nebyl vybrán žádný zápisník.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Zastavování synchronizace, počkejte prosím...","No such command: %s":"Příkaz neexistuje\" %s","The command \"%s\" is only available in GUI mode":"Příkaz \"%s\" je dostupný pouze v grafickém rozhraní","Cannot change encrypted item":"Nelze editovat zašifrovanou položku","Missing required argument: %s":"Chybí povinný parametr: %s","%s: %s":"%s: %s","Your choice: ":"Vaše volba: ","Invalid answer: %s":"Neplatná odpověď: %s","Attaches the given file to the note.":"Přiloží soubor k poznámce.","Cannot find \"%s\".":"Výraz \"%s\" nebyl nalezen.","Runs the commands contained in the text file. There should be one command per line.":"Spustí příkazy z textového souboru. Každý příkaz by měl být na vlastním řádku.","Displays the given note.":"Zobrazí vybranou poznámku.","Displays the complete information about note.":"Zobrazí veškeré informace o poznámce.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Získá nebo nastaví konfigurační hodnotu. Pokud není [hodnota] specifikována, zobrazí hodnotu položky [jméno]. Pokud není specifikována [hodnota] ani [jméno], je zobrazena současná konfigurace.","Also displays unset and hidden config variables.":"Zobrazí i nenastavené a schované konfigurační proměnné.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplikuje poznámky vyhovující <note> do [notebook]. Pokud není notebook (zápisník) specifikován, je poznámka duplikována v tom současném.","Marks a to-do as done.":"Označí úkol jako hotový.","Note is not a to-do: \"%s\"":"Poznámka není úkol: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Nastavuje šifrování. Příkazy jsou `enable` (zapnout), `disable` (vypnout), `decrypt` (dešifrovat), `status` (stav) a `target-status` (stav v cíli synchronizace).","Enter master password:":"Zadejte hlavní heslo:","Operation cancelled":"Operace zrušena","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Probíhá dešifrování... Počkejte prosím na jeho dokončení. Podle množství dat může zabrat i několik minut.","Decrypted items: %d":"Dešifrované položky: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Přeskočené položky: %d (použijte --retry-failed-items pro nový pokus o dešifrování)","Completed decryption.":"Dešifrování dokončeno.","Confirm password:":"Potvrďte heslo:","Passwords do not match!":"Hesla se neshodují!","Enabled":"Zapnuto","Disabled":"Vypnuto","Encryption is: %s":"Šifrování je: %s","Edit note.":"Upravit poznámku.","No text editor is defined. Please set it using `config editor <editor-path>`":"Nebyl vybrán textový editor. Prosím nastavte jej pomocí `config editor <editor-path>`","No active notebook.":"Není vybrán žádný zápisník.","Note does not exist: \"%s\". Create it?":"Poznámka \"%s\" neexistuje. Chcete ji vytvořit?","Starting to edit note. Close the editor to get back to the prompt.":"Začínám s úpravou poznámky. Pro návrat do příkazové řádky ukončete editor.","Error opening note in editor: %s":"Chyba při otevírání poznámky v editoru: %s","Note has been saved.":"Poznámka uložena.","Exits the application.":"Ukončí aplikaci.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exportuje data Joplinu do zadané cesty. Bez dalších voleb exportuje veškerý obsah databáze včetně zápisníků, poznámek, štítků a příloh.","Destination format: %s":"Cílový formát: %s","Exports only the given note.":"Exportuje pouze vybranou poznámku.","Exports only the given notebook.":"Exportuje pouze vybraný zápisník.","Displays a geolocation URL for the note.":"Zobrazí geolokační URL poznámky.","Displays usage information.":"Zobrazí informace o použití.","For information on how to custLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"For at slette en etikette, fjern etikette fra de tilhørende noter.","Please select the note or notebook to be deleted first.":"Vælg først noten eller notesbogen der skal slettes.","Press Ctrl+D or type \"exit\" to exit the application":"Tast Ctrl+D eller tast \"exit\" for at afslutte app'en","More than one item match \"%s\". Please narrow down your query.":"Mere end et emne matcher \"%s\". Præciser din søgning.","No notebook selected.":"Ingen notesbog er valgt.","No notebook has been specified.":"Ingen notesbog er specificeret.","Y":"J","n":"n","N":"N","y":"j","Cancelling background synchronisation... Please wait.":"Annullerer baggrunds synkronisering... Vent venligst.","No such command: %s":"Kommando findes ikke: %s","The command \"%s\" is only available in GUI mode":"Kommando \"%s\" er kun til rådighed i GUI tilstand","Cannot change encrypted item":"Kan ikke ændre krypteret emne","Missing required argument: %s":"Mangler krævet argument: %s","%s: %s":"%s: %s","Your choice: ":"Dit valg: ","Invalid answer: %s":"Forkert svar: %s","Attaches the given file to the note.":"Vedhæfter valgt fil til noten.","Cannot find \"%s\".":"Kan ikke finde \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Afvikler kommandoerne i tekstfilen. Der skal være én kommando pr. linje.","Displays the given note.":"Viser valgt note.","Displays the complete information about note.":"Viser komplet information om note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Henter eller tilføjer konfigurationsværdi. Hvis [value] er tilføjet, vises værdien af [name]. Hvis hverken [name] eller [value] er tilføjet, vises aktuel konfiguration.","Also displays unset and hidden config variables.":"Viser også tomme eller skjulte konfigurations variabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Kopierer alle noter der matcher <note> til [notebook]. Hvis notesbog ikke er udfyldt, kopieres til aktuel notesbog.","Marks a to-do as done.":"Markerer en opgave som udført.","Note is not a to-do: \"%s\"":"Noten er ikke en opgave: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Håndterer E2EE konfiguration. Kommandoer er `enable`(aktiver), `disable`(sluk), `decrypt`(dekrypter), `status`, `decrypt-file`(dekrypter fil) og `target-status` (modtager-status).","Enter master password:":"Indtast hovedkodeord:","Operation cancelled":"Udførelse annulleret","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Dekryptering startet... Vent venligst da kan tage adskillige minutter afhængig af mængden der skal dekrypteres.","Decrypted items: %d":"Dekrypterede emner: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Oversprungne emner: %d (brug --retry-failed-items for at prøve at dekryptere dem igen)","Completed decryption.":"Dekryptering færdig.","Confirm password:":"Bekræft adgangskode:","Passwords do not match!":"Adgangskoder stemmer ikke overens!","Enabled":"Aktiveret","Disabled":"Deaktiveret","Encryption is: %s":"Kryptering er: %s","Edit note.":"Rediger note.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen teksteditor er valgt. Vælg en ved at indstille `config editor <editor-path>`","No active notebook.":"Ingen aktiv notesbog.","Note does not exist: \"%s\". Create it?":"Note eksisterer ikke: \"%s\". Skal den oprettes?","Starting to edit note. Close the editor to get back to the prompt.":"Noteredigering startet. Luk redigering for at komme tilbage til kommandoprompten.","Error opening note in editor: %s":"Fejl ved åbning af note i editor: %s","Note has been saved.":"Note gemt.","Exits the application.":"Lukker programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Eksporterer Joplin data til den valgte sti. Standard er eksport af hele databasen inkl. notesbøger, noter, etiketter og ressourcer.","Destination format: %s":"Destinationsformat: %s","Exports only the given note.":"Eksporterer kun valgt note.","Exports only the given notebook.":"Eksporterer kun valgt notesbog.","Displays a geolocation URL for the note.":"Vis geolokations-URL for noten.","Displays usage information.":"Viser brugsinformation.","For information on how to customise the shortcuts please visit %s":"For info om tilpasning af links, besøg %s","Shortcuts are not available in CLI mode.":"Links er ikke til rådighed i CLI-tilstand.","Type `help [command]` for more information about a command; or type `help all` for the coLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"For at slette en etikette, fjern etikette fra de tilhørende noter.","Please select the note or notebook to be deleted first.":"Vælg først noten eller notesbogen der skal slettes.","Press Ctrl+D or type \"exit\" to exit the application":"Tast Ctrl+D eller tast \"exit\" for at afslutte app'en","More than one item match \"%s\". Please narrow down your query.":"Mere end et emne matcher \"%s\". Præciser din søgning.","No notebook selected.":"Ingen notesbog er valgt.","No notebook has been specified.":"Ingen notesbog er specificeret.","Y":"J","n":"n","N":"N","y":"j","Cancelling background synchronisation... Please wait.":"Annullerer baggrunds synkronisering... Vent venligst.","No such command: %s":"Kommando findes ikke: %s","The command \"%s\" is only available in GUI mode":"Kommando \"%s\" er kun til rådighed i GUI tilstand","Cannot change encrypted item":"Kan ikke ændre krypteret emne","Missing required argument: %s":"Mangler krævet argument: %s","%s: %s":"%s: %s","Your choice: ":"Dit valg: ","Invalid answer: %s":"Forkert svar: %s","Attaches the given file to the note.":"Vedhæfter valgt fil til noten.","Cannot find \"%s\".":"Kan ikke finde \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Afvikler kommandoerne i tekstfilen. Der skal være én kommando pr. linje.","Displays the given note.":"Viser valgt note.","Displays the complete information about note.":"Viser komplet information om note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Henter eller tilføjer konfigurationsværdi. Hvis [value] er tilføjet, vises værdien af [name]. Hvis hverken [name] eller [value] er tilføjet, vises aktuel konfiguration.","Also displays unset and hidden config variables.":"Viser også tomme eller skjulte konfigurations variabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Kopierer alle noter der matcher <note> til [notebook]. Hvis notesbog ikke er udfyldt, kopieres til aktuel notesbog.","Marks a to-do as done.":"Markerer en opgave som udført.","Note is not a to-do: \"%s\"":"Noten er ikke en opgave: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Håndterer E2EE konfiguration. Kommandoer er `enable`(aktiver), `disable`(sluk), `decrypt`(dekrypter), `status`, `decrypt-file`(dekrypter fil) og `target-status` (modtager-status).","Enter master password:":"Indtast hovedkodeord:","Operation cancelled":"Udførelse annulleret","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Dekryptering startet... Vent venligst da kan tage adskillige minutter afhængig af mængden der skal dekrypteres.","Decrypted items: %d":"Dekrypterede emner: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Oversprungne emner: %d (brug --retry-failed-items for at prøve at dekryptere dem igen)","Completed decryption.":"Dekryptering færdig.","Confirm password:":"Bekræft adgangskode:","Passwords do not match!":"Adgangskoder stemmer ikke overens!","Enabled":"Aktiveret","Disabled":"Deaktiveret","Encryption is: %s":"Kryptering er: %s","Edit note.":"Rediger note.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen teksteditor er valgt. Vælg en ved at indstille `config editor <editor-path>`","No active notebook.":"Ingen aktiv notesbog.","Note does not exist: \"%s\". Create it?":"Note eksisterer ikke: \"%s\". Skal den oprettes?","Starting to edit note. Close the editor to get back to the prompt.":"Noteredigering startet. Luk redigering for at komme tilbage til kommandoprompten.","Error opening note in editor: %s":"Fejl ved åbning af note i editor: %s","Note has been saved.":"Note gemt.","Exits the application.":"Lukker programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Eksporterer Joplin data til den valgte sti. Standard er eksport af hele databasen inkl. notesbøger, noter, etiketter og ressourcer.","Destination format: %s":"Destinationsformat: %s","Exports only the given note.":"Eksporterer kun valgt note.","Exports only the given notebook.":"Eksporterer kun valgt notesbog.","Displays a geolocation URL for the note.":"Vis geolokations-URL for noten.","Displays usage information.":"Viser brugsinformation.","For information on how to customise the shortcuts please visit %s":"For info om tilpasning af links, besøg %s","Shortcuts are not available in CLI mode.":"Links er ikke til rådighed i CLI-tilstand.","Type `help [command]` for more information about a command; or type `help all` for the coLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Um ein Schlagwort zu löschen, entferne es bei allen damit verbundenen Notizen.","Please select the note or notebook to be deleted first.":"Bitte wähle zuerst eine Notiz oder ein Notizbuch aus, das gelöscht werden soll.","Press Ctrl+D or type \"exit\" to exit the application":"Drücke Strg+D oder tippe „exit“, um die Anwendung zu beenden","More than one item match \"%s\". Please narrow down your query.":"Mehr als ein Element stimmt mit „%s“ überein. Bitte schränke deine Suche ein.","No notebook selected.":"Kein Notizbuch ausgewählt.","No notebook has been specified.":"Es wurde kein Notizbuch festgelegt.","Y":"J","n":"n","N":"N","y":"j","Cancelling background synchronisation... Please wait.":"Hintergrundsynchronisation wird abgebrochen … Bitte warten.","No such command: %s":"Ungültiger Befehl: %s","The command \"%s\" is only available in GUI mode":"Der Befehl „%s“ ist nur im GUI-Modus verfügbar","Cannot change encrypted item":"Kann verschlüsseltes Objekt nicht ändern","Missing required argument: %s":"Fehlendes erforderliches Argument: %s","%s: %s":"%s: %s","Your choice: ":"Deine Auswahl: ","Invalid answer: %s":"Ungültige Antwort: %s","Attaches the given file to the note.":"Hängt die ausgewählte Datei an die Notiz an.","Cannot find \"%s\".":"Kann „%s“ nicht finden.","Runs the commands contained in the text file. There should be one command per line.":"Führe Befehle aus Textdatei aus. Jede Zeile darf nur einen Befehl enthalten.","Displays the given note.":"Zeigt die jeweilige Notiz an.","Displays the complete information about note.":"Zeigt alle Informationen über die Notiz an.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Holt oder legt einen Konfigurationswert fest. Wenn [value] nicht angegeben ist, wird der Wert von [name] angezeigt. Wenn weder [name] noch [value] angegeben sind, wird die aktuelle Konfiguration aufgelistet.","Also displays unset and hidden config variables.":"Zeigt auch nicht gesetzte und versteckte Konfigurationsvariablen an.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Dupliziert die Notizen, die mit <note> übereinstimmen, nach [notebook]. Wenn kein Notizbuch angegeben ist, wird die Notiz im aktuellen Notizbuch dupliziert.","Marks a to-do as done.":"Markiert eine Aufgabe als erledigt.","Note is not a to-do: \"%s\"":"Notiz ist keine Aufgabe: „%s“","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Verwaltet die E2EE-Konfiguration. Die Befehle lauten `enable`, `disable`, `decrypt`, `status`, `decrypt-file` und `target-status`.","Enter master password:":"Master-Passwort eingeben:","Operation cancelled":"Vorgang abgebrochen","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Entschlüsselung wird gestartet ... Bitte warten, da dies je nach Umfang der zu entschlüsselnden Daten mehrere Minuten dauern kann.","Decrypted items: %d":"Entschlüsselte Objekte: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Übersprungene Objekte: %d (benutze --retry-failed-items um erneut eine Entschlüsselung zu versuchen)","Completed decryption.":"Entschlüsselung abgeschlossen.","Confirm password:":"Passwort bestätigen:","Passwords do not match!":"Passwörter sind nicht identisch!","Enabled":"Aktiviert","Disabled":"Deaktiviert","Encryption is: %s":"Verschlüsselung ist: %s","Edit note.":"Notiz bearbeiten.","No text editor is defined. Please set it using `config editor <editor-path>`":"Kein Texteditor definiert. Bitte lege einen mit `config editor <Pfad-Zum-Texteditor>` fest","No active notebook.":"Kein aktives Notizbuch.","Note does not exist: \"%s\". Create it?":"Notiz „%s“ existiert nicht. Soll sie erstellt werden?","Starting to edit note. Close the editor to get back to the prompt.":"Beginne die Notiz zu bearbeiten. Schließe das Textverarbeitungsprogramm, um zurück zum Terminal zu gelangen.","Error opening note in editor: %s":"Fehler beim Öffnen der Notiz im Editor: %s","Note has been saved.":"Die Notiz wurde gespeichert.","Exits the application.":"Beendet die Anwendung.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exportiert Joplin-Dateien in den angegebenen Pfad. Standardmäßig wird die komplette Datenbank inklusive Notizbüchern, Notizen, Schlagwörtern und Anhängen exportiert.","Destination format: %s":"Zielformat: %s","Exports only the given note.":"Exportiert nur die angegebene Notiz.","Exports only the given notebook.":"Exportiert nur das angegebene Notizbuch.","Displays a geolocation URL forLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Um ein Schlagwort zu löschen, entferne es bei allen damit verbundenen Notizen.","Please select the note or notebook to be deleted first.":"Bitte wähle zuerst eine Notiz oder ein Notizbuch aus, das gelöscht werden soll.","Press Ctrl+D or type \"exit\" to exit the application":"Drücke Strg+D oder tippe „exit“, um die Anwendung zu beenden","More than one item match \"%s\". Please narrow down your query.":"Mehr als ein Element stimmt mit „%s“ überein. Bitte schränke deine Suche ein.","No notebook selected.":"Kein Notizbuch ausgewählt.","No notebook has been specified.":"Es wurde kein Notizbuch festgelegt.","Y":"J","n":"n","N":"N","y":"j","Cancelling background synchronisation... Please wait.":"Hintergrundsynchronisation wird abgebrochen … Bitte warten.","No such command: %s":"Ungültiger Befehl: %s","The command \"%s\" is only available in GUI mode":"Der Befehl „%s“ ist nur im GUI-Modus verfügbar","Cannot change encrypted item":"Kann verschlüsseltes Objekt nicht ändern","Missing required argument: %s":"Fehlendes erforderliches Argument: %s","%s: %s":"%s: %s","Your choice: ":"Deine Auswahl: ","Invalid answer: %s":"Ungültige Antwort: %s","Attaches the given file to the note.":"Hängt die ausgewählte Datei an die Notiz an.","Cannot find \"%s\".":"Kann „%s“ nicht finden.","Runs the commands contained in the text file. There should be one command per line.":"Führe Befehle aus Textdatei aus. Jede Zeile darf nur einen Befehl enthalten.","Displays the given note.":"Zeigt die jeweilige Notiz an.","Displays the complete information about note.":"Zeigt alle Informationen über die Notiz an.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Holt oder legt einen Konfigurationswert fest. Wenn [value] nicht angegeben ist, wird der Wert von [name] angezeigt. Wenn weder [name] noch [value] angegeben sind, wird die aktuelle Konfiguration aufgelistet.","Also displays unset and hidden config variables.":"Zeigt auch nicht gesetzte und versteckte Konfigurationsvariablen an.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Dupliziert die Notizen, die mit <note> übereinstimmen, nach [notebook]. Wenn kein Notizbuch angegeben ist, wird die Notiz im aktuellen Notizbuch dupliziert.","Marks a to-do as done.":"Markiert eine Aufgabe als erledigt.","Note is not a to-do: \"%s\"":"Notiz ist keine Aufgabe: „%s“","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Verwaltet die E2EE-Konfiguration. Die Befehle lauten `enable`, `disable`, `decrypt`, `status`, `decrypt-file` und `target-status`.","Enter master password:":"Master-Passwort eingeben:","Operation cancelled":"Vorgang abgebrochen","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Entschlüsselung wird gestartet ... Bitte warten, da dies je nach Umfang der zu entschlüsselnden Daten mehrere Minuten dauern kann.","Decrypted items: %d":"Entschlüsselte Objekte: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Übersprungene Objekte: %d (benutze --retry-failed-items um erneut eine Entschlüsselung zu versuchen)","Completed decryption.":"Entschlüsselung abgeschlossen.","Confirm password:":"Passwort bestätigen:","Passwords do not match!":"Passwörter sind nicht identisch!","Enabled":"Aktiviert","Disabled":"Deaktiviert","Encryption is: %s":"Verschlüsselung ist: %s","Edit note.":"Notiz bearbeiten.","No text editor is defined. Please set it using `config editor <editor-path>`":"Kein Texteditor definiert. Bitte lege einen mit `config editor <Pfad-Zum-Texteditor>` fest","No active notebook.":"Kein aktives Notizbuch.","Note does not exist: \"%s\". Create it?":"Notiz „%s“ existiert nicht. Soll sie erstellt werden?","Starting to edit note. Close the editor to get back to the prompt.":"Beginne die Notiz zu bearbeiten. Schließe das Textverarbeitungsprogramm, um zurück zum Terminal zu gelangen.","Error opening note in editor: %s":"Fehler beim Öffnen der Notiz im Editor: %s","Note has been saved.":"Die Notiz wurde gespeichert.","Exits the application.":"Beendet die Anwendung.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exportiert Joplin-Dateien in den angegebenen Pfad. Standardmäßig wird die komplette Datenbank inklusive Notizbüchern, Notizen, Schlagwörtern und Anhängen exportiert.","Destination format: %s":"Zielformat: %s","Exports only the given note.":"Exportiert nur die angegebene Notiz.","Exports only the given notebook.":"Exportiert nur das angegebene Notizbuch.","Displays a geolocation URL forLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Para eliminar una etiqueta, desmarque las notas asociadas.","Please select the note or notebook to be deleted first.":"Primero seleccione la nota o libreta que desea eliminar.","Press Ctrl+D or type \"exit\" to exit the application":"Pulse Ctrl+D o escriba «salir» para salir de la aplicación","More than one item match \"%s\". Please narrow down your query.":"Hay más de un elemento que coincide con «%s». Intente mejorar su consulta.","No notebook selected.":"Ninguna libreta ha sido seleccionada.","No notebook has been specified.":"Ninguna libreta ha sido especificada.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Cancelando sincronización en segundo plano... Por favor espere.","No such command: %s":"El comando no existe: %s","The command \"%s\" is only available in GUI mode":"El comando «%s» solamente está disponible en modo GUI","Cannot change encrypted item":"No se puede cambiar un elemento cifrado","Missing required argument: %s":"Falta un argumento requerido: %s","%s: %s":"%s: %s","Your choice: ":"Su elección: ","Invalid answer: %s":"Respuesta inválida: %s","Attaches the given file to the note.":"Adjuntar archivo dado a la nota.","Cannot find \"%s\".":"No se puede encontrar «%s».","Runs the commands contained in the text file. There should be one command per line.":"Ejecuta los comandos contenidos en el archivo de texto. Debe haber un comando por línea.","Displays the given note.":"Muestra la nota dada.","Displays the complete information about note.":"Mostrar la información completa acerca de la nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtiene o configura un valor. Si no se provee el [valor], se mostrará el valor de [nombre]. Si no se provee [nombre] ni [valor], se listará la configuración actual.","Also displays unset and hidden config variables.":"También muestra variables no configuradas u ocultas.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica las notas que coincidan con <nota> a [libreta]. Si no se especifica una libreta la nota se duplica en la libreta actual.","Marks a to-do as done.":"Marca una tarea como hecha.","Note is not a to-do: \"%s\"":"La nota no es una tarea: «%s»","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gestiona la configuración E2EE. Los comandos disponibles son `enable`, `disable`, `decrypt`, `status`, `decrypt-file` y `target-status`.","Enter master password:":"Introduzca la contraseña maestra:","Operation cancelled":"Operación cancelada","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Iniciando descifrado... Por favor espere, pues puede tardar varios minutos dependiendo de cuanto haya que descifrar.","Decrypted items: %d":"Elementos descifrados: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Elementos omitidos: %d (use --retry-failed-items para intentar descifrarlos nuevamente)","Completed decryption.":"Descifrado completado.","Confirm password:":"Confirmar contraseña:","Passwords do not match!":"¡Las contraseñas no coinciden!","Enabled":"Habilitado","Disabled":"Deshabilitado","Encryption is: %s":"El cifrado está: %s","Edit note.":"Editar nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"No hay editor de texto definido. Por favor configure uno usando `config editor <editor-ruta>`","No active notebook.":"No hay libreta activa.","Note does not exist: \"%s\". Create it?":"La nota no existe: «%s». ¿Crearla?","Starting to edit note. Close the editor to get back to the prompt.":"Iniciando la edición de una nota. Cierre el editor para regresar a la ventana de diálogo.","Error opening note in editor: %s":"Error al abrir la nota en el editor: %s","Note has been saved.":"La nota ha sido guardada.","Exits the application.":"Sale de la aplicación.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta los datos de Joplin a la ruta dada. Por defecto, se exportará la base de datos completa incluyendo libretas, notas, etiquetas y recursos.","Destination format: %s":"Formato de destino: %s","Exports only the given note.":"Exporta únicamente la nota dada.","Exports only the given notebook.":"Exporta únicamente la libreta dada.","Displays a geolocation URL for the note.":"Muestra la URL de geolocalización de la nota.","Displays usage information.":"Muestra información de uso.","For information on how to customise the shortcuts please visit %s":"Para información de cómo personalizar losLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Para eliminar una etiqueta, desmarque las notas asociadas.","Please select the note or notebook to be deleted first.":"Primero seleccione la nota o libreta que desea eliminar.","Press Ctrl+D or type \"exit\" to exit the application":"Pulse Ctrl+D o escriba «salir» para salir de la aplicación","More than one item match \"%s\". Please narrow down your query.":"Hay más de un elemento que coincide con «%s». Intente mejorar su consulta.","No notebook selected.":"Ninguna libreta ha sido seleccionada.","No notebook has been specified.":"Ninguna libreta ha sido especificada.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Cancelando sincronización en segundo plano... Por favor espere.","No such command: %s":"El comando no existe: %s","The command \"%s\" is only available in GUI mode":"El comando «%s» solamente está disponible en modo GUI","Cannot change encrypted item":"No se puede cambiar un elemento cifrado","Missing required argument: %s":"Falta un argumento requerido: %s","%s: %s":"%s: %s","Your choice: ":"Su elección: ","Invalid answer: %s":"Respuesta inválida: %s","Attaches the given file to the note.":"Adjuntar archivo dado a la nota.","Cannot find \"%s\".":"No se puede encontrar «%s».","Runs the commands contained in the text file. There should be one command per line.":"Ejecuta los comandos contenidos en el archivo de texto. Debe haber un comando por línea.","Displays the given note.":"Muestra la nota dada.","Displays the complete information about note.":"Mostrar la información completa acerca de la nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtiene o configura un valor. Si no se provee el [valor], se mostrará el valor de [nombre]. Si no se provee [nombre] ni [valor], se listará la configuración actual.","Also displays unset and hidden config variables.":"También muestra variables no configuradas u ocultas.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica las notas que coincidan con <nota> a [libreta]. Si no se especifica una libreta la nota se duplica en la libreta actual.","Marks a to-do as done.":"Marca una tarea como hecha.","Note is not a to-do: \"%s\"":"La nota no es una tarea: «%s»","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gestiona la configuración E2EE. Los comandos disponibles son `enable`, `disable`, `decrypt`, `status`, `decrypt-file` y `target-status`.","Enter master password:":"Introduzca la contraseña maestra:","Operation cancelled":"Operación cancelada","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Iniciando descifrado... Por favor espere, pues puede tardar varios minutos dependiendo de cuanto haya que descifrar.","Decrypted items: %d":"Elementos descifrados: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Elementos omitidos: %d (use --retry-failed-items para intentar descifrarlos nuevamente)","Completed decryption.":"Descifrado completado.","Confirm password:":"Confirmar contraseña:","Passwords do not match!":"¡Las contraseñas no coinciden!","Enabled":"Habilitado","Disabled":"Deshabilitado","Encryption is: %s":"El cifrado está: %s","Edit note.":"Editar nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"No hay editor de texto definido. Por favor configure uno usando `config editor <editor-ruta>`","No active notebook.":"No hay libreta activa.","Note does not exist: \"%s\". Create it?":"La nota no existe: «%s». ¿Crearla?","Starting to edit note. Close the editor to get back to the prompt.":"Iniciando la edición de una nota. Cierre el editor para regresar a la ventana de diálogo.","Error opening note in editor: %s":"Error al abrir la nota en el editor: %s","Note has been saved.":"La nota ha sido guardada.","Exits the application.":"Sale de la aplicación.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta los datos de Joplin a la ruta dada. Por defecto, se exportará la base de datos completa incluyendo libretas, notas, etiquetas y recursos.","Destination format: %s":"Formato de destino: %s","Exports only the given note.":"Exporta únicamente la nota dada.","Exports only the given notebook.":"Exporta únicamente la libreta dada.","Displays a geolocation URL for the note.":"Muestra la URL de geolocalización de la nota.","Displays usage information.":"Muestra información de uso.","For information on how to customise the shortcuts please visit %s":"Para información de cómo personalizar losLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Pour supprimer une vignette, enlever là des notes associées.","Please select the note or notebook to be deleted first.":"Veuillez d'abord sélectionner un carnet.","Press Ctrl+D or type \"exit\" to exit the application":"Appuyez sur Ctrl+D ou tapez \"exit\" pour sortir du logiciel","More than one item match \"%s\". Please narrow down your query.":"Plus d'un objet correspond à \"%s\". Veuillez préciser votre requête.","No notebook selected.":"Aucun carnet n'est sélectionné.","No notebook has been specified.":"Aucun carnet n'est spécifié.","Y":"O","n":"n","N":"N","y":"o","Cancelling background synchronisation... Please wait.":"Annulation de la synchronisation... Veuillez patienter.","No such command: %s":"Commande invalide : %s","The command \"%s\" is only available in GUI mode":"La commande \"%s\" est disponible uniquement en mode d'interface graphique","Cannot change encrypted item":"Un objet chiffré ne peut pas être modifié","Missing required argument: %s":"Paramètre requis manquant : %s","%s: %s":"%s : %s","Your choice: ":"Votre choix : ","Invalid answer: %s":"Réponse invalide : %s","Attaches the given file to the note.":"Joindre le fichier fourni à la note.","Cannot find \"%s\".":"Impossible de trouver \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Exécute les commandes contenues dans le fichier texte. Il doit y avoir une commande par ligne.","Displays the given note.":"Affiche la note.","Displays the complete information about note.":"Affiche tous les détails de la note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtient ou modifie une valeur de configuration. Si la [valeur] n'est pas fournie, la valeur de [nom] sera affichée. Si ni le [nom] ni la [valeur] ne sont fournis, la configuration complète sera affichée.","Also displays unset and hidden config variables.":"Afficher également les variables cachées.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Copier les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est spécifié, la note est dupliquée sur place.","Marks a to-do as done.":"Marquer la tâche comme complétée.","Note is not a to-do: \"%s\"":"La note n'est pas une tâche : \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gérer la configuration E2EE (Chiffrement de bout à bout). Les commandes sont `enable`, `disable`, `decrypt` et `status`, `decrypt-file` et `target-status`.","Enter master password:":"Entrer le mot de passe maître :","Operation cancelled":"Opération annulée","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Démarrage du déchiffrement... Veuillez patienter car cela pourrait prendre plusieurs minutes selon le nombre d'objets à déchiffrer.","Decrypted items: %d":"Objets déchiffrés : %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Objets ignorés : %d (utilisez --retry-failed-items pour les déchiffrer à nouveau)","Completed decryption.":"Déchiffrement complété.","Confirm password:":"Confirmer le mot de passe :","Passwords do not match!":"Les mots de passe ne correspondent pas !","Enabled":"Activé","Disabled":"Désactivé","Encryption is: %s":"Le chiffrement est : %s","Edit note.":"Éditer la note.","No text editor is defined. Please set it using `config editor <editor-path>`":"Aucun éditeur de texte n'est défini. Veuillez le définir en utilisant la commande `config editor <chemin-editeur>`","No active notebook.":"Aucun carnet actif.","Note does not exist: \"%s\". Create it?":"Cette note n'existe pas : \"%s\". La créer ?","Starting to edit note. Close the editor to get back to the prompt.":"Édition de la note en cours. Fermez l'éditeur de texte pour retourner à l'invite de commande.","Error opening note in editor: %s":"Erreur lors de l'ouverture de la note dans l'éditeur de texte : %s","Note has been saved.":"La note a été enregistrée.","Exits the application.":"Quitter le logiciel.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporter les données de Joplin. Par défaut, la base de donnée complète sera exportée, y compris les carnets, notes, tags et ressources.","Destination format: %s":"Format de la destination : %s","Exports only the given note.":"Exporter uniquement la note spécifiée.","Exports only the given notebook.":"Exporter uniquement le carnet spécifié.","Displays a geolocation URL for the note.":"Afficher une URL de géolocalisation pour la note.","Displays usage information."Line truncated
|
||||
{"To delete a tag, untag the associated notes.":"Pour supprimer une vignette, enlever là des notes associées.","Please select the note or notebook to be deleted first.":"Veuillez d'abord sélectionner un carnet.","Press Ctrl+D or type \"exit\" to exit the application":"Appuyez sur Ctrl+D ou tapez \"exit\" pour sortir du logiciel","More than one item match \"%s\". Please narrow down your query.":"Plus d'un objet correspond à \"%s\". Veuillez préciser votre requête.","No notebook selected.":"Aucun carnet n'est sélectionné.","No notebook has been specified.":"Aucun carnet n'est spécifié.","Y":"O","n":"n","N":"N","y":"o","Cancelling background synchronisation... Please wait.":"Annulation de la synchronisation... Veuillez patienter.","No such command: %s":"Commande invalide : %s","The command \"%s\" is only available in GUI mode":"La commande \"%s\" est disponible uniquement en mode d'interface graphique","Cannot change encrypted item":"Un objet chiffré ne peut pas être modifié","Missing required argument: %s":"Paramètre requis manquant : %s","%s: %s":"%s : %s","Your choice: ":"Votre choix : ","Invalid answer: %s":"Réponse invalide : %s","Attaches the given file to the note.":"Joindre le fichier fourni à la note.","Cannot find \"%s\".":"Impossible de trouver \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Exécute les commandes contenues dans le fichier texte. Il doit y avoir une commande par ligne.","Displays the given note.":"Affiche la note.","Displays the complete information about note.":"Affiche tous les détails de la note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtient ou modifie une valeur de configuration. Si la [valeur] n'est pas fournie, la valeur de [nom] sera affichée. Si ni le [nom] ni la [valeur] ne sont fournis, la configuration complète sera affichée.","Also displays unset and hidden config variables.":"Afficher également les variables cachées.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Copier les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est spécifié, la note est dupliquée sur place.","Marks a to-do as done.":"Marquer la tâche comme complétée.","Note is not a to-do: \"%s\"":"La note n'est pas une tâche : \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gérer la configuration E2EE (Chiffrement de bout à bout). Les commandes sont `enable`, `disable`, `decrypt` et `status`, `decrypt-file` et `target-status`.","Enter master password:":"Entrer le mot de passe maître :","Operation cancelled":"Opération annulée","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Démarrage du déchiffrement... Veuillez patienter car cela pourrait prendre plusieurs minutes selon le nombre d'objets à déchiffrer.","Decrypted items: %d":"Objets déchiffrés : %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Objets ignorés : %d (utilisez --retry-failed-items pour les déchiffrer à nouveau)","Completed decryption.":"Déchiffrement complété.","Confirm password:":"Confirmer le mot de passe :","Passwords do not match!":"Les mots de passe ne correspondent pas !","Enabled":"Activé","Disabled":"Désactivé","Encryption is: %s":"Le chiffrement est : %s","Edit note.":"Éditer la note.","No text editor is defined. Please set it using `config editor <editor-path>`":"Aucun éditeur de texte n'est défini. Veuillez le définir en utilisant la commande `config editor <chemin-editeur>`","No active notebook.":"Aucun carnet actif.","Note does not exist: \"%s\". Create it?":"Cette note n'existe pas : \"%s\". La créer ?","Starting to edit note. Close the editor to get back to the prompt.":"Édition de la note en cours. Fermez l'éditeur de texte pour retourner à l'invite de commande.","Error opening note in editor: %s":"Erreur lors de l'ouverture de la note dans l'éditeur de texte : %s","Note has been saved.":"La note a été enregistrée.","Exits the application.":"Quitter le logiciel.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporter les données de Joplin. Par défaut, la base de donnée complète sera exportée, y compris les carnets, notes, tags et ressources.","Destination format: %s":"Format de la destination : %s","Exports only the given note.":"Exporter uniquement la note spécifiée.","Exports only the given notebook.":"Exporter uniquement le carnet spécifié.","Displays a geolocation URL for the note.":"Afficher une URL de géolocalisation pour la note.","Displays usage information."Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Za brisanje oznake, ukloni oznaku s povezanih bilježaka.","Please select the note or notebook to be deleted first.":"Najprije odaberi bilješku ili bilježnicu za brisanje.","Press Ctrl+D or type \"exit\" to exit the application":"Zatvori program pomoću prečaca Ctrl+D ili upiši „exit”","More than one item match \"%s\". Please narrow down your query.":"Više elemenata se poklapaju s „%s”. Ograniči pretragu.","No notebook selected.":"Nijedna bilježnica nije odabrana.","No notebook has been specified.":"Nijedna bilježnica nije određena.","Y":"D","n":"n","N":"N","y":"d","Cancelling background synchronisation... Please wait.":"Prekidanje sinkronizacije u pozadini … Pričekaj.","No such command: %s":"Naredba ne postoji: %s","The command \"%s\" is only available in GUI mode":"Naredba „%s” dostupna je samo u modusu grafičkog sučelja","Cannot change encrypted item":"Nije moguće promijeniti šifriran element","Missing required argument: %s":"Nedostaje obavezni argument: %s","%s: %s":"%s: %s","Your choice: ":"Tvoj izbor: ","Invalid answer: %s":"Neispravan odgovor: %s","Attaches the given file to the note.":"Prilaže zadanu datoteku bilješci.","Cannot find \"%s\".":"Nije moguće pronaći „%s”.","Runs the commands contained in the text file. There should be one command per line.":"Pokreće naredbe koje se nalaze u tekstualnoj datoteci. Naredbe se moraju zapisti pojedinačno u zasebne retke.","Displays the given note.":"Prikazuje zadanu bilješku.","Displays the complete information about note.":"Prikazuje potpune podatke o bilješci.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Nabavlja ili postavlja vrijednost konfiguracije. Ako vrijednost [value] nije zadana, prikazat će vrijednost imena [name]. Ako [name] niti [value] nisu zadani, ispisat će trenutačnu konfiguraciju.","Also displays unset and hidden config variables.":"Također prikazuje nepostavljene i skrivene varijable konfiguracije.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplicira bilješke koje se poklapaju s bilješkom <note> u bilježnicu [notebook]. Ako nijedna bilježnica nije zadana, bilješka se duplicira u trenutačnu bilježnicu.","Marks a to-do as done.":"Označava zadatak završenim.","Note is not a to-do: \"%s\"":"Bilješka nije zadatak: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Upravlja konfiguracijom za obostrano šifriranje. Naredbe su `enable` (aktiviraj), `disable` (deaktiviraj), `decrypt` (dešifriraj), `status` (stanje), `decrypt-file` (dešifriraj datoteku) i `target-status` (stanje cilja).","Enter master password:":"Upiši glavnu lozinku:","Operation cancelled":"Operacija je prekinuta","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Pokretanje dešifriranja … Pričekaj, jer može potrajati nekoliko minuta, ovisno o količini dešifriranja.","Decrypted items: %d":"Dešifrirani elementi: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Preskočeni elementi: %d (koristi --retry-failed-items za ponovno dešifriranje)","Completed decryption.":"Dešifriranje je završeno.","Confirm password:":"Potvrdi lozinku:","Passwords do not match!":"Lozinke se ne poklapaju!","Enabled":"Aktivirano","Disabled":"Deaktivirano","Encryption is: %s":"Šifriranje je: %s","Edit note.":"Uredi bilješku.","No text editor is defined. Please set it using `config editor <editor-path>`":"Program za uređivanje teksta nije određen. Postavi ga pomoću `config editor <editor-path>` (gdje je editor-path putanja do programa)","No active notebook.":"Nema aktivne bilježnice.","Note does not exist: \"%s\". Create it?":"Bilješka ne postoji: „%s”. Želiš li je stvoriti?","Starting to edit note. Close the editor to get back to the prompt.":"Početak uređivanja bilješke. Zatvori uređivač za vraćanje na terminal.","Error opening note in editor: %s":"Greška prilikom otvaranja bilješke u uređivaču: %s","Note has been saved.":"Bilješka je spremljena.","Exits the application.":"Zatvara program.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Izvozi Joplin podatke u zadanu putanju. Standardno izvozi cijelu bazu podataka uključujući bilježnice, bilješke, zadatke i resurse.","Destination format: %s":"Format odredišta: %s","Exports only the given note.":"Izvozi samo zadanu bilješku.","Exports only the given notebook.":"Izvozi samo zadanu bilježnicu.","Displays a geolocation URL for the note.":"Prikazuje URL geografskih podataka mjesta za bilješku.",Line truncated
|
||||
{"To delete a tag, untag the associated notes.":"Za brisanje oznake, ukloni oznaku s povezanih bilježaka.","Please select the note or notebook to be deleted first.":"Najprije odaberi bilješku ili bilježnicu za brisanje.","Press Ctrl+D or type \"exit\" to exit the application":"Zatvori program pomoću prečaca Ctrl+D ili upiši „exit”","More than one item match \"%s\". Please narrow down your query.":"Više elemenata se poklapaju s „%s”. Ograniči pretragu.","No notebook selected.":"Nijedna bilježnica nije odabrana.","No notebook has been specified.":"Nijedna bilježnica nije određena.","Y":"D","n":"n","N":"N","y":"d","Cancelling background synchronisation... Please wait.":"Prekidanje sinkronizacije u pozadini … Pričekaj.","No such command: %s":"Naredba ne postoji: %s","The command \"%s\" is only available in GUI mode":"Naredba „%s” dostupna je samo u modusu grafičkog sučelja","Cannot change encrypted item":"Nije moguće promijeniti šifriran element","Missing required argument: %s":"Nedostaje obavezni argument: %s","%s: %s":"%s: %s","Your choice: ":"Tvoj izbor: ","Invalid answer: %s":"Neispravan odgovor: %s","Attaches the given file to the note.":"Prilaže zadanu datoteku bilješci.","Cannot find \"%s\".":"Nije moguće pronaći „%s”.","Runs the commands contained in the text file. There should be one command per line.":"Pokreće naredbe koje se nalaze u tekstualnoj datoteci. Naredbe se moraju zapisti pojedinačno u zasebne retke.","Displays the given note.":"Prikazuje zadanu bilješku.","Displays the complete information about note.":"Prikazuje potpune podatke o bilješci.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Nabavlja ili postavlja vrijednost konfiguracije. Ako vrijednost [value] nije zadana, prikazat će vrijednost imena [name]. Ako [name] niti [value] nisu zadani, ispisat će trenutačnu konfiguraciju.","Also displays unset and hidden config variables.":"Također prikazuje nepostavljene i skrivene varijable konfiguracije.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplicira bilješke koje se poklapaju s bilješkom <note> u bilježnicu [notebook]. Ako nijedna bilježnica nije zadana, bilješka se duplicira u trenutačnu bilježnicu.","Marks a to-do as done.":"Označava zadatak završenim.","Note is not a to-do: \"%s\"":"Bilješka nije zadatak: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Upravlja konfiguracijom za obostrano šifriranje. Naredbe su `enable` (aktiviraj), `disable` (deaktiviraj), `decrypt` (dešifriraj), `status` (stanje), `decrypt-file` (dešifriraj datoteku) i `target-status` (stanje cilja).","Enter master password:":"Upiši glavnu lozinku:","Operation cancelled":"Operacija je prekinuta","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Pokretanje dešifriranja … Pričekaj, jer može potrajati nekoliko minuta, ovisno o količini dešifriranja.","Decrypted items: %d":"Dešifrirani elementi: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Preskočeni elementi: %d (koristi --retry-failed-items za ponovno dešifriranje)","Completed decryption.":"Dešifriranje je završeno.","Confirm password:":"Potvrdi lozinku:","Passwords do not match!":"Lozinke se ne poklapaju!","Enabled":"Aktivirano","Disabled":"Deaktivirano","Encryption is: %s":"Šifriranje je: %s","Edit note.":"Uredi bilješku.","No text editor is defined. Please set it using `config editor <editor-path>`":"Program za uređivanje teksta nije određen. Postavi ga pomoću `config editor <editor-path>` (gdje je editor-path putanja do programa)","No active notebook.":"Nema aktivne bilježnice.","Note does not exist: \"%s\". Create it?":"Bilješka ne postoji: „%s”. Želiš li je stvoriti?","Starting to edit note. Close the editor to get back to the prompt.":"Početak uređivanja bilješke. Zatvori uređivač za vraćanje na terminal.","Error opening note in editor: %s":"Greška prilikom otvaranja bilješke u uređivaču: %s","Note has been saved.":"Bilješka je spremljena.","Exits the application.":"Zatvara program.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Izvozi Joplin podatke u zadanu putanju. Standardno izvozi cijelu bazu podataka uključujući bilježnice, bilješke, zadatke i resurse.","Destination format: %s":"Format odredišta: %s","Exports only the given note.":"Izvozi samo zadanu bilješku.","Exports only the given notebook.":"Izvozi samo zadanu bilježnicu.","Displays a geolocation URL for the note.":"Prikazuje URL geografskih podataka mjesta za bilješku.",Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Untuk menghapus sebuah label, hapus label dari catatan terkait.","Please select the note or notebook to be deleted first.":"Silakan pilih catatan atau buku catatan yang akan dihapus terlebih dahulu.","Press Ctrl+D or type \"exit\" to exit the application":"Tekan Ctrl+D atau ketik \"exit\" untuk keluar dari aplikasi","More than one item match \"%s\". Please narrow down your query.":"Lebih dari satu item cocok dengan \"%s\". Silakan persempit kueri Anda.","No notebook selected.":"Tidak ada buku catatan yang terpilih.","No notebook has been specified.":"Belum ada buku catatan yang ditentukan.","Y":"Y","n":"t","N":"T","y":"y","Cancelling background synchronisation... Please wait.":"Membatalkan proses sinkronisasi latar belakang... Mohon tunggu.","No such command: %s":"Tidak ada perintah semacam ini: %s","The command \"%s\" is only available in GUI mode":"Perintah \"%s\" hanya tersedia dalam mode GUI","Cannot change encrypted item":"Tidak dapat mengubah item yang terenkripsi","Missing required argument: %s":"Argumen yang dibutuhkan tidak ada: %s","%s: %s":"%s: %s","Your choice: ":"Pilihan Anda: ","Invalid answer: %s":"Jawaban tidak valid: %s","Attaches the given file to the note.":"Melampirkan berkas yang dipilih ke catatan.","Cannot find \"%s\".":"Tidak dapat menemukan \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Menjalankan perintah yang terkandung dalam file teks. Harus ada satu perintah per baris.","Displays the given note.":"Menampilkan catatan yang dipilih.","Displays the complete information about note.":"Menampilkan informasi lengkap tentang catatan.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Mendapatkan atau menyetel nilai konfigurasi. Jika [value] (nilai) tidak tersedia, maka akan menampilkan nilai dari [name] (nama). Jika [name] maupun [value] tidak tersedia juga, maka akan menampilkan daftar konfigurasi saat ini.","Also displays unset and hidden config variables.":"Juga menampilkan variabel konfigurasi yang belum disetel dan yang tersembunyi.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Menduplikasi catatan yang sesuai dengan <note> (catatan) ke [notebook] (buku catatan). Jika tidak ada buku catatan yang ditentukan maka catatan akan diduplikasi ke buku catatan saat ini.","Marks a to-do as done.":"Tandai tugas telah selesai.","Note is not a to-do: \"%s\"":"Catatan bukan sebuah tugas: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Mengelola konfigurasi E2EE. Terdapat beberapa perintah yaitu `enable`, `disable`, `decrypt`, `status`, `decrypt-file` dan `target-status`.","Enter master password:":"Masukkan kata sandi master:","Operation cancelled":"Operasi dibatalkan","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Memulai dekripsi… Mohon tunggu beberapa saat, kemungkinan proses akan memakan waktu beberapa menit tergantung seberapa besar yang akan didekripsi.","Decrypted items: %d":"Item terdekripsi: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Item yang dilewati: %d (gunakan --retry-failed-items untuk mencoba mendekripsinya lagi)","Completed decryption.":"Proses dekripsi selesai.","Confirm password:":"Konfirmasi kata sandi:","Passwords do not match!":"Kata sandi tidak cocok!","Enabled":"Diaktifkan","Disabled":"Dinonaktifkan","Encryption is: %s":"Enkripsi adalah: %s","Edit note.":"Ubah catatan.","No text editor is defined. Please set it using `config editor <editor-path>`":"Tidak ada editor teks yang diatur. Silakan setel menggunakan `config editor <editor-path>`","No active notebook.":"Tidak ada buku catatan yang aktif.","Note does not exist: \"%s\". Create it?":"Catatan tidak ada: \"%s\". Buat?","Starting to edit note. Close the editor to get back to the prompt.":"Mulai mengedit catatan. Tutup editor untuk kembali ke prompt.","Error opening note in editor: %s":"Terjadi kesalahan saat membuka catatan di editor: %s","Note has been saved.":"Catatan sudah disimpan.","Exits the application.":"Keluar dari aplikasi.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Mengekspor data Joplin ke alamat direktori yang diberikan. Secara otomatis, ini akan mengekspor basis data lengkap termasuk buku catatan, catatan, label dan sumber daya.","Destination format: %s":"Format tujuan: %s","Exports only the given note.":"Mengekspor hanya catatan yang diberikan.","Exports only the given notebook.":"Mengekspor hanya buku catatan yang diberikan.","Displays a geolocation URL for the note.":"MenamLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Untuk menghapus sebuah label, hapus label dari catatan terkait.","Please select the note or notebook to be deleted first.":"Silakan pilih catatan atau buku catatan yang akan dihapus terlebih dahulu.","Press Ctrl+D or type \"exit\" to exit the application":"Tekan Ctrl+D atau ketik \"exit\" untuk keluar dari aplikasi","More than one item match \"%s\". Please narrow down your query.":"Lebih dari satu item cocok dengan \"%s\". Silakan persempit kueri Anda.","No notebook selected.":"Tidak ada buku catatan yang terpilih.","No notebook has been specified.":"Belum ada buku catatan yang ditentukan.","Y":"Y","n":"t","N":"T","y":"y","Cancelling background synchronisation... Please wait.":"Membatalkan proses sinkronisasi latar belakang... Mohon tunggu.","No such command: %s":"Tidak ada perintah semacam ini: %s","The command \"%s\" is only available in GUI mode":"Perintah \"%s\" hanya tersedia dalam mode GUI","Cannot change encrypted item":"Tidak dapat mengubah item yang terenkripsi","Missing required argument: %s":"Argumen yang dibutuhkan tidak ada: %s","%s: %s":"%s: %s","Your choice: ":"Pilihan Anda: ","Invalid answer: %s":"Jawaban tidak valid: %s","Attaches the given file to the note.":"Melampirkan berkas yang dipilih ke catatan.","Cannot find \"%s\".":"Tidak dapat menemukan \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Menjalankan perintah yang terkandung dalam file teks. Harus ada satu perintah per baris.","Displays the given note.":"Menampilkan catatan yang dipilih.","Displays the complete information about note.":"Menampilkan informasi lengkap tentang catatan.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Mendapatkan atau menyetel nilai konfigurasi. Jika [value] (nilai) tidak tersedia, maka akan menampilkan nilai dari [name] (nama). Jika [name] maupun [value] tidak tersedia juga, maka akan menampilkan daftar konfigurasi saat ini.","Also displays unset and hidden config variables.":"Juga menampilkan variabel konfigurasi yang belum disetel dan yang tersembunyi.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Menduplikasi catatan yang sesuai dengan <note> (catatan) ke [notebook] (buku catatan). Jika tidak ada buku catatan yang ditentukan maka catatan akan diduplikasi ke buku catatan saat ini.","Marks a to-do as done.":"Tandai tugas telah selesai.","Note is not a to-do: \"%s\"":"Catatan bukan sebuah tugas: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Mengelola konfigurasi E2EE. Terdapat beberapa perintah yaitu `enable`, `disable`, `decrypt`, `status`, `decrypt-file` dan `target-status`.","Enter master password:":"Masukkan kata sandi master:","Operation cancelled":"Operasi dibatalkan","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Memulai dekripsi… Mohon tunggu beberapa saat, kemungkinan proses akan memakan waktu beberapa menit tergantung seberapa besar yang akan didekripsi.","Decrypted items: %d":"Item terdekripsi: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Item yang dilewati: %d (gunakan --retry-failed-items untuk mencoba mendekripsinya lagi)","Completed decryption.":"Proses dekripsi selesai.","Confirm password:":"Konfirmasi kata sandi:","Passwords do not match!":"Kata sandi tidak cocok!","Enabled":"Diaktifkan","Disabled":"Dinonaktifkan","Encryption is: %s":"Enkripsi adalah: %s","Edit note.":"Ubah catatan.","No text editor is defined. Please set it using `config editor <editor-path>`":"Tidak ada editor teks yang diatur. Silakan setel menggunakan `config editor <editor-path>`","No active notebook.":"Tidak ada buku catatan yang aktif.","Note does not exist: \"%s\". Create it?":"Catatan tidak ada: \"%s\". Buat?","Starting to edit note. Close the editor to get back to the prompt.":"Mulai mengedit catatan. Tutup editor untuk kembali ke prompt.","Error opening note in editor: %s":"Terjadi kesalahan saat membuka catatan di editor: %s","Note has been saved.":"Catatan sudah disimpan.","Exits the application.":"Keluar dari aplikasi.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Mengekspor data Joplin ke alamat direktori yang diberikan. Secara otomatis, ini akan mengekspor basis data lengkap termasuk buku catatan, catatan, label dan sumber daya.","Destination format: %s":"Format tujuan: %s","Exports only the given note.":"Mengekspor hanya catatan yang diberikan.","Exports only the given notebook.":"Mengekspor hanya buku catatan yang diberikan.","Displays a geolocation URL for the note.":"MenamLine truncated
|
||||
@@ -48,7 +48,7 @@ stats['bg_BG'] = {"percentDone":56};
|
||||
stats['ca'] = {"percentDone":95};
|
||||
stats['hr_HR'] = {"percentDone":96};
|
||||
stats['cs_CZ'] = {"percentDone":95};
|
||||
stats['da_DK'] = {"percentDone":96};
|
||||
stats['da_DK'] = {"percentDone":99};
|
||||
stats['de_DE'] = {"percentDone":95};
|
||||
stats['et_EE'] = {"percentDone":54};
|
||||
stats['en_GB'] = {"percentDone":100};
|
||||
@@ -64,7 +64,7 @@ stats['hu_HU'] = {"percentDone":84};
|
||||
stats['nl_BE'] = {"percentDone":87};
|
||||
stats['nl_NL'] = {"percentDone":90};
|
||||
stats['nb_NO'] = {"percentDone":96};
|
||||
stats['fa'] = {"percentDone":68};
|
||||
stats['fa'] = {"percentDone":67};
|
||||
stats['pl_PL'] = {"percentDone":90};
|
||||
stats['pt_BR'] = {"percentDone":96};
|
||||
stats['pt_PT'] = {"percentDone":90};
|
||||
@@ -73,13 +73,13 @@ stats['sl_SI'] = {"percentDone":91};
|
||||
stats['sv'] = {"percentDone":96};
|
||||
stats['th_TH'] = {"percentDone":42};
|
||||
stats['vi'] = {"percentDone":96};
|
||||
stats['tr_TR'] = {"percentDone":95};
|
||||
stats['tr_TR'] = {"percentDone":99};
|
||||
stats['uk_UA'] = {"percentDone":89};
|
||||
stats['el_GR'] = {"percentDone":92};
|
||||
stats['ru_RU'] = {"percentDone":90};
|
||||
stats['ru_RU'] = {"percentDone":89};
|
||||
stats['sr_RS'] = {"percentDone":81};
|
||||
stats['zh_CN'] = {"percentDone":96};
|
||||
stats['zh_TW'] = {"percentDone":95};
|
||||
stats['zh_CN'] = {"percentDone":99};
|
||||
stats['zh_TW'] = {"percentDone":94};
|
||||
stats['ja_JP'] = {"percentDone":95};
|
||||
stats['ko'] = {"percentDone":95};
|
||||
module.exports = { locales: locales, stats: stats };
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"タグを削除するには、関連するノートからタグを外してください。","Please select the note or notebook to be deleted first.":"まず削除するノートかノートブックを選択してください。","Press Ctrl+D or type \"exit\" to exit the application":"アプリケーションを終了するには、Ctrl+Dまたは\"exit\"と入力してください","More than one item match \"%s\". Please narrow down your query.":"一つ以上のアイテムが\"%s\"に一致しました。クエリを絞るようにしてください。","No notebook selected.":"ノートブックが選択されていません。","No notebook has been specified.":"ノートブックが選択されていません。","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"バックグラウンド同期を中止中… しばらくお待ちください。","No such command: %s":"コマンドが違います:%s","The command \"%s\" is only available in GUI mode":"コマンド \"%s\"は、GUIのみで有効です","Cannot change encrypted item":"暗号化したアイテムは変更できません","Missing required argument: %s":"引数が足りません:%s","%s: %s":"%s: %s","Your choice: ":"選択: ","Invalid answer: %s":"無効な入力:%s","Attaches the given file to the note.":"選択したファイルをノートに添付します。","Cannot find \"%s\".":"\"%s\"は見つかりませんでした。","Runs the commands contained in the text file. There should be one command per line.":"テキストファイルに含まれるコマンドを実行します。テキストファイルには1行1コマンドで記述する必要があります。","Displays the given note.":"選択したノートを表示します。","Displays the complete information about note.":"ノートに関するすべての情報を表示します。","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"設定を行います。[value]がない場合は、[name]で示された設定項目の値を表示します。両方とも指定されていない場合は、現在の設定のリストを表示します。","Also displays unset and hidden config variables.":"未設定または非表示の設定項目も表示します。","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"<note>に一致するノートを[notebook]に複製します。[notebook]が指定されていない場合は、現在のノートブックに複製を行います。","Marks a to-do as done.":"ToDoを完了としてマークします。","Note is not a to-do: \"%s\"":"ノートはToDoリストではありません:\"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"エンドツーエンド暗号化(E2EE)の設定コマンドです。<command>には `enable`, `disable`, `decrypt`, `status`, `target-status` があります。","Enter master password:":"マスターパスワードを入力してください:","Operation cancelled":"操作をキャンセルしました","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"復号を開始しました... どのぐらいの数を復号するかによりますが、数分かかりますのでお待ちください。","Decrypted items: %d":"復号済み(非暗号化)アイテム: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"スキップされたアイテム: %d (再度復号化を試みるには--retry-failed-itemsオプションを使用してください)","Completed decryption.":"復号が完了しました。","Confirm password:":"パスワード(確認用):","Passwords do not match!":"パスワードが一致しません!","Enabled":"有効","Disabled":"無効","Encryption is: %s":"暗号化: %s","Edit note.":"ノートを編集する。","No text editor is defined. Please set it using `config editor <editor-path>`":"テキストエディターが定義されていません。`config editor <editor-path>`で設定を行ってください","No active notebook.":"有効なノートブックがありません。","Note does not exist: \"%s\". Create it?":"\"%s\"というノートはありません。作成しますか?","Starting to edit note. Close the editor to get back to the prompt.":"ノートの編集を開始します。エディターを閉じると元の画面に戻ることができます。","Error opening note in editor: %s":"次のエディターで開く際にエラー: %s","Note has been saved.":"ノートは保存されました。","Exits the application.":"アプリケーションの終Line truncated
|
||||
{"To delete a tag, untag the associated notes.":"タグを削除するには、関連するノートからタグを外してください。","Please select the note or notebook to be deleted first.":"まず削除するノートかノートブックを選択してください。","Press Ctrl+D or type \"exit\" to exit the application":"アプリケーションを終了するには、Ctrl+Dまたは\"exit\"と入力してください","More than one item match \"%s\". Please narrow down your query.":"一つ以上のアイテムが\"%s\"に一致しました。クエリを絞るようにしてください。","No notebook selected.":"ノートブックが選択されていません。","No notebook has been specified.":"ノートブックが選択されていません。","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"バックグラウンド同期を中止中… しばらくお待ちください。","No such command: %s":"コマンドが違います:%s","The command \"%s\" is only available in GUI mode":"コマンド \"%s\"は、GUIのみで有効です","Cannot change encrypted item":"暗号化したアイテムは変更できません","Missing required argument: %s":"引数が足りません:%s","%s: %s":"%s: %s","Your choice: ":"選択: ","Invalid answer: %s":"無効な入力:%s","Attaches the given file to the note.":"選択したファイルをノートに添付します。","Cannot find \"%s\".":"\"%s\"は見つかりませんでした。","Runs the commands contained in the text file. There should be one command per line.":"テキストファイルに含まれるコマンドを実行します。テキストファイルには1行1コマンドで記述する必要があります。","Displays the given note.":"選択したノートを表示します。","Displays the complete information about note.":"ノートに関するすべての情報を表示します。","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"設定を行います。[value]がない場合は、[name]で示された設定項目の値を表示します。両方とも指定されていない場合は、現在の設定のリストを表示します。","Also displays unset and hidden config variables.":"未設定または非表示の設定項目も表示します。","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"<note>に一致するノートを[notebook]に複製します。[notebook]が指定されていない場合は、現在のノートブックに複製を行います。","Marks a to-do as done.":"ToDoを完了としてマークします。","Note is not a to-do: \"%s\"":"ノートはToDoリストではありません:\"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"エンドツーエンド暗号化(E2EE)の設定コマンドです。<command>には `enable`, `disable`, `decrypt`, `status`, `target-status` があります。","Enter master password:":"マスターパスワードを入力してください:","Operation cancelled":"操作をキャンセルしました","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"復号を開始しました... どのぐらいの数を復号するかによりますが、数分かかりますのでお待ちください。","Decrypted items: %d":"復号済み(非暗号化)アイテム: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"スキップされたアイテム: %d (再度復号化を試みるには--retry-failed-itemsオプションを使用してください)","Completed decryption.":"復号が完了しました。","Confirm password:":"パスワード(確認用):","Passwords do not match!":"パスワードが一致しません!","Enabled":"有効","Disabled":"無効","Encryption is: %s":"暗号化: %s","Edit note.":"ノートを編集する。","No text editor is defined. Please set it using `config editor <editor-path>`":"テキストエディターが定義されていません。`config editor <editor-path>`で設定を行ってください","No active notebook.":"有効なノートブックがありません。","Note does not exist: \"%s\". Create it?":"\"%s\"というノートはありません。作成しますか?","Starting to edit note. Close the editor to get back to the prompt.":"ノートの編集を開始します。エディターを閉じると元の画面に戻ることができます。","Error opening note in editor: %s":"次のエディターで開く際にエラー: %s","Note has been saved.":"ノートは保存されました。","Exits the application.":"アプリケーションの終Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"For å slette en merkelapp, fjern merkelappen fra merkede notater.","Please select the note or notebook to be deleted first.":"Vennligst velg notatet eller notatboken som skal slettes først.","Press Ctrl+D or type \"exit\" to exit the application":"Trykk Ctrl+D eller skriv \"exit\" for å avslutte programmet","More than one item match \"%s\". Please narrow down your query.":"Mer enn ett treff for \"%s\". Vennligst gjør søket mer spesifikt.","No notebook selected.":"Ingen notatbok valgt.","No notebook has been specified.":"Ingen notatbok har blitt spesifisert.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Avbryter bakgrunnssynkronisering… Vennligst vent.","No such command: %s":"Ingen kommando: %s","The command \"%s\" is only available in GUI mode":"Kommandoen \"%s\" er kun tilgjengelig i GUI-modus","Cannot change encrypted item":"Kan ikke endre kryptert element","Missing required argument: %s":"Mangler nødvendig argument: %s","%s: %s":"%s: %s","Your choice: ":"Ditt valg: ","Invalid answer: %s":"Ugyldig svar: %s","Attaches the given file to the note.":"Legger ved den valgte filen til notatet.","Cannot find \"%s\".":"Finner ikke \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Kjør kommandoene som finnes i denne tekstfilen. En kommando per linje.","Displays the given note.":"Viser det valgte notatet.","Displays the complete information about note.":"Viser den komplette informasjonen om notatet.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Skaffer eller setter en konfigurasjonsverdi. Hvis [value] ikke er angitt vil den vise verdien av [name]. Hvis hverken [name] eller [value] ikke er angitt, vil den vise den gjeldende konfigurasjonen.","Also displays unset and hidden config variables.":"Viser også ikke-satte og skjulte konfigurasjonsvariabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Dupliserer notatene som samsvarer med <note> til [notebook]. Hvis ingen notatbok er spesifisert blir notatet duplisert til gjeldende notatbok.","Marks a to-do as done.":"Markerer et gjøremål som ferdig.","Note is not a to-do: \"%s\"":"Notat er ikke et gjøremål: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Konfigurerer E2EE-konfigurasjon. Tilgjengelige kommandoer er: `enable`(aktiver), `disable`(lukk), `decrypt`(dekrypter), `status` og `target-status` (mottager-status).","Enter master password:":"Skriv inn masterpassordet:","Operation cancelled":"Operasjon avbrutt","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Starter dekryptering... Vennligst vent da det kan ta flere minutter avhengig av mengden som skal dekrypteres.","Decrypted items: %d":"Dekrypterte elementer: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Hoppet over elementer: %d (bruk --retry-failed-items for å forsøke å dekryptere på nytt)","Completed decryption.":"Dekryptering fullført.","Confirm password:":"Bekreft passord:","Passwords do not match!":"Passordene er ikke like!","Enabled":"Aktivert","Disabled":"Deaktivitert","Encryption is: %s":"Kryptering er: %s","Edit note.":"Rediger notat.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen teksteditor er valgt. Velg en ved å bruke `config editor <editor-path>`","No active notebook.":"Ingen aktiv notatbok.","Note does not exist: \"%s\". Create it?":"Notat eksisterer ikke: \"%s\". Vil du opprette det?","Starting to edit note. Close the editor to get back to the prompt.":"Notatredigering startet. Lukk editoren for å komme tilbake til kommandolinjen.","Error opening note in editor: %s":"Feil ved åpning av notat i editor: %s","Note has been saved.":"Notat har blitt lagret.","Exits the application.":"Avslutter programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Eksporterer Joplin-data til angitt sti. Standard er eksport av den komplette database inkludert notatbøker, notater, merkelapper og ressurser.","Destination format: %s":"Målformat: %s","Exports only the given note.":"Eksporterer kun valgt notat.","Exports only the given notebook.":"Eksporterer kun valgt notatbok.","Displays a geolocation URL for the note.":"Viser den komplette stedsinformasjonen for notatet.","Displays usage information.":"Vis brukerinformasjon.","For information on how to customise the shortcuts please visit %s":"For informasjon om hvordan tilpasse snarveier, vennligst besøk %s","Shortcuts are not available in CLLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"For å slette en merkelapp, fjern merkelappen fra merkede notater.","Please select the note or notebook to be deleted first.":"Vennligst velg notatet eller notatboken som skal slettes først.","Press Ctrl+D or type \"exit\" to exit the application":"Trykk Ctrl+D eller skriv \"exit\" for å avslutte programmet","More than one item match \"%s\". Please narrow down your query.":"Mer enn ett treff for \"%s\". Vennligst gjør søket mer spesifikt.","No notebook selected.":"Ingen notatbok valgt.","No notebook has been specified.":"Ingen notatbok har blitt spesifisert.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Avbryter bakgrunnssynkronisering… Vennligst vent.","No such command: %s":"Ingen kommando: %s","The command \"%s\" is only available in GUI mode":"Kommandoen \"%s\" er kun tilgjengelig i GUI-modus","Cannot change encrypted item":"Kan ikke endre kryptert element","Missing required argument: %s":"Mangler nødvendig argument: %s","%s: %s":"%s: %s","Your choice: ":"Ditt valg: ","Invalid answer: %s":"Ugyldig svar: %s","Attaches the given file to the note.":"Legger ved den valgte filen til notatet.","Cannot find \"%s\".":"Finner ikke \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Kjør kommandoene som finnes i denne tekstfilen. En kommando per linje.","Displays the given note.":"Viser det valgte notatet.","Displays the complete information about note.":"Viser den komplette informasjonen om notatet.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Skaffer eller setter en konfigurasjonsverdi. Hvis [value] ikke er angitt vil den vise verdien av [name]. Hvis hverken [name] eller [value] ikke er angitt, vil den vise den gjeldende konfigurasjonen.","Also displays unset and hidden config variables.":"Viser også ikke-satte og skjulte konfigurasjonsvariabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Dupliserer notatene som samsvarer med <note> til [notebook]. Hvis ingen notatbok er spesifisert blir notatet duplisert til gjeldende notatbok.","Marks a to-do as done.":"Markerer et gjøremål som ferdig.","Note is not a to-do: \"%s\"":"Notat er ikke et gjøremål: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Konfigurerer E2EE-konfigurasjon. Tilgjengelige kommandoer er: `enable`(aktiver), `disable`(lukk), `decrypt`(dekrypter), `status` og `target-status` (mottager-status).","Enter master password:":"Skriv inn masterpassordet:","Operation cancelled":"Operasjon avbrutt","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Starter dekryptering... Vennligst vent da det kan ta flere minutter avhengig av mengden som skal dekrypteres.","Decrypted items: %d":"Dekrypterte elementer: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Hoppet over elementer: %d (bruk --retry-failed-items for å forsøke å dekryptere på nytt)","Completed decryption.":"Dekryptering fullført.","Confirm password:":"Bekreft passord:","Passwords do not match!":"Passordene er ikke like!","Enabled":"Aktivert","Disabled":"Deaktivitert","Encryption is: %s":"Kryptering er: %s","Edit note.":"Rediger notat.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen teksteditor er valgt. Velg en ved å bruke `config editor <editor-path>`","No active notebook.":"Ingen aktiv notatbok.","Note does not exist: \"%s\". Create it?":"Notat eksisterer ikke: \"%s\". Vil du opprette det?","Starting to edit note. Close the editor to get back to the prompt.":"Notatredigering startet. Lukk editoren for å komme tilbake til kommandolinjen.","Error opening note in editor: %s":"Feil ved åpning av notat i editor: %s","Note has been saved.":"Notat har blitt lagret.","Exits the application.":"Avslutter programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Eksporterer Joplin-data til angitt sti. Standard er eksport av den komplette database inkludert notatbøker, notater, merkelapper og ressurser.","Destination format: %s":"Målformat: %s","Exports only the given note.":"Eksporterer kun valgt notat.","Exports only the given notebook.":"Eksporterer kun valgt notatbok.","Displays a geolocation URL for the note.":"Viser den komplette stedsinformasjonen for notatet.","Displays usage information.":"Vis brukerinformasjon.","For information on how to customise the shortcuts please visit %s":"For informasjon om hvordan tilpasse snarveier, vennligst besøk %s","Shortcuts are not available in CLLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Para eliminar uma tag, remova a tag das notas associadas a ela.","Please select the note or notebook to be deleted first.":"Por favor, primeiro, selecione a nota ou caderno a excluir.","Press Ctrl+D or type \"exit\" to exit the application":"Digite Ctrl+D ou \"exit\" para sair da aplicação","More than one item match \"%s\". Please narrow down your query.":"Mais que um item combinam com \"%s\". Por favor, refine sua pesquisa.","No notebook selected.":"Nenhum caderno selecionado.","No notebook has been specified.":"Nenhum caderno foi especificado.","Y":"S","n":"n","N":"N","y":"s","Cancelling background synchronisation... Please wait.":"Cancelando sincronização em segundo plano... Por favor, aguarde.","No such command: %s":"Não existe o comando: \"%s\"","The command \"%s\" is only available in GUI mode":"O comando \"%s\" está disponível somente em modo gráfico","Cannot change encrypted item":"Não é possível mudar um item criptografado","Missing required argument: %s":"Argumento necessário faltando: %s","%s: %s":"%s: %s","Your choice: ":"Sua escolha: ","Invalid answer: %s":"Resposta inválida: %s","Attaches the given file to the note.":"Anexa o arquivo dado à nota.","Cannot find \"%s\".":"Não posso encontrar \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Executa os comandos contidos no arquivo de texto. Deve haver um comando por linha.","Displays the given note.":"Exibe a nota informada.","Displays the complete information about note.":"Exibe a informação completa sobre a nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtém ou define um valor de configuração. Se [valor] não for fornecido, ele mostrará o valor de [nome]. Se nem [nome] nem [valor] forem fornecidos, ele listará a configuração atual.","Also displays unset and hidden config variables.":"Também exibe variáveis de configuração não definidas e ocultas.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica as notas que correspondem a <nota> para o [caderno]. Se nenhum caderno for especificado, a nota será duplicada no caderno atual.","Marks a to-do as done.":"Marca uma tarefa como feita.","Note is not a to-do: \"%s\"":"Nota não é uma tarefa: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gerencia a configuração E2EE. Os comandos são `enable`, `disable`, `decrypt`, `status`, `decrypt-file` e `target-status`.","Enter master password:":"Digite a senha mestra:","Operation cancelled":"Operação cancelada","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Iniciando descriptografação... Por favor aguarde, pois isso pode demorar vários minutos, dependendo de quanto há para descriptografar.","Decrypted items: %d":"Itens descriptografados: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Items ignorados: %d (use --retry-failed-items para tentar novamente)","Completed decryption.":"Descriptografação completada.","Confirm password:":"Confirme a senha:","Passwords do not match!":"As senhas não coincidem!","Enabled":"Habilitado","Disabled":"Desabilitado","Encryption is: %s":"Criptografia está: %s","Edit note.":"Editar nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"Nenhum editor de texto está definido. Defina-o usando o comando `config editor <caminho-do-editor>`","No active notebook.":"Nenhum caderno ativo.","Note does not exist: \"%s\". Create it?":"A nota não existe: \"%s\". Criar?","Starting to edit note. Close the editor to get back to the prompt.":"Começando a editar a nota. Feche o editor para voltar ao prompt.","Error opening note in editor: %s":"Erro ao abir a nota no editor: %s","Note has been saved.":"Nota gravada.","Exits the application.":"Sai da aplicação.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta os dados do Joplin para o diretório informado. Por padrão, ele exportará o banco de dados completo, incluindo cadernos, notas, tags e recursos.","Destination format: %s":"Formato do destino: %s","Exports only the given note.":"Exporta apenas a nota fornecida.","Exports only the given notebook.":"Exporta apenas o caderno fornecido.","Displays a geolocation URL for the note.":"Exibe uma URL de geolocalização para a nota.","Displays usage information.":"Exibe informações de uso.","For information on how to customise the shortcuts please visit %s":"Para informações sobre como customizar os atalhos, por favor visite %s","Shortcuts Line truncated
|
||||
{"To delete a tag, untag the associated notes.":"Para eliminar uma tag, remova a tag das notas associadas a ela.","Please select the note or notebook to be deleted first.":"Por favor, primeiro, selecione a nota ou caderno a excluir.","Press Ctrl+D or type \"exit\" to exit the application":"Digite Ctrl+D ou \"exit\" para sair da aplicação","More than one item match \"%s\". Please narrow down your query.":"Mais que um item combinam com \"%s\". Por favor, refine sua pesquisa.","No notebook selected.":"Nenhum caderno selecionado.","No notebook has been specified.":"Nenhum caderno foi especificado.","Y":"S","n":"n","N":"N","y":"s","Cancelling background synchronisation... Please wait.":"Cancelando sincronização em segundo plano... Por favor, aguarde.","No such command: %s":"Não existe o comando: \"%s\"","The command \"%s\" is only available in GUI mode":"O comando \"%s\" está disponível somente em modo gráfico","Cannot change encrypted item":"Não é possível mudar um item criptografado","Missing required argument: %s":"Argumento necessário faltando: %s","%s: %s":"%s: %s","Your choice: ":"Sua escolha: ","Invalid answer: %s":"Resposta inválida: %s","Attaches the given file to the note.":"Anexa o arquivo dado à nota.","Cannot find \"%s\".":"Não posso encontrar \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Executa os comandos contidos no arquivo de texto. Deve haver um comando por linha.","Displays the given note.":"Exibe a nota informada.","Displays the complete information about note.":"Exibe a informação completa sobre a nota.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtém ou define um valor de configuração. Se [valor] não for fornecido, ele mostrará o valor de [nome]. Se nem [nome] nem [valor] forem fornecidos, ele listará a configuração atual.","Also displays unset and hidden config variables.":"Também exibe variáveis de configuração não definidas e ocultas.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplica as notas que correspondem a <nota> para o [caderno]. Se nenhum caderno for especificado, a nota será duplicada no caderno atual.","Marks a to-do as done.":"Marca uma tarefa como feita.","Note is not a to-do: \"%s\"":"Nota não é uma tarefa: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Gerencia a configuração E2EE. Os comandos são `enable`, `disable`, `decrypt`, `status`, `decrypt-file` e `target-status`.","Enter master password:":"Digite a senha mestra:","Operation cancelled":"Operação cancelada","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Iniciando descriptografação... Por favor aguarde, pois isso pode demorar vários minutos, dependendo de quanto há para descriptografar.","Decrypted items: %d":"Itens descriptografados: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Items ignorados: %d (use --retry-failed-items para tentar novamente)","Completed decryption.":"Descriptografação completada.","Confirm password:":"Confirme a senha:","Passwords do not match!":"As senhas não coincidem!","Enabled":"Habilitado","Disabled":"Desabilitado","Encryption is: %s":"Criptografia está: %s","Edit note.":"Editar nota.","No text editor is defined. Please set it using `config editor <editor-path>`":"Nenhum editor de texto está definido. Defina-o usando o comando `config editor <caminho-do-editor>`","No active notebook.":"Nenhum caderno ativo.","Note does not exist: \"%s\". Create it?":"A nota não existe: \"%s\". Criar?","Starting to edit note. Close the editor to get back to the prompt.":"Começando a editar a nota. Feche o editor para voltar ao prompt.","Error opening note in editor: %s":"Erro ao abir a nota no editor: %s","Note has been saved.":"Nota gravada.","Exits the application.":"Sai da aplicação.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporta os dados do Joplin para o diretório informado. Por padrão, ele exportará o banco de dados completo, incluindo cadernos, notas, tags e recursos.","Destination format: %s":"Formato do destino: %s","Exports only the given note.":"Exporta apenas a nota fornecida.","Exports only the given notebook.":"Exporta apenas o caderno fornecido.","Displays a geolocation URL for the note.":"Exibe uma URL de geolocalização para a nota.","Displays usage information.":"Exibe informações de uso.","For information on how to customise the shortcuts please visit %s":"Para informações sobre como customizar os atalhos, por favor visite %s","Shortcuts Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"För att ta bort en tagg, ta bort de associerade anteckningarna.","Please select the note or notebook to be deleted first.":"Välj anteckningen eller anteckningsboken som ska tas bort först.","Press Ctrl+D or type \"exit\" to exit the application":"Tryck Ctrl+D eller skriv \"exit\" för att avsluta programmet","More than one item match \"%s\". Please narrow down your query.":"Mer än ett objekt matchar \"%s\". Begränsa din förfråga.","No notebook selected.":"Ingen anteckningsbok vald.","No notebook has been specified.":"Ingen anteckningsbok har angivits.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Avbryter bakgrundssynkronisering... vänta.","No such command: %s":"Inget sådant kommando: %s","The command \"%s\" is only available in GUI mode":"Kommandot \"%s\" är endast tillgängligt i läge för grafiskt gränssnitt","Cannot change encrypted item":"Kan inte ändra krypterat objekt","Missing required argument: %s":"Saknade obligatoriskt argument: %s","%s: %s":"%s: %s","Your choice: ":"Ditt val: ","Invalid answer: %s":"Ogiltigt svar: %s","Attaches the given file to the note.":"Bifogar den angivna filen till anteckningen.","Cannot find \"%s\".":"Kan inte hitta \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Kör kommandona i textfilen. Det ska finnas ett kommando per rad.","Displays the given note.":"Visar den angivna anteckningen.","Displays the complete information about note.":"Visar fullständig information om anteckning.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Hämtar eller ställer in ett konfigureringsvärde. Om [value] inte anges kommer det att visa värdet på [name]. Om varken [name] eller [value] anges, kommer det att lista den nuvarande konfigurationen.","Also displays unset and hidden config variables.":"Visar även inte inställda och dolda konfigurationsvariabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplicerar anteckningarna som matchar <note> till [notebook]. Om ingen anteckningsbok är angiven kopieras anteckningen i den aktuella anteckningsboken.","Marks a to-do as done.":"Märker en att-göra som gjord.","Note is not a to-do: \"%s\"":"Anteckning är inte en att-göra: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Hanterar E2EE-konfiguration. Kommandona är `enable`,` disable`, `decrypt`,` status`, `decrypt-file` och `target-status`.","Enter master password:":"Ange huvudlösenord:","Operation cancelled":"Operation avbruten","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Startar dekryptering... Vänta eftersom det kan ta flera minuter beroende på hur mycket som ska dekrypteras.","Decrypted items: %d":"Dekrypterade objekt: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Överhoppade objekt: %d (använd --retry-failed-items för att försöka dekryptera dem igen)","Completed decryption.":"Dekryptering färdig.","Confirm password:":"Bekräfta lösenord:","Passwords do not match!":"Lösenorden matchar inte!","Enabled":"Aktiverad","Disabled":"Inaktiverad","Encryption is: %s":"Kryptering är: %s","Edit note.":"Redigera anteckning.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen textredigerare är definierad. Ange det med `config editor <editor-path>`","No active notebook.":"Ingen aktiv anteckningsbok.","Note does not exist: \"%s\". Create it?":"Anteckning finns inte: \"%s\". Skapa den?","Starting to edit note. Close the editor to get back to the prompt.":"Börjar redigera anteckning. Stäng redigeraren för att komma tillbaka till prompten.","Error opening note in editor: %s":"Fel vid öppning av anteckning i redigeraren: %s","Note has been saved.":"Anteckning har sparats.","Exits the application.":"Avslutar programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporterar Joplin-data till den angivna sökvägen. Som standard exporterar den hela databasen inklusive anteckningsböcker, anteckningar, taggar och resurser.","Destination format: %s":"Destinationsformat: %s","Exports only the given note.":"Exporterar endast den angivna anteckningen.","Exports only the given notebook.":"Exporterar endast den angivna anteckningsboken.","Displays a geolocation URL for the note.":"Visar en geolokaliserings-webbadress för anteckningen.","Displays usage information.":"Visar användningsinformation.","For information on how to customise the shortcuts please visit %s":"För infoLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"För att ta bort en tagg, ta bort de associerade anteckningarna.","Please select the note or notebook to be deleted first.":"Välj anteckningen eller anteckningsboken som ska tas bort först.","Press Ctrl+D or type \"exit\" to exit the application":"Tryck Ctrl+D eller skriv \"exit\" för att avsluta programmet","More than one item match \"%s\". Please narrow down your query.":"Mer än ett objekt matchar \"%s\". Begränsa din förfråga.","No notebook selected.":"Ingen anteckningsbok vald.","No notebook has been specified.":"Ingen anteckningsbok har angivits.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Avbryter bakgrundssynkronisering... vänta.","No such command: %s":"Inget sådant kommando: %s","The command \"%s\" is only available in GUI mode":"Kommandot \"%s\" är endast tillgängligt i läge för grafiskt gränssnitt","Cannot change encrypted item":"Kan inte ändra krypterat objekt","Missing required argument: %s":"Saknade obligatoriskt argument: %s","%s: %s":"%s: %s","Your choice: ":"Ditt val: ","Invalid answer: %s":"Ogiltigt svar: %s","Attaches the given file to the note.":"Bifogar den angivna filen till anteckningen.","Cannot find \"%s\".":"Kan inte hitta \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Kör kommandona i textfilen. Det ska finnas ett kommando per rad.","Displays the given note.":"Visar den angivna anteckningen.","Displays the complete information about note.":"Visar fullständig information om anteckning.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Hämtar eller ställer in ett konfigureringsvärde. Om [value] inte anges kommer det att visa värdet på [name]. Om varken [name] eller [value] anges, kommer det att lista den nuvarande konfigurationen.","Also displays unset and hidden config variables.":"Visar även inte inställda och dolda konfigurationsvariabler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Duplicerar anteckningarna som matchar <note> till [notebook]. Om ingen anteckningsbok är angiven kopieras anteckningen i den aktuella anteckningsboken.","Marks a to-do as done.":"Märker en att-göra som gjord.","Note is not a to-do: \"%s\"":"Anteckning är inte en att-göra: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Hanterar E2EE-konfiguration. Kommandona är `enable`,` disable`, `decrypt`,` status`, `decrypt-file` och `target-status`.","Enter master password:":"Ange huvudlösenord:","Operation cancelled":"Operation avbruten","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Startar dekryptering... Vänta eftersom det kan ta flera minuter beroende på hur mycket som ska dekrypteras.","Decrypted items: %d":"Dekrypterade objekt: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Överhoppade objekt: %d (använd --retry-failed-items för att försöka dekryptera dem igen)","Completed decryption.":"Dekryptering färdig.","Confirm password:":"Bekräfta lösenord:","Passwords do not match!":"Lösenorden matchar inte!","Enabled":"Aktiverad","Disabled":"Inaktiverad","Encryption is: %s":"Kryptering är: %s","Edit note.":"Redigera anteckning.","No text editor is defined. Please set it using `config editor <editor-path>`":"Ingen textredigerare är definierad. Ange det med `config editor <editor-path>`","No active notebook.":"Ingen aktiv anteckningsbok.","Note does not exist: \"%s\". Create it?":"Anteckning finns inte: \"%s\". Skapa den?","Starting to edit note. Close the editor to get back to the prompt.":"Börjar redigera anteckning. Stäng redigeraren för att komma tillbaka till prompten.","Error opening note in editor: %s":"Fel vid öppning av anteckning i redigeraren: %s","Note has been saved.":"Anteckning har sparats.","Exits the application.":"Avslutar programmet.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporterar Joplin-data till den angivna sökvägen. Som standard exporterar den hela databasen inklusive anteckningsböcker, anteckningar, taggar och resurser.","Destination format: %s":"Destinationsformat: %s","Exports only the given note.":"Exporterar endast den angivna anteckningen.","Exports only the given notebook.":"Exporterar endast den angivna anteckningsboken.","Displays a geolocation URL for the note.":"Visar en geolokaliserings-webbadress för anteckningen.","Displays usage information.":"Visar användningsinformation.","For information on how to customise the shortcuts please visit %s":"För infoLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Bir etiketi silmek için ilişkilendirilmiş notların etiketini kaldırın.","Please select the note or notebook to be deleted first.":"Lütfen önce silinecek notu veya not defterini seçin.","Press Ctrl+D or type \"exit\" to exit the application":"Uygulamadan çıkmak için Ctrl + D tuşlarına basın veya \"exit\" yazın","More than one item match \"%s\". Please narrow down your query.":"Birden fazla öğe \"%s\" ile eşleşiyor. Lütfen sorgunuzu daraltınız.","No notebook selected.":"Seçili defter yok.","No notebook has been specified.":"Hiçbir not defteri belirtilmedi.","Y":"E","n":"h","N":"H","y":"h","Cancelling background synchronisation... Please wait.":"Arka plan senkronizasyonu iptal ediliyor... Lütfen bekleyin.","No such command: %s":"Böyle bir komut yok: %s","The command \"%s\" is only available in GUI mode":"\"%s\" komutu sadece grafik arayüzünde kullanılabilir","Cannot change encrypted item":"Şifrelenmiş öğe değiştirilemiyor","Missing required argument: %s":"Gerekli parametre eksik gözüküyor: %s","%s: %s":"%s: %s","Your choice: ":"Seçiminiz: ","Invalid answer: %s":"Yanlış cevap: %s","Attaches the given file to the note.":"Verilen dosyayı nota iliştirir.","Cannot find \"%s\".":"\"%s\" bulunamıyor.","Runs the commands contained in the text file. There should be one command per line.":"Metin dosyasındaki komutları çalıştırır. Her bir komut ayrı satırda olmalıdır.","Displays the given note.":"Verilen notu görüntüler.","Displays the complete information about note.":"Notla ilgili tüm bilgileri görüntüler.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Ayar değeri alınır veya ayarlanır. Eğer [değer] sağlanmamışsa, [isim] kısmı gözükecektir. Eğer [isim] ve [değer] bilgilerinin ikisi de mevcut değilse, mevcut olan yapılandırmayı listeleyecek.","Also displays unset and hidden config variables.":"Ayrıca ayarlanmamış ve gizlenmiş yapılandırma değişkenlerini de görüntüler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"<Not> ile eşleşen notları [notebook] not defterine çoğaltır. Not belirtilmemişse, not geçerli not defterinde çoğaltılır.","Marks a to-do as done.":"Yapılacakları yapıldı olarak işaretler.","Note is not a to-do: \"%s\"":"Bu not yapılacaklar listesi değildir: “%s”","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Uçtan Uca Şifreleme ayarını yönetir. Komutlar `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.","Enter master password:":"Ana parolayı girin:","Operation cancelled":"İşlem iptal edildi","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Şifre çözme başlatılıyor... Çözülecek dosya sayısına bağlı olarak biraz zaman alabilir, lütfen bekleyiniz.","Decrypted items: %d":"Şifresi çözülen öğeler: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Atlanan öğeler: %d (--retry-failed parametresi ile şifrelemelerini çözmeyi yeniden deneyebilirsiniz)","Completed decryption.":"Şifre çözümü tamamlandı.","Confirm password:":"Parolayı doğrula:","Passwords do not match!":"Parolalar eşleşmiyor!","Enabled":"Etkin","Disabled":"Pasif","Encryption is: %s":"Şifreleme: %s","Edit note.":"Notu düzenle.","No text editor is defined. Please set it using `config editor <editor-path>`":"Hiçbir metin editörü tanımlanmadı. Lütfen `config editor <editor-path>` komutunu kullanarak editörü ayarlayınız","No active notebook.":"Aktif not defteri yok.","Note does not exist: \"%s\". Create it?":"\"%s\" notu mevcut değil. Oluşturulsun mu?","Starting to edit note. Close the editor to get back to the prompt.":"Notu düzenlemeye başlıyorsunuz. Doğrulamaya dönmek için editörü kapamanız gerekmekte.","Error opening note in editor: %s":"Editörde not açılırken hata oluştu: %s","Note has been saved.":"Not kaydedildi.","Exits the application.":"Uygulamadan çıkar.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Joplin verilerini belirtilen yere aktarır. Varsayılan olarak, not defterleri, notlar, etiketler ve kaynaklar dahil olmak üzere tüm veritabanını dışa aktarır.","Destination format: %s":"Hedef biçimi: %s","Exports only the given note.":"Yalnızca seçilen notu dışa aktarır.","Exports only the given notebook.":"Yalnızca seçilen not defterini dışa aktarır.","Displays a geolocation URL for the note.":"Not için bir coğrafi konum URL'i görüntüler.","Displays usageLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Bir etiketi silmek için ilişkilendirilmiş notların etiketini kaldırın.","Please select the note or notebook to be deleted first.":"Lütfen önce silinecek notu veya not defterini seçin.","Press Ctrl+D or type \"exit\" to exit the application":"Uygulamadan çıkmak için Ctrl + D tuşlarına basın veya \"exit\" yazın","More than one item match \"%s\". Please narrow down your query.":"Birden fazla öğe \"%s\" ile eşleşiyor. Lütfen sorgunuzu daraltınız.","No notebook selected.":"Seçili defter yok.","No notebook has been specified.":"Hiçbir not defteri belirtilmedi.","Y":"E","n":"h","N":"H","y":"h","Cancelling background synchronisation... Please wait.":"Arka plan senkronizasyonu iptal ediliyor... Lütfen bekleyin.","No such command: %s":"Böyle bir komut yok: %s","The command \"%s\" is only available in GUI mode":"\"%s\" komutu sadece grafik arayüzünde kullanılabilir","Cannot change encrypted item":"Şifrelenmiş öğe değiştirilemiyor","Missing required argument: %s":"Gerekli parametre eksik gözüküyor: %s","%s: %s":"%s: %s","Your choice: ":"Seçiminiz: ","Invalid answer: %s":"Yanlış cevap: %s","Attaches the given file to the note.":"Verilen dosyayı nota iliştirir.","Cannot find \"%s\".":"\"%s\" bulunamıyor.","Runs the commands contained in the text file. There should be one command per line.":"Metin dosyasındaki komutları çalıştırır. Her bir komut ayrı satırda olmalıdır.","Displays the given note.":"Verilen notu görüntüler.","Displays the complete information about note.":"Notla ilgili tüm bilgileri görüntüler.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Ayar değeri alınır veya ayarlanır. Eğer [değer] sağlanmamışsa, [isim] kısmı gözükecektir. Eğer [isim] ve [değer] bilgilerinin ikisi de mevcut değilse, mevcut olan yapılandırmayı listeleyecek.","Also displays unset and hidden config variables.":"Ayrıca ayarlanmamış ve gizlenmiş yapılandırma değişkenlerini de görüntüler.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"<Not> ile eşleşen notları [notebook] not defterine çoğaltır. Not belirtilmemişse, not geçerli not defterinde çoğaltılır.","Marks a to-do as done.":"Yapılacakları yapıldı olarak işaretler.","Note is not a to-do: \"%s\"":"Bu not yapılacaklar listesi değildir: “%s”","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Uçtan Uca Şifreleme ayarını yönetir. Komutlar `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.","Enter master password:":"Ana parolayı girin:","Operation cancelled":"İşlem iptal edildi","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Şifre çözme başlatılıyor... Çözülecek dosya sayısına bağlı olarak biraz zaman alabilir, lütfen bekleyiniz.","Decrypted items: %d":"Şifresi çözülen öğeler: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Atlanan öğeler: %d (--retry-failed parametresi ile şifrelemelerini çözmeyi yeniden deneyebilirsiniz)","Completed decryption.":"Şifre çözümü tamamlandı.","Confirm password:":"Parolayı doğrula:","Passwords do not match!":"Parolalar eşleşmiyor!","Enabled":"Etkin","Disabled":"Pasif","Encryption is: %s":"Şifreleme: %s","Edit note.":"Notu düzenle.","No text editor is defined. Please set it using `config editor <editor-path>`":"Hiçbir metin editörü tanımlanmadı. Lütfen `config editor <editor-path>` komutunu kullanarak editörü ayarlayınız","No active notebook.":"Aktif not defteri yok.","Note does not exist: \"%s\". Create it?":"\"%s\" notu mevcut değil. Oluşturulsun mu?","Starting to edit note. Close the editor to get back to the prompt.":"Notu düzenlemeye başlıyorsunuz. Doğrulamaya dönmek için editörü kapamanız gerekmekte.","Error opening note in editor: %s":"Editörde not açılırken hata oluştu: %s","Note has been saved.":"Not kaydedildi.","Exits the application.":"Uygulamadan çıkar.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Joplin verilerini belirtilen yere aktarır. Varsayılan olarak, not defterleri, notlar, etiketler ve kaynaklar dahil olmak üzere tüm veritabanını dışa aktarır.","Destination format: %s":"Hedef biçimi: %s","Exports only the given note.":"Yalnızca seçilen notu dışa aktarır.","Exports only the given notebook.":"Yalnızca seçilen not defterini dışa aktarır.","Displays a geolocation URL for the note.":"Not için bir coğrafi konum URL'i görüntüler.","Displays usageLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"Để xóa nhãn, hãy gỡ nhãn khỏi các ghi chú đã được gắn.","Please select the note or notebook to be deleted first.":"Vui lòng chọn ghi chú hoặc sổ ghi chú cần được xóa.","Press Ctrl+D or type \"exit\" to exit the application":"Vui lòng nhấn Ctrl+D hoặc gõ \"exit\" để thoát khỏi ứng dụng","More than one item match \"%s\". Please narrow down your query.":"Nhiều hơn một mục được tìm thấy với \"%s\". Hãy truy vấn cụ thể hơn nữa.","No notebook selected.":"Chưa có sổ ghi chú nào được chọn.","No notebook has been specified.":"Chưa có sổ ghi chú nào được chỉ định.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Hủy đồng bộ hóa đang chạy dưới nền… Vui lòng chờ.","No such command: %s":"Không có lệnh: %s","The command \"%s\" is only available in GUI mode":"Lệnh \"%s\" chỉ có thể sử dụng trong chế độ GUI","Cannot change encrypted item":"Không thể thay đổi những mục đã được mã hóa","Missing required argument: %s":"Thiếu đối số cho hàm: %s","%s: %s":"%s: %s","Your choice: ":"Lựa chọn của bạn ","Invalid answer: %s":"Câu trả lời không hợp lệ: %s","Attaches the given file to the note.":"Đính kèm tập tin được lựa chọn vào ghi chú.","Cannot find \"%s\".":"Không tìm thấy \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Thực thi các lệnh trong tập tin văn bản. Mỗi dòng chỉ nên chứa một lệnh.","Displays the given note.":"Hiển thị ghi chú được lựa chọn.","Displays the complete information about note.":"Hiển thị toàn bộ thông tin của ghi chú.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Lấy hoặc cài đặt cấu hình. Nếu [cấu hình] không được cung cấp, cấu hình của [tên] sẽ được hiển thị. Nếu cả [tên] và [cấu hình] đều không được cung cấp, danh cách các cấu hình hiện tại sẽ được hiển thị.","Also displays unset and hidden config variables.":"Biến chưa được đặt và biến ẩn của cấu hình cũng sẽ được hiển thị.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Sao chép những note trùng với <note> tới [notebook]. Nếu không có notebook nào được chỉ định, note sẽ được sao chép tới notebook hiện tại.","Marks a to-do as done.":"Đánh dấu một to-do đã hoàn thành.","Note is not a to-do: \"%s\"":"Ghi chú này không phải là to-do: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Quản lý cấu hình E2EE. Câu lệnh bao gồm `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.","Enter master password:":"Điền mật khẩu master:","Operation cancelled":"Thi hành đã được hủy","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Bắt đầu giải mã… Vui lòng chờ, quá trình có thể mất vài phút tùy vào số lượng cần giải mã.","Decrypted items: %d":"Những mục đã được giải mã: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Bỏ qua các mục: %d (sử dụng —retry-failed-items để thử giải mã lại)","Completed decryption.":"Giải mã hoàn tất.","Confirm password:":"Xác nhận mật khẩu:","Passwords do not match!":"Mật khẩu không trùng!","Enabled":"Đã bật","Disabled":"Đã tắt","Encryption is: %s":"Mã hóa là: %s","Edit note.":"Sửa ghi chú.","No text editor is defined. Please set it using `config editor <editor-path>`":"Chưa có trình biên tập văn bản nào được lựa chon. Vui lòng lựa chọn trình biên tập văn bản sử dụng `config editor <editor-path>`","No active notebook.":"Không có ghi chú nào đang được sử dụng.","Note does not exist: \"%s\". Create it?":"Không có note: \"%s\". Tạo lập nó?","Starting to edit note. Close the editor to get back to the prompt.":"Bắt đầu chỉnh sửa ghi chú. Tắt trình soạn thảo để quay lại lời nhắc.","Error opening note in editor: %s":"Lỗi khi mở note trong trình chỉnh sửa: %s","Note has been saved.":"Ghi chú chưa được lưu.","Exits the application.":"Thoát ứng dụng.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Xuất dữ liệu từ Joplin tới đường dLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"Để xóa nhãn, hãy gỡ nhãn khỏi các ghi chú đã được gắn.","Please select the note or notebook to be deleted first.":"Vui lòng chọn ghi chú hoặc sổ ghi chú cần được xóa.","Press Ctrl+D or type \"exit\" to exit the application":"Vui lòng nhấn Ctrl+D hoặc gõ \"exit\" để thoát khỏi ứng dụng","More than one item match \"%s\". Please narrow down your query.":"Nhiều hơn một mục được tìm thấy với \"%s\". Hãy truy vấn cụ thể hơn nữa.","No notebook selected.":"Chưa có sổ ghi chú nào được chọn.","No notebook has been specified.":"Chưa có sổ ghi chú nào được chỉ định.","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"Hủy đồng bộ hóa đang chạy dưới nền… Vui lòng chờ.","No such command: %s":"Không có lệnh: %s","The command \"%s\" is only available in GUI mode":"Lệnh \"%s\" chỉ có thể sử dụng trong chế độ GUI","Cannot change encrypted item":"Không thể thay đổi những mục đã được mã hóa","Missing required argument: %s":"Thiếu đối số cho hàm: %s","%s: %s":"%s: %s","Your choice: ":"Lựa chọn của bạn ","Invalid answer: %s":"Câu trả lời không hợp lệ: %s","Attaches the given file to the note.":"Đính kèm tập tin được lựa chọn vào ghi chú.","Cannot find \"%s\".":"Không tìm thấy \"%s\".","Runs the commands contained in the text file. There should be one command per line.":"Thực thi các lệnh trong tập tin văn bản. Mỗi dòng chỉ nên chứa một lệnh.","Displays the given note.":"Hiển thị ghi chú được lựa chọn.","Displays the complete information about note.":"Hiển thị toàn bộ thông tin của ghi chú.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Lấy hoặc cài đặt cấu hình. Nếu [cấu hình] không được cung cấp, cấu hình của [tên] sẽ được hiển thị. Nếu cả [tên] và [cấu hình] đều không được cung cấp, danh cách các cấu hình hiện tại sẽ được hiển thị.","Also displays unset and hidden config variables.":"Biến chưa được đặt và biến ẩn của cấu hình cũng sẽ được hiển thị.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Sao chép những note trùng với <note> tới [notebook]. Nếu không có notebook nào được chỉ định, note sẽ được sao chép tới notebook hiện tại.","Marks a to-do as done.":"Đánh dấu một to-do đã hoàn thành.","Note is not a to-do: \"%s\"":"Ghi chú này không phải là to-do: \"%s\"","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"Quản lý cấu hình E2EE. Câu lệnh bao gồm `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.","Enter master password:":"Điền mật khẩu master:","Operation cancelled":"Thi hành đã được hủy","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"Bắt đầu giải mã… Vui lòng chờ, quá trình có thể mất vài phút tùy vào số lượng cần giải mã.","Decrypted items: %d":"Những mục đã được giải mã: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"Bỏ qua các mục: %d (sử dụng —retry-failed-items để thử giải mã lại)","Completed decryption.":"Giải mã hoàn tất.","Confirm password:":"Xác nhận mật khẩu:","Passwords do not match!":"Mật khẩu không trùng!","Enabled":"Đã bật","Disabled":"Đã tắt","Encryption is: %s":"Mã hóa là: %s","Edit note.":"Sửa ghi chú.","No text editor is defined. Please set it using `config editor <editor-path>`":"Chưa có trình biên tập văn bản nào được lựa chon. Vui lòng lựa chọn trình biên tập văn bản sử dụng `config editor <editor-path>`","No active notebook.":"Không có ghi chú nào đang được sử dụng.","Note does not exist: \"%s\". Create it?":"Không có note: \"%s\". Tạo lập nó?","Starting to edit note. Close the editor to get back to the prompt.":"Bắt đầu chỉnh sửa ghi chú. Tắt trình soạn thảo để quay lại lời nhắc.","Error opening note in editor: %s":"Lỗi khi mở note trong trình chỉnh sửa: %s","Note has been saved.":"Ghi chú chưa được lưu.","Exits the application.":"Thoát ứng dụng.","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"Xuất dữ liệu từ Joplin tới đường dLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"To delete a tag, untag the associated notes.":"移除相关笔记的标签后才可删除此标签。","Please select the note or notebook to be deleted first.":"请先选择需要删除的笔记或笔记本。","Press Ctrl+D or type \"exit\" to exit the application":"按 Ctrl+D 或输入 \"exit\" 退出程序","More than one item match \"%s\". Please narrow down your query.":"有多条项目符合“%s”。请缩小您的检索范围。","No notebook selected.":"未选择笔记本。","No notebook has been specified.":"未指定笔记本。","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"正在取消后台同步... 请稍候。","No such command: %s":"不存在该命令:%s","The command \"%s\" is only available in GUI mode":"命令“%s”仅在 GUI 模式下可用","Cannot change encrypted item":"无法更改已加密条目","Missing required argument: %s":"缺失必选参数:%s","%s: %s":"%s:%s","Your choice: ":"您的选择: ","Invalid answer: %s":"答案无效:%s","Attaches the given file to the note.":"将选定文件添加到笔记中。","Cannot find \"%s\".":"无法找到“%s”。","Runs the commands contained in the text file. There should be one command per line.":"执行文本文件中包含的命令。每个命令占一行。","Displays the given note.":"显示选定笔记。","Displays the complete information about note.":"显示有关笔记的完整信息。","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"读取或设置配置数值。如果 [value] 值没有提供,它将显示 [name] 值。如果没有提供 [name] 或 [value] 值,它将列出当前配置。","Also displays unset and hidden config variables.":"同时显示未设置的与隐藏的配置变量。","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"复制符合 <note> 的笔记至 [notebook]。若无指定的笔记本,该笔记将被复制至当前笔记本。","Marks a to-do as done.":"标记待办事项为完成。","Note is not a to-do: \"%s\"":"笔记并非待办事项:“%s”","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"管理 E2EE 配置。命令为: `enable`、`disable`、`decrypt`、`status`、`decrypt-file` 和 `target-status`。","Enter master password:":"输入主密码:","Operation cancelled":"操作已取消","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"开始解密,请稍候... 取决于需解密的文件数量,解密环节可能需要等待几分钟。","Decrypted items: %d":"解密条目: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"跳过条目: %d (使用 —retry-failed-items 来尝试重新解密)","Completed decryption.":"已完成解密。","Confirm password:":"确认密码:","Passwords do not match!":"密码不匹配!","Enabled":"已启用","Disabled":"已禁用","Encryption is: %s":"加密状态: %s","Edit note.":"编辑笔记。","No text editor is defined. Please set it using `config editor <editor-path>`":"未设置指定的文本编辑器。请通过 `config editor <editor-path>` 设置","No active notebook.":"无活动笔记本。","Note does not exist: \"%s\". Create it?":"笔记不存在: \"%s\" 。是否创建?","Starting to edit note. Close the editor to get back to the prompt.":"开始编辑笔记。关闭编辑器将回到提示符。","Error opening note in editor: %s":"在编辑器中打开笔记出错:%s","Note has been saved.":"笔记已被保存。","Exits the application.":"退出应用。","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"导出 Joplin 数据到选定路径。默认将导出包含笔记本、笔记、标签与资源等完整的数据库。","Destination format: %s":"目标格式:%s","Exports only the given note.":"仅导出选定笔记。","Exports only the given notebook.":"仅导出选定笔记本。","Displays a geolocation URL for the note.":"显示该笔记的地理位置 URL。","Displays usage information.":"显示用法提示。","For information on how to customise the shortcuts please visit %s":"有关如何自定义快捷键,请访问 %s","Shortcuts are not available in CLI mode.":"快捷键在 CLI 模式下不可用。","Type `help [command]` for more information about a command; or type `help all` for the complete usage information.":"输入 `help [command]` 来获取有关该命令的更多信息;或输入 `help all` 获取完整的用法提示。","The possible commands are:":"可用的命令有:","In any command, a note or notebook can be referred to bLine truncated
|
||||
{"To delete a tag, untag the associated notes.":"移除相关笔记的标签后才可删除此标签。","Please select the note or notebook to be deleted first.":"请先选择需要删除的笔记或笔记本。","Press Ctrl+D or type \"exit\" to exit the application":"按 Ctrl+D 或输入 \"exit\" 退出程序","More than one item match \"%s\". Please narrow down your query.":"有多条项目符合“%s”。请缩小您的检索范围。","No notebook selected.":"未选择笔记本。","No notebook has been specified.":"未指定笔记本。","Y":"Y","n":"n","N":"N","y":"y","Cancelling background synchronisation... Please wait.":"正在取消后台同步... 请稍候。","No such command: %s":"不存在该命令:%s","The command \"%s\" is only available in GUI mode":"命令“%s”仅在 GUI 模式下可用","Cannot change encrypted item":"无法更改已加密条目","Missing required argument: %s":"缺失必选参数:%s","%s: %s":"%s:%s","Your choice: ":"您的选择: ","Invalid answer: %s":"答案无效:%s","Attaches the given file to the note.":"将选定文件添加到笔记中。","Cannot find \"%s\".":"无法找到“%s”。","Runs the commands contained in the text file. There should be one command per line.":"执行文本文件中包含的命令。每个命令占一行。","Displays the given note.":"显示选定笔记。","Displays the complete information about note.":"显示有关笔记的完整信息。","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"读取或设置配置数值。如果 [value] 值没有提供,它将显示 [name] 值。如果没有提供 [name] 或 [value] 值,它将列出当前配置。","Also displays unset and hidden config variables.":"同时显示未设置的与隐藏的配置变量。","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"复制符合 <note> 的笔记至 [notebook]。若无指定的笔记本,该笔记将被复制至当前笔记本。","Marks a to-do as done.":"标记待办事项为完成。","Note is not a to-do: \"%s\"":"笔记并非待办事项:“%s”","Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file` and `target-status`.":"管理 E2EE 配置。命令为: `enable`、`disable`、`decrypt`、`status`、`decrypt-file` 和 `target-status`。","Enter master password:":"输入主密码:","Operation cancelled":"操作已取消","Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.":"开始解密,请稍候... 取决于需解密的文件数量,解密环节可能需要等待几分钟。","Decrypted items: %d":"解密条目: %d","Skipped items: %d (use --retry-failed-items to retry decrypting them)":"跳过条目: %d (使用 —retry-failed-items 来尝试重新解密)","Completed decryption.":"已完成解密。","Confirm password:":"确认密码:","Passwords do not match!":"密码不匹配!","Enabled":"已启用","Disabled":"已禁用","Encryption is: %s":"加密状态: %s","Edit note.":"编辑笔记。","No text editor is defined. Please set it using `config editor <editor-path>`":"未设置指定的文本编辑器。请通过 `config editor <editor-path>` 设置","No active notebook.":"无活动笔记本。","Note does not exist: \"%s\". Create it?":"笔记不存在: \"%s\" 。是否创建?","Starting to edit note. Close the editor to get back to the prompt.":"开始编辑笔记。关闭编辑器将回到提示符。","Error opening note in editor: %s":"在编辑器中打开笔记出错:%s","Note has been saved.":"笔记已被保存。","Exits the application.":"退出应用。","Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.":"导出 Joplin 数据到选定路径。默认将导出包含笔记本、笔记、标签与资源等完整的数据库。","Destination format: %s":"目标格式:%s","Exports only the given note.":"仅导出选定笔记。","Exports only the given notebook.":"仅导出选定笔记本。","Displays a geolocation URL for the note.":"显示该笔记的地理位置 URL。","Displays usage information.":"显示用法提示。","For information on how to customise the shortcuts please visit %s":"有关如何自定义快捷键,请访问 %s","Shortcuts are not available in CLI mode.":"快捷键在 CLI 模式下不可用。","Type `help [command]` for more information about a command; or type `help all` for the complete usage information.":"输入 `help [command]` 来获取有关该命令的更多信息;或输入 `help all` 获取完整的用法提示。","The possible commands are:":"可用的命令有:","In any command, a note or notebook can be referred to bLine truncated
|
||||
@@ -1,13 +1,13 @@
|
||||
const { revisionService, setupDatabaseAndSynchronizer, db, switchClient } = require('../testing/test-utils.js');
|
||||
const SearchEngine = require('../services/searchengine/SearchEngine').default;
|
||||
const ResourceService = require('../services/ResourceService').default;
|
||||
const ItemChangeUtils = require('../services/ItemChangeUtils').default;
|
||||
const Note = require('../models/Note').default;
|
||||
const ItemChange = require('../models/ItemChange').default;
|
||||
import { revisionService, setupDatabaseAndSynchronizer, db, switchClient, msleep } from '../testing/test-utils';
|
||||
import SearchEngine from '../services/searchengine/SearchEngine';
|
||||
import ResourceService from '../services/ResourceService';
|
||||
import ItemChangeUtils from '../services/ItemChangeUtils';
|
||||
import Note from '../models/Note';
|
||||
import ItemChange from '../models/ItemChange';
|
||||
|
||||
let searchEngine = null;
|
||||
let searchEngine: SearchEngine = null;
|
||||
|
||||
describe('models_ItemChange', function() {
|
||||
describe('models/ItemChange', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
@@ -27,17 +27,28 @@ describe('models_ItemChange', function() {
|
||||
const resourceService = new ResourceService();
|
||||
|
||||
await searchEngine.syncTables();
|
||||
|
||||
// If we run this now, it should not delete any change because
|
||||
// the resource service has not yet processed the change
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
await ItemChangeUtils.deleteProcessedChanges(0);
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
await resourceService.indexNoteResources();
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
await ItemChangeUtils.deleteProcessedChanges(0);
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
await revisionService().collectRevisions();
|
||||
|
||||
// If we don't set a TTL it will default to 90 days so it won't delete
|
||||
// either.
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
// All changes should be at least 4 ms old now
|
||||
await msleep(4);
|
||||
|
||||
// Now it should delete all changes older than 3 ms
|
||||
await ItemChangeUtils.deleteProcessedChanges(3);
|
||||
expect(await ItemChange.lastChangeId()).toBe(0);
|
||||
}));
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import BaseModel, { ModelType } from '../BaseModel';
|
||||
import shim from '../shim';
|
||||
import eventManager from '../eventManager';
|
||||
import { ItemChangeEntity } from '../services/database/types';
|
||||
const Mutex = require('async-mutex').Mutex;
|
||||
|
||||
export interface ChangeSinceIdOptions {
|
||||
limit?: number;
|
||||
fields?: string[];
|
||||
}
|
||||
|
||||
export default class ItemChange extends BaseModel {
|
||||
|
||||
private static addChangeMutex_: any = new Mutex();
|
||||
@@ -24,7 +30,7 @@ export default class ItemChange extends BaseModel {
|
||||
return BaseModel.TYPE_ITEM_CHANGE;
|
||||
}
|
||||
|
||||
static async add(itemType: ModelType, itemId: string, type: number, changeSource: any = null, beforeChangeItemJson: string = null) {
|
||||
public static async add(itemType: ModelType, itemId: string, type: number, changeSource: any = null, beforeChangeItemJson: string = null) {
|
||||
if (changeSource === null) changeSource = ItemChange.SOURCE_UNSPECIFIED;
|
||||
if (!beforeChangeItemJson) beforeChangeItemJson = '';
|
||||
|
||||
@@ -57,14 +63,14 @@ export default class ItemChange extends BaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
static async lastChangeId() {
|
||||
public static async lastChangeId() {
|
||||
const row = await this.db().selectOne('SELECT max(id) as max_id FROM item_changes');
|
||||
return row && row.max_id ? row.max_id : 0;
|
||||
}
|
||||
|
||||
// Because item changes are recorded in the background, this function
|
||||
// can be used for synchronous code, in particular when unit testing.
|
||||
static async waitForAllSaved() {
|
||||
public static async waitForAllSaved() {
|
||||
return new Promise((resolve) => {
|
||||
const iid = shim.setInterval(() => {
|
||||
if (!ItemChange.saveCalls_.length) {
|
||||
@@ -75,8 +81,32 @@ export default class ItemChange extends BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
static async deleteOldChanges(lowestChangeId: number) {
|
||||
public static async deleteOldChanges(lowestChangeId: number, itemMinTtl: number) {
|
||||
if (!lowestChangeId) return;
|
||||
return this.db().exec('DELETE FROM item_changes WHERE id <= ?', [lowestChangeId]);
|
||||
|
||||
const cutOffDate = Date.now() - itemMinTtl;
|
||||
|
||||
return this.db().exec(`
|
||||
DELETE FROM item_changes
|
||||
WHERE id <= ?
|
||||
AND created_time <= ?
|
||||
`, [lowestChangeId, cutOffDate]);
|
||||
}
|
||||
|
||||
public static async changesSinceId(changeId: number, options: ChangeSinceIdOptions = null): Promise<ItemChangeEntity[]> {
|
||||
options = {
|
||||
limit: 100,
|
||||
fields: ['id', 'item_type', 'item_id', 'type', 'created_time'],
|
||||
...options,
|
||||
};
|
||||
|
||||
return this.db().selectAll(`
|
||||
SELECT ${this.db().escapeFieldsToString(options.fields)}
|
||||
FROM item_changes
|
||||
WHERE id > ?
|
||||
ORDER BY id
|
||||
LIMIT ?
|
||||
`, [changeId, options.limit]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ export default class MasterKey extends BaseItem {
|
||||
}
|
||||
}
|
||||
return output;
|
||||
// return this.modelSelectOne('SELECT * FROM master_keys WHERE created_time >= (SELECT max(created_time) FROM master_keys)');
|
||||
}
|
||||
|
||||
static allWithoutEncryptionMethod(masterKeys: MasterKeyEntity[], method: number) {
|
||||
|
||||
@@ -919,6 +919,7 @@ class Setting extends BaseModel {
|
||||
'encryption.enabled': { value: false, type: SettingItemType.Bool, public: false },
|
||||
'encryption.activeMasterKeyId': { value: '', type: SettingItemType.String, public: false },
|
||||
'encryption.passwordCache': { value: {}, type: SettingItemType.Object, public: false, secure: true },
|
||||
'encryption.masterPassword': { value: '', type: SettingItemType.String, public: false, secure: true },
|
||||
'encryption.shouldReencrypt': {
|
||||
value: -1, // will be set on app startup
|
||||
type: SettingItemType.Int,
|
||||
|
||||
Generated
+15
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@joplin/lib",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@joplin/lib",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"async-mutex": "^0.1.3",
|
||||
@@ -64,6 +64,7 @@
|
||||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/css": "^0.0.33",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^14.14.6",
|
||||
@@ -1003,6 +1004,12 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/css": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/css/-/css-0.0.33.tgz",
|
||||
"integrity": "sha512-qjeDgh86R0LIeEM588q65yatc8Yyo/VvSIYFqq8JOIHDolhGNX0rz7k/OuxqDpnpqlefoHj8X4Ai/6hT9IWtKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "9.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz",
|
||||
@@ -9688,6 +9695,12 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/css": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/css/-/css-0.0.33.tgz",
|
||||
"integrity": "sha512-qjeDgh86R0LIeEM588q65yatc8Yyo/VvSIYFqq8JOIHDolhGNX0rz7k/OuxqDpnpqlefoHj8X4Ai/6hT9IWtKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/fs-extra": {
|
||||
"version": "9.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/lib",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"description": "Joplin Core library",
|
||||
"author": "Laurent Cozic",
|
||||
"homepage": "",
|
||||
@@ -16,6 +16,7 @@
|
||||
"test-ci": "npm run test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/css": "^0.0.33",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^14.14.6",
|
||||
@@ -25,11 +26,11 @@
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/fork-htmlparser2": "^4.1.33",
|
||||
"@joplin/fork-sax": "^1.2.37",
|
||||
"@joplin/renderer": "~2.4",
|
||||
"@joplin/turndown": "^4.0.55",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.37",
|
||||
"@joplin/fork-htmlparser2": "^4.1.34",
|
||||
"@joplin/fork-sax": "^1.2.38",
|
||||
"@joplin/renderer": "^2.4.1",
|
||||
"@joplin/turndown": "^4.0.56",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.38",
|
||||
"async-mutex": "^0.1.3",
|
||||
"aws-sdk": "^2.588.0",
|
||||
"base-64": "^0.1.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ import ResourceService from './ResourceService';
|
||||
import Logger from '../Logger';
|
||||
import shim from '../shim';
|
||||
import KvStore from './KvStore';
|
||||
import EncryptionService from './e2ee/EncryptionService';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
|
||||
@@ -28,7 +29,7 @@ export default class DecryptionWorker {
|
||||
private kvStore_: KvStore = null;
|
||||
private maxDecryptionAttempts_ = 2;
|
||||
private startCalls_: boolean[] = [];
|
||||
private encryptionService_: any = null;
|
||||
private encryptionService_: EncryptionService = null;
|
||||
|
||||
constructor() {
|
||||
this.state_ = 'idle';
|
||||
@@ -134,6 +135,11 @@ export default class DecryptionWorker {
|
||||
this.logger().info(msg);
|
||||
const ids = await MasterKey.allIds();
|
||||
|
||||
// Note that the current implementation means that a warning will be
|
||||
// displayed even if the user has no encrypted note. Just having
|
||||
// encrypted master key is sufficient. Not great but good enough for
|
||||
// now.
|
||||
|
||||
if (ids.length) {
|
||||
if (options.masterKeyNotLoadedHandler === 'throw') {
|
||||
// By trying to load the master key here, we throw the "masterKeyNotLoaded" error
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import Setting from '../models/Setting';
|
||||
import ItemChange from '../models/ItemChange';
|
||||
|
||||
const dayMs = 86400000;
|
||||
|
||||
export default class ItemChangeUtils {
|
||||
static async deleteProcessedChanges() {
|
||||
static async deleteProcessedChanges(itemMinTtl: number = dayMs * 90) {
|
||||
const lastProcessedChangeIds = [
|
||||
Setting.value('resourceService.lastProcessedChangeId'),
|
||||
Setting.value('searchEngine.lastProcessedChangeId'),
|
||||
@@ -10,6 +12,6 @@ export default class ItemChangeUtils {
|
||||
];
|
||||
|
||||
const lowestChangeId = Math.min(...lastProcessedChangeIds);
|
||||
await ItemChange.deleteOldChanges(lowestChangeId);
|
||||
await ItemChange.deleteOldChanges(lowestChangeId, itemMinTtl);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import JoplinError from '../../JoplinError';
|
||||
import { getActiveMasterKeyId, setActiveMasterKeyId } from '../synchronizer/syncInfoUtils';
|
||||
const { padLeft } = require('../../string-utils.js');
|
||||
|
||||
const logger = Logger.create('EncryptionService');
|
||||
|
||||
function hexPad(s: string, length: number) {
|
||||
return padLeft(s, length, '0');
|
||||
}
|
||||
@@ -52,7 +54,6 @@ export default class EncryptionService {
|
||||
private decryptedMasterKeys_: Record<string, DecryptedMasterKey> = {};
|
||||
public defaultEncryptionMethod_ = EncryptionService.METHOD_SJCL_1A; // public because used in tests
|
||||
private defaultMasterKeyEncryptionMethod_ = EncryptionService.METHOD_SJCL_4;
|
||||
private logger_ = new Logger();
|
||||
|
||||
private headerTemplates_ = {
|
||||
// Template version 1
|
||||
@@ -80,7 +81,6 @@ export default class EncryptionService {
|
||||
this.decryptedMasterKeys_ = {};
|
||||
this.defaultEncryptionMethod_ = EncryptionService.METHOD_SJCL_1A;
|
||||
this.defaultMasterKeyEncryptionMethod_ = EncryptionService.METHOD_SJCL_4;
|
||||
this.logger_ = new Logger();
|
||||
|
||||
this.headerTemplates_ = {
|
||||
// Template version 1
|
||||
@@ -97,14 +97,6 @@ export default class EncryptionService {
|
||||
return this.instance_;
|
||||
}
|
||||
|
||||
setLogger(l: Logger) {
|
||||
this.logger_ = l;
|
||||
}
|
||||
|
||||
logger() {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
loadedMasterKeysCount() {
|
||||
return Object.keys(this.decryptedMasterKeys_).length;
|
||||
}
|
||||
@@ -139,10 +131,14 @@ export default class EncryptionService {
|
||||
|
||||
public async loadMasterKey(model: MasterKeyEntity, password: string, makeActive = false) {
|
||||
if (!model.id) throw new Error('Master key does not have an ID - save it first');
|
||||
|
||||
logger.info(`Loading master key: ${model.id}. Make active:`, makeActive);
|
||||
|
||||
this.decryptedMasterKeys_[model.id] = {
|
||||
plainText: await this.decryptMasterKey_(model, password),
|
||||
updatedTime: model.updated_time,
|
||||
};
|
||||
|
||||
if (makeActive) this.setActiveMasterKeyId(model.id);
|
||||
}
|
||||
|
||||
@@ -245,7 +241,7 @@ export default class EncryptionService {
|
||||
return plainText;
|
||||
}
|
||||
|
||||
async checkMasterKeyPassword(model: MasterKeyEntity, password: string) {
|
||||
public async checkMasterKeyPassword(model: MasterKeyEntity, password: string) {
|
||||
try {
|
||||
await this.decryptMasterKey_(model, password);
|
||||
} catch (error) {
|
||||
@@ -255,7 +251,7 @@ export default class EncryptionService {
|
||||
return true;
|
||||
}
|
||||
|
||||
wrapSjclError(sjclError: any) {
|
||||
private wrapSjclError(sjclError: any) {
|
||||
const error = new Error(sjclError.message);
|
||||
error.stack = sjclError.stack;
|
||||
return error;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { afterAllCleanUp, setupDatabaseAndSynchronizer, switchClient, encryptionService } from '../../testing/test-utils';
|
||||
import { afterAllCleanUp, setupDatabaseAndSynchronizer, switchClient, encryptionService, expectNotThrow } from '../../testing/test-utils';
|
||||
import MasterKey from '../../models/MasterKey';
|
||||
import { showMissingMasterKeyMessage } from './utils';
|
||||
import { localSyncInfo, setMasterKeyEnabled } from '../synchronizer/syncInfoUtils';
|
||||
import { migrateMasterPassword, showMissingMasterKeyMessage } from './utils';
|
||||
import { localSyncInfo, setActiveMasterKeyId, setMasterKeyEnabled } from '../synchronizer/syncInfoUtils';
|
||||
import Setting from '../../models/Setting';
|
||||
|
||||
describe('e2ee/utils', function() {
|
||||
|
||||
@@ -34,9 +35,40 @@ describe('e2ee/utils', function() {
|
||||
setMasterKeyEnabled(mk2.id, true);
|
||||
expect(showMissingMasterKeyMessage(localSyncInfo(), [mk1.id, mk2.id])).toBe(true);
|
||||
|
||||
await expectNotThrow(async () => showMissingMasterKeyMessage(localSyncInfo(), ['not_downloaded_yet']));
|
||||
|
||||
const syncInfo = localSyncInfo();
|
||||
syncInfo.masterKeys = [];
|
||||
expect(showMissingMasterKeyMessage(syncInfo, [mk1.id, mk2.id])).toBe(false);
|
||||
});
|
||||
|
||||
it('should do the master password migration', async () => {
|
||||
const mk1 = await MasterKey.save(await encryptionService().generateMasterKey('111111'));
|
||||
const mk2 = await MasterKey.save(await encryptionService().generateMasterKey('222222'));
|
||||
|
||||
Setting.setValue('encryption.passwordCache', {
|
||||
[mk1.id]: '111111',
|
||||
[mk2.id]: '222222',
|
||||
});
|
||||
|
||||
await migrateMasterPassword();
|
||||
|
||||
{
|
||||
expect(Setting.value('encryption.masterPassword')).toBe('');
|
||||
const newCache = Setting.value('encryption.passwordCache');
|
||||
expect(newCache[mk1.id]).toBe('111111');
|
||||
expect(newCache[mk2.id]).toBe('222222');
|
||||
}
|
||||
|
||||
setActiveMasterKeyId(mk1.id);
|
||||
await migrateMasterPassword();
|
||||
|
||||
{
|
||||
expect(Setting.value('encryption.masterPassword')).toBe('111111');
|
||||
const newCache = Setting.value('encryption.passwordCache');
|
||||
expect(newCache[mk1.id]).toBe(undefined);
|
||||
expect(newCache[mk2.id]).toBe('222222');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -4,11 +4,11 @@ import MasterKey from '../../models/MasterKey';
|
||||
import Setting from '../../models/Setting';
|
||||
import { MasterKeyEntity } from './types';
|
||||
import EncryptionService from './EncryptionService';
|
||||
import { getActiveMasterKeyId, masterKeyEnabled, setEncryptionEnabled, SyncInfo } from '../synchronizer/syncInfoUtils';
|
||||
import { getActiveMasterKey, getActiveMasterKeyId, masterKeyEnabled, setEncryptionEnabled, SyncInfo } from '../synchronizer/syncInfoUtils';
|
||||
|
||||
const logger = Logger.create('e2ee/utils');
|
||||
|
||||
export async function setupAndEnableEncryption(service: EncryptionService, masterKey: MasterKeyEntity = null, password: string = null) {
|
||||
export async function setupAndEnableEncryption(service: EncryptionService, masterKey: MasterKeyEntity = null, masterPassword: string = null) {
|
||||
if (!masterKey) {
|
||||
// May happen for example if there are master keys in info.json but none
|
||||
// of them is set as active. But in fact, unless there is a bug in the
|
||||
@@ -18,10 +18,8 @@ export async function setupAndEnableEncryption(service: EncryptionService, maste
|
||||
|
||||
setEncryptionEnabled(true, masterKey ? masterKey.id : null);
|
||||
|
||||
if (masterKey && password) {
|
||||
const passwordCache = Setting.value('encryption.passwordCache');
|
||||
passwordCache[masterKey.id] = password;
|
||||
Setting.setValue('encryption.passwordCache', passwordCache);
|
||||
if (masterPassword) {
|
||||
Setting.setValue('encryption.masterPassword', masterPassword);
|
||||
}
|
||||
|
||||
// Mark only the non-encrypted ones for sync since, if there are encrypted ones,
|
||||
@@ -47,6 +45,8 @@ export async function setupAndDisableEncryption(service: EncryptionService) {
|
||||
}
|
||||
|
||||
export async function toggleAndSetupEncryption(service: EncryptionService, enabled: boolean, masterKey: MasterKeyEntity, password: string) {
|
||||
logger.info('toggleAndSetupEncryption: enabled:', enabled, ' Master key', masterKey);
|
||||
|
||||
if (!enabled) {
|
||||
await setupAndDisableEncryption(service);
|
||||
} else {
|
||||
@@ -68,17 +68,65 @@ export async function generateMasterKeyAndEnableEncryption(service: EncryptionSe
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
// Migration function to initialise the master password. Normally it is set when
|
||||
// enabling E2EE, but previously it wasn't. So here we check if the password is
|
||||
// set. If it is not, we set it from the active master key. It needs to be
|
||||
// called after the settings have been initialized.
|
||||
export async function migrateMasterPassword() {
|
||||
if (Setting.value('encryption.masterPassword')) return; // Already migrated
|
||||
|
||||
logger.info('Master password is not set - trying to get it from the active master key...');
|
||||
|
||||
const mk = getActiveMasterKey();
|
||||
if (!mk) return;
|
||||
|
||||
const masterPassword = Setting.value('encryption.passwordCache')[mk.id];
|
||||
if (masterPassword) {
|
||||
Setting.setValue('encryption.masterPassword', masterPassword);
|
||||
logger.info('Master password is now set.');
|
||||
|
||||
// Also clear the key passwords that match the master password to avoid
|
||||
// any confusion.
|
||||
const cache = Setting.value('encryption.passwordCache');
|
||||
const newCache = { ...cache };
|
||||
for (const [mkId, password] of Object.entries(cache)) {
|
||||
if (password === masterPassword) {
|
||||
delete newCache[mkId];
|
||||
}
|
||||
}
|
||||
Setting.setValue('encryption.passwordCache', newCache);
|
||||
await Setting.saveAll();
|
||||
}
|
||||
}
|
||||
|
||||
// All master keys normally should be decryped with the master password, however
|
||||
// previously any master key could be encrypted with any password, so to support
|
||||
// this legacy case, we first check if the MK decrypts with the master password.
|
||||
// If not, try with the master key specific password, if any is defined.
|
||||
export async function findMasterKeyPassword(service: EncryptionService, masterKey: MasterKeyEntity): Promise<string> {
|
||||
const masterPassword = Setting.value('encryption.masterPassword');
|
||||
if (masterPassword && await service.checkMasterKeyPassword(masterKey, masterPassword)) {
|
||||
logger.info('findMasterKeyPassword: Using master password');
|
||||
return masterPassword;
|
||||
}
|
||||
|
||||
logger.info('findMasterKeyPassword: No master password is defined - trying to get master key specific password');
|
||||
|
||||
const passwords = Setting.value('encryption.passwordCache');
|
||||
return passwords[masterKey.id];
|
||||
}
|
||||
|
||||
export async function loadMasterKeysFromSettings(service: EncryptionService) {
|
||||
const masterKeys = await MasterKey.all();
|
||||
const passwords = Setting.value('encryption.passwordCache');
|
||||
const activeMasterKeyId = getActiveMasterKeyId();
|
||||
|
||||
logger.info(`Trying to load ${masterKeys.length} master keys...`);
|
||||
|
||||
for (let i = 0; i < masterKeys.length; i++) {
|
||||
const mk = masterKeys[i];
|
||||
const password = passwords[mk.id];
|
||||
if (service.isMasterKeyLoaded(mk)) continue;
|
||||
|
||||
const password = await findMasterKeyPassword(service, mk);
|
||||
if (!password) continue;
|
||||
|
||||
try {
|
||||
@@ -98,8 +146,22 @@ export function showMissingMasterKeyMessage(syncInfo: SyncInfo, notLoadedMasterK
|
||||
|
||||
for (let i = notLoadedMasterKeys.length - 1; i >= 0; i--) {
|
||||
const mk = syncInfo.masterKeys.find(mk => mk.id === notLoadedMasterKeys[i]);
|
||||
|
||||
// A "notLoadedMasterKey" is a key that either doesn't exist or for
|
||||
// which a password hasn't been set yet. For the purpose of this
|
||||
// function, we only want to notify the user about unset passwords.
|
||||
// Master keys that haven't been downloaded yet should normally be
|
||||
// downloaded at some point.
|
||||
// https://github.com/laurent22/joplin/issues/5391
|
||||
if (!mk) continue;
|
||||
if (!masterKeyEnabled(mk)) notLoadedMasterKeys.pop();
|
||||
}
|
||||
|
||||
return !!notLoadedMasterKeys.length;
|
||||
}
|
||||
|
||||
export function getDefaultMasterKey(): MasterKeyEntity {
|
||||
const mk = getActiveMasterKey();
|
||||
if (mk) return mk;
|
||||
return MasterKey.latest();
|
||||
}
|
||||
@@ -5,27 +5,28 @@ import { ImportExportResult } from './types';
|
||||
import Setting from '../../models/Setting';
|
||||
|
||||
export default class InteropService_Importer_Base {
|
||||
|
||||
private metadata_: any = null;
|
||||
protected sourcePath_: string = '';
|
||||
protected options_: any = {};
|
||||
|
||||
setMetadata(md: any) {
|
||||
public setMetadata(md: any) {
|
||||
this.metadata_ = md;
|
||||
}
|
||||
|
||||
metadata() {
|
||||
public metadata() {
|
||||
return this.metadata_;
|
||||
}
|
||||
|
||||
async init(sourcePath: string, options: any) {
|
||||
public async init(sourcePath: string, options: any) {
|
||||
this.sourcePath_ = sourcePath;
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
async exec(result: ImportExportResult): Promise<ImportExportResult> {}
|
||||
public async exec(result: ImportExportResult): Promise<ImportExportResult> {}
|
||||
|
||||
async temporaryDirectory_(createIt: boolean) {
|
||||
protected async temporaryDirectory_(createIt: boolean) {
|
||||
const md5 = require('md5');
|
||||
const tempDir = `${Setting.value('tempDir')}/${md5(Math.random() + Date.now())}`;
|
||||
if (createIt) await require('fs-extra').mkdirp(tempDir);
|
||||
|
||||
@@ -5,15 +5,27 @@ export default class InteropService_Importer_Custom extends InteropService_Impor
|
||||
|
||||
private module_: Module = null;
|
||||
|
||||
constructor(handler: Module) {
|
||||
public constructor(handler: Module) {
|
||||
super();
|
||||
this.module_ = handler;
|
||||
}
|
||||
|
||||
async exec(result: ImportExportResult): Promise<ImportExportResult> {
|
||||
public async exec(result: ImportExportResult): Promise<ImportExportResult> {
|
||||
// When passing the options to the plugin, we strip off any function
|
||||
// because they won't serialized over ipc.
|
||||
|
||||
const processedOptions: any = {};
|
||||
|
||||
if (this.options_) {
|
||||
for (const [k, v] of Object.entries(this.options_)) {
|
||||
if (typeof v === 'function') continue;
|
||||
processedOptions[k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
return this.module_.onExec({
|
||||
sourcePath: this.sourcePath_,
|
||||
options: this.options_,
|
||||
options: processedOptions,
|
||||
warnings: result.warnings,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@ export default function manifestFromObject(o: any): PluginManifest {
|
||||
return o[name];
|
||||
};
|
||||
|
||||
const getBoolean = (name: string, required: boolean = true, defaultValue: boolean = false): boolean => {
|
||||
if (required && !o[name]) throw new Error(`Missing required field: ${name}`);
|
||||
if (!o[name]) return defaultValue;
|
||||
if (typeof o[name] !== 'boolean') throw new Error(`Field must be a boolean: ${name}`);
|
||||
return o[name];
|
||||
};
|
||||
|
||||
const permissions: PluginPermission[] = [];
|
||||
|
||||
const manifest: PluginManifest = {
|
||||
@@ -39,6 +46,8 @@ export default function manifestFromObject(o: any): PluginManifest {
|
||||
repository_url: getString('repository_url', false),
|
||||
keywords: getStrings('keywords', false),
|
||||
permissions: permissions,
|
||||
|
||||
_recommended: getBoolean('_recommended', false, false),
|
||||
};
|
||||
|
||||
validatePluginId(manifest.id);
|
||||
|
||||
Loaded 100 of 194 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user