1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-04-08 11:04:42 +02:00

Compare commits

..

400 Commits

Author SHA1 Message Date
Laurent Cozic
737a494db8 update 2026-04-08 09:44:23 +01:00
Laurent Cozic
b8bfe85f21 update 2026-04-05 19:05:44 +01:00
Laurent Cozic
379a53eca5 Revert "Desktop: Fixes #14613: Fix JPEG image paste from clipboard on Linux (#14750)"
This reverts commit 05fc3e9104.

Ref: https://github.com/laurent22/joplin/issues/15022#issuecomment-4189250496
2026-04-05 18:48:56 +01:00
renovate[bot]
548d1a49ba Update dependency @types/uuid to v11 (#15018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-05 18:46:19 +01:00
Laurent Cozic
7e08d0c77d iOS 13.6.4 2026-04-05 18:44:40 +01:00
Laurent Cozic
cb3878afa6 Android 3.6.15 2026-04-05 16:20:59 +01:00
Laurent Cozic
af0cab64cf Desktop release v3.6.7 2026-04-05 13:49:51 +01:00
Aissa Benfodda
671a7c9acf Server: Fixes #583: Redirect to correct share when following links between independently published notes (#14963) 2026-04-05 13:44:50 +01:00
Sriram Varun Kumar
a8a6fe2520 Mobile: Fixes #14984: Fix encrypted notes not decrypting after updating master password (#14996) 2026-04-05 13:44:18 +01:00
Zain Ul Abedin
c5bcb170e9 Mobile: Fixes #14771: Prevent Note Tags dialog from closing before discard confirmation on web (#14998) 2026-04-05 13:43:49 +01:00
Sriram Varun Kumar
b6ce57aad5 Chore: Mobile: Fixes #14974: Settings > Editor > Editor font has no effect on the Rich Text Editor (#15014) 2026-04-05 13:37:14 +01:00
renovate[bot]
d26c2cc96f Update dependency esbuild to v0.27.2 (#15011)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-05 13:34:47 +01:00
Harsh Gupta
c9cebd6016 Desktop: Fixes #12910: Fixed Custom Dictionary.txt being saved to wrong directory (#14749) 2026-04-05 13:16:30 +01:00
renovate[bot]
b90458f387 Update dependency esbuild to v0.27.1 (#15009)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-04 18:15:55 +01:00
renovate[bot]
1a2d045ed2 Update dependency @crowdin/cli to v4.12.0 (#14985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-04 16:44:25 +01:00
renovate[bot]
719d5ce4bb Update dependency nan to v2.24.0 (#14986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-04 16:44:20 +01:00
Henry Heino
76f0f1494e Chore: Development: Fix VSCode 1.114.0 shows a large number of tsc errors (#14989) 2026-04-04 16:44:12 +01:00
Harsh Gupta
e4f916bea5 Desktop: Fixes #14990: Fix inline formatting with trailing/leading whitespace (#14991) 2026-04-04 16:43:57 +01:00
Sriram Varun Kumar
cf9098e6a3 Mobile: Fixes #14974: Fix editor font setting being ignored in the Rich Text Editor (#14995) 2026-04-04 16:38:21 +01:00
Vishal Patel
18ffdb2f50 Mobile: Add toolbar button reordering with up/down arrows (#14485)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-04-04 16:23:30 +01:00
Himanshu Mishra
acd2ef4edf Desktop: Replace smalltalk with React Dialog to add password visibility in encryption setup (#14739) 2026-04-02 16:43:52 +01:00
Aissa Benfodda
9d91d4f85c Desktop: Fixes #12994: Share owner sees "Leave notebook" instead of "Share notebook" when server is offline (#14923) 2026-04-02 16:34:48 +01:00
Devrajsinh Gohil
635af9748a macOS: Resolves #9637: Added fullscreen shortcut (Ctrl + Cmd + F) (#14926) 2026-04-02 16:34:20 +01:00
Harsh Gupta
612e5a08f3 Desktop: Fixes #14950: Inline computed styles when copying from the Markdown preview pane (#14973) 2026-04-02 16:29:13 +01:00
Henry Heino
d3477f8626 Desktop: Importing from OneNote: Fix import of ink with negative bounding box coordinates (#14981) 2026-04-02 16:22:49 +01:00
Zain Ul Abedin
9e836a8984 Mobile: Fixes #14771: Show confirmation dialog before closing tags dialog with unsaved changes (#14777) 2026-04-02 16:08:26 +01:00
Laurent Cozic
3f14ffdf73 lock file 2026-04-02 14:42:35 +01:00
Joplin Bot
fd9f6c11ab Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-04-01 02:47:55 +00:00
FischLu
0cc79724c3 Desktop: Enable Copy and Select All in viewer and read-only modes (#14956) 2026-03-31 19:30:44 +01:00
mrjo118
e6fddd054a Desktop: Fixes #14628: Fix incorrectly re-instated code (#14962) 2026-03-31 15:58:12 +01:00
Henry Heino
860b22b0e7 Desktop,Cli: Fixes #14954: Fix changes made in an external editor are sometimes ignored (#14957) 2026-03-31 15:57:52 +01:00
Fardin96
281b0ed124 Mobile: Fixes #11122: Tag's note list fails to update after removing the tag from a note (#14944) 2026-03-31 15:47:27 +01:00
krevad
5dc5cb62db All: Translation: Update sv.po (#14943) 2026-03-31 15:45:46 +01:00
renovate[bot]
28bb43b3b5 Update dependency @playwright/test to v1.57.0 (#14902)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-31 15:33:32 +01:00
Dipanshu Rawat
c8bfcb16be Desktop: Fixes #14890: Disable "Expand all notebooks" button when no sub-notebooks exist (#14891) 2026-03-31 15:24:36 +01:00
Alex
634956bcc6 Desktop: Fixes #9436: Fix Markdown export losing folders that differ only by special characters (#14869) 2026-03-31 15:13:22 +01:00
Henry Heino
346ab98133 Desktop: Upgrade Electron to v40.8.3 (#14882) 2026-03-31 15:11:15 +01:00
Henry Heino
55008c9de9 Chore: Mobile: Add /pluginAssets to .gitignore (#14961) 2026-03-31 11:30:42 +01:00
mrjo118
f4ba70c49c Desktop: Fixes #14628: Fix renderer crashes still occuring due to incorrect merge (#14953) 2026-03-30 13:06:52 +01:00
renovate[bot]
e61379ed59 Update dependency git to v2.51.2 (#14951)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-29 20:28:09 +01:00
Sandesh Prakash Dawkhar
75cd9b4cb7 Desktop: Fixes #14919: Prevent Plugin API callback registry memory leak (#14920) 2026-03-29 20:21:30 +01:00
Kaushalendra Singh
43120d2b3e Desktop: Fixes #14628: prevent renderer crash when closing secondary window (#14849) 2026-03-29 11:40:30 +01:00
jellyfrostt
5656731dca Chore: Mobile: Fixes #14834: Fix JSDOM scrollIntoView error in tests (#14870) 2026-03-29 11:39:22 +01:00
Laurent Cozic
4cfe54161d Chore: Add appClose logger statements to desktop app (#14927) 2026-03-29 11:38:05 +01:00
renovate[bot]
7f2a95f66e Update dependency ldapts to v8.0.36 (#14938)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-29 05:53:44 +00:00
renovate[bot]
75819f3be3 Update dependency react-native-localize to v3.6.1 (#14932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 14:30:05 +00:00
Manvendra Kumar Singh
e709921310 Chore: Fixes #14878: Prevent focusing undefined titleInputRef in dialog (#14879) 2026-03-27 12:25:28 +00:00
renovate[bot]
b19d47ca4a Update dependency python to v3.14.0 (#14884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 12:22:53 +00:00
Henry Heino
516981b80c Desktop: Fixes #14628: Fix crash when closing secondary windows (#14892) 2026-03-27 12:21:13 +00:00
Laurent Cozic
a90d162989 Server: Move deletion of objects outside of transaction block (#14898) 2026-03-27 12:18:40 +00:00
Henry Heino
6cf9f1cc11 Windows: Fixes #14903: Fix most Windows-specific test failures (#14904) 2026-03-27 12:17:12 +00:00
Henry Heino
ee7362564c Chore: CI: Fix test warnings (#14907) 2026-03-27 12:13:25 +00:00
Muhammad Zohaib Irshad
cdf5367934 Clipper: Make the styling of dialogues consistent (#14908) 2026-03-27 12:13:18 +00:00
Henry Heino
7a76c31c26 Chore: Server: Fix incorrect error message (#14915) 2026-03-27 12:10:56 +00:00
Sandesh Prakash Dawkhar
004ab78a7a Desktop: Fixes #14914: RTE checklists should create unchecked items on Enter (#14918) 2026-03-27 12:10:27 +00:00
Ashutosh Singh
a7067c30c4 Desktop: Fixes #9673: Frontmatter export: Include notebook icon in frontmatter export (#14582) 2026-03-27 11:47:41 +00:00
renovate[bot]
be081316b3 Update dependency @types/serviceworker to v0.0.172 (#14901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-25 15:05:36 +00:00
renovate[bot]
c9fb33cb20 Update dependency ldapts to v8.0.35 (#14894)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-25 13:47:05 +00:00
renovate[bot]
dfdc0f3c35 Update dependency ldapts to v8.0.33 (#14887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-24 12:42:21 +00:00
Laurent Cozic
0fa3a509d6 Mobile, Desktop: Revert: Start sync when app opens or resumes (#14889) 2026-03-24 12:39:45 +00:00
renovate[bot]
18cf0a95ad Update dependency @types/serviceworker to v0.0.171 (#14885)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-24 09:05:36 +00:00
Laurent Cozic
7d454123f9 CI: Revert cancel-in-progress change as it does not do anything 2026-03-23 20:39:37 +00:00
renovate[bot]
e4fb72cd08 Update dependency ldapts to v8.0.32 (#14876)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 20:28:25 +00:00
Laurent Cozic
741e1b19e5 Revert "Desktop Fix: #14788 prevent sync panel from jumping during sync" (#14875) 2026-03-23 15:51:59 +00:00
dipok
6637c05cc8 CLI: Add clear command to clear console output (#14844) 2026-03-23 12:37:18 +00:00
Yousef Genedy
5877670e33 Mobile: Resolves #14789: Implement note attachments management screen (#14818) 2026-03-23 12:33:19 +00:00
Dipanshu Rawat
2320beec39 Desktop Fixes #14788: Prevent sync panel from jumping during sync (#14792) 2026-03-23 12:26:14 +00:00
Ehtesham Zahid
a0effc9ff8 Desktop: Resolves #14778: Improve checkbox completion icon in detailed note list (#14780) 2026-03-23 12:12:34 +00:00
Henry Heino
92cd5630f7 Chore: OneNote importer: Fix linter errors and standardize formatting (#14858) 2026-03-23 09:19:18 +00:00
Laurent Cozic
9fbca68062 Chore: Removed some "any" variables (#14825) 2026-03-22 23:14:16 +00:00
Jose Riha
953fb20006 All: Translation: Update sk_SK.po (#14867) 2026-03-22 14:25:27 -04:00
renovate[bot]
fb18be14a1 Update dependency ldapts to v8.0.31 (#14866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-22 14:02:33 +00:00
Eric Duarte
75c4dbc9df All: Translation: Update es_ES.po (#14862)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-21 18:15:22 -04:00
renovate[bot]
1f5b4269ab Update dependency pg-boss to v10.4.0 (#14837)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-21 12:21:29 +00:00
Henry Heino
9c23574977 Chore: Server: Remove auto-generated explicit any in types.ts (#14855) 2026-03-21 12:17:43 +00:00
Henry Heino
fe5ff98429 Chore: Editor: Strengthen compatibility layer event types (#14856) 2026-03-21 12:17:30 +00:00
Henry Heino
b721b3ac77 Chore: OneNote importer: Remove unused callback (#14859) 2026-03-21 12:17:06 +00:00
Rohit
638485376c All: Fixes #14540: Prevent duplicate tags caused by Unicode normalization (#14599) 2026-03-21 12:14:37 +00:00
Victor Gherardi
575f4235c3 iOS: Fixes #12968: Fix mobile app unable to attach file with special characters in the name (#14736) 2026-03-21 12:05:55 +00:00
renovate[bot]
8184d3ef37 Update Slashgear/action-check-pr-title action to v5 (#14857)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 22:58:59 +00:00
renovate[bot]
1262a5a1ff Update dependency ldapts to v8.0.30 (#14853)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 21:19:49 +00:00
moaaz
05fc3e9104 Desktop: Fixes #14613: Fix JPEG image paste from clipboard on Linux (#14750) 2026-03-20 20:02:06 +00:00
Laurent Cozic
064e72c43a Revert "Desktop: Resolves #7914: Add support for Ctrl/Cmd+Wheel to zoom in and out (#14684)"
This reverts commit 21d12a2b46.

Due to: https://github.com/laurent22/joplin/pull/14817
2026-03-20 10:20:10 +00:00
mrjo118
088d8eb159 Mobile: Disable auto correct, auto complete and auto capitalize for setting search field (#14810) 2026-03-20 10:18:42 +00:00
renovate[bot]
333bc5d123 Update dependency ldapts to v8.0.29 (#14842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 10:17:47 +00:00
Henry Heino
93f4c97433 Chore: Desktop: Fix warning during build: Migrate away from the deprecated Sass API (#14803) 2026-03-20 10:17:23 +00:00
Henry Heino
eeeb7d6ba1 Desktop: Accessibility: Fix accessibility issues flagged by automated tools in the note properties dialog (#14798) 2026-03-20 10:16:04 +00:00
renovate[bot]
bda1dc2aa8 Update dependency @types/serviceworker to v0.0.170 (#14838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 08:45:24 +00:00
Victor Gherardi
4073596373 Chore: Fixes #14832: CI: Update handleAnchorClick tests to use dispatchEvent for click simulation (#14833) 2026-03-20 00:46:43 +00:00
Henry Heino
c16eb16af4 Chore: Desktop: Re-enable settings screen accessibility tests (#14793) 2026-03-19 07:20:02 -07:00
renovate[bot]
0c0d7713df Update dependency ldapts to v8.0.28 (#14829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-19 08:20:01 +00:00
renovate[bot]
5161d18d19 Update dependency fs-extra to v11.3.3 (#14819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 21:05:09 +00:00
renovate[bot]
2dcb5374fa Update dependency ldapts to v8.0.27 (#14814)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 11:37:22 +00:00
Vinayreddy765
4c103173ba Desktop: Resolves #14717: Improve clarity of master password warning message (#14724)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-18 10:03:42 +00:00
Moaz Hashem
6d919376dc Desktop: Resolves #14797: Completed date/time is shown as a number (#14808) 2026-03-18 09:55:44 +00:00
Harsh Gupta
08dac7f60b Desktop: Fixes #14245: Incomplete (out of screen) ABC Sheet Music rendering (#14767) 2026-03-18 09:55:33 +00:00
Kaushalendra Singh
087e271f61 Desktop: Fixes #14223: Fix OneNote zip import path when .one files are at root level (#14605) 2026-03-18 09:54:50 +00:00
renovate[bot]
7713bbf65d Update dependency @types/serviceworker to v0.0.169 (#14813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 08:43:54 +00:00
Laurent Cozic
ea4efa6a16 Revert "Resolves #12208 Joplin Desktop UI overlap in top left corner on small screens (#14667)"
This reverts commit 745a68f26b.

Due to: https://github.com/laurent22/joplin/issues/14801
2026-03-17 20:50:00 +00:00
renovate[bot]
c6dc7aa05c Update dependency glob to v11.1.0 (#14799)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 19:41:51 +00:00
Henry Heino
0e6cafbe9f Server: Fix share processing task failure (#14795)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-17 17:53:05 +00:00
Joplin Bot
559559c2d1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-17 13:25:32 +00:00
Laurent Cozic
3223d9c6f9 Desktop release v3.6.6 2026-03-17 09:06:13 +00:00
renovate[bot]
991cbc4dc0 Update dependency nodejs to v24.11.1 (#14783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 03:38:46 +00:00
Joplin Bot
af0318293c Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-17 02:17:20 +00:00
Laurent Cozic
6033f9c6e6 iOS 13.6.3 2026-03-16 22:30:03 +00:00
Laurent Cozic
f400f3839d Android 3.6.14 2026-03-16 22:17:00 +00:00
Laurent Cozic
c7736f9e80 Desktop release v3.6.5 2026-03-16 22:05:59 +00:00
mrjo118
5abd5803fb Mobile: Fixes #14722: Fix incorrect sizing of the tag association screen when opening and dismissing the onscreen keyboard (#14772) 2026-03-16 21:34:40 +00:00
Kareem Abu Al Enein
615677cf18 Mobile: Fixes #13957: Fixed log screen auto-scroll loop during search (#14757) 2026-03-16 21:33:42 +00:00
Ashutosh Singh
21d12a2b46 Desktop: Resolves #7914: Add support for Ctrl/Cmd+Wheel to zoom in and out (#14684) 2026-03-16 21:25:28 +00:00
Anuradha Verma
11c17d43eb Desktop: Fix note list losing focus after moving note to trash (#14650) 2026-03-16 21:23:40 +00:00
Laurent Cozic
120cdaabac Chore: Upgrade gettext-extractor to fix broken CI
The package was printing thousands of debugging statement due to the developer forgetting console.error statements in his lib
2026-03-16 21:08:15 +00:00
Keshav
3a9fbc7e67 Mobile: Fixes #14727: Fix OneDrive auth code double-encoding on mobile (#14776) 2026-03-16 20:51:16 +00:00
madhan112007
c9aaaa952e Mobile: Fixes #14286: Fix openFolder x-callback-url link on Android (#14765) 2026-03-16 20:50:39 +00:00
Keshav
d97121a63a Mobile: Fixes #14685: Restrict sidebar gestures to notebook list (#14733) 2026-03-16 20:50:11 +00:00
Moaz Hashem
4bd98f4819 Desktop: Resolves #14621: Application crashes when deleting a notebook (#14651)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-16 20:49:41 +00:00
Henry Heino
426500437d All: Sync: Fix notebook sharing can fail due to incorrect read-only share state (#14770) 2026-03-16 20:48:07 +00:00
Avanish Gupta
c9dace8b4d Desktop: Make encryption-related strings translatable (#14752) 2026-03-16 12:10:44 +00:00
mrjo118
f9654a3438 Mobile: Disable auto correct, auto complete and auto capitalize for search fields (#14759) 2026-03-16 11:22:27 +00:00
renovate[bot]
7d888a50af Update dependency ldapts to v8.0.25 (#14762)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-16 08:36:22 +00:00
renovate[bot]
65eb5e3afe Update dependency nodejs to v24.11.0 (#14744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-15 09:49:05 +00:00
renovate[bot]
7a9dc4a607 Update dependency ldapts to v8.0.24 (#14743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-15 08:50:00 +00:00
Surendra Manjhi
d20cc87756 Chore: Regression: Skip base64 conversion for svg images (#14721)
Ref: https://github.com/laurent22/joplin/pull/14632
2026-03-14 12:50:02 +00:00
Justin Charles
6d310f6b27 Desktop: Fixes #14658: Always require password confirmation when changing master password after encryption (#14692)
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
2026-03-14 12:45:51 +00:00
Ehtesham Zahid
d2b273bfb0 Desktop: Fixes #14687: Prevent TypeError in handleAppFailure when window is destroyed (#14689) 2026-03-14 12:44:10 +00:00
Ash092016
1ff71a64e1 All: Fixes #14419: Added validation for Joplin Server URL protocol (#14612) 2026-03-14 12:38:00 +00:00
renovate[bot]
e442544070 Update dependency ldapts to v8.0.23 (#14731)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 11:09:58 +00:00
renovate[bot]
ba93bcc06d Update dependency ldapts to v8.0.22 (#14729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 09:55:31 +00:00
ChimzyFire
2d545158d0 Desktop: Fixes #10795: Add WCAG 2.2 accessibility labels to Mermaid chart button (#14617) 2026-03-14 01:14:23 +00:00
renovate[bot]
364ea03e5d Update dependency prosemirror-history to v1.5.0 (#14725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 10:36:23 +00:00
renovate[bot]
082aa70a48 Update dependency ldapts to v8.0.21 (#14723)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 08:45:59 +00:00
renovate[bot]
e9fe4036b1 Update dependency react-native-svg to v15.15.1 (#14718)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 22:33:54 +00:00
renovate[bot]
5ab02cfe52 Update dependency sass to v1.94.3 (#14720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 22:33:45 +00:00
Ashutosh Singh
ce8d9a1cdf Desktop: Resolves #14659: Reuse master password dialog when enabling E2EE (#14664) 2026-03-12 18:58:16 +00:00
Jalina Hirushan
745a68f26b Resolves #12208 Joplin Desktop UI overlap in top left corner on small screens (#14667) 2026-03-12 18:51:53 +00:00
bwat47
667ff1797d Desktop: Fixes #13107: html to markdown conversion sometimes converting links to plaintext with <ins> tags (#14683) 2026-03-12 18:47:49 +00:00
renovate[bot]
e5274c5cff Update dependency sass to v1.94.0 (#14690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 18:41:09 +00:00
Dev Gupta
03c3d6ae4a Desktop: Fixes #14660: Text inputs are disabled after re-encrypt notes dialog journey (#14691) 2026-03-12 18:40:55 +00:00
Aayushi Rajesh
9a3673a38f Doc: Fixes #14645: Fix for navigation order mentioned (#14715) 2026-03-12 18:36:02 +00:00
renovate[bot]
99124e4feb Update dependency react-native-svg to v15.15.0 (#14716)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 18:35:33 +00:00
Laurent Cozic
cf51782f4f Desktop: Fixes #14637: cut/copy context menu options don't appear when right clicking joplin resource links in markdown editor (#14711) 2026-03-12 18:35:17 +00:00
Ashutosh Singh
8bde0bf0ec Desktop: Fixes #14079: Improve updater error message on rate limit (#14549) 2026-03-12 18:25:18 +00:00
Kanishka..
e8372c76aa Desktop: Resolves #8611: Add toggle button to hide/show sync panel (#14593) 2026-03-12 18:16:52 +00:00
Ash092016
e1dc36c0a5 Mobile: Resolves #14603: Password and confirm password fields when enabling encryption auto capitalise first character (#14611) 2026-03-12 18:13:06 +00:00
Henry Heino
8d168dc330 Server: Fix delta API can return changes in wrong order (#14713) 2026-03-12 12:22:26 +00:00
renovate[bot]
321afbe110 Update dependency ldapts to v8.0.20 (#14693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 10:24:18 +00:00
Henry Heino
2e3daad78e Desktop: Fixes #14663: Fix crash when rapidly closing secondary windows (#14702) 2026-03-12 01:18:56 +00:00
Laurent Cozic
2132c2cdf4 Revert "Desktop: Fix context menu missing cut/copy when selecting resource links in markdown editor" (#14710) 2026-03-11 21:19:55 +00:00
Sergio
67aff20e39 Desktop: Fixes #14676: Toggling checkboxes in the note history viewer opens an open with prompt on Windows (#14679) 2026-03-11 16:19:46 +00:00
Gnana Pragadeesh K
3719e1eee0 Mobile: Fixes #14152: Fix font-size inconsistency of code block and inline code (#14463) 2026-03-11 16:19:08 +00:00
Laurent Cozic
4abe83fdb6 Doc: Fix broken language selector on website 2026-03-10 18:49:04 +00:00
Laurent Cozic
6ba912e5aa Chore: Fixed website localisation issue 2026-03-10 15:32:29 +00:00
Surendra Manjhi
8533083730 Desktop: Fixes #14627: use resourceUrl() for base64 images in pasteAsMarkdown (#14632) 2026-03-10 12:38:00 +00:00
Yugal Kaushik
754ff28b36 Desktop: Fixes #101111: ENEX import no longer breaks bullet items with a line break into separate paragraphs (#14642) 2026-03-10 12:36:48 +00:00
Ahmed Idani
b663c64def All: Fixes #14412: Skip share consistency check when not using Joplin Server/Cloud (#14649) 2026-03-10 12:35:55 +00:00
Laurent Cozic
998b26d9a4 Doc: Update CLAUDE.md to specify whitespace rules
Clarified guidelines on whitespace changes in code.
2026-03-10 12:31:00 +00:00
Veivel P
b097cf9a6a Desktop: Resolves #14143: Fixed scrolling behaviour in long lines for TinyMCE and CodeMirror (#14669) 2026-03-10 12:26:03 +00:00
Vinayreddy765
e22c367566 Desktop: Fixes #14637: Fix context menu missing cut/copy when selecting resource links in markdown editor (#14638)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-10 12:20:40 +00:00
Justin Charles
71a2e98155 Desktop: Fixes #14661: hide new note/todo buttons when no notebook exists (#14674)
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
2026-03-10 12:15:34 +00:00
Davideb18
714bbd6d23 Desktop: Fixes #11823: Fixed cancel behavior labels when switching config screens (#14677) 2026-03-10 12:14:04 +00:00
Akshaj Rawat
eda03333a6 Desktop: Fixes #12394: Fix search bar remaining empty when navigating back (#14488) 2026-03-10 12:01:16 +00:00
divyanshkhurana06
93f17a87fa Desktop: Fixes #14142: Fix search highlights breaking mermaid diagram rendering (#14516) 2026-03-10 11:57:15 +00:00
Dipanshu Rawat
c765306e6f Chore: ArrayUtils optimize unique and removeElement functions, improve type handling (#14552)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-10 11:38:28 +00:00
Justin Charles
f05fe5754d Desktop: Fixes #14542: Fix Prevent unclosed frontmatter from breaking Markdown rendering (#14563)
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
2026-03-10 11:31:38 +00:00
Keshav
d046bfa14b Desktop: Resolves #10562: Preserve table customization made on RTE (#14572) 2026-03-10 11:29:59 +00:00
Yousef Genedy
2a681008dd Mobile, Desktop: Resolves #9481: Start sync when app opens or resumes (#14574) 2026-03-10 11:27:46 +00:00
Ashutosh Singh
7214823c74 Chore: Resolves #12037: Remove JSDOM from Turndown package (#14653) 2026-03-09 14:09:08 +00:00
renovate[bot]
ed5b92a91e Update dependency ldapts to v8.0.18 (#14655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 10:27:43 +00:00
Aayushi Rajesh
2c8a9eee61 Doc: Add Plugins link to website navigation (#14645) 2026-03-09 09:10:33 +00:00
renovate[bot]
6451305c89 Update dependency esbuild to v0.26.0 (#14654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 09:05:27 +00:00
Henry Heino
5fd0dc23da Desktop: Fixes #14584: Fix changes to editor settings not applied until editor reloads (#14586) 2026-03-08 21:11:54 +00:00
renovate[bot]
fd3b133b16 Update dependency dompurify to v3.3.1 (#14648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 17:12:46 +00:00
renovate[bot]
118bc3edf1 Update dependency git to v2.51.0 (#14646)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 14:39:59 +00:00
renovate[bot]
d90836bc50 Update dependency ldapts to v8.0.17 (#14641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 13:45:27 +00:00
Dipanshu Rawat
9a477dbeb9 Chore: Fix typo for enum for Right value (#14575)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-08 12:01:31 +00:00
Justin Charles
5271081b3a Docs: Add plugin website link in README (#14626)
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
2026-03-08 11:58:25 +00:00
bwat47
b26370fc5a Desktop, Mobile: Fixes #14630: underline disappearing from ++insert++ syntax when cursor is on that line (#14631) 2026-03-08 11:57:51 +00:00
Laurent Cozic
737c7dcdb4 CI: Do not cancel CI execution on dev branch 2026-03-08 11:17:08 +00:00
Joplin Bot
04babe0261 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-07 18:44:23 +00:00
Laurent Cozic
85e5bbd246 Desktop release v3.6.4 2026-03-07 16:17:05 +00:00
bwat47
f819e1c88b Desktop, Mobile: Fixes #14564: Implement cursor-aware markup rendering and hide bulletpoints on task lists (#14573) 2026-03-07 16:15:48 +00:00
Ashutosh Singh
79c153c498 Desktop, Mobile: Fixes #12793: Prevent a failing plugin from blocking other plugins (#14577) 2026-03-07 16:14:05 +00:00
Harsh Gupta
1db9903926 Desktop: Fixes #12355: Auto-scroll to selected note from 'Go to Anything' search results (#14591) 2026-03-07 16:12:31 +00:00
Surendra Manjhi
e736e05d1c Desktop: Fixes #13140: Normalize img alt line breaks and convert data: URLs when pasting from Word (#14518) 2026-03-07 15:44:35 +00:00
Surendra Manjhi
5ef10676d8 Desktop: Fixes #14525: Show only relevant options in context menu when right-clicking a note link (#14528) 2026-03-07 15:42:55 +00:00
yentropysack
b38613ca22 Mobile: Fixes #9938: Fix in-page links don't work if clicked in succession (#14538)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-07 15:42:08 +00:00
Justin Charles
ea486fbe13 All: Fixes #14543: Fix ++insert++ syntax rendering fix in markdown (#14547)
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-07 15:39:53 +00:00
Laurent Cozic
d2784aff54 Plugins: Add support for joplin.fs.archiveExtract plugin method (#14625) 2026-03-07 15:33:27 +00:00
renovate[bot]
7308d9541e Update dependency ldapts to v8.0.14 (#14614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 00:57:38 +00:00
renovate[bot]
d6ac709e5f Update dependency ldapts to v8.0.13 (#14592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-05 22:46:54 +00:00
Sriram Varun Kumar
b290046e66 Mobile: Fixes #14555: Fix tapping rendered image scrolling to cursor position (#14580) 2026-03-05 13:20:23 +00:00
Henry Heino
c2321a04ae Chore: Importing from OneNote: Add test to verify that errors are reported to JavaScript (#14550) 2026-03-05 09:13:18 +00:00
mrjo118
3df77a4395 Desktop, Mobile: Fix issue where the revision service does not start on the first launch of the app (#14554) 2026-03-05 09:06:04 +00:00
mrjo118
38fd790719 Mobile: Add ability to set per notebook sorting on mobile (#14562) 2026-03-05 09:04:26 +00:00
Vinayreddy765
40bfa9dd3d Desktop: Show feedback message when master passwords do not match (#14566) 2026-03-05 09:01:03 +00:00
Henry Heino
8d08e5df60 Desktop: Importing from OneNote: Fix importing cross-page links (#14567) 2026-03-05 09:00:16 +00:00
Ash092016
4121c47e18 CI: Add concurrency block to cancel outdated workflow runs (#14570) 2026-03-05 09:00:02 +00:00
Yugal Kaushik
d30e6ad0da Desktop: Fixes #13178: Invisible cursor in legacy editor when using dark theme in separate window (#14557)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-03-05 08:32:09 +00:00
Yugal Kaushik
be712df89d Mobile: Fixes #14534: Call unmount() in Note.test.tsx tests to suppress act() warnings (#14535) 2026-03-05 08:31:44 +00:00
Sriram Varun Kumar
f7762c403e Mobile: Rich Text Editor: Fix extra blank line above nested lists (#14504) 2026-03-05 08:31:22 +00:00
renovate[bot]
b89d37de84 Update dependency @types/serviceworker to v0.0.168 (#14578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-05 08:26:56 +00:00
Ashutosh Singh
a7b9af61c0 Desktop: Fixes #14500: Fixes zh_TW locale detection on first start (#14527) 2026-03-04 20:00:12 +00:00
Laurent Cozic
a3186cdfe1 Doc: Add CLAUDE.md rule regarding duplicate tests 2026-03-04 18:48:05 +00:00
Laurent Cozic
0a580493a2 Doc: Added YouTube link to main website page and removed Lemmy link 2026-03-04 16:07:39 +00:00
Laurent Cozic
7a7bf72aa8 Chore: Minor fix to Paste as Markdown feature 2026-03-04 16:06:27 +00:00
Laurent Cozic
a20a584273 Desktop: Add "Paste as Markdown" command for Markdown editor (#14556) 2026-03-04 14:31:54 +00:00
Sriram Varun Kumar
ae30e8cf00 CLI: Fix trailing spaces in ls -l output (#14559) 2026-03-04 10:16:22 +00:00
Joplin Bot
1a7bb9131a Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-04 02:14:13 +00:00
Harsh Gupta
81ed35b117 Desktop: Resolves #12210: Translate Find and Replace dialog in Rich Text editor (#14529) 2026-03-03 16:48:40 +00:00
Sriram Varun Kumar
2704495ac6 Desktop: Fixes #14196: Fix file:// links with backslashes for Windows UNC paths (#14541) 2026-03-03 16:38:08 +00:00
Parth Thirwani
a96f7c6ee7 Desktop: Fixes #13883: Secondary windows no longer follow primary selection after moving notes (#14498)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-03-03 15:32:04 +00:00
Henry Heino
af706ac1b3 Web: Add welcome notes specific to the web app (#14499) 2026-03-03 15:30:03 +00:00
Henry Heino
766ef933b9 Web: Link to the official web app when attempting to sync with Joplin Cloud (#14523) 2026-03-03 15:09:14 +00:00
Surendra Manjhi
35de2aca18 Desktop: Fixes #12313: Prevent All Notes sort order from overwriting shared notebook sort on relaunch (#14524) 2026-03-03 15:08:35 +00:00
Ahmed Idani
c1827e1b9e Desktop: Fixes #14522: App fails to restart on Linux AppImage (#14530) 2026-03-03 14:59:53 +00:00
Henry Heino
89e3544a0c Chore: Desktop: Fix automated tests fail when the system locale is not English (#14531) 2026-03-03 14:58:47 +00:00
mrjo118
7f40e9e661 Mobile: Prevent focus issues and keyboard opening when opening a note in view mode (#14533) 2026-03-03 14:58:10 +00:00
Akshaj Rawat
20405ea95f Desktop: Resolves #12326: Add keyboard shortcuts to toolbar buttons (#14408) 2026-03-03 13:39:57 +00:00
Akshaj Rawat
2574e18c2f Desktop: Fixes #14271: Error message is incorrect when plugin manifest is invalid (#14374) 2026-03-03 13:36:08 +00:00
Joplin Bot
36b25a9517 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-03 02:18:36 +00:00
Laurent Cozic
b3e0575361 iOS 13.6.2 2026-03-02 22:16:27 +00:00
Joplin Bot
f9f40b3c9b Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-02 18:59:44 +00:00
Laurent Cozic
b59721f4b3 Android 3.6.13 2026-03-02 17:47:33 +00:00
Laurent Cozic
891ab3e317 Desktop release v3.6.3 2026-03-02 17:26:21 +00:00
Laurent Cozic
0e156796bc Desktop: Fix editor plugins receiving stale note body during navigation (#14513) 2026-03-01 18:54:42 +00:00
renovate[bot]
f2b558cb75 Update dependency react-native-localize to v3.6.0 (#14511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-01 15:47:39 +00:00
renovate[bot]
322657ef72 Update dependency gettext-extractor to v4.0.3 (#14508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-01 13:17:45 +00:00
renovate[bot]
c1e99afd2e Update dependency samlify to v2.10.2 (#14509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-01 13:12:44 +00:00
Sriram Varun Kumar
b3822e2700 CLI: Fixes #13158: Fix null crash in e2ee decrypt command (#14461)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-03-01 12:21:21 +00:00
Nagmani Upadhyay
a43f46fc01 Mobile: Fixes #11793: uses consistent padding in plugin info dialog (#14466) 2026-03-01 12:20:22 +00:00
Kanishka..
50a26b63c8 Desktop: Fixes #13679: Fix sidebar scroll jump when expanding/collapsing folders (#14467) 2026-03-01 12:20:02 +00:00
Harsh Gupta
02c1c75587 Desktop: Fixes #12401: copying from markdown preview including theme background colour (#14474) 2026-03-01 12:11:16 +00:00
Sriram Varun Kumar
345632324d Desktop: Fix UI freeze when closing plugin dialog with Escape key (#14477)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-03-01 12:08:58 +00:00
mrjo118
8073e03daf Mobile: Prevent race condition when refreshing note contents on mobile (#14486) 2026-03-01 11:58:15 +00:00
Laurent Cozic
7feb953c70 Chore: Trying to use CodeRabbit to validate pull request descriptions 2026-03-01 11:57:51 +00:00
yentropysack
8e895fb2c0 Desktop: Fixes #12385: Copy and paste from markdown preview includes search highlight effect (#14493) 2026-03-01 11:24:41 +00:00
Harsh Gupta
ee97c41309 Desktop, Mobile: Resolves #12220: Add new option to disable the Joplin icon for internal note links (#14503) 2026-03-01 11:16:14 +00:00
Joplin Bot
c9a55563b5 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-03-01 02:33:23 +00:00
GeorgiPopovIT
39f5dc8c95 All: Translation: Update bg_BG.po (#14505) 2026-02-28 19:48:02 -05:00
Joplin Bot
9256ab197a Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-28 18:44:15 +00:00
Laurent Cozic
ee2869da86 Doc: Fix sponsor link 2026-02-28 17:51:48 +00:00
Henry Heino
e11441cfbc Web: Move web app out of beta (#14497) 2026-02-28 12:01:50 +00:00
Yugal Kaushik
2b5be639ce All: Resolves #14336: Store note history settings in sync info (#14449)
Signed-off-by: yugalkaushik <yugalkaushik14@gmail.com>
2026-02-28 12:01:23 +00:00
GeorgiPopovIT
cf3d7f5b88 All: Translation: Update bg_BG.po (#14482) 2026-02-27 12:32:19 -05:00
Mihai Vasiliu
595452f30e All: Translation: Update ro_RO.po and ro_MD.po (#14470) 2026-02-27 12:30:11 -05:00
Henry Heino
33c4029547 Server: Performance: Improve performance of share maintenance task (#14484) 2026-02-27 14:31:48 +00:00
Laurent Cozic
eb238efc7b Transcribe v3.6.6 2026-02-26 21:08:39 +00:00
Laurent Cozic
513341f103 Transcribe: Upgraded image to node:24-bookworm to fix build issue 2026-02-26 21:08:18 +00:00
Henry Heino
65b7c4be26 Doc: Link to GSoC pull request guidelines in the pull request template (#14478) 2026-02-26 17:45:58 +00:00
Henry Heino
344a3c2605 Server: Fixes #14107: Update item ownership information when the original owner no longer has access (#14469) 2026-02-26 15:25:22 +00:00
Laurent Cozic
3fc724c076 Transcribe v3.6.5 2026-02-26 15:06:58 +00:00
Laurent Cozic
044fab96c2 Chore: Update dictionary 2026-02-26 15:06:36 +00:00
Laurent Cozic
df10bbdf2d Transcribe: Fixed location of llamacpp library 2026-02-26 15:05:38 +00:00
Joplin Bot
65d7d12533 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-26 02:14:48 +00:00
Laurent Cozic
814a09035a Transcribe v3.6.3 2026-02-25 21:20:24 +00:00
Laurent Cozic
aadc05bd6c Merge branch 'release-3.5' into dev 2026-02-25 17:50:37 +00:00
Laurent Cozic
0c1511f39e Desktop release v3.5.13 2026-02-25 17:46:43 +00:00
Laurent Cozic
d75d0df88a Chore: Refactor and simplify Transcribe server (#14462) 2026-02-25 17:46:08 +00:00
Henry Heino
2249b3aa7f Desktop: Upgrade tar to v7.5.8 (#14464) 2026-02-25 17:38:10 +00:00
Henry Heino
5d9a6151ea Merge remote-tracking branch 'origin/release-3.5' into dev 2026-02-25 07:41:50 -08:00
Henry Heino
d3ea5bc4a2 Mobile,Desktop: Resolves #13215: Markdown editor: Enable in-editor rendering by default (#13878)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-02-25 08:56:54 +00:00
horvatkm
0ea374cc87 All: Fix status 400 error on Tomcat WebDAV servers (#14332)
Co-authored-by: horvatkm <horvatkm@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
Co-authored-by: mrjo118 <jo.118@hotmail.com>
2026-02-25 08:56:24 +00:00
Sriram Varun Kumar
a53f196cae All: Fixes #14335: Support include_deleted parameter for GET /folders endpoint (#14421) 2026-02-25 08:46:59 +00:00
Ashutosh Singh
7b73b4ba87 Desktop: Resolves #9336: Add editor and sync target to about dialog (#14443) 2026-02-25 08:46:35 +00:00
Henry Heino
99e6d3961f All: Fix unexpected conflicts created during sync (#14453) 2026-02-25 08:45:42 +00:00
renovate[bot]
d0f82fb03b Update dependency nodejs to v24.10.0 (#14454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 08:45:18 +00:00
mrjo118
b1b96e9529 Mobile: Fixes #14452: Make the view / edit note button hidden when an editor plugin is visible (#14458) 2026-02-25 08:42:48 +00:00
Henry Heino
18e178e6cf Chore: Update plugin types (#14457) 2026-02-25 08:41:55 +00:00
Harsh Gupta
075b16a4d2 Desktop: Fixes #12569: Prevent 4th backtick when closing fenced code block (#14423)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-02-24 22:19:09 +00:00
mrjo118
6d50a947dd Mobile: Fixes #14387: Reset undo/redo button state when toggling an editor plugin (#14444) 2026-02-24 22:18:14 +00:00
Kanishka..
cb12e4efb0 All: Fixes #12545: Handle missing script assets in HTML export (#14442) 2026-02-24 22:17:46 +00:00
renovate[bot]
c63eac19c9 Update dependency axios to v1.13.0 (#14450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 22:15:30 +00:00
Henry Heino
2544a55373 Chore: Fix incorrect test for versionInfo (#14451) 2026-02-24 22:13:40 +00:00
Henry Heino
932dbbed1a Server: Fix user can incorrectly retain access to shared items in some cases (#14438) 2026-02-24 22:08:15 +00:00
renovate[bot]
af040cbb79 Update dependency @pmmmwh/react-refresh-webpack-plugin to v0.6.2 (#14448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 13:11:46 +00:00
Henry Heino
9833250bea Chore: Sync fuzzer: Include the step at which an action happened in the action log (#14407) 2026-02-24 09:54:05 +00:00
Henry Heino
3bcdc1b362 Server: Fix user can incorrectly retain access to shared items in some cases (#14445)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-02-24 09:50:02 +00:00
renovate[bot]
036e503d39 Update dependency @react-native-community/datetimepicker to v8.5.1 (#14441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-23 21:15:58 +00:00
Joplin Bot
8667b28db3 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-23 19:12:48 +00:00
renovate[bot]
3c317ccdc1 Update dependency @react-native-community/datetimepicker to v8.5.0 (#14439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-23 19:02:07 +00:00
Laurent Cozic
6a0fc3e36e Doc: Added news item for warrant canary 2026-02-23 18:34:55 +00:00
Laurent Cozic
a95b5744ad Doc: Update sponsors 2026-02-23 16:32:31 +00:00
Sriram Varun Kumar
33eb2f02f8 Desktop: Fixes #14328: "Copy dev mode command to clipboard" does not work when path contains spaces (#14432) 2026-02-23 13:48:55 +00:00
Yugal Kaushik
93732f8df6 Desktop, Cli: Fixes #14139: Remove empty hidden divs from ENEX imports (#14411) 2026-02-22 18:15:17 +00:00
Kanishka..
f589197915 All: Resolves #13216: Move editor settings to dedicated editor section (#14403) 2026-02-22 09:00:16 +00:00
Harsh Gupta
55199244ba Doc: Added video tutorials to documentation pages (#14410) 2026-02-22 08:54:31 +00:00
Ashutosh Singh
6ea3180aee Desktop, Mobile: Resolves #13755: Add waving hand emoji to welcome notebook (#14398) 2026-02-21 11:15:48 +00:00
Laurent Cozic
471bb1bf2b Chore: Fix Code Rabbit auto-labelling 2026-02-20 21:47:30 +00:00
Laurent Cozic
e3948dab24 Desktop: Add context menu to non-image resources in Markdown editor (#14402) 2026-02-20 21:30:32 +00:00
Henry Heino
950cc54bf0 Docs: Add information about the sync fuzzer to the "Debugging the server project" page (#14404) 2026-02-20 21:29:41 +00:00
Anmol Garg
56d43fc3a5 Server: Fixes #14355: Admin emails sorting fails due to invalid user_id column (#14399) 2026-02-20 19:46:39 +00:00
Yugal Kaushik
45ad3ee078 Server: Fixes #14384: Remove warning logged on first startup (#14401)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-02-20 19:35:37 +00:00
Laurent Cozic
8b2b0dfd8b Update CLAUDE.md 2026-02-20 19:15:39 +00:00
mrjo118
90de267c62 Desktop, Mobile: Fixes #13660: Defer starting revision service maintenance until the initial sync has completed (#14394) 2026-02-20 11:27:39 +00:00
Henry Heino
085fe0a1cf Server: Remove support for DELTA_INCLUDES_ITEMS (#14393) 2026-02-20 11:26:46 +00:00
Henry Heino
009f3ed692 Desktop,Mobile,Cli: Fixes #14383: Fix unexpected conflicts sometimes created after a full sync (#14388) 2026-02-20 11:26:36 +00:00
Henry Heino
2763a219e4 Chore: Sync fuzzer: Add utilities to allow reproducing a conflict-related share issue (#14382) 2026-02-20 11:26:24 +00:00
Henry Heino
01a51589fd Server: Fixes #14343: Fix certain note content is corrupted when uploaded to the server (#14379) 2026-02-20 11:26:16 +00:00
mrjo118
ba414a4e01 Mobile: Refresh note when updated via the API when in edit mode (#14378) 2026-02-20 11:26:05 +00:00
mrjo118
2da78b37b8 Mobile: Resolves #11521: Remember the viewing / editing mode (updated) (#14363) 2026-02-20 11:22:34 +00:00
Henry Heino
3ef21b0fff Server: Improve name generation for uploaded files (#14392) 2026-02-20 11:04:55 +00:00
Laurent Cozic
77353b015e Desktop: Resolves #12400: Add a text layer over OCR-ed PDF files to make them accessible (#14390) 2026-02-20 11:04:36 +00:00
Laurent Cozic
b6dc7730fc Chore: Update Code Rabbit auto-tagging feature 2026-02-20 10:42:21 +00:00
Laurent Cozic
e96b8d1079 Add comment guideline for duplicated code
Add guideline for commenting on duplicated code.
2026-02-19 22:58:21 +00:00
renovate[bot]
16abb027c2 Update dependency raw-body to v3.0.2 (#14389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-19 22:24:11 +00:00
Laurent Cozic
8af0c451c6 Chore: Add CLAUDE.md to configure Claude 2026-02-19 21:57:22 +00:00
Joplin Bot
9badf985cb Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-19 19:02:02 +00:00
Laurent Cozic
59c6be2234 Doc: Update sponsors 2026-02-19 17:19:42 +00:00
Laurent Cozic
f418b0cc6f Transcribe v3.6.2 2026-02-19 17:03:00 +00:00
Laurent Cozic
9649beea4e Transcribe v3.6.1 2026-02-19 13:58:14 +00:00
Laurent Cozic
440b93f40f Chore: Fixed git-changelog for Transcribe 2026-02-19 13:57:02 +00:00
Laurent Cozic
5beccb9a86 Chore: Refactor Transcribe server (#14381) 2026-02-19 12:51:42 +00:00
Laurent Cozic
8aca7445c7 Doc: Update canary warrant 2026-02-19 10:31:44 +00:00
Laurent Cozic
89f9c6a5e1 Refine instructions for PR labels in .coderabbit.yaml 2026-02-18 23:01:08 +00:00
Laurent Cozic
b240c7fafc Doc: Resolves #13124: Create a warrant canary page (#14375)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-02-18 20:45:57 +00:00
renovate[bot]
d893680a84 Update dependency @axe-core/playwright to v4.11.0 (#14377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 20:44:24 +00:00
Laurent Cozic
d1b316516a Chore: Fixed issue with image path in Transcribe 2026-02-18 19:15:37 +00:00
Laurent Cozic
535158e07a Chore: Clean up Code Rabbit config and add knowledge_base property 2026-02-18 12:08:53 +00:00
mrjo118
5776aff0df Mobile: Remove redundant navigation history for notes or folders which were deleted (#13428) 2026-02-18 10:48:31 +00:00
Laurent Cozic
59e38bac45 Update .coderabbit.yaml 2026-02-18 08:26:45 +00:00
Henry Heino
e581c4cd67 Mobile: Fixes #14195: Fix biometric 'try again' button is off-screen on certain devices (#14373) 2026-02-18 08:01:35 +00:00
Henry Heino
e6604e369f Web: Fixes #11799: Fix "delete plugin" confirm dialog shown beneath plugin info dialog (#14337) 2026-02-18 07:57:09 +00:00
Henry Heino
60f76afa54 Mobile: Fixes #13871: Fix profile data not deleted when removing profiles (#14369) 2026-02-18 07:56:34 +00:00
Henry Heino
fc2f0994fa Web: Fix save button is greyed out after saving settings, then changing a setting (#14349) 2026-02-18 01:03:33 +00:00
Henry Heino
908d568f6e Chore: Editor CI: Retry flaky test on failure (#14364) 2026-02-18 00:24:12 +00:00
Laurent Cozic
45b44b962e All: Fixes #14352: YouTube videos are displayed inline too (#14370) 2026-02-17 22:49:21 +00:00
renovate[bot]
ced97edb52 Update dependency lint-staged to v16.2.7 (#14371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-17 22:49:09 +00:00
Laurent Cozic
ed620b7ec0 Doc: Add support for multiple language on website front page (#14365) 2026-02-17 22:48:59 +00:00
Laurent Cozic
44f77fa04b Chore: Auto-apply labels to PR using Code Rabbit 2026-02-17 21:30:51 +00:00
Laurent Cozic
730f7074fd Chore: Make Code Rabbit comments less noisy 2026-02-17 20:54:03 +00:00
Laurent Cozic
3dc6c6d272 Chore: Make Code Rabbit comments less noisy 2026-02-17 20:53:26 +00:00
Joplin Bot
6edc74ed3a Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-17 19:08:04 +00:00
mrjo118
0192033845 Mobile: Fixes #14255: Add a reveal in notebook option for notes (#14338) 2026-02-17 17:21:11 +00:00
mrjo118
7285270df3 API: Add a delete revisions for note API (#13882) 2026-02-17 17:20:52 +00:00
Dwong33
ab05bb8cc5 All: Translation: Update zh_TW.po (#14362) 2026-02-17 10:35:34 -05:00
Henry Heino
887084a6a0 Chore: Sync fuzzer: Support saving and restoring fuzzer state (#14340) 2026-02-17 11:11:37 +00:00
Ronald Eddy Jr
a2f6906668 Desktop: Resolves #14301: Fix Escape key not closing PromptDialog (#14325) 2026-02-17 11:07:19 +00:00
Laurent Cozic
5ad4c31b44 Desktop: Display context menu when right-clicking an image in Markdown editor (#14209) 2026-02-17 11:05:28 +00:00
mrjo118
b099840f97 Mobile: Fixes #14194: Hide the expand / collapse title button when the title is too long (#14203) 2026-02-17 11:04:40 +00:00
mrjo118
60fec1ce69 Chore: Move resetting of revision 'oldNote' content to the model and broadcast a new event instead of mutating the value (#13881) 2026-02-17 11:01:59 +00:00
mrjo118
231c9a2343 Desktop: Synchronise pending changes when closing the app (#13845) 2026-02-17 10:59:40 +00:00
mrjo118
a72ea3f2ae All: Fixes #13782: When cleaning old revisions, ensure revisions are merged for all revision branches (#13795) 2026-02-17 10:58:08 +00:00
mrjo118
9f89fee494 Mobile: Add an import txt function (#13742)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-02-17 10:57:32 +00:00
mrjo118
2c3e6d5e11 Mobile: Trigger a note refresh when viewing or editing a note and the contents are updated via the API (#13671) 2026-02-17 10:52:57 +00:00
mrjo118
dbf7b6195e All: Fixes #13611: Fix missing conflict scenario (#13624) 2026-02-17 10:51:44 +00:00
mrjo118
365729c759 Desktop: Exclude trashed notebooks from the list of notebooks on the move to notebook dialog (#13572) 2026-02-17 10:51:08 +00:00
Henry Heino
34dfcb9668 Mobile: Upgrade React Native to v0.81.6 (#14330) 2026-02-17 09:59:05 +00:00
Yousef Genedy
32585576a9 Desktop: Fixes #14350: Make notebook search accent-insensitive in GotoAnything (#14360) 2026-02-17 08:37:13 +00:00
renovate[bot]
ef32d53f72 Update dependency form-data to v4.0.5 (#14357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-15 09:39:24 +00:00
renovate[bot]
232ff19824 Update dependency style-to-js to v1.1.21 (#14354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 09:27:37 +00:00
renovate[bot]
d3d32fc072 Update dependency style-to-js to v1.1.20 (#14353)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 08:28:36 +00:00
renovate[bot]
a7ac7535b7 Update dependency node-gyp to v11.5.0 (#14344)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-13 21:06:55 +00:00
renovate[bot]
cdb1de52eb Update dependency @types/yargs to v17.0.35 (#14346)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-12 22:50:18 +00:00
mrjo118
e7a4227f6f Chore: Change getValidActiveFolder to ignore virtual folders (#13761) 2026-02-11 18:53:29 +00:00
Laurent Cozic
4d9c161c43 Chore: Make CodeRabbit ignore pull requests from Renovate 2026-02-11 16:20:53 +00:00
Laurent Cozic
8eaca2edf9 Desktop: Resolves #14292: Display percentage completion of checkbox lists in note list (#14312) 2026-02-11 12:42:55 +00:00
renovate[bot]
35bb52302f Update dependency react to v19.1.5 (#14327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
Co-authored-by: Henry Heino <personalizedrefrigerator@gmail.com>
2026-02-11 12:41:41 +00:00
renovate[bot]
e181fef1ae Update dependency dompurify to v3.3.0 (#14329)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-10 18:38:48 +00:00
Joplin Bot
f6c8f5b6ca Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-10 18:37:06 +00:00
Laurent Cozic
0ec4571540 Doc: Add press release for HMD Terra M 2026-02-10 18:26:05 +00:00
Laurent Cozic
7bd8255e26 Doc: Add press release for HMD Terra M 2026-02-10 18:21:01 +00:00
Joplin Bot
a7050f678e Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-02-10 13:24:13 +00:00
renovate[bot]
c4895bdb7b Update dependency nodemon to v3.1.11 (#14314)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-10 12:57:21 +00:00
Laurent Cozic
452a3663b9 Chore: Change "Sync" dialog title to "Synchronisation" 2026-02-10 11:06:40 +00:00
Laurent Cozic
f5843e4651 Update renovate.json5 2026-02-10 10:30:42 +00:00
Lakshay Manchanda
9bdf5f4a63 Desktop: Fixes #14080: Dark mode not respected in emoji window (#14303) 2026-02-10 10:20:44 +00:00
Henry Heino
e3028e39fe Desktop: Security: Strengthen Content-Security-Policy (#14316) 2026-02-10 10:15:13 +00:00
Ronald Eddy Jr
14284be1c2 Desktop: Resolves #13794: Add Close Window shortcut and menu item on Windows/Linux (#14317) 2026-02-10 10:14:28 +00:00
Ronald Eddy Jr
bfa0a80772 Doc: Fix broken internal links in documentation (#14318) 2026-02-10 10:12:20 +00:00
Ronald Eddy Jr
5b99c40fbd Fix typos and grammar in user-facing documentation (#14319) 2026-02-10 10:11:38 +00:00
Ronald Eddy Jr
adab482fb1 Doc: Fix typos and grammar in developer documentation (#14320) 2026-02-10 10:10:51 +00:00
Henry Heino
df7a04f552 Desktop: Importing from OneNote: Enable stricter path sanitization on Windows (#14321) 2026-02-10 10:09:34 +00:00
Henry Heino
68073e4ad8 Desktop: Importing from OneNote: Make "module not found" message more useful (#14324) 2026-02-10 10:09:21 +00:00
Henry Heino
8ad1dfa2bf Desktop, Cli: Upgrade tar to v7.5.7 (#14313) 2026-02-10 08:41:12 +00:00
renovate[bot]
38e1ede8b4 Update dependency react-native-svg to v15.14.0 (#14310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 18:05:25 +00:00
renovate[bot]
4afa3aa1ee Update dependency react-native-webview to v13.16.0 (#14311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 18:05:04 +00:00
renovate[bot]
413db88fc9 Update dependency nodejs to v24.9.0 (#14308)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 14:09:00 +00:00
renovate[bot]
20d88a2add Update dependency prosemirror-transform to v1.10.5 (#14307)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 14:08:15 +00:00
Henry Heino
0da94b2f8e Android: Fixes #14267: Fix titlebar underline missing on some Android devices (#14273) 2026-02-09 14:05:10 +00:00
Laurent Cozic
6d306267d8 Doc: Clarify our stance regarding AI-generated code in CLA (#14026) 2026-02-09 12:54:12 +00:00
Henry Heino
adb1367dcc Android: Fixes #14268: Fix additional space included above keyboard (#14272) 2026-02-09 12:52:09 +00:00
Henry Heino
1d9864fae7 Android: Fixes #14265: Opt out of Android 16 predictive back behavior (#14281) 2026-02-09 12:51:14 +00:00
Henry Heino
a5a1634fb0 Android: Fixes #14266: Fix import/export buttons have wrong background after task completes (#14282) 2026-02-09 12:51:06 +00:00
Henry Heino
fdaf9c4b5d Chore: Sync fuzzer: Fix fuzzer failure caused by incorrect expected state (#14283) 2026-02-09 12:50:45 +00:00
Henry Heino
767c9cd587 Chore: Simplify and refactor the "should support hiding and showing panels" test (#14284) 2026-02-09 12:50:33 +00:00
Henry Heino
266b177047 Web: Fix production build (#14285) 2026-02-09 12:50:23 +00:00
Henry Heino
1d4478c28e Mobile: Fixes #14275: Improve dropdown menu positioning (#14288) 2026-02-09 12:50:15 +00:00
Henry Heino
47f15b6c32 Server: Fixes #14110: Fix new clients on an existing account can download previously unshared items (#14289) 2026-02-09 12:50:07 +00:00
Henry Heino
9edfa0c2b0 Cli: Fix help text for unpublish command (#14293) 2026-02-09 12:49:16 +00:00
Henry Heino
9d4506a6f8 Chore: Sync fuzzer: Do not attempt to unpublish read-only notes (#14294) 2026-02-09 12:49:09 +00:00
Henry Heino
4cd9501165 Desktop: Importing from OneNote: Improve handwriting import (#14305) 2026-02-09 12:46:35 +00:00
renovate[bot]
335ba15784 Update dependency python to 3.14 (#14270)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-02-09 10:34:56 +00:00
renovate[bot]
f88c1df7ff Update dependency react-native-share to v12.2.1 (#14304)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 10:34:41 +00:00
renovate[bot]
a6c42898df Update dependency @types/serviceworker to v0.0.167 (#14297)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-08 23:43:14 +00:00
Laurent Cozic
cbc9b452e1 Chore: Add CodeRabbit config 2026-02-08 22:48:23 +00:00
renovate[bot]
3739fac751 Update dependency @playwright/test to v1.56.1 (#14295)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-07 12:45:09 +00:00
renovate[bot]
7a745b872a Update dependency @playwright/test to v1.56.0 (#14269)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-07 09:28:20 +00:00
Henry Heino
eeaed07a53 Mobile: Fix heading links (#14201) 2026-02-04 10:09:19 +00:00
Henry Heino
f497d898bc Windows: Fixes #14084: .onepkg file import: Fix import failure when notebook titles contain certain Unicode characters (#14090) 2026-01-26 16:56:39 +00:00
818 changed files with 23217 additions and 14905 deletions

110
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,110 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: "en-GB"
reviews:
high_level_summary: false
estimate_code_review_effort: false
poem: false
auto_review:
enabled: true
drafts: false
ignore_usernames:
- "renovate[bot]"
auto_apply_labels: true
labeling_instructions:
- label: "accessibility"
instructions: "Apply when the PR contains changes related to accessibility, screen readers, keyboard navigation, or ARIA attributes"
- label: "android"
instructions: "Apply when the PR modifies files under packages/app-mobile/android/. Or when the PR modifies files under packages/app-mobile and the change is specific to Android only"
- label: "api"
instructions: "Apply when the PR modifies files under packages/lib/services/rest/"
- label: "bug"
instructions: "Apply when the PR fixes a bug or unexpected behaviour"
- label: "ci"
instructions: "Apply when the PR modifies files under .github/workflows/ or .circleci/"
- label: "cli"
instructions: "Apply when the PR modifies files under packages/app-cli/, except if all the modified files are under packages/app-cli/tests/"
- label: "clipper"
instructions: "Apply when the PR modifies files under packages/app-clipper/"
- label: "database"
instructions: "Apply when the PR is mainly about modifying database schema, migrations, or database-related logic"
- label: "desktop"
instructions: "Apply when the PR modifies files under packages/app-desktop/"
- label: "documentation"
instructions: "Apply when the PR modifies files under readme/"
- label: "draw"
instructions: "Apply when the PR modifies files under packages/default-plugins and relates to the JS-Draw drawing plugin"
- label: "editor"
instructions: "Apply when the PR modifies files under packages/editor/ or packages/app-mobile/components/NoteEditor/"
- label: "enhancement"
instructions: "Apply when the PR adds a new feature or improves existing functionality (not a bug fix)"
- label: "export"
instructions: "Apply when the PR is mainly about changes to the export functionality (PDF, HTML, JEX, etc.)"
- label: "import"
instructions: "Apply when the PR is mainly about changes to the import functionality (Evernote, Markdown, etc.)"
- label: "iOS"
instructions: "Apply when the PR modifies files under packages/app-mobile/ios/. Or when the PR modifies files under packages/app-mobile and the change is specific to iOS only"
- label: "linux"
instructions: "Apply when the PR is mainly about changes specific to Linux"
- label: "linux/wayland"
instructions: "Apply when the PR is mainly about changes specific to Linux Wayland"
- label: "macOS"
instructions: "Apply when the PR is mainly about changes specific to macOS"
- label: "markdown-editor"
instructions: "Apply when the PR modifies files under packages/editor/CodeMirror"
- label: "mobile"
instructions: "Apply when the PR modifies files under packages/app-mobile/"
- label: "OCR"
instructions: "Apply when the PR contains changes related to OCR (optical character recognition) functionality"
- label: "performance"
instructions: "Apply when the PR improves performance, reduces memory usage, or optimises speed"
- label: "plugins"
instructions: "Apply when the PR modifies files under packages/lib/services/plugins/ or packages/plugin-repo-cli/"
- label: "Regression"
instructions: "Apply when the linked issue, if any, has the Regression label"
- label: "renderer"
instructions: "Apply when the PR modifies files under packages/renderer/ or packages/turndown/"
- label: "search"
instructions: "Apply when the PR is mainly about changes to the search functionality"
- label: "security"
instructions: "Apply when the PR is mainly about addressing a security vulnerability or improving security"
- label: "server"
instructions: "Apply when the PR modifies files under packages/server/"
- label: "Sharing"
instructions: "Apply when the PR is mainly about changes to the note or notebook/folder sharing features"
- label: "sync"
instructions: "Apply when the PR modifies files under packages/lib/services/synchronizer/, packages/lib/Sync*.ts or packages/lib/services/e2ee/"
- label: "tags"
instructions: "Apply when the PR is mainly about changes to the tag management or tagging functionality"
- label: "transcribe"
instructions: "Apply when the PR modifies files under packages/transcribe"
- label: "translation"
instructions: "Apply when the PR modifies files under packages/tools/locales/ or **/locales/"
- label: "Voice typing"
instructions: "Apply when the PR is mainly about changes to the voice typing functionality"
- label: "web"
instructions: "Apply when the PR modifies files under packages/app-web/. Or when the PR modifies files under packages/app-mobile and the change is specific to the web app only"
- label: "windows"
instructions: "Apply when the PR is mainly about changes specific to Windows"
pre_merge_checks:
description:
mode: "warning"
custom_checks:
- name: "PR Description Must Follow Guidelines"
mode: "error"
instructions: |
Fail if the pull request description does not include clear sections for:
- Problem or user-impact description
- A high-level Solution explanation
- Any Test Plan or verification steps
The description should align with our PR guidelines
at https://github.com/joplin/gsoc/blob/master/pull_request_guidelines.md
and should not just restate the diff or implementation details.
knowledge_base:
code_guidelines:
enabled: true
filePatterns:
- "readme/dev/coding_style.md"
- "readme/dev/index.md"
- "CLAUDE.md"

View File

@@ -17,3 +17,4 @@ packages/server/db-*.sqlite
packages/server/dist/
packages/server/logs/
packages/server/temp/
packages/transcribe/.env

View File

@@ -31,6 +31,7 @@
# QUEUE_DATABASE_PASSWORD=transcribe
# QUEUE_DATABASE_PORT=5431
# HTR_CLI_IMAGES_FOLDER=/home/user/images_storage
# HTR_CLI_MODELS_FOLDER=/home/user/transcribe_models
# =============================================================================
# DEV CONFIG EXAMPLE

View File

@@ -1,35 +1,33 @@
# Joplin Transcribe Configuration
#
# Copy this file to .env-transcribe and update the values.
# =============================================================================
# Required
# -----------------------------------------------------------------------------
# =============================================================================
SERVER_PORT=4567
# Set a secure API key for authentication
API_KEY=changeme
API_KEY=random-string
QUEUE_TTL=900000
QUEUE_RETRY_COUNT=2
QUEUE_MAINTENANCE_INTERVAL=30000
IMAGE_MAX_DIMENSION=400
# =============================================================================
# Optional (defaults are set in the Docker image)
# =============================================================================
HTR_CLI_DOCKER_IMAGE=joplin/htr-cli:latest
# Fullpath to images folder e.g.:
#HTR_CLI_IMAGES_FOLDER=/home/user/joplin/packages/transcribe/images
HTR_CLI_IMAGES_FOLDER=
# Server port (default: 4567)
# SERVER_PORT=4567
QUEUE_DRIVER=pg
# Maximum image dimension for processing (default: 400)
# IMAGE_MAX_DIMENSION=400
# Queue driver: sqlite (default) or pg
# QUEUE_DRIVER=sqlite
FILE_STORAGE_MAINTENANCE_INTERVAL=3600000
FILE_STORAGE_TTL=604800000 # one week
# =============================================================================
# PostgreSQL settings (only if QUEUE_DRIVER=pg)
# =============================================================================
# =============================================================================
# Queue driver
# -----------------------------------------------------------------------------
# =============================================================================
#
# QUEUE_DATABASE_NAME=./queue.sqlite3
QUEUE_DATABASE_NAME=transcribe
QUEUE_DATABASE_USER=transcribe
QUEUE_DATABASE_PASSWORD=transcribe
QUEUE_DATABASE_PORT=5432
QUEUE_DATABASE_HOST=localhost
# QUEUE_DATABASE_NAME=transcribe
# QUEUE_DATABASE_USER=transcribe
# QUEUE_DATABASE_PASSWORD=transcribe
# QUEUE_DATABASE_PORT=5432
# QUEUE_DATABASE_HOST=localhost

View File

@@ -103,6 +103,7 @@ packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
packages/app-cli/app/command-cat.js
packages/app-cli/app/command-clear.js
packages/app-cli/app/command-config.js
packages/app-cli/app/command-cp.js
packages/app-cli/app/command-done.test.js
@@ -169,6 +170,7 @@ packages/app-desktop/bridge.js
packages/app-desktop/checkForUpdates.js
packages/app-desktop/commands/copyDevCommand.js
packages/app-desktop/commands/copyToClipboard.js
packages/app-desktop/commands/createAccessibleDocument.js
packages/app-desktop/commands/editProfileConfig.js
packages/app-desktop/commands/emptyTrash.js
packages/app-desktop/commands/exportDeletionLog.test.js
@@ -208,7 +210,6 @@ packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/Dialog.js
packages/app-desktop/gui/DialogButtonRow.js
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
packages/app-desktop/gui/DialogTitle.js
@@ -218,6 +219,8 @@ packages/app-desktop/gui/EditFolderDialog/Dialog.js
packages/app-desktop/gui/EditFolderDialog/IconSelector.js
packages/app-desktop/gui/EmojiBox.js
packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js
packages/app-desktop/gui/EncryptionConfigScreen/enableFlow.test.js
packages/app-desktop/gui/EncryptionConfigScreen/enableFlow.js
packages/app-desktop/gui/ErrorBoundary.js
packages/app-desktop/gui/ExtensionBadge.js
packages/app-desktop/gui/FolderIconBox.js
@@ -248,6 +251,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/normalizeAccelerator.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/normalizeAccelerator.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearchExtension.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearchHandler.js
@@ -269,6 +273,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useContentScriptRegistration.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useEditorSettings.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useKeymap.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useRefocusOnVisiblePaneChange.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useSyncEditorValue.js
@@ -301,6 +307,7 @@ packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteViewer.js
packages/app-desktop/gui/NoteEditor/commands/focusElementToolbar.js
packages/app-desktop/gui/NoteEditor/commands/index.js
packages/app-desktop/gui/NoteEditor/commands/pasteAsMarkdown.js
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
@@ -338,9 +345,11 @@ packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList2.js
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
packages/app-desktop/gui/NoteList/commands/index.js
packages/app-desktop/gui/NoteList/utils/UseAutoScroll.test.js
packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.js
packages/app-desktop/gui/NoteList/utils/types.js
packages/app-desktop/gui/NoteList/utils/useActiveDescendantId.js
packages/app-desktop/gui/NoteList/utils/useAutoScroll.js
packages/app-desktop/gui/NoteList/utils/useDragAndDrop.js
packages/app-desktop/gui/NoteList/utils/useFocusNote.js
packages/app-desktop/gui/NoteList/utils/useFocusVisible.js
@@ -349,6 +358,8 @@ packages/app-desktop/gui/NoteList/utils/useMoveNote.js
packages/app-desktop/gui/NoteList/utils/useOnKeyDown.js
packages/app-desktop/gui/NoteList/utils/useOnNoteClick.js
packages/app-desktop/gui/NoteList/utils/useOnNoteDoubleClick.js
packages/app-desktop/gui/NoteList/utils/useRefocusOnDeletion.test.js
packages/app-desktop/gui/NoteList/utils/useRefocusOnDeletion.js
packages/app-desktop/gui/NoteList/utils/useScroll.js
packages/app-desktop/gui/NoteList/utils/useVisibleRange.test.js
packages/app-desktop/gui/NoteList/utils/useVisibleRange.js
@@ -370,8 +381,8 @@ packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.js
packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.test.js
packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.js
packages/app-desktop/gui/NoteListItem/utils/types.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.test.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.js
packages/app-desktop/gui/NoteListItem/utils/useItemEventHandlers.js
packages/app-desktop/gui/NoteListItem/utils/useOnContextMenu.js
packages/app-desktop/gui/NoteListItem/utils/useRenderedNote.js
packages/app-desktop/gui/NoteListItem/utils/useRootElement.test.js
@@ -394,7 +405,9 @@ packages/app-desktop/gui/PopupNotification/PopupNotificationList.js
packages/app-desktop/gui/PopupNotification/PopupNotificationProvider.js
packages/app-desktop/gui/PopupNotification/types.js
packages/app-desktop/gui/ProfileEditor.js
packages/app-desktop/gui/PromptDialog.test.js
packages/app-desktop/gui/PromptDialog.js
packages/app-desktop/gui/QuitSyncDialog.js
packages/app-desktop/gui/ResizableLayout/LayoutItemContainer.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
packages/app-desktop/gui/ResizableLayout/ResizableLayout.js
@@ -459,7 +472,6 @@ packages/app-desktop/gui/ToolbarSpace.js
packages/app-desktop/gui/TrashNotification/TrashNotification.js
packages/app-desktop/gui/TrashNotification/TrashNotificationMessage.js
packages/app-desktop/gui/UpdateNotification/UpdateNotification.js
packages/app-desktop/gui/WebDavOidcLoginScreen.js
packages/app-desktop/gui/WindowCommandsAndDialogs/AppDialogs.js
packages/app-desktop/gui/WindowCommandsAndDialogs/ModalMessageOverlay.js
packages/app-desktop/gui/WindowCommandsAndDialogs/PluginDialogs.js
@@ -524,7 +536,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useSyncDialogState.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowCommands.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.js
packages/app-desktop/gui/dialogs.js
packages/app-desktop/gui/hooks/useDocument.js
packages/app-desktop/gui/hooks/useEffectDebugger.js
packages/app-desktop/gui/hooks/useElementHeight.js
packages/app-desktop/gui/hooks/useImperativeHandlerDebugger.js
@@ -557,6 +568,7 @@ packages/app-desktop/integration-tests/models/NoteEditorScreen.js
packages/app-desktop/integration-tests/models/NoteList.js
packages/app-desktop/integration-tests/models/SettingsScreen.js
packages/app-desktop/integration-tests/models/Sidebar.js
packages/app-desktop/integration-tests/multiWindow.spec.js
packages/app-desktop/integration-tests/noteList.spec.js
packages/app-desktop/integration-tests/pluginApi.spec.js
packages/app-desktop/integration-tests/resizableLayout.spec.js
@@ -578,6 +590,7 @@ packages/app-desktop/integration-tests/util/setMessageBoxResponse.js
packages/app-desktop/integration-tests/util/setSettingValue.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/integration-tests/util/waitForNextWindowMatching.js
packages/app-desktop/integration-tests/wcag.spec.js
packages/app-desktop/main-html.js
packages/app-desktop/main.js
@@ -606,10 +619,6 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
packages/app-desktop/services/plugins/types.js
packages/app-desktop/services/restart.js
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
packages/app-desktop/tools/bundleJs.js
packages/app-desktop/tools/copy7Zip.js
@@ -624,10 +633,12 @@ packages/app-desktop/utils/checkForUpdatesUtils.test.js
packages/app-desktop/utils/checkForUpdatesUtils.js
packages/app-desktop/utils/checkForUpdatesUtilsTestData.js
packages/app-desktop/utils/customProtocols/constants.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.content.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.plugins.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.js
packages/app-desktop/utils/customProtocols/registerCustomProtocols.js
packages/app-desktop/utils/getAssetPath.js
packages/app-desktop/utils/initReact.js
packages/app-desktop/utils/initializeCommandService.js
packages/app-desktop/utils/isSafeToOpen.test.js
packages/app-desktop/utils/isSafeToOpen.js
@@ -643,6 +654,7 @@ packages/app-mobile/commands/newNote.js
packages/app-mobile/commands/openItem.js
packages/app-mobile/commands/openNote.js
packages/app-mobile/commands/scrollToHash.js
packages/app-mobile/commands/util/goToFolder.js
packages/app-mobile/commands/util/goToNote.js
packages/app-mobile/commands/util/showResource.js
packages/app-mobile/components/BetaChip.js
@@ -686,13 +698,16 @@ packages/app-mobile/components/EditorToolbar/utils/isSelected.js
packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.js
packages/app-mobile/components/EditorToolbar/utils/toolbarButtonsFromState.js
packages/app-mobile/components/EditorToolbar/utils/useButtonSize.js
packages/app-mobile/components/EditorToolbar/utils/useSaveToolbarButtons.test.js
packages/app-mobile/components/EditorToolbar/utils/useSaveToolbarButtons.js
packages/app-mobile/components/EditorToolbar/utils/useToolbarEditorState.test.js
packages/app-mobile/components/EditorToolbar/utils/useToolbarEditorState.js
packages/app-mobile/components/ExtendedWebView/index.jest.js
packages/app-mobile/components/ExtendedWebView/index.js
packages/app-mobile/components/ExtendedWebView/index.web.js
packages/app-mobile/components/ExtendedWebView/types.js
packages/app-mobile/components/ExtendedWebView/utils/polyfillScrollFunctions.js
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
packages/app-mobile/components/FeedbackBanner.test.js
packages/app-mobile/components/FeedbackBanner.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
@@ -730,12 +745,13 @@ packages/app-mobile/components/NoteList.js
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.js
packages/app-mobile/components/ProfileSwitcher/useProfileConfig.js
packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.test.js
packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.js
packages/app-mobile/components/SafeAreaView.js
packages/app-mobile/components/ScreenHeader/Menu.js
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
packages/app-mobile/components/ScreenHeader/WarningBanner.js
packages/app-mobile/components/ScreenHeader/WarningBox.js
packages/app-mobile/components/ScreenHeader/WebBetaButton.js
packages/app-mobile/components/ScreenHeader/index.js
packages/app-mobile/components/SearchInput.js
packages/app-mobile/components/SelectDateTimeDialog.js
@@ -860,6 +876,8 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/Notes/TextWrapCalculator.js
packages/app-mobile/components/screens/ResourceScreen.js
packages/app-mobile/components/screens/SearchScreen/SearchBar.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
@@ -876,9 +894,10 @@ packages/app-mobile/components/screens/dropbox-login.js
packages/app-mobile/components/screens/encryption-config.test.js
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/folder.js
packages/app-mobile/components/screens/resourceScreenUtils.test.js
packages/app-mobile/components/screens/resourceScreenUtils.js
packages/app-mobile/components/screens/status.js
packages/app-mobile/components/screens/tags.js
packages/app-mobile/components/screens/webdav-oidc-login.js
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/testing/TestProviderStack.js
packages/app-mobile/components/voiceTyping/AudioRecordingBanner.js
@@ -899,6 +918,7 @@ packages/app-mobile/contentScripts/markdownEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/markdownEditorBundle/utils/useCodeMirrorPlugins.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.handleAnchorClick.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/types.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/addPluginAssets.js
@@ -978,6 +998,7 @@ packages/app-mobile/utils/image/fileToImage.web.js
packages/app-mobile/utils/image/getImageDimensions.js
packages/app-mobile/utils/image/resizeImage.js
packages/app-mobile/utils/initReact.js
packages/app-mobile/utils/initReact.web.js
packages/app-mobile/utils/initializeCommandService.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
@@ -1244,7 +1265,6 @@ packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.test.js
packages/lib/ObjectUtils.js
packages/lib/OidcApi.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
packages/lib/PoorManIntervals.js
@@ -1254,17 +1274,15 @@ packages/lib/SyncTargetFilesystem.js
packages/lib/SyncTargetJoplinCloud.js
packages/lib/SyncTargetJoplinServer.js
packages/lib/SyncTargetJoplinServerSAML.js
packages/lib/SyncTargetNextcloud.js
packages/lib/SyncTargetNone.js
packages/lib/SyncTargetOneDrive.js
packages/lib/SyncTargetRegistry.js
packages/lib/SyncTargetWebDAV.js
packages/lib/Synchronizer.js
packages/lib/TaskQueue.js
packages/lib/WebDavApi.js
packages/lib/WelcomeUtils.test.js
packages/lib/WelcomeUtils.js
packages/lib/array.js
packages/lib/base-oauth-node-utils.js
packages/lib/callbackUrlUtils.test.js
packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
@@ -1286,10 +1304,12 @@ packages/lib/commands/synchronize.js
packages/lib/commands/toggleAllFolders.test.js
packages/lib/commands/toggleAllFolders.js
packages/lib/commands/toggleEditorPlugin.js
packages/lib/components/Dialog.js
packages/lib/components/EncryptionConfigScreen/utils.test.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextDismissLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextReadMoreLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/useEditorTypeMigrationBanner.js
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
packages/lib/components/shared/NoteRevisionViewer/getHelpMessage.js
packages/lib/components/shared/NoteRevisionViewer/useDeleteHistoryClick.js
@@ -1312,6 +1332,7 @@ packages/lib/components/shared/reduxSharedMiddleware.js
packages/lib/components/shared/side-menu-shared.test.js
packages/lib/components/shared/side-menu-shared.js
packages/lib/database-driver-better-sqlite.js
packages/lib/database-driver.js
packages/lib/database.js
packages/lib/debug/DebugService.js
packages/lib/determineBaseAppDirs.js
@@ -1334,6 +1355,7 @@ packages/lib/fsDriver.test.js
packages/lib/geolocation-node.js
packages/lib/getAppName.test.js
packages/lib/getAppName.js
packages/lib/hooks/dom/useDocument.js
packages/lib/hooks/plugins/usePlugin.js
packages/lib/hooks/plugins/useVisiblePluginEditorViewIds.js
packages/lib/hooks/useAsyncEffect.js
@@ -1414,8 +1436,6 @@ packages/lib/models/utils/userData.test.js
packages/lib/models/utils/userData.js
packages/lib/net-utils.js
packages/lib/ntp.js
packages/lib/oidc-api-node-utils.js
packages/lib/onedrive-api-node-utils.js
packages/lib/onedrive-api.test.js
packages/lib/onedrive-api.js
packages/lib/path-utils.js
@@ -1428,7 +1448,9 @@ packages/lib/services/AlarmServiceDriverNode.js
packages/lib/services/BaseService.js
packages/lib/services/CommandService.test.js
packages/lib/services/CommandService.js
packages/lib/services/DecryptionWorker.test.js
packages/lib/services/DecryptionWorker.js
packages/lib/services/ExternalEditWatcher.test.js
packages/lib/services/ExternalEditWatcher.js
packages/lib/services/ExternalEditWatcher/utils.js
packages/lib/services/ItemChangeUtils.js
@@ -1516,6 +1538,7 @@ packages/lib/services/interop/InteropService_Importer_Md.test.js
packages/lib/services/interop/InteropService_Importer_Md.js
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
packages/lib/services/interop/InteropService_Importer_OneNote.postprocessHtml.test.js
packages/lib/services/interop/InteropService_Importer_OneNote.test.js
packages/lib/services/interop/InteropService_Importer_OneNote.js
packages/lib/services/interop/InteropService_Importer_Raw.test.js
@@ -1533,6 +1556,7 @@ packages/lib/services/keychain/KeychainServiceDriver.dummy.js
packages/lib/services/keychain/KeychainServiceDriver.electron.js
packages/lib/services/keychain/KeychainServiceDriver.node.js
packages/lib/services/keychain/KeychainServiceDriverBase.js
packages/lib/services/noteList/checkboxPieCss.js
packages/lib/services/noteList/defaultLeftToRightListRenderer.js
packages/lib/services/noteList/defaultListRenderer.js
packages/lib/services/noteList/defaultMultiColumnsRenderer.js
@@ -1548,6 +1572,7 @@ packages/lib/services/ocr/OcrService.js
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.test.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.js
packages/lib/services/ocr/utils/createAccessiblePdf.js
packages/lib/services/ocr/utils/filterOcrText.test.js
packages/lib/services/ocr/utils/filterOcrText.js
packages/lib/services/ocr/utils/types.js
@@ -1569,6 +1594,7 @@ packages/lib/services/plugins/api/JoplinCommands.js
packages/lib/services/plugins/api/JoplinContentScripts.js
packages/lib/services/plugins/api/JoplinData.js
packages/lib/services/plugins/api/JoplinFilters.js
packages/lib/services/plugins/api/JoplinFs.js
packages/lib/services/plugins/api/JoplinImaging.js
packages/lib/services/plugins/api/JoplinInterop.js
packages/lib/services/plugins/api/JoplinPlugins.js
@@ -1667,6 +1693,10 @@ packages/lib/services/share/ShareService.test.js
packages/lib/services/share/ShareService.js
packages/lib/services/share/invitationRespond.js
packages/lib/services/share/reducer.js
packages/lib/services/sortOrder/PerFolderSortOrderService.test.js
packages/lib/services/sortOrder/PerFolderSortOrderService.js
packages/lib/services/sortOrder/notesSortOrderUtils.test.js
packages/lib/services/sortOrder/notesSortOrderUtils.js
packages/lib/services/spellChecker/SpellCheckerService.js
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
packages/lib/services/style/cssToTheme.test.js
@@ -1719,6 +1749,7 @@ packages/lib/shim-init-node.js
packages/lib/shim.js
packages/lib/string-utils.test.js
packages/lib/string-utils.js
packages/lib/testing/dom-test-environment.js
packages/lib/testing/plugins/createTestPlugin.js
packages/lib/testing/share/makeMockShareInvitation.js
packages/lib/testing/share/mockShareService.js
@@ -1866,25 +1897,29 @@ packages/tools/checkLibPaths.test.js
packages/tools/checkLibPaths.js
packages/tools/convertThemesToCss.js
packages/tools/fuzzer/ActionRunner.js
packages/tools/fuzzer/ActionTracker.js
packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
packages/tools/fuzzer/Server.js
packages/tools/fuzzer/Fuzzer.js
packages/tools/fuzzer/cli.js
packages/tools/fuzzer/constants.js
packages/tools/fuzzer/ipc/Client.js
packages/tools/fuzzer/ipc/ClientPool.js
packages/tools/fuzzer/ipc/Server.js
packages/tools/fuzzer/model/ActionTracker.js
packages/tools/fuzzer/model/FolderRecord.js
packages/tools/fuzzer/model/NoteRecord.js
packages/tools/fuzzer/model/ResourceRecord.js
packages/tools/fuzzer/sync-fuzzer.js
packages/tools/fuzzer/model/Serializable.js
packages/tools/fuzzer/model/types.js
packages/tools/fuzzer/types.js
packages/tools/fuzzer/utils/ProgressBar.js
packages/tools/fuzzer/utils/SeededRandom.js
packages/tools/fuzzer/utils/diffSortedStringArrays.test.js
packages/tools/fuzzer/utils/diffSortedStringArrays.js
packages/tools/fuzzer/utils/extractResourceIds.js
packages/tools/fuzzer/utils/getBinaryDiffDebugMessage.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/hangingIndent.js
packages/tools/fuzzer/utils/logDiffDebug.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/randomId.test.js
packages/tools/fuzzer/utils/randomId.js
@@ -1931,6 +1966,7 @@ packages/tools/update-readme-contributors.js
packages/tools/update-readme-download.test.js
packages/tools/update-readme-download.js
packages/tools/update-readme-sponsors.js
packages/tools/updateCanary.js
packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.test.js
packages/tools/utils/discourse.js
@@ -1958,6 +1994,7 @@ packages/tools/website/utils/parser.js
packages/tools/website/utils/pressCarousel.js
packages/tools/website/utils/processTranslations.js
packages/tools/website/utils/render.js
packages/tools/website/utils/supportedLocales.js
packages/tools/website/utils/types.js
packages/whisper-voice-typing/src/index.js
packages/whisper-voice-typing/src/specs/Whisper.nitro.js

View File

@@ -314,7 +314,7 @@ module.exports = {
selector: 'interface',
format: null,
'filter': {
'regex': '^(RSA|RSAKeyPair|iOS.*|OAuth.*)$',
'regex': '^(RSA|RSAKeyPair|iOS.*)$',
'match': true,
},
},

View File

@@ -1,6 +1,12 @@
<!--
Please prefix the title with the platform you are targetting:
Before contributing, please read the contribution guidelines: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
If this is a Google Summer of Code pull request, please read the [GSoC pull request guidelines](https://github.com/joplin/gsoc/blob/master/pull_request_guidelines.md).
---
**Pull request title**: Please prefix the title with the platform you are targetting.
Here are some examples of good titles:
@@ -20,6 +26,4 @@ If it's not related to any platform (such as a translation, change to the docume
Then please append the issue that you've addressed or fixed. Use "Resolves #123" for new features or improvements and "Fixes #123" for bug fixes.
AND PLEASE READ THE GUIDE: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
-->

View File

@@ -1,5 +1,6 @@
name: Build macOS M1
on: [push, pull_request]
jobs:
Main:
# We always process desktop release tags, because they also publish the release
@@ -28,7 +29,7 @@ jobs:
# See github-action-main.yml for explanation
- uses: actions/setup-python@v5
with:
python-version: '3.13'
python-version: '3.14'
- name: Set Publish Flag
run: |

View File

@@ -4,6 +4,6 @@ jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: Slashgear/action-check-pr-title@v4.3.0
- uses: Slashgear/action-check-pr-title@v5.0.1
with:
regexp: "(Desktop|Mobile|All|Cli|Tools|Chore|Clipper|Server|Android|iOS|Plugins|CI|Plugin Repo|Doc): (Fixes|Resolves) #[0-9]+: .+"

View File

@@ -1,5 +1,6 @@
name: Joplin Continuous Integration
on: [push, pull_request]
jobs:
Main:
# We always process server or desktop release tags, because they also publish the release

View File

@@ -72,4 +72,4 @@ runs:
# Ref: https://github.com/nodejs/node-gyp/issues/2869
- uses: actions/setup-python@v5
with:
python-version: '3.13'
python-version: '3.14'

View File

@@ -1,5 +1,6 @@
name: Joplin UI tests
on: [push, pull_request]
permissions:
contents: read
jobs:

88
.gitignore vendored
View File

@@ -76,6 +76,7 @@ packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
packages/app-cli/app/command-cat.js
packages/app-cli/app/command-clear.js
packages/app-cli/app/command-config.js
packages/app-cli/app/command-cp.js
packages/app-cli/app/command-done.test.js
@@ -142,6 +143,7 @@ packages/app-desktop/bridge.js
packages/app-desktop/checkForUpdates.js
packages/app-desktop/commands/copyDevCommand.js
packages/app-desktop/commands/copyToClipboard.js
packages/app-desktop/commands/createAccessibleDocument.js
packages/app-desktop/commands/editProfileConfig.js
packages/app-desktop/commands/emptyTrash.js
packages/app-desktop/commands/exportDeletionLog.test.js
@@ -181,7 +183,6 @@ packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/Dialog.js
packages/app-desktop/gui/DialogButtonRow.js
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
packages/app-desktop/gui/DialogTitle.js
@@ -191,6 +192,8 @@ packages/app-desktop/gui/EditFolderDialog/Dialog.js
packages/app-desktop/gui/EditFolderDialog/IconSelector.js
packages/app-desktop/gui/EmojiBox.js
packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js
packages/app-desktop/gui/EncryptionConfigScreen/enableFlow.test.js
packages/app-desktop/gui/EncryptionConfigScreen/enableFlow.js
packages/app-desktop/gui/ErrorBoundary.js
packages/app-desktop/gui/ExtensionBadge.js
packages/app-desktop/gui/FolderIconBox.js
@@ -221,6 +224,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/normalizeAccelerator.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/normalizeAccelerator.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearchExtension.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearchHandler.js
@@ -242,6 +246,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useContentScriptRegistration.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useEditorSettings.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useKeymap.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useRefocusOnVisiblePaneChange.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useSyncEditorValue.js
@@ -274,6 +280,7 @@ packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteViewer.js
packages/app-desktop/gui/NoteEditor/commands/focusElementToolbar.js
packages/app-desktop/gui/NoteEditor/commands/index.js
packages/app-desktop/gui/NoteEditor/commands/pasteAsMarkdown.js
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
@@ -311,9 +318,11 @@ packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList2.js
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
packages/app-desktop/gui/NoteList/commands/index.js
packages/app-desktop/gui/NoteList/utils/UseAutoScroll.test.js
packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.js
packages/app-desktop/gui/NoteList/utils/types.js
packages/app-desktop/gui/NoteList/utils/useActiveDescendantId.js
packages/app-desktop/gui/NoteList/utils/useAutoScroll.js
packages/app-desktop/gui/NoteList/utils/useDragAndDrop.js
packages/app-desktop/gui/NoteList/utils/useFocusNote.js
packages/app-desktop/gui/NoteList/utils/useFocusVisible.js
@@ -322,6 +331,8 @@ packages/app-desktop/gui/NoteList/utils/useMoveNote.js
packages/app-desktop/gui/NoteList/utils/useOnKeyDown.js
packages/app-desktop/gui/NoteList/utils/useOnNoteClick.js
packages/app-desktop/gui/NoteList/utils/useOnNoteDoubleClick.js
packages/app-desktop/gui/NoteList/utils/useRefocusOnDeletion.test.js
packages/app-desktop/gui/NoteList/utils/useRefocusOnDeletion.js
packages/app-desktop/gui/NoteList/utils/useScroll.js
packages/app-desktop/gui/NoteList/utils/useVisibleRange.test.js
packages/app-desktop/gui/NoteList/utils/useVisibleRange.js
@@ -343,8 +354,8 @@ packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.js
packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.test.js
packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.js
packages/app-desktop/gui/NoteListItem/utils/types.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.test.js
packages/app-desktop/gui/NoteListItem/utils/useItemElement.js
packages/app-desktop/gui/NoteListItem/utils/useItemEventHandlers.js
packages/app-desktop/gui/NoteListItem/utils/useOnContextMenu.js
packages/app-desktop/gui/NoteListItem/utils/useRenderedNote.js
packages/app-desktop/gui/NoteListItem/utils/useRootElement.test.js
@@ -367,7 +378,9 @@ packages/app-desktop/gui/PopupNotification/PopupNotificationList.js
packages/app-desktop/gui/PopupNotification/PopupNotificationProvider.js
packages/app-desktop/gui/PopupNotification/types.js
packages/app-desktop/gui/ProfileEditor.js
packages/app-desktop/gui/PromptDialog.test.js
packages/app-desktop/gui/PromptDialog.js
packages/app-desktop/gui/QuitSyncDialog.js
packages/app-desktop/gui/ResizableLayout/LayoutItemContainer.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
packages/app-desktop/gui/ResizableLayout/ResizableLayout.js
@@ -432,7 +445,6 @@ packages/app-desktop/gui/ToolbarSpace.js
packages/app-desktop/gui/TrashNotification/TrashNotification.js
packages/app-desktop/gui/TrashNotification/TrashNotificationMessage.js
packages/app-desktop/gui/UpdateNotification/UpdateNotification.js
packages/app-desktop/gui/WebDavOidcLoginScreen.js
packages/app-desktop/gui/WindowCommandsAndDialogs/AppDialogs.js
packages/app-desktop/gui/WindowCommandsAndDialogs/ModalMessageOverlay.js
packages/app-desktop/gui/WindowCommandsAndDialogs/PluginDialogs.js
@@ -497,7 +509,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useSyncDialogState.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowCommands.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.js
packages/app-desktop/gui/dialogs.js
packages/app-desktop/gui/hooks/useDocument.js
packages/app-desktop/gui/hooks/useEffectDebugger.js
packages/app-desktop/gui/hooks/useElementHeight.js
packages/app-desktop/gui/hooks/useImperativeHandlerDebugger.js
@@ -530,6 +541,7 @@ packages/app-desktop/integration-tests/models/NoteEditorScreen.js
packages/app-desktop/integration-tests/models/NoteList.js
packages/app-desktop/integration-tests/models/SettingsScreen.js
packages/app-desktop/integration-tests/models/Sidebar.js
packages/app-desktop/integration-tests/multiWindow.spec.js
packages/app-desktop/integration-tests/noteList.spec.js
packages/app-desktop/integration-tests/pluginApi.spec.js
packages/app-desktop/integration-tests/resizableLayout.spec.js
@@ -551,6 +563,7 @@ packages/app-desktop/integration-tests/util/setMessageBoxResponse.js
packages/app-desktop/integration-tests/util/setSettingValue.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/integration-tests/util/waitForNextWindowMatching.js
packages/app-desktop/integration-tests/wcag.spec.js
packages/app-desktop/main-html.js
packages/app-desktop/main.js
@@ -579,10 +592,6 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
packages/app-desktop/services/plugins/types.js
packages/app-desktop/services/restart.js
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
packages/app-desktop/tools/bundleJs.js
packages/app-desktop/tools/copy7Zip.js
@@ -597,10 +606,12 @@ packages/app-desktop/utils/checkForUpdatesUtils.test.js
packages/app-desktop/utils/checkForUpdatesUtils.js
packages/app-desktop/utils/checkForUpdatesUtilsTestData.js
packages/app-desktop/utils/customProtocols/constants.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.content.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.plugins.test.js
packages/app-desktop/utils/customProtocols/handleCustomProtocols.js
packages/app-desktop/utils/customProtocols/registerCustomProtocols.js
packages/app-desktop/utils/getAssetPath.js
packages/app-desktop/utils/initReact.js
packages/app-desktop/utils/initializeCommandService.js
packages/app-desktop/utils/isSafeToOpen.test.js
packages/app-desktop/utils/isSafeToOpen.js
@@ -616,6 +627,7 @@ packages/app-mobile/commands/newNote.js
packages/app-mobile/commands/openItem.js
packages/app-mobile/commands/openNote.js
packages/app-mobile/commands/scrollToHash.js
packages/app-mobile/commands/util/goToFolder.js
packages/app-mobile/commands/util/goToNote.js
packages/app-mobile/commands/util/showResource.js
packages/app-mobile/components/BetaChip.js
@@ -659,13 +671,16 @@ packages/app-mobile/components/EditorToolbar/utils/isSelected.js
packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.js
packages/app-mobile/components/EditorToolbar/utils/toolbarButtonsFromState.js
packages/app-mobile/components/EditorToolbar/utils/useButtonSize.js
packages/app-mobile/components/EditorToolbar/utils/useSaveToolbarButtons.test.js
packages/app-mobile/components/EditorToolbar/utils/useSaveToolbarButtons.js
packages/app-mobile/components/EditorToolbar/utils/useToolbarEditorState.test.js
packages/app-mobile/components/EditorToolbar/utils/useToolbarEditorState.js
packages/app-mobile/components/ExtendedWebView/index.jest.js
packages/app-mobile/components/ExtendedWebView/index.js
packages/app-mobile/components/ExtendedWebView/index.web.js
packages/app-mobile/components/ExtendedWebView/types.js
packages/app-mobile/components/ExtendedWebView/utils/polyfillScrollFunctions.js
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
packages/app-mobile/components/FeedbackBanner.test.js
packages/app-mobile/components/FeedbackBanner.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
@@ -703,12 +718,13 @@ packages/app-mobile/components/NoteList.js
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.js
packages/app-mobile/components/ProfileSwitcher/useProfileConfig.js
packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.test.js
packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.js
packages/app-mobile/components/SafeAreaView.js
packages/app-mobile/components/ScreenHeader/Menu.js
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
packages/app-mobile/components/ScreenHeader/WarningBanner.js
packages/app-mobile/components/ScreenHeader/WarningBox.js
packages/app-mobile/components/ScreenHeader/WebBetaButton.js
packages/app-mobile/components/ScreenHeader/index.js
packages/app-mobile/components/SearchInput.js
packages/app-mobile/components/SelectDateTimeDialog.js
@@ -833,6 +849,8 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/Notes/TextWrapCalculator.js
packages/app-mobile/components/screens/ResourceScreen.js
packages/app-mobile/components/screens/SearchScreen/SearchBar.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
@@ -849,9 +867,10 @@ packages/app-mobile/components/screens/dropbox-login.js
packages/app-mobile/components/screens/encryption-config.test.js
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/folder.js
packages/app-mobile/components/screens/resourceScreenUtils.test.js
packages/app-mobile/components/screens/resourceScreenUtils.js
packages/app-mobile/components/screens/status.js
packages/app-mobile/components/screens/tags.js
packages/app-mobile/components/screens/webdav-oidc-login.js
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/testing/TestProviderStack.js
packages/app-mobile/components/voiceTyping/AudioRecordingBanner.js
@@ -872,6 +891,7 @@ packages/app-mobile/contentScripts/markdownEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/markdownEditorBundle/utils/useCodeMirrorPlugins.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.handleAnchorClick.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/types.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/addPluginAssets.js
@@ -951,6 +971,7 @@ packages/app-mobile/utils/image/fileToImage.web.js
packages/app-mobile/utils/image/getImageDimensions.js
packages/app-mobile/utils/image/resizeImage.js
packages/app-mobile/utils/initReact.js
packages/app-mobile/utils/initReact.web.js
packages/app-mobile/utils/initializeCommandService.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
@@ -1217,7 +1238,6 @@ packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.test.js
packages/lib/ObjectUtils.js
packages/lib/OidcApi.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
packages/lib/PoorManIntervals.js
@@ -1227,17 +1247,15 @@ packages/lib/SyncTargetFilesystem.js
packages/lib/SyncTargetJoplinCloud.js
packages/lib/SyncTargetJoplinServer.js
packages/lib/SyncTargetJoplinServerSAML.js
packages/lib/SyncTargetNextcloud.js
packages/lib/SyncTargetNone.js
packages/lib/SyncTargetOneDrive.js
packages/lib/SyncTargetRegistry.js
packages/lib/SyncTargetWebDAV.js
packages/lib/Synchronizer.js
packages/lib/TaskQueue.js
packages/lib/WebDavApi.js
packages/lib/WelcomeUtils.test.js
packages/lib/WelcomeUtils.js
packages/lib/array.js
packages/lib/base-oauth-node-utils.js
packages/lib/callbackUrlUtils.test.js
packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
@@ -1259,10 +1277,12 @@ packages/lib/commands/synchronize.js
packages/lib/commands/toggleAllFolders.test.js
packages/lib/commands/toggleAllFolders.js
packages/lib/commands/toggleEditorPlugin.js
packages/lib/components/Dialog.js
packages/lib/components/EncryptionConfigScreen/utils.test.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextDismissLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextReadMoreLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/useEditorTypeMigrationBanner.js
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
packages/lib/components/shared/NoteRevisionViewer/getHelpMessage.js
packages/lib/components/shared/NoteRevisionViewer/useDeleteHistoryClick.js
@@ -1285,6 +1305,7 @@ packages/lib/components/shared/reduxSharedMiddleware.js
packages/lib/components/shared/side-menu-shared.test.js
packages/lib/components/shared/side-menu-shared.js
packages/lib/database-driver-better-sqlite.js
packages/lib/database-driver.js
packages/lib/database.js
packages/lib/debug/DebugService.js
packages/lib/determineBaseAppDirs.js
@@ -1307,6 +1328,7 @@ packages/lib/fsDriver.test.js
packages/lib/geolocation-node.js
packages/lib/getAppName.test.js
packages/lib/getAppName.js
packages/lib/hooks/dom/useDocument.js
packages/lib/hooks/plugins/usePlugin.js
packages/lib/hooks/plugins/useVisiblePluginEditorViewIds.js
packages/lib/hooks/useAsyncEffect.js
@@ -1387,8 +1409,6 @@ packages/lib/models/utils/userData.test.js
packages/lib/models/utils/userData.js
packages/lib/net-utils.js
packages/lib/ntp.js
packages/lib/oidc-api-node-utils.js
packages/lib/onedrive-api-node-utils.js
packages/lib/onedrive-api.test.js
packages/lib/onedrive-api.js
packages/lib/path-utils.js
@@ -1401,7 +1421,9 @@ packages/lib/services/AlarmServiceDriverNode.js
packages/lib/services/BaseService.js
packages/lib/services/CommandService.test.js
packages/lib/services/CommandService.js
packages/lib/services/DecryptionWorker.test.js
packages/lib/services/DecryptionWorker.js
packages/lib/services/ExternalEditWatcher.test.js
packages/lib/services/ExternalEditWatcher.js
packages/lib/services/ExternalEditWatcher/utils.js
packages/lib/services/ItemChangeUtils.js
@@ -1489,6 +1511,7 @@ packages/lib/services/interop/InteropService_Importer_Md.test.js
packages/lib/services/interop/InteropService_Importer_Md.js
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
packages/lib/services/interop/InteropService_Importer_OneNote.postprocessHtml.test.js
packages/lib/services/interop/InteropService_Importer_OneNote.test.js
packages/lib/services/interop/InteropService_Importer_OneNote.js
packages/lib/services/interop/InteropService_Importer_Raw.test.js
@@ -1506,6 +1529,7 @@ packages/lib/services/keychain/KeychainServiceDriver.dummy.js
packages/lib/services/keychain/KeychainServiceDriver.electron.js
packages/lib/services/keychain/KeychainServiceDriver.node.js
packages/lib/services/keychain/KeychainServiceDriverBase.js
packages/lib/services/noteList/checkboxPieCss.js
packages/lib/services/noteList/defaultLeftToRightListRenderer.js
packages/lib/services/noteList/defaultListRenderer.js
packages/lib/services/noteList/defaultMultiColumnsRenderer.js
@@ -1521,6 +1545,7 @@ packages/lib/services/ocr/OcrService.js
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.test.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.js
packages/lib/services/ocr/utils/createAccessiblePdf.js
packages/lib/services/ocr/utils/filterOcrText.test.js
packages/lib/services/ocr/utils/filterOcrText.js
packages/lib/services/ocr/utils/types.js
@@ -1542,6 +1567,7 @@ packages/lib/services/plugins/api/JoplinCommands.js
packages/lib/services/plugins/api/JoplinContentScripts.js
packages/lib/services/plugins/api/JoplinData.js
packages/lib/services/plugins/api/JoplinFilters.js
packages/lib/services/plugins/api/JoplinFs.js
packages/lib/services/plugins/api/JoplinImaging.js
packages/lib/services/plugins/api/JoplinInterop.js
packages/lib/services/plugins/api/JoplinPlugins.js
@@ -1640,6 +1666,10 @@ packages/lib/services/share/ShareService.test.js
packages/lib/services/share/ShareService.js
packages/lib/services/share/invitationRespond.js
packages/lib/services/share/reducer.js
packages/lib/services/sortOrder/PerFolderSortOrderService.test.js
packages/lib/services/sortOrder/PerFolderSortOrderService.js
packages/lib/services/sortOrder/notesSortOrderUtils.test.js
packages/lib/services/sortOrder/notesSortOrderUtils.js
packages/lib/services/spellChecker/SpellCheckerService.js
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
packages/lib/services/style/cssToTheme.test.js
@@ -1692,6 +1722,7 @@ packages/lib/shim-init-node.js
packages/lib/shim.js
packages/lib/string-utils.test.js
packages/lib/string-utils.js
packages/lib/testing/dom-test-environment.js
packages/lib/testing/plugins/createTestPlugin.js
packages/lib/testing/share/makeMockShareInvitation.js
packages/lib/testing/share/mockShareService.js
@@ -1839,25 +1870,29 @@ packages/tools/checkLibPaths.test.js
packages/tools/checkLibPaths.js
packages/tools/convertThemesToCss.js
packages/tools/fuzzer/ActionRunner.js
packages/tools/fuzzer/ActionTracker.js
packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
packages/tools/fuzzer/Server.js
packages/tools/fuzzer/Fuzzer.js
packages/tools/fuzzer/cli.js
packages/tools/fuzzer/constants.js
packages/tools/fuzzer/ipc/Client.js
packages/tools/fuzzer/ipc/ClientPool.js
packages/tools/fuzzer/ipc/Server.js
packages/tools/fuzzer/model/ActionTracker.js
packages/tools/fuzzer/model/FolderRecord.js
packages/tools/fuzzer/model/NoteRecord.js
packages/tools/fuzzer/model/ResourceRecord.js
packages/tools/fuzzer/sync-fuzzer.js
packages/tools/fuzzer/model/Serializable.js
packages/tools/fuzzer/model/types.js
packages/tools/fuzzer/types.js
packages/tools/fuzzer/utils/ProgressBar.js
packages/tools/fuzzer/utils/SeededRandom.js
packages/tools/fuzzer/utils/diffSortedStringArrays.test.js
packages/tools/fuzzer/utils/diffSortedStringArrays.js
packages/tools/fuzzer/utils/extractResourceIds.js
packages/tools/fuzzer/utils/getBinaryDiffDebugMessage.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/hangingIndent.js
packages/tools/fuzzer/utils/logDiffDebug.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/randomId.test.js
packages/tools/fuzzer/utils/randomId.js
@@ -1904,6 +1939,7 @@ packages/tools/update-readme-contributors.js
packages/tools/update-readme-download.test.js
packages/tools/update-readme-download.js
packages/tools/update-readme-sponsors.js
packages/tools/updateCanary.js
packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.test.js
packages/tools/utils/discourse.js
@@ -1931,8 +1967,8 @@ packages/tools/website/utils/parser.js
packages/tools/website/utils/pressCarousel.js
packages/tools/website/utils/processTranslations.js
packages/tools/website/utils/render.js
packages/tools/website/utils/supportedLocales.js
packages/tools/website/utils/types.js
packages/whisper-voice-typing/src/index.js
packages/whisper-voice-typing/src/specs/Whisper.nitro.js
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD

View File

@@ -0,0 +1,24 @@
# Resolves an issue in which notes and attachments larger than 16 KB
# could become corrupted during the upload process.
# See https://github.com/laurent22/joplin/issues/14343
diff --git a/src/parsers/JSON.js b/src/parsers/JSON.js
index 9a096c25778c7c68be1ddd9dd78faa85bd1d8ec3..6d6bfd2d3789313a7adc8966ab8e58c3d3167356 100644
--- a/src/parsers/JSON.js
+++ b/src/parsers/JSON.js
@@ -12,13 +12,14 @@ class JSONParser extends Transform {
}
_transform(chunk, encoding, callback) {
- this.chunks.push(String(chunk)); // todo consider using a string decoder
+ this.chunks.push(chunk); // type: Uint8Array
callback();
}
_flush(callback) {
try {
- const fields = JSON.parse(this.chunks.join(''));
+ const data = Buffer.concat(this.chunks);
+ const fields = JSON.parse(data.toString('utf-8'));
Object.keys(fields).forEach((key) => {
const value = fields[key];
this.push({ key, value });

View File

@@ -658,13 +658,84 @@ footer .bottom-links-row p {
}
.language-switcher {
display: inline;
display: inline-block;
position: relative;
margin-left: 20px;
}
.language-switcher > button {
border: none;
background-color: transparent;
color: #0557ba;
cursor: pointer;
padding: 0;
}
.language-switcher > button:hover {
opacity: 0.8;
}
.language-switcher .dropdown-menu {
min-width: 100px;
padding: 5px 0 !important;
margin: 0 !important;
text-align: left;
}
.language-switcher .dropdown-menu li {
padding: 0 !important;
margin: 0 !important;
list-style: none;
}
.language-switcher .dropdown-item {
color: #333 !important;
padding: 8px 15px !important;
margin: 0 !important;
display: block;
text-align: left;
width: 100%;
box-sizing: border-box;
}
.language-switcher .dropdown-item.active {
background-color: #0557ba !important;
color: #fff !important;
margin: 0 !important;
border-radius: 0 !important;
}
.language-switcher .dropdown-item:hover:not(.active) {
background-color: #f0f0f0;
}
/* Language switcher on front page (blue background) */
.navbar-frontpage .language-switcher > button {
color: #fff;
}
/* Mobile language section */
.menu-mobile-language {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.mobile-menu-language-label {
color: #90b1d9;
margin-bottom: 10px;
font-size: 0.9em;
}
.mobile-language-link {
display: inline-block;
margin: 0 10px;
padding: 5px 15px;
border-radius: 5px;
}
.mobile-language-link.active {
background-color: rgba(255, 255, 255, 0.2);
}
.joplin-cloud-feature-list .feature-description {
@@ -1280,11 +1351,7 @@ footer .bottom-links-row p {
ENGLISH VERSION
*****************************************************************/
:lang(en-gb) #made-in-france-section {
display: none;
}
:lang(en-gb) .top-section-img-cn {
:not(:lang(zh-cn)) .top-section-img-cn {
display: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -124,7 +124,53 @@ async function setupDownloadPage() {
}
}
// Supported locale path prefixes (language code -> URL path)
// Most languages use their code directly (fr, de), with exceptions mapped here
const localePathOverrides = {
'zh': 'cn',
};
// List of supported language codes
const supportedLanguages = ['fr', 'de', 'zh'];
function getLocalePath(langCode) {
const pathPrefix = localePathOverrides[langCode] || langCode;
return '/' + pathPrefix;
}
function setupLocaleRedirect() {
// Only redirect on the front page (root path or index.html)
const path = window.location.pathname;
const isRootPage = path === '/' || path === '/index.html' || path === '';
if (!isRootPage) return;
// Check if user has explicitly chosen to stay on current locale
const localePreference = (localStorage.getItem('joplin-locale-preference') || '').toLowerCase();
if (localePreference === 'en') return;
// Get user's preferred language from browser
const browserLang = (navigator.language || navigator.userLanguage || '').toLowerCase();
// Extract the base language code (e.g., 'fr' from 'fr-ca')
const langCode = browserLang.split('-')[0];
// Check if we support this language
if (!supportedLanguages.includes(langCode)) return;
window.location.href = getLocalePath(langCode) + '/';
}
// Allow users to switch language and remember their preference
function setLocalePreference(locale, url) {
localStorage.setItem('joplin-locale-preference', locale);
window.location.href = url;
}
// Expose globally for language switcher links
window.setLocalePreference = setLocalePreference;
$(function () {
setupMobileMenu();
setupLocaleRedirect();
void setupDownloadPage();
});

View File

@@ -0,0 +1,164 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0.1\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:10
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:14
msgid "/month"
msgstr "/Monat"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:22
msgid "/year"
msgstr "/Jahr"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:71
msgid "<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."
msgstr "<a href=\"https://joplincloud.com\">Joplin Cloud</a> ermöglicht es Ihnen, Ihre Notizen geräteübergreifend zu synchronisieren. Sie können Notizen veröffentlichen und mit Freunden, Familie oder Kollegen gemeinsam an Notizbüchern arbeiten."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:206
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr "Passen Sie es <span class=\"frame-bg frame-bg-yellow-lg\">an</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:105
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span>-Notizen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr "100 % <span class=\"frame-bg frame-bg-yellow-lg\">Ihre Daten</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:299
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr "Eine <span class=\"frame-bg frame-bg-yellow-lg\">französische</span> Alternative"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:237
msgid "Access your notes from your computer, phone or tablet by synchronising with various services, including Joplin Cloud, Dropbox and OneDrive. The app is available on Windows, macOS, Linux, Android and iOS. A terminal app is also available!"
msgstr "Greifen Sie von Ihrem Computer, Smartphone oder Tablet auf Ihre Notizen zu, indem Sie sie mit verschiedenen Diensten wie Joplin Cloud, Dropbox und OneDrive synchronisieren. Die App ist für Windows, macOS, Linux, Android und iOS verfügbar. Eine Terminal-App ist ebenfalls verfügbar!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:121
msgid "Already have a Joplin Cloud account? <a href=\"https://joplincloud.com\">Login now</a>"
msgstr "Sie haben bereits ein Joplin-Cloud-Konto? <a href=\"https://joplincloud.com\">Jetzt anmelden</a>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:209
msgid "Customise the app with plugins, custom themes and multiple text editors (Rich Text or Markdown). Or create your own scripts and plugins using the Extension API."
msgstr "Passen Sie die App mit Plugins, eigenen Designs und verschiedenen Texteditoren (Rich Text oder Markdown) an. Oder erstellen Sie mit der Erweiterungs-API eigene Skripte und Plugins."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:243
msgid "Download it now"
msgstr "Jetzt herunterladen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:113
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:64
msgid "Download the app"
msgstr "App herunterladen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:214
msgid "Find out more"
msgstr "Mehr erfahren"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:55
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr "Befreien Sie Ihre <span class=\"frame-bg frame-bg-blue\">Notizen</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:176
msgid "Get the clipper"
msgstr "Clipper herunterladen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:108
msgid "Images, videos, PDFs and audio files are supported. Create math expressions and diagrams directly from the app. Take photos with the mobile app and save them to a note."
msgstr "Bilder, Videos, PDFs und Audiodateien werden unterstützt. Erstellen Sie mathematische Ausdrücke und Diagramme direkt in der App. Machen Sie Fotos mit der mobilen App und speichern Sie sie in einer Notiz."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:328
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr "In der <span class=\"frame-bg frame-bg-yellow\">Presse</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:68
msgid "Joplin Cloud"
msgstr "Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:302
msgid "Joplin Cloud is based in France. This means your data is protected by strict European Union privacy laws. In addition, Joplin Cloud implements strong end-to-end encryption so that not even us can have access to your data."
msgstr "Joplin Cloud hat seinen Sitz in Frankreich. Das bedeutet, dass Ihre Daten durch strenge Datenschutzgesetze der Europäischen Union geschützt sind. Darüber hinaus verwendet Joplin Cloud eine starke Ende-zu-Ende-Verschlüsselung, sodass nicht einmal wir Zugriff auf Ihre Daten haben."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:58
msgid "Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device."
msgstr "Joplin ist eine Open-Source-App für Notizen. Halten Sie Ihre Gedanken fest und greifen Sie sicher von jedem Gerät darauf zu."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:79
msgid "Joplin Server Business"
msgstr "Joplin Server Business"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:82
msgid "Joplin Server Business is a synchronisation server that you can install on your own infrastructure, so that your data remains private and secure within your business."
msgstr "Joplin Server Business ist ein Synchronisationsserver, den Sie auf Ihrer eigenen Infrastruktur installieren können, sodass Ihre Daten innerhalb Ihres Unternehmens privat und sicher bleiben."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:263
msgid "More about E2EE"
msgstr "Mehr zu E2EE"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:392
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr "Unsere <span class=\"frame-bg frame-bg-blue-lg\">Sponsoren</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:46
msgid "Our synchronisation and sharing <span class=\"frame-bg frame-bg-yellow\">solutions</span>"
msgstr "Unsere <span class=\"frame-bg frame-bg-yellow\">Lösungen</span> für Synchronisation und Zusammenarbeit"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:91
msgid "Pay Monthly"
msgstr "Monatlich zahlen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:98
msgid "Pay Yearly"
msgstr "Jährlich zahlen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:168
msgid "Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr "Speichern Sie <span class=\"frame-bg frame-bg-blue\">Webseiten</span> <br>als Notizen"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:66
msgid "Sign up with Joplin Cloud"
msgstr "Mit Joplin Cloud registrieren"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid "Synchronise and share your notes with our range of plans."
msgstr "Synchronisieren und teilen Sie Ihre Notizen mit unseren verschiedenen Tarifen."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:395
msgid "Thank you for your support!"
msgstr "Vielen Dank für Ihre Unterstützung!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:258
msgid "The app is open source and your notes are saved to an open format, so you'll always have access to them. Uses End-To-End Encryption (E2EE) to secure your notes and ensure no-one but yourself can access them."
msgstr "Die App ist Open Source und Ihre Notizen werden in einem offenen Format gespeichert, sodass Sie jederzeit Zugriff darauf haben. Sie verwendet Ende-zu-Ende-Verschlüsselung (E2EE), um Ihre Notizen zu schützen und sicherzustellen, dass niemand außer Ihnen darauf zugreifen kann."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:145
msgid "Try it now"
msgstr "Jetzt ausprobieren"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:171
msgid "Use the web clipper extension, available on Chrome and Firefox, to save web pages or take screenshots as notes."
msgstr "Verwenden Sie die Web-Clipper-Erweiterung für Chrome und Firefox, um Webseiten zu speichern oder Screenshots als Notizen zu erstellen."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:139
msgid "With Joplin Cloud, share your notes with your friends, family or colleagues and collaborate on them."
msgstr "Mit Joplin Cloud können Sie Ihre Notizen mit Freunden, Familie oder Kollegen teilen und gemeinsam daran arbeiten."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr "Gemeinsam <span class=\"frame-bg frame-bg-yellow\">arbeiten</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:142
msgid "You can also publish a note to the internet and share the URL with others."
msgstr "Sie können eine Notiz auch im Internet veröffentlichen und die URL mit anderen teilen."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:234
msgid "Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you are"
msgstr "Ihre Notizen, <span class=\"frame-bg frame-bg-blue-lg\">überall</span>, wo Sie sind"

View File

@@ -1,8 +1,6 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr_FR\n"
@@ -11,18 +9,235 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0.1\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:63
msgid "Download the app"
msgstr "Télécharger l'application"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:10
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:14
msgid "/month"
msgstr "/mois"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:22
msgid "/year"
msgstr "/an"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:71
msgid ""
"<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."
msgstr ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> vous permet de "
"synchroniser vos notes entre vos appareils. Il vous permet également de "
"publier des notes et de collaborer sur des carnets avec vos amis, votre "
"famille ou vos collègues."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:206
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr "<span class=\"frame-bg frame-bg-yellow-lg\">Personnalisez</span>-la"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:105
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr "Notes <span class=\"frame-bg frame-bg-yellow\">multimédia</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr "100 % <span class=\"frame-bg frame-bg-yellow-lg\">vos données</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:299
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr ""
"Une alternative <span class=\"frame-bg frame-bg-yellow-lg\">française</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:237
msgid ""
"Access your notes from your computer, phone or tablet by synchronising with "
"various services, including Joplin Cloud, Dropbox and OneDrive. The app is "
"available on Windows, macOS, Linux, Android and iOS. A terminal app is also "
"available!"
msgstr ""
"Accédez à vos notes depuis votre ordinateur, téléphone ou tablette en les "
"synchronisant avec différents services, notamment Joplin Cloud, Dropbox et "
"OneDrive. L’application est disponible sur Windows, macOS, Linux, Android et "
"iOS. Une application en ligne de commande est également disponible !"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:121
msgid ""
"Already have a Joplin Cloud account? <a href=\"https://joplincloud.com"
"\">Login now</a>"
msgstr ""
"Vous avez déjà un compte Joplin Cloud ? <a href=\"https://joplincloud.com"
"\">Connectez-vous maintenant</a>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:209
msgid ""
"Customise the app with plugins, custom themes and multiple text editors "
"(Rich Text or Markdown). Or create your own scripts and plugins using the "
"Extension API."
msgstr ""
"Personnalisez l’application avec des extensions, des thèmes personnalisés et "
"plusieurs éditeurs de texte (texte enrichi ou Markdown). Ou créez vos "
"propres scripts et extensions grâce à l’API d’extension."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:243
msgid "Download it now"
msgstr "Téléchargez maintenant"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:113
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:64
msgid "Download the app"
msgstr "Télécharger l'appli"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:214
msgid "Find out more"
msgstr "En savoir plus"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:55
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr "Libérez vos <span class=\"frame-bg frame-bg-blue\">notes</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
msgid "Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device."
msgstr "Joplin est une application libre de prise de notes. Capturez vos pensées et accédez-y de façon sécurisé depuis n'importe quel appareil."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:176
msgid "Get the clipper"
msgstr "Obtenir le clipper"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:65
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:108
msgid ""
"Images, videos, PDFs and audio files are supported. Create math expressions "
"and diagrams directly from the app. Take photos with the mobile app and save "
"them to a note."
msgstr ""
"Les images, vidéos, PDF et fichiers audio sont pris en charge. Créez des "
"expressions mathématiques et des diagrammes directement depuis "
"l’application. Prenez des photos avec l’application mobile et enregistrez-"
"les dans une note."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:328
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr "Dans la <span class=\"frame-bg frame-bg-yellow\">presse</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:68
msgid "Joplin Cloud"
msgstr "Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:302
msgid ""
"Joplin Cloud is based in France. This means your data is protected by strict "
"European Union privacy laws. In addition, Joplin Cloud implements strong end-"
"to-end encryption so that not even us can have access to your data."
msgstr ""
"Joplin Cloud est basé en France. Cela signifie que vos données sont "
"protégées par les lois strictes de l’Union européenne en matière de "
"confidentialité. De plus, Joplin Cloud met en œuvre un chiffrement de bout "
"en bout robuste afin que même nous ne puissions pas accéder à vos données."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:58
msgid ""
"Joplin is an open source note-taking app. Capture your thoughts and securely "
"access them from any device."
msgstr ""
"Joplin est une application libre de prise de notes. Capturez vos pensées et "
"accédez-y de façon sécurisée depuis n'importe quel appareil."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:79
msgid "Joplin Server Business"
msgstr "Joplin Server Business"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:82
msgid ""
"Joplin Server Business is a synchronisation server that you can install on "
"your own infrastructure, so that your data remains private and secure within "
"your business."
msgstr ""
"Joplin Server Business est un serveur de synchronisation que vous pouvez "
"installer sur votre propre infrastructure, afin que vos données restent "
"privées et sécurisées au sein de votre entreprise."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:263
msgid "More about E2EE"
msgstr "En savoir plus sur le chiffrement de bout en bout"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:392
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr "Nos <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:46
msgid ""
"Our synchronisation and sharing <span class=\"frame-bg frame-bg-yellow"
"\">solutions</span>"
msgstr ""
"Nos <span class=\"frame-bg frame-bg-yellow\">solutions</span> de "
"synchronisation et de partage"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:91
msgid "Pay Monthly"
msgstr "Payer mensuellement"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:98
msgid "Pay Yearly"
msgstr "Payer annuellement"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:168
msgid ""
"Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr ""
"Enregistrez des <span class=\"frame-bg frame-bg-blue\">pages web</span> "
"<br>comme notes"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:66
msgid "Sign up with Joplin Cloud"
msgstr "S'inscrire sur Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid "Synchronise and share your notes with our range of plans."
msgstr "Synchronisez et partagez vos notes grâce à notre gamme d’offres."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:395
msgid "Thank you for your support!"
msgstr "Merci pour votre soutien !"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:258
msgid ""
"The app is open source and your notes are saved to an open format, so you'll "
"always have access to them. Uses End-To-End Encryption (E2EE) to secure your "
"notes and ensure no-one but yourself can access them."
msgstr ""
"L’application est open source et vos notes sont enregistrées dans un format "
"ouvert, vous aurez donc toujours accès à celles-ci. Elle utilise le "
"chiffrement de bout en bout (E2EE) pour sécuriser vos notes et garantir que "
"personne d’autre que vous ne puisse y accéder."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:145
msgid "Try it now"
msgstr "Essayez-la maintenant"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:171
msgid ""
"Use the web clipper extension, available on Chrome and Firefox, to save web "
"pages or take screenshots as notes."
msgstr ""
"Utilisez l’extension Web Clipper, disponible sur Chrome et Firefox, pour "
"enregistrer des pages web ou des captures d’écran comme notes."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:139
msgid ""
"With Joplin Cloud, share your notes with your friends, family or colleagues "
"and collaborate on them."
msgstr ""
"Avec Joplin Cloud, partagez vos notes avec vos amis, votre famille ou vos "
"collègues et collaborez dessus."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr "Travaillez <span class=\"frame-bg frame-bg-yellow\">ensemble</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:142
msgid ""
"You can also publish a note to the internet and share the URL with others."
msgstr ""
"Vous pouvez également publier une note sur Internet et partager son URL avec "
"d’autres."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:234
msgid ""
"Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you "
"are"
msgstr ""
"Vos notes, <span class=\"frame-bg frame-bg-blue-lg\">partout</span> où vous "
"êtes"

View File

@@ -9,194 +9,213 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0.1\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:13
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:9
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:10
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:14
msgid "/month"
msgstr "/月"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:19
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:22
msgid "/year"
msgstr "/年"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:8
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:71
msgid ""
"<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."
msgstr ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> 允许您在不同设备上同步"
"您的笔记。它还可以让您发布笔记,并与您的朋友、家人或同事在笔记本上进行协作。"
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> 允许您在不同设备之间同步笔记。"
"它还支持发布笔记,并与朋友、家人或同事协作共享笔记本。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:205
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:206
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr "<span class=\"frame-bg frame-bg-yellow-lg\">定制</span>它 根据您的需要"
msgstr "<span class=\"frame-bg frame-bg-yellow-lg\">自定义</span>它"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:104
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:105
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr "<span class=\"frame-bg frame-bg-yellow\">多媒体</span>说明"
msgstr "<span class=\"frame-bg frame-bg-yellow\">多媒体</span>笔记"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:256
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr "百分之百<span class=\"frame-bg frame-bg-yellow-lg\">你的数据</span>"
msgstr "100% <span class=\"frame-bg frame-bg-yellow-lg\">属于你的数据</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:299
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr "一个<span class=\"frame-bg frame-bg-yellow-lg\">法国</span>替代方案"
msgstr "一个<span class=\"frame-bg frame-bg-yellow-lg\">法国</span>替代方案"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:236
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:237
msgid ""
"Access your notes from your computer, phone or tablet by synchronising with "
"various services, including Joplin Cloud, Dropbox and OneDrive. The app is "
"available on Windows, macOS, Linux, Android and iOS. A terminal app is also "
"available!"
msgstr ""
"通过与各种服务同步,包括Joplin Cloud、DropboxOneDrive,从你的电脑、手机或平"
"板电脑访问你的笔记。该应用程序可在Windows、macOS、Linux、Android和iOS上使用。"
"终端应用也可使用!"
"通过与包括 Joplin Cloud、DropboxOneDrive 在内的多种服务同步,"
"您可以在电脑、手机或平板上访问笔记。该应用支持 Windows、macOS、Linux、Android 和 iOS。"
"同时还提供终端版本应用!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:121
msgid ""
"Already have a Joplin Cloud account? <a href=\"https://joplincloud.com"
"\">Login now</a>"
"Already have a Joplin Cloud account? <a href=\"https://"
"joplincloud.com\">Login now</a>"
msgstr ""
"已经拥有 Joplin Cloud 账户?<a href=\"https://joplincloud.com\">立即登录</a>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:208
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:209
msgid ""
"Customise the app with plugins, custom themes and multiple text editors "
"(Rich Text or Markdown). Or create your own scripts and plugins using the "
"Extension API."
msgstr ""
"插件、自定义主题和多文本编辑器(富文本或马克顿)来定制该应用程序。或者使"
"用扩展API创建自己的脚本和插件。"
"通过插件、自定义主题和多文本编辑器(富文本或 Markdown)来自定义应用。"
"您也可以使用扩展 API 创建自己的脚本和插件。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:242
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:243
msgid "Download it now"
msgstr "下载该应用程序"
msgstr "立即下载"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:112
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:63
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:113
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:64
msgid "Download the app"
msgstr "下载应用程序"
msgstr "下载应用"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:213
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:214
msgid "Find out more"
msgstr "了解更多"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:55
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr "释放你的<span class=\"frame-bg frame-bg-blue\">笔记</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:175
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:176
msgid "Get the clipper"
msgstr "获取剪子"
msgstr "获取网页剪藏器"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:107
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:108
msgid ""
"Images, videos, PDFs and audio files are supported. Create math expressions "
"and diagrams directly from the app. Take photos with the mobile app and save "
"them to a note."
msgstr ""
"Joplin,由于其起源和设计,适应并尊重中国的标准和规则。这保证了您的使用不受限"
"制,以及您的使用数据的完全透明和安全。"
"支持图片、视频、PDF 和音频文件。可在应用内直接创建数学公式和图表。"
"还可通过移动端拍照并保存到笔记中。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:328
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr ""
msgstr "媒体<span class=\"frame-bg frame-bg-yellow\">报道</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:5
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
msgstr "乔普林云<span class=\"frame-bg frame-bg-yellow\">计划</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:68
msgid "Joplin Cloud"
msgstr "Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:302
msgid ""
"Joplin Cloud is based in France. This means your data is protected by strict "
"European Union privacy laws. In addition, Joplin Cloud implements strong end-"
"to-end encryption so that not even us can have access to your data."
msgstr ""
"Joplin Cloud 位于法国这意味着您的数据受到严格的欧盟隐私法保护。 此外,"
"Joplin Cloud 实施了强大的端到端加密,因此即使是我们也无法访问您的数据。"
"Joplin Cloud 位于法国这意味着您的数据受到严格的欧盟隐私法保护。"
"此外,Joplin Cloud 采用强大的端到端加密技术,确保连我们也无法访问您的数据。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:58
msgid ""
"Joplin is an open source note-taking app. Capture your thoughts and securely "
"access them from any device."
msgstr ""
"Joplin是一开源的记事本应用程序。捕捉你的想法并从任何设备上安全访问它们。"
"Joplin 是一开源笔记应用。随时记录想法,并可在任何设备上安全访问。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
msgid "More about E2EE"
msgstr "关于E2EE的更多信息"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:79
msgid "Joplin Server Business"
msgstr "Joplin Server 商业版"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:82
msgid ""
"Joplin Server Business is a synchronisation server that you can install on "
"your own infrastructure, so that your data remains private and secure within "
"your business."
msgstr ""
"Joplin Server 商业版是一款可部署在您自有基础设施上的同步服务器,"
"确保您的数据在企业内部保持私密与安全。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:23
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:263
msgid "More about E2EE"
msgstr "了解更多关于 E2EE"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:392
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr "我们的<span class=\"frame-bg frame-bg-blue-lg\">赞助商</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:46
msgid ""
"Our synchronisation and sharing <span class=\"frame-bg frame-bg-"
"yellow\">solutions</span>"
msgstr ""
"我们的同步与共享<span class=\"frame-bg frame-bg-yellow\">解决方案</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:91
msgid "Pay Monthly"
msgstr "月度"
msgstr "按月付费"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:30
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:98
msgid "Pay Yearly"
msgstr "每年一次"
msgstr "按年付费"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:167
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:168
msgid ""
"Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr "保存<span class=\"frame-bg frame-bg-blue\">网页</span> <br>为笔记"
msgstr "<span class=\"frame-bg frame-bg-blue\">网页</span><br>保存为笔记"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:65
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:66
msgid "Sign up with Joplin Cloud"
msgstr "与乔布林云签约"
msgstr "注册 Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid "Synchronise and share your notes with our range of plans."
msgstr "通过我们的多种方案同步并共享您的笔记。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:395
msgid "Thank you for your support!"
msgstr ""
msgstr "感谢您的支持!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:258
msgid ""
"The app is open source and your notes are saved to an open format, so you'll "
"always have access to them. Uses End-To-End Encryption (E2EE) to secure your "
"notes and ensure no-one but yourself can access them."
msgstr ""
"该应用程序是开源的,你的笔记被保存为开放格式,所以你将永远可以访问它们。使"
"用端端加密(E2EE)保护的笔记,确保除了你自己之外没有人可以访问它们。"
"该应用为开源软件,笔记以开放格式保存,确保您始终可以访问。"
"用端端加密(E2EE)保护的笔记,确保只有您本人可以访问。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:144
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:145
msgid "Try it now"
msgstr "现在就试试吧"
msgstr "立即体验"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:170
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:171
msgid ""
"Use the web clipper extension, available on Chrome and Firefox, to save web "
"pages or take screenshots as notes."
msgstr "使用Chrome和Firefox上的web clipper扩展,可以保存网页或截图作为笔记。"
msgstr ""
"使用适用于 Chrome 和 Firefox 的网页剪藏扩展,将网页或截图保存为笔记。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:139
msgid ""
"With Joplin Cloud, share your notes with your friends, family or colleagues "
"and collaborate on them."
msgstr "通过乔普林云,与你的朋友、家人或同事分享你的笔记,并进行合作。"
msgstr ""
"通过 Joplin Cloud,与朋友、家人或同事共享笔记并协作编辑。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:137
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr "<span class=\"frame-bg frame-bg-yellow\">一起</span>工作"
msgstr "<span class=\"frame-bg frame-bg-yellow\">协作</span>工作"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:141
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:142
msgid ""
"You can also publish a note to the internet and share the URL with others."
msgstr "您还可以将笔记发布到 Internet 并与他人共享 URL。"
msgstr "您还可以将笔记发布到互联网,并与他人分享链接。"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:233
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:234
msgid ""
"Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you "
"are"
msgstr ""
"的笔记<span class=\"frame-bg frame-bg-blue-lg\">你在哪里都可以</span>"
#~ msgid ""
#~ "Joplin, due to its origin and design, adapts and respects Chinese "
#~ "standards and rules. This guarantees your unrestricted use and complete "
#~ "transparency and security of your usage data."
#~ msgstr ""
#~ "Joplin,由于其起源和设计,适应并尊重中国的标准和规则。这保证了您的使用不受"
#~ "限制,以及您的使用数据的完全透明和安全。"
"无论身在何处,您的笔记<span class=\"frame-bg frame-bg-blue-lg\">随时可达</span>"

View File

@@ -1,4 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Sun, 11 Jan 2026 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><item><title><![CDATA[What's new in Joplin 3.5]]></title><description><![CDATA[<h2>Improvements across desktop and mobile<a name="improvements-across-desktop-and-mobile" href="#improvements-across-desktop-and-mobile" class="heading-anchor">🔗</a></h2>
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Mon, 23 Feb 2026 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate><item><title><![CDATA[Introducing our Warrant Canary]]></title><description><![CDATA[<p>We have introduced a publicly signed warrant canary for Joplin.</p>
<p>A warrant canary is a regularly updated statement confirming that, as of the stated date, the project has not received secret legal orders, gag orders, or demands requiring the introduction of backdoors into the software or its infrastructure.</p>
<p>The canary is:</p>
<ul>
<li>
<p>Cryptographically signed using a dedicated OpenPGP key</p>
</li>
<li>
<p>Updated every 60 days</p>
</li>
<li>
<p>Published in plain text for independent verification</p>
</li>
</ul>
<p>If the canary is not updated within its stated validity window, it should be considered expired.</p>
<p>You can view and verify the current canary here:</p>
<p><a href="https://raw.githubusercontent.com/laurent22/joplin/refs/heads/dev/readme/canary.txt">https://raw.githubusercontent.com/laurent22/joplin/refs/heads/dev/readme/canary.txt</a></p>
<p>With additional information on how it is generated and managed there:</p>
<p><a href="https://github.com/laurent22/joplin/blob/dev/readme/canary.md">https://github.com/laurent22/joplin/blob/dev/readme/canary.md</a></p>
<p>This measure is intended to improve transparency and provide an additional signal to the community. It does not prevent legal orders, but it helps ensure that any material change in our legal status cannot occur silently.</p>
]]></description><link>https://joplinapp.org/news/20260223-warrant-canary</link><guid isPermaLink="false">20260223-warrant-canary</guid><pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Joplin will come preloaded on the HMD Terra M]]></title><description><![CDATA[<div style="overflow: auto;">
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260210-hmd-joplin-logo.png" width="200px" style="float: left; margin-right: 16px; margin-bottom: 16px;"/>
<p>We’re happy to announce a collaboration with <a href="https://www.hmdsecure.com/">HMD Secure</a>, who will preload Joplin on their upcoming device, the HMD Terra M.</p>
<p>This partnership brings Joplin to a new class of rugged, professional devices built for instant reliable communication, and reflects a shared focus on reliability, security, and long-term use.</p>
</div>
<h2>About HMD Secure<a name="about-hmd-secure" href="#about-hmd-secure" class="heading-anchor">🔗</a></h2>
<p>HMD Secure Oy is a subsidiary of HMD (Human Mobile Devices), the largest European smartphone manufacturer. Headquartered in Finland, HMD Secure develops rugged, sovereign, and secure solutions for governments, defence, public safety, enterprise, and critical infrastructure.</p>
<p>Built on a foundation of European R&amp;D and enhanced supply chain traceability and security, HMD Secure offers organisations a trusted platform for sovereignty, resilience, and long-term control.</p>
<h2>About the HMD Terra M<a name="about-the-hmd-terra-m" href="#about-the-hmd-terra-m" class="heading-anchor">🔗</a></h2>
<p>The <a href="https://www.hmdsecure.com/hmd-terra-m">HMD Terra M</a> is a compact, ultra-rugged smart feature phone delivered as a fully managed, mission-critical communications solution. Designed for professionals operating in demanding environments, it combines MIL-STD-810H and IP68/IP69K durability with instant Push-to-Talk, programmable PTT and emergency keys, loud high-output audio, and long battery life.</p>
<p>Built for rapid enterprise deployment, Terra M supports modern connectivity including dual SIM and eSIM, enterprise-grade MDM, and secure applications—enabling organisations to deploy, manage, and scale frontline communications reliably from day one.</p>
<h2>Why Joplin on the Terra M<a name="why-joplin-on-the-terra-m" href="#why-joplin-on-the-terra-m" class="heading-anchor">🔗</a></h2>
<p>Joplin’s <strong>offline-first design</strong>, <strong>end-to-end encryption</strong>, and focus on <strong>data ownership</strong> make it a natural fit for a device built to be trusted in the field. With Joplin preloaded, Terra M users can securely capture notes, procedures, and checklists from day one, even in challenging conditions.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260210-hmd-terra-m.jpg" alt="The HMD Terra M phone"></p>
]]></description><link>https://joplinapp.org/news/20260210-hmd-terra-m</link><guid isPermaLink="false">20260210-hmd-terra-m</guid><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[What's new in Joplin 3.5]]></title><description><![CDATA[<h2>Improvements across desktop and mobile<a name="improvements-across-desktop-and-mobile" href="#improvements-across-desktop-and-mobile" class="heading-anchor">🔗</a></h2>
<h3>More stable and consistent Markdown editing<a name="more-stable-and-consistent-markdown-editing" href="#more-stable-and-consistent-markdown-editing" class="heading-anchor">🔗</a></h3>
<p>The Markdown editor has been refined to feel more stable and closer to the final rendered view. Headings in the editor now more closely match how they appear when viewing a note, reducing the visual jump between editing and reading. Layout issues have also been addressed so elements like rendered checkboxes and images no longer cause the editor to shift unexpectedly while typing.</p>
<p>The ABC music notation plugin appeared to be popular but had some limitations. With this new version, ABC is now part of the app, which means it can now work from published notes, and from the Rich Text editor!</p>
@@ -494,34 +528,4 @@ sys 0m38.013s</p>
]]></description><link>https://joplinapp.org/news/20230508-release-2-10</link><guid isPermaLink="false">20230508-release-2-10</guid><pubDate>Wed, 10 May 2023 12:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 2.10</twitter-text></item><item><title><![CDATA[Joplin will participate in JdLL 2023!]]></title><description><![CDATA[<p>On 1 and 2 April 2023, we will have a stand for Joplin at the <a href="https://www.jdll.org/">Journées du Logiciel Libre</a> in Lyon, France. The JdLL has been taking place in Lyon for 24 years and is a popular open source conference in France. We had a stand in 2020 and 2021 but that was cancelled due to Covid, so this year is a first for Joplin!</p>
<p>Admission is free, so don't hesitate to come and meet us, exchange ideas and learn more about Joplin!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230202-jdll.jpg" alt="Joplin at JdLL 2023"></p>
]]></description><link>https://joplinapp.org/news/20230302-jdll-2023</link><guid isPermaLink="false">20230302-jdll-2023</guid><pubDate>Thu, 02 Mar 2023 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Introducing the "GitHub Actions Raw Log Viewer" extension for Chrome]]></title><description><![CDATA[<p>If you've ever used GitHub Actions, you will find that they provide by default a nice coloured output for the log. It looks good and it's even interactive! (You can click to collapse/expand blocks of text) But unfortunately it doesn't scale to large workflows, like we have for Joplin - the log can freeze and it will take forever to search for something. Indeed searching is done in &quot;real time&quot;... which mostly means it will freeze for a minute or two for each letter you type in the search box. Not great.</p>
<p>Thankfully GitHub provides an alternative access: the raw logs. This is much better because they will open as plain text, without any styling or JS magic, which means you can use the browser native search and it will be fast.</p>
<p>But now the problem is that raw logs look like this:</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-ga-raw-log.png" alt="Raw log without extension"></p>
<p>While it's not impossible to read, all colours that would display nicely in a terminal are gone and replaced by <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI codes</a>. You can find what you need in there but it's not particularly easy.</p>
<p>This is where the new <strong>GitHub Action Raw Log Viewer</strong> extension for Chrome can help. It will parse your raw log and convert the ANSI codes to proper colours. This results in a much more readable rendering:</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-ga-raw-log-colored.png" alt="Raw log with extension"></p>
<p>The extension is fast even for very large logs and it's of course easy to search for text since it simply works with your browser built-in search.</p>
<p>The extension is open source, with the code available here: <a href="https://github.com/laurent22/github-actions-logs-extension">https://github.com/laurent22/github-actions-logs-extension</a></p>
<p>And to install it, follow this link:</p>
<p><a href="https://chrome.google.com/webstore/detail/github-action-raw-log-vie/lgejlnoopmcdglhfjblaeldbcfnmjddf"><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-extension-get-it-now.png" alt="Download GitHub Action Raw Log Viewer extension"></a></p>
]]></description><link>https://joplinapp.org/news/20230116-github-actions-log-viewer</link><guid isPermaLink="false">20230116-github-actions-log-viewer</guid><pubDate>Mon, 16 Jan 2023 00:00:00 GMT</pubDate><twitter-text>Introducing the &quot;GitHub Action Raw Log Viewer&quot; extension for Chrome</twitter-text></item><item><title><![CDATA[Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)]]></title><description><![CDATA[<p>As was <a href="https://discourse.joplinapp.org/t/rfc-switch-to-agpl-license-for-joplin-server/16529">discussed last year</a>, Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0) for the desktop, mobile and CLI applications, as well as the web clipper.</p>
<p>Any open source or commercial fork of Joplin will have to license any changes they make under AGPL, and share these changes back with the community. This is the main reason we switch to this license. It allows us to continue releasing the project as open source while ensuring that those who benefit commercially (or not) from it share back their changes.</p>
<h2>What is the GPL license?<a name="what-is-the-gpl-license" href="#what-is-the-gpl-license" class="heading-anchor">🔗</a></h2>
<p>The AGPL license is based on the GPL license. This is what tldr;Legal has to say about the GPL license:</p>
<blockquote>
<p>You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build &amp; install instructions. (<a href="https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)">source</a>)</p>
</blockquote>
<h2>What is the AGPL license?<a name="what-is-the-agpl-license" href="#what-is-the-agpl-license" class="heading-anchor">🔗</a></h2>
<p>This is the license we'll use for Joplin from now on:</p>
<blockquote>
<p>The AGPL license differs from the other GNU licenses in that it was built for network software. You can distribute modified versions if you keep track of the changes and the date you made them. As per usual with GNU licenses, you must license derivatives under AGPL. It provides the same restrictions and freedoms as the GPLv3 but with an additional clause which makes it so that source code must be distributed along with web publication. Since web sites and services are never distributed in the traditional sense, the AGPL is the GPL of the web. (<a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">source</a>)</p>
</blockquote>
<h2>What does it change for users?<a name="what-does-it-change-for-users" href="#what-does-it-change-for-users" class="heading-anchor">🔗</a></h2>
<p>There is no changes for users of Joplin - the apps remain open sources and you can still use them freely.</p>
<h2>What does it change for developers?<a name="what-does-it-change-for-developers" href="#what-does-it-change-for-developers" class="heading-anchor">🔗</a></h2>
<p>Any code you develop for Joplin will also remain open source. The only difference is that we'll ask to sign an Individual Contributor License Agreement (CLA) to ensure that the copyright of the entire codebase remains with the Joplin organisation. This is necessary so that if we ever want to change the license again we are able to do so without having to get the agreement of each individual contributor afterwards (which would be nearly impossible).</p>
<p>This is a bit of an extra constraint but it is hard to avoid. Contributor License Agreements are very common for GPL or AGPL projects. For example Apache, Canonical or Python all require their contributors to sign a CLA.</p>
<h2>Questions?<a name="questions" href="#questions" class="heading-anchor">🔗</a></h2>
<p>If you have any questions please let us know. Overall we believe this is a positive improvements for Joplin as it means any work derives from it will also benefit the project.</p>
]]></description><link>https://joplinapp.org/news/20221221-agpl</link><guid isPermaLink="false">20221221-agpl</guid><pubDate>Wed, 21 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)</twitter-text></item></channel></rss>
]]></description><link>https://joplinapp.org/news/20230302-jdll-2023</link><guid isPermaLink="false">20230302-jdll-2023</guid><pubDate>Thu, 02 Mar 2023 00:00:00 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>

View File

@@ -14,6 +14,7 @@
<link rel="stylesheet" href="{{{assetUrls.css.fontawesome}}}">
{{> openGraphTags}}
{{> rssFeedLink}}
{{> hreflangTags}}
<link
rel="stylesheet"
href="{{cssBaseUrl}}/bootstrap5.0.2.min.css"

View File

@@ -26,6 +26,7 @@ https://github.com/laurent22/joplin/blob/dev/{{{sourceMarkdownFile}}}
<meta name="theme-color" content="#000000" />
{{> openGraphTags}}
{{> rssFeedLink}}
{{> hreflangTags}}
<link
rel="stylesheet"
href="{{cssBaseUrl}}/bootstrap5.0.2.min.css"

View File

@@ -0,0 +1,4 @@
{{#availableLocales}}
<link rel="alternate" hreflang="{{hreflang}}" href="https://joplinapp.org{{#pathPrefix}}/{{pathPrefix}}{{/pathPrefix}}{{currentPath}}" />
{{/availableLocales}}
<link rel="alternate" hreflang="x-default" href="https://joplinapp.org{{currentPath}}" />

View File

@@ -13,24 +13,21 @@
</div>
<div class="col-9 text-right d-none d-md-block">
{{> twitterLink}}
<a href="{{baseUrl}}/plugins/" class="fw500">Plugins</a>
<a href="{{baseUrl}}/news/" class="fw500">News</a>
<a href="{{baseUrl}}/help/" class="fw500">Help</a>
<a href="{{forumUrl}}" class="fw500">Forum</a>
<!-- <a href="{{baseUrl}}/cn/" class="fw500">中文</a> -->
<!--
<div class="dropdown language-switcher">
<button class="fw500" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
Language
<button class="fw500" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-globe"></i> {{locale.code}}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
<ul class="dropdown-menu dropdown-menu-end">
{{#availableLocales}}
<li><a class="dropdown-item {{#isActive}}active{{/isActive}}" href="{{baseUrl}}/{{pathPrefix}}" onclick="setLocalePreference('{{code}}', this.href); return false;">{{name}}</a></li>
{{/availableLocales}}
</ul>
</div>
-->
{{#showJoplinCloudLinks}}
{{> joplinCloudButton}}
@@ -39,7 +36,6 @@
</div>
<div class="col-9 text-right d-block d-md-none navbar-mobile-content">
{{> twitterLink}}
<!-- <a href="{{baseUrl}}/cn/" class="fw500 chinese-page-link">中文</a> -->
{{> joplinCloudButton}}
{{> supportButton}}
@@ -63,6 +59,7 @@
</div>
<div class="text-center menu-mobile-top">
<a href="{{baseUrl}}/plugins/" class="fw500 mobile-menu-link">Plugins</a>
<a href="{{baseUrl}}/news/" class="fw500 mobile-menu-link">News</a>
<a href="{{baseUrl}}/help/" class="fw500 mobile-menu-link">Help</a>
<a href="{{forumUrl}}" class="fw500 mobile-menu-link">Forum</a>
@@ -74,6 +71,13 @@
{{/showJoplinCloudLinks}}
{{> supportButton}}
</div>
<div class="text-center menu-mobile-language">
<p class="fw500 mobile-menu-language-label"><i class="fas fa-globe"></i> Language</p>
{{#availableLocales}}
<a href="{{baseUrl}}/{{pathPrefix}}" class="fw500 mobile-menu-link mobile-language-link {{#isActive}}active{{/isActive}}" onclick="setLocalePreference('{{code}}', this.href); return false;">{{name}}</a>
{{/availableLocales}}
</div>
</div>
{{#showToc}}
@@ -81,7 +85,7 @@
{{/showToc}}
{{> socialFeeds}}
<div>
<p class="light-blue mobile-menu-link-bottom text-center">
Copyright &copy; 2016-{{yyyy}} Laurent&nbsp;Cozic

View File

@@ -3,9 +3,9 @@
<a class="social-link-bluesky" href="https://bsky.app/profile/joplinapp.bsky.social" title="Joplin Bluesky feed"><i class="fa-brands fa-bluesky"></i></a>
<a class="social-link-mastodon" href="https://mastodon.social/@joplinapp" title="Joplin Mastodon feed"><i class="fab fa-mastodon"></i></a>
<a class="social-link-patreon" href="https://www.patreon.com/joplin" title="Joplin Patreon"><i class="fab fa-patreon"></i></a>
<a class="social-link-youtube" href="https://youtube.com/@joplinapp" title="Joplin YouTube channel"><i class="fab fa-youtube"></i></a>
<a class="social-link-discord" href="https://discord.gg/VSj7AFHvpq" title="Joplin Discord chat"><i class="fab fa-discord"></i></a>
<a class="social-link-linkedin" href="https://www.linkedin.com/company/joplin" title="Joplin LinkedIn Feed"><i class="fab fa-linkedin"></i></a>
<a class="social-link-lemmy" href="https://sopuli.xyz/c/joplinapp" title="Joplin Lemmy Community"><i class="fas fa-otter"></i></a>
<a class="social-link-github" href="https://github.com/laurent22/joplin/" title="Joplin GitHub repository"><i class="fab fa-github"></i></a>
</div>
</div>

View File

@@ -2,140 +2,156 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:13
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:9
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:10
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:14
msgid "/month"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:19
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:22
msgid "/year"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:8
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:71
msgid "<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."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:205
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:206
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:104
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:105
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:256
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:299
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:236
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:237
msgid "Access your notes from your computer, phone or tablet by synchronising with various services, including Joplin Cloud, Dropbox and OneDrive. The app is available on Windows, macOS, Linux, Android and iOS. A terminal app is also available!"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:121
msgid "Already have a Joplin Cloud account? <a href=\"https://joplincloud.com\">Login now</a>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:208
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:209
msgid "Customise the app with plugins, custom themes and multiple text editors (Rich Text or Markdown). Or create your own scripts and plugins using the Extension API."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:242
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:243
msgid "Download it now"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:112
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:63
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:113
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:64
msgid "Download the app"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:213
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:214
msgid "Find out more"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:55
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:175
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:176
msgid "Get the clipper"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:107
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:108
msgid "Images, videos, PDFs and audio files are supported. Create math expressions and diagrams directly from the app. Take photos with the mobile app and save them to a note."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:328
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:5
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:68
msgid "Joplin Cloud"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:302
msgid "Joplin Cloud is based in France. This means your data is protected by strict European Union privacy laws. In addition, Joplin Cloud implements strong end-to-end encryption so that not even us can have access to your data."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:58
msgid "Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:79
msgid "Joplin Server Business"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:82
msgid "Joplin Server Business is a synchronisation server that you can install on your own infrastructure, so that your data remains private and secure within your business."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:263
msgid "More about E2EE"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:392
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:23
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:46
msgid "Our synchronisation and sharing <span class=\"frame-bg frame-bg-yellow\">solutions</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:91
msgid "Pay Monthly"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:30
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:98
msgid "Pay Yearly"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:167
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:168
msgid "Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:65
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:66
msgid "Sign up with Joplin Cloud"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid "Synchronise and share your notes with our range of plans."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:395
msgid "Thank you for your support!"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:258
msgid "The app is open source and your notes are saved to an open format, so you'll always have access to them. Uses End-To-End Encryption (E2EE) to secure your notes and ensure no-one but yourself can access them."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:144
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:145
msgid "Try it now"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:170
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:171
msgid "Use the web clipper extension, available on Chrome and Firefox, to save web pages or take screenshots as notes."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:139
msgid "With Joplin Cloud, share your notes with your friends, family or colleagues and collaborate on them."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:137
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:141
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:142
msgid "You can also publish a note to the internet and share the URL with others."
msgstr ""
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:233
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:234
msgid "Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you are"
msgstr ""

View File

@@ -0,0 +1,14 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEaZWFlBYJKwYBBAHaRw8BAQdAIh3xQbjaS0EC+8WuKXNPjVF/ayq0/2GZlheR
qj1G3Qe0RUpvcGxpbiBDYW5hcnkgU2lnbmluZyBLZXkgKFdhcnJhbnQgQ2FuYXJ5
IEtleSkgPGNhbmFyeUBqb3BsaW5hcHAub3JnPoiZBBMWCgBBFiEE+CD4MG3QBaEC
0YzVlGrp+lkV71MFAmmVhZQCGwMFCQPCZwAFCwkIBwICIgIGFQoJCAsCBBYCAwEC
HgcCF4AACgkQlGrp+lkV71MZtwD/Ufd4OAcgkl5T6MSB+WDFg8BXvpaBZfNnZkoo
LrOoqNAA/iqGiiBRoarlus2ATOiWhyXaEpRUQcEeaRhhqHW0BGcCuDgEaZWFlBIK
KwYBBAGXVQEFAQEHQFORKWRLp4hDYzR8Q5IRyF9AIjoziR+sj4icUdvZx4Z6AwEI
B4h+BBgWCgAmFiEE+CD4MG3QBaEC0YzVlGrp+lkV71MFAmmVhZQCGwwFCQPCZwAA
CgkQlGrp+lkV71Nu+AD9Gw4qEmL8WNCNs7idc8CRpGpS2DhasNTV398lbKYzco0B
ANlMrGlMc0w1KhuFxdU4fF3s/ktUUnjJwosxK94l5/MJ
=C9VN
-----END PGP PUBLIC KEY BLOCK-----

18
CLAUDE.md Normal file
View File

@@ -0,0 +1,18 @@
# Joplin Guidelines
## Quick Reference
- Tabs for indentation
- Single quotes for strings
- Proper TypeScript types (avoid `any`)
- Comments should be only with `//` and should not contain jsdoc syntax
- If you duplicate a substantial block of code, add a comment above it noting the duplication and referencing the original location.
- When creating Jest tests, there should be only one `describe()` statement in the file.
- Focus on testing essential behaviour and edge cases — avoid adding tests for every minor detail.
- Avoid duplicating code in tests; when testing the same logic with different inputs, use `test.each` or shared helpers instead of repeating similar test blocks.
- Do not make white space changes - do not add unnecessary new lines, or spaces to existing code, or wrap existing code.
## Full Documentation
- Coding style: [readme/dev/coding_style.md](readme/dev/coding_style.md)
- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)

View File

@@ -1,26 +1,25 @@
FROM node:24-bullseye
FROM node:24-bookworm
RUN apt-get update \
&& apt-get install -y \
ca-certificates curl \
python3 tini
## install docker
RUN install -m 0755 -d /etc/apt/keyrings
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
RUN chmod a+r /etc/apt/keyrings/docker.asc
RUN echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo bullseye) stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt-get update \
&& apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \
ca-certificates curl wget unzip \
python3 tini \
&& rm -rf /var/lib/apt/lists/*
ENV NODE_ENV=production
RUN corepack enable
# Download llama.cpp binary
WORKDIR /opt/llama
RUN wget -q https://github.com/ggml-org/llama.cpp/releases/download/b5449/llama-b5449-bin-ubuntu-x64.zip \
&& unzip llama-b5449-bin-ubuntu-x64.zip \
&& rm llama-b5449-bin-ubuntu-x64.zip \
&& chmod +x /opt/llama/build/bin/llama-mtmd-cli
# Create non-root user for security
RUN groupadd -r transcribe && useradd -r -g transcribe -m transcribe
WORKDIR /app
COPY .yarn/releases ./.yarn/releases
@@ -44,7 +43,21 @@ RUN BUILD_SEQUENCIAL=1 yarn install --inline-builds \
&& yarn cache clean \
&& rm -rf .yarn/berry
# Create data directory and set permissions
RUN mkdir -p /data/images \
&& chown -R transcribe:transcribe /data
WORKDIR /app/packages/transcribe
# Switch to non-root user
USER transcribe
# Set environment variables
ENV HTR_CLI_BINARY_PATH=/opt/llama/build/bin/llama-mtmd-cli
ENV LD_LIBRARY_PATH=/opt/llama/build/bin
ENV DATA_DIR=/data
ENV QUEUE_DRIVER=sqlite
# Start the Node.js application
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["yarn", "start"]

View File

@@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
# Sponsors
<!-- SPONSORS-ORG -->
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://www.slotozilla.com/nz/no-deposit-bonus"><img title="casino without making any upfront cost" width="256" src="https://joplinapp.org/images/sponsors/Slotozilla.png" alt="casino without making any upfront cost"/></a> <a href="https://writepaper.com/"><img title="best service to write my paper for me" width="256" src="https://joplinapp.org/images/sponsors/WritePaper.png" alt="best service to write my paper for me"/></a> <a href="https://paperwriter.com/"><img title="high-quality paper writing service PaperWriter" width="256" src="https://joplinapp.org/images/sponsors/PaperWriter.png" alt="high-quality paper writing service PaperWriter"/></a> <a href="https://www.bestetf.net/"><img title="BestETF" width="256" src="https://joplinapp.org/images/sponsors/BestEtf.png" alt="BestETF"/></a> <a href="https://freespinny.io/free-spins-no-deposit/"><img title="Freespinny.io Free Spins Bonus site" width="256" src="https://joplinapp.org/images/sponsors/Freespinny.png" alt="Freespinny.io Free Spins Bonus site"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://domyessay.com"><img title="Essay writers DoMyEssay are dedicated to providing top-notch, custom-written papers that meet your academic requirements" width="256" src="https://joplinapp.org/images/sponsors/DoMyEssay.png" alt="DoMyEssay"/></a> <a href="https://essaypro.com/"><img title="best essay writing service" width="256" src="https://joplinapp.org/images/sponsors/EssayPro.png" alt="best essay writing service"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://uk.notgamstop.com/bonuses/free-spins-no-deposit-no-gamstop/"><img title="free spins no deposit at NotGamstop" width="256" src="https://joplinapp.org/images/sponsors/NotGamStop.jpg" alt="free spins no deposit at NotGamstop"/></a> <a href="https://www.writemyessay.com/"><img title="writing service for students WriteMyEssay" width="256" src="https://joplinapp.org/images/sponsors/WriteMyEssay.png" alt="writing service for students WriteMyEssay"/></a> <a href="https://essayservice.com/"><img title="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"/></a>
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://essayservice.com/"><img title="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"/></a> <a href="https://thenationonlineng.net/casino-en-ligne/casino-en-ligne-payant-au-canada/"><img title="casino en ligne le plus payant" width="256" src="https://joplinapp.org/images/sponsors/TheNationOnline.jpg" alt="casino en ligne le plus payant"/></a>
<!-- SPONSORS-ORG -->
* * *
@@ -39,9 +39,9 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
<!-- SPONSORS-GITHUB -->
| | | | |
| :---: | :---: | :---: | :---: |
| <img width="50" src="https://avatars2.githubusercontent.com/u/97193607?s=96&v=4"/></br>[Akhil-CM](https://github.com/Akhil-CM) | <img width="50" src="https://avatars2.githubusercontent.com/u/552452?s=96&v=4"/></br>[andypiper](https://github.com/andypiper) | <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/1177810?s=96&v=4"/></br>[felixstorm](https://github.com/felixstorm) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/668977?s=96&v=4"/></br>[ugoertz](https://github.com/ugoertz) |
| | | | |
| <img width="50" src="https://avatars2.githubusercontent.com/u/552452?s=96&v=4"/></br>[andypiper](https://github.com/andypiper) | <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) | <img width="50" src="https://avatars2.githubusercontent.com/u/1177810?s=96&v=4"/></br>[felixstorm](https://github.com/felixstorm) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/8030470?s=96&v=4"/></br>[Galliver7](https://github.com/Galliver7) | <img width="50" src="https://avatars2.githubusercontent.com/u/4721118?s=96&v=4"/></br>[GPrimola](https://github.com/GPrimola) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/668977?s=96&v=4"/></br>[ugoertz](https://github.com/ugoertz) | | | |
<!-- SPONSORS-GITHUB -->
# Community
@@ -61,6 +61,14 @@ Name | Description
Please see the guide for information on how to contribute to the development of Joplin: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
## Warrant Canary Signing Key
Fingerprint:
F820 F830 6DD0 05A1 02D1 8CD5 946A E9FA 5915 EF53
Public key: https://github.com/laurent22/joplin/raw/dev/Assets/keys/joplin-canary-signing-key.asc
# Contributors
Thank you to everyone who've contributed to Joplin's source code!

View File

@@ -63,6 +63,7 @@
"/readme/_i18n",
"/readme/about/changelog/desktop.md",
"/readme/licenses.md",
"/readme/canary.txt",
"/readme/i18n",
"cspell.json",
"node_modules"

View File

@@ -9,15 +9,15 @@
"vips.dev": {
"platforms": ["aarch64-darwin"],
},
"nodejs": "24.8.0",
"nodejs": "24.11.1",
"pkg-config": "latest",
"python": "3.13.3",
"python": "3.14.0",
"bat": "latest",
"electron": {
"version": "latest",
"excluded_platforms": ["aarch64-darwin", "x86_64-darwin"],
},
"git": "2.50.1",
"git": "2.51.2",
},
"shell": {
"init_hook": [

View File

@@ -1,23 +0,0 @@
services:
ocis:
image: owncloud/ocis:latest
container_name: ocis
entrypoint: /bin/sh
command: ["-c", "ocis init --insecure true || true; ocis server"]
environment:
OCIS_URL: https://localhost:9200
OCIS_INSECURE: "true"
PROXY_ENABLE_BASIC_AUTH: "false"
IDM_ADMIN_PASSWORD: admin
OCIS_LOG_LEVEL: warn
# Allow Joplin's redirect URIs
IDP_INSECURE: "true"
IDP_IDENTIFIER_REGISTRATION_CONF: /etc/ocis/clients.yaml
ports:
- "9200:9200"
volumes:
- ocis_data:/var/lib/ocis
- ./ocis-clients.yaml:/etc/ocis/clients.yaml:ro
volumes:
ocis_data:

View File

@@ -84,8 +84,8 @@ services:
profiles:
- full
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${HTR_CLI_IMAGES_FOLDER}:/app/packages/transcribe/images
- ${HTR_CLI_MODELS_FOLDER}:/opt/models:ro
depends_on:
- transcribe-db
ports:
@@ -94,6 +94,16 @@ services:
- transcribe-network
- shared-network
restart: unless-stopped
# Security: limit resources to prevent runaway processes
deploy:
resources:
limits:
memory: 16G
cpus: '4'
# Security: read-only root filesystem with only images folder writable
read_only: true
tmpfs:
- /tmp
environment:
- APP_PORT=4567
- DB_CLIENT=pg
@@ -103,5 +113,6 @@ services:
- QUEUE_DATABASE_PORT=${QUEUE_DATABASE_PORT}
- QUEUE_DATABASE_HOST=transcribe-db
- API_KEY=${TRANSCRIBE_API_KEY}
- HTR_CLI_IMAGES_FOLDER=${HTR_CLI_IMAGES_FOLDER}
- HTR_CLI_IMAGES_FOLDER=/app/packages/transcribe/images
- HTR_CLI_MODELS_FOLDER=/opt/models

View File

@@ -0,0 +1,44 @@
# Standalone docker-compose for Joplin Transcribe
#
# Uses SQLite for the queue (no external database needed).
# Data is stored in a named volume for proper permissions.
#
# Usage:
#
# 1. Download models:
# mkdir -p ./data/models
# wget -O ./data/models/Model-7.6B-Q4_K_M.gguf https://huggingface.co/openbmb/MiniCPM-o-2_6-gguf/resolve/main/Model-7.6B-Q4_K_M.gguf
# wget -O ./data/models/mmproj-model-f16.gguf https://huggingface.co/openbmb/MiniCPM-o-2_6-gguf/resolve/main/mmproj-model-f16.gguf
#
# 2. Configure:
# cp .env-transcribe-sample .env
# # Edit .env and set API_KEY
#
# 3. Run:
# docker compose -f docker-compose.transcribe.yml up
volumes:
transcribe-data:
services:
transcribe:
image: joplin/transcribe:amd64-latest
ports:
- "4567:4567"
volumes:
- transcribe-data:/data
- ./data/models:/data/models:ro
restart: unless-stopped
# Security: limit resources to prevent runaway processes
deploy:
resources:
limits:
memory: 16G
cpus: '4'
# Security: read-only root filesystem
read_only: true
tmpfs:
- /tmp
- /home/transcribe/.cache
env_file:
- .env

View File

@@ -1,12 +0,0 @@
clients:
- id: joplin
name: Joplin
application_type: native
redirect_uris:
- http://localhost:9968
- http://localhost:8968
- http://localhost:8868
- http://127.0.0.1:9968
- http://127.0.0.1:8968
- http://127.0.0.1:8868
- joplin://oidc-callback

View File

@@ -38,7 +38,7 @@
"linter-precommit": "eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
"linter": "eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
"packageJsonLint": "node ./packages/tools/packageJsonLint.js",
"syncFuzzer": "node ./packages/tools/fuzzer/sync-fuzzer.js",
"syncFuzzer": "node ./packages/tools/fuzzer/cli.js",
"postinstall": "husky && gulp build",
"postPreReleasesToForum": "node ./packages/tools/postPreReleasesToForum",
"publishAll": "git pull && yarn buildParallel && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
@@ -60,6 +60,7 @@
"test": "yarn workspaces foreach --worktree --parallel --verbose --interlaced --jobs 2 run test",
"tsc": "yarn workspaces foreach --worktree --parallel --verbose --interlaced run tsc",
"updateIgnored": "node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js",
"updateCanary": "node ./packages/tools/updateCanary",
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
"updateNews": "node ./packages/tools/website/updateNews",
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
@@ -71,6 +72,7 @@
"@crowdin/cli": "4",
"@joplin/utils": "~2.12",
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
"@types/jest": "29.5.14",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"cspell": "5.21.2",
@@ -81,12 +83,12 @@
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-react": "7.37.5",
"execa": "5.1.1",
"fs-extra": "11.3.2",
"glob": "11.0.3",
"fs-extra": "11.3.3",
"glob": "11.1.0",
"gulp": "4.0.2",
"husky": "9.1.7",
"lerna": "3.22.1",
"lint-staged": "16.2.6",
"lint-staged": "16.2.7",
"madge": "8.0.0",
"npm-package-json-lint": "9.0.0",
"typescript": "5.8.3"
@@ -95,8 +97,8 @@
"@types/fs-extra": "11.0.4",
"eslint-plugin-github": "4.10.2",
"http-server": "14.1.1",
"node-gyp": "11.4.2",
"nodemon": "3.1.10"
"node-gyp": "11.5.0",
"nodemon": "3.1.11"
},
"packageManager": "yarn@4.9.2",
"resolutions": {
@@ -123,6 +125,7 @@
"depd@npm:~1.1.2": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:2.0.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:^1.1.2": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:^1.1.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch"
"depd@npm:^1.1.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"formidable@npm:^2.0.1": "patch:formidable@npm%3A2.1.2#~/.yarn/patches/formidable-npm-2.1.2-40ba18d67f.patch"
}
}

View File

@@ -1,7 +1,7 @@
import BaseApplication from '@joplin/lib/BaseApplication';
import { refreshFolders } from '@joplin/lib/folders-screen-utils.js';
import ResourceService from '@joplin/lib/services/ResourceService';
import BaseModel, { ModelType } from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import BaseItem from '@joplin/lib/models/BaseItem';
import Note from '@joplin/lib/models/Note';
@@ -15,20 +15,22 @@ import RevisionService from '@joplin/lib/services/RevisionService';
import shim from '@joplin/lib/shim';
import setupCommand from './setupCommand';
import { FolderEntity, NoteEntity } from '@joplin/lib/services/database/types';
type FolderOrNoteType = ModelType.Note | ModelType.Folder | 'folderOrNote';
import initializeCommandService from './utils/initializeCommandService';
const { cliUtils } = require('./cli-utils.js');
const Cache = require('@joplin/lib/Cache');
class Application extends BaseApplication {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic command loading system
private commands_: Record<string, any> = {};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic command metadata
private commandMetadata_: any = null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic command type
private activeCommand_: any = null;
private allCommandsLoaded_ = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic GUI type with many optional methods
private gui_: any = null;
private cache_ = new Cache();
@@ -40,18 +42,16 @@ class Application extends BaseApplication {
return this.gui().stdoutMaxWidth();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async guessTypeAndLoadItem(pattern: string, options: any = null) {
let type = BaseModel.TYPE_NOTE;
public async guessTypeAndLoadItem(pattern: string, options: { parent?: FolderEntity } | null = null) {
let type: FolderOrNoteType = ModelType.Note;
if (pattern.indexOf('/') === 0) {
type = BaseModel.TYPE_FOLDER;
type = ModelType.Folder;
pattern = pattern.substr(1);
}
return this.loadItem(type, pattern, options);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async loadItem(type: ModelType | 'folderOrNote', pattern: string, options: any = null) {
public async loadItem(type: FolderOrNoteType, pattern: string, options: { parent?: FolderEntity } | null = null) {
const output = await this.loadItems(type, pattern, options);
if (output.length > 1) {
@@ -75,37 +75,36 @@ class Application extends BaseApplication {
}
}
public async loadItemOrFail(type: ModelType | 'folderOrNote', pattern: string) {
public async loadItemOrFail(type: FolderOrNoteType, pattern: string) {
const output = await this.loadItem(type, pattern);
if (!output) throw new Error(_('Cannot find "%s".', pattern));
return output;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async loadItems(type: ModelType | 'folderOrNote', pattern: string, options: any = null): Promise<(FolderEntity | NoteEntity)[]> {
public async loadItems(type: FolderOrNoteType, pattern: string, options: { parent?: FolderEntity } | null = null): Promise<(FolderEntity | NoteEntity)[]> {
if (type === 'folderOrNote') {
const folders: FolderEntity[] = await this.loadItems(BaseModel.TYPE_FOLDER, pattern, options);
const folders: FolderEntity[] = await this.loadItems(ModelType.Folder, pattern, options);
if (folders.length) return folders;
return await this.loadItems(BaseModel.TYPE_NOTE, pattern, options);
return await this.loadItems(ModelType.Note, pattern, options);
}
pattern = pattern ? pattern.toString() : '';
if (type === BaseModel.TYPE_FOLDER && (pattern === Folder.conflictFolderTitle() || pattern === Folder.conflictFolderId())) return [Folder.conflictFolder()];
if (type === ModelType.Folder && (pattern === Folder.conflictFolderTitle() || pattern === Folder.conflictFolderId())) return [Folder.conflictFolder()];
if (!options) options = {};
const parent = options.parent ? options.parent : app().currentFolder();
const ItemClass = BaseItem.itemClass(type);
if (type === BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) {
if (type === ModelType.Note && pattern.indexOf('*') >= 0) {
// Handle it as pattern
if (!parent) throw new Error(_('No notebook selected.'));
return await Note.previews(parent.id, { titlePattern: pattern });
} else {
// Single item
let item = null;
if (type === BaseModel.TYPE_NOTE) {
if (type === ModelType.Note) {
if (!parent) throw new Error(_('No notebook has been specified.'));
item = await (ItemClass as typeof Note).loadFolderNoteByField(parent.id, 'title', pattern);
} else {
@@ -172,7 +171,7 @@ class Application extends BaseApplication {
}
if (uiType !== null) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic command type
const temp: Record<string, any> = {};
for (const n in this.commands_) {
if (!this.commands_.hasOwnProperty(n)) continue;
@@ -233,8 +232,7 @@ class Application extends BaseApplication {
CommandClass = require(`${__dirname}/command-${name}.js`);
} catch (error) {
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const e: any = new Error(_('No such command: %s', name));
const e: Error & { type?: string } = new Error(_('No such command: %s', name));
e.type = 'notFound';
throw e;
} else {
@@ -253,8 +251,7 @@ class Application extends BaseApplication {
isDummy: () => {
return true;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
prompt: (initialText = '', promptString = '', options: any = null) => {
prompt: (initialText = '', promptString = '', options: Record<string, unknown> | null = null) => {
return cliUtils.prompt(initialText, promptString, options);
},
showConsole: () => {},
@@ -276,8 +273,7 @@ class Application extends BaseApplication {
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async execCommand(argv: string[]): Promise<any> {
public async execCommand(argv: string[]): Promise<void> {
if (!argv.length) return this.execCommand(['help']);
// reg.logger().debug('execCommand()', argv);
const commandName = argv[0];
@@ -396,8 +392,7 @@ class Application extends BaseApplication {
const keychainEnabled = this.checkIfKeychainEnabled(argv);
argv = await super.start(argv, { keychainEnabled });
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
cliUtils.setStdout((object: any) => {
cliUtils.setStdout((object: string) => {
return this.stdout(object);
});
@@ -448,7 +443,7 @@ class Application extends BaseApplication {
this.gui_.setLogger(this.logger());
await this.gui_.start();
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Redux dispatch type requires AnyAction
await refreshFolders((action: any) => this.store().dispatch(action), '');
const tags = await Tag.allWithNotes();

View File

@@ -31,9 +31,14 @@ cliUtils.printArray = function(logFunction, rows) {
const line = [];
for (let col = 0; col < colWidths.length; col++) {
const item = rows[row][col];
const width = colWidths[col];
const dir = colAligns[col] === ALIGN_LEFT ? stringPadding.RIGHT : stringPadding.LEFT;
line.push(stringPadding(item, width, ' ', dir));
const isLastCol = col === colWidths.length - 1;
if (isLastCol) {
line.push(item ? item.toString() : '');
} else {
const width = colWidths[col];
const dir = colAligns[col] === ALIGN_LEFT ? stringPadding.RIGHT : stringPadding.LEFT;
line.push(stringPadding(item, width, ' ', dir));
}
}
logFunction(line.join(' '));
}

View File

@@ -402,7 +402,17 @@ async function fetchAllNotes() {
lines.push('');
}
if (model.type === BaseModel.TYPE_NOTE || model.type === BaseModel.TYPE_FOLDER) {
if (model.type === BaseModel.TYPE_NOTE) {
lines.push(`By default, the ${singular} will be moved **to the trash**. To permanently delete it, add the query parameter \`permanent=1\``);
lines.push('');
lines.push('### DELETE /notes/:id/revisions');
lines.push('');
lines.push('Deletes all the revisions attached to this note.');
lines.push('');
}
if (model.type === BaseModel.TYPE_FOLDER) {
lines.push(`By default, the ${singular} will be moved **to the trash**. To permanently delete it, add the query parameter \`permanent=1\``);
lines.push('');
}

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import shim from '@joplin/lib/shim';
class Command extends BaseCommand {
@@ -17,7 +17,7 @@ class Command extends BaseCommand {
public override async action(args: any) {
const title = args['note'];
const note = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
const note = await app().loadItem(ModelType.Note, title, { parent: app().currentFolder() });
this.encryptionCheck(note);
if (!note) throw new Error(_('Cannot find "%s".', title));

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import BaseItem from '@joplin/lib/models/BaseItem';
import Note from '@joplin/lib/models/Note';
@@ -22,7 +22,7 @@ class Command extends BaseCommand {
public override async action(args: any) {
const title = args['note'];
const item = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
const item = await app().loadItem(ModelType.Note, title, { parent: app().currentFolder() });
if (!item) throw new Error(_('Cannot find "%s".', title));
let content = '';

View File

@@ -0,0 +1,19 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
class Command extends BaseCommand {
public override usage() {
return 'clear';
}
public override description() {
return _('Clears the console output.');
}
public override async action() {
app().gui().widget('console').clear();
}
}
module.exports = Command;

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note';
class Command extends BaseCommand {
@@ -17,14 +17,14 @@ class Command extends BaseCommand {
public override async action(args: any) {
let folder = null;
if (args['notebook']) {
folder = await app().loadItem(BaseModel.TYPE_FOLDER, args['notebook']);
folder = await app().loadItem(ModelType.Folder, args['notebook']);
} else {
folder = app().currentFolder();
}
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args['note']);
const notes = await app().loadItems(ModelType.Note, args['note']);
if (!notes.length) throw new Error(_('Cannot find "%s".', args['note']));
for (let i = 0; i < notes.length; i++) {

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note';
import time from '@joplin/lib/time';
import { NoteEntity } from '@joplin/lib/services/database/types';
@@ -17,7 +17,7 @@ class Command extends BaseCommand {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public static async handleAction(commandInstance: BaseCommand, args: any, isCompleted: boolean) {
const note: NoteEntity = await app().loadItem(BaseModel.TYPE_NOTE, args.note);
const note: NoteEntity = await app().loadItem(ModelType.Note, args.note);
commandInstance.encryptionCheck(note);
if (!note) throw new Error(_('Cannot find "%s".', args.note));
if (!note.is_todo) throw new Error(_('Note is not a to-do: "%s"', args.note));

View File

@@ -6,7 +6,7 @@ import app from './app';
import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
class Command extends BaseCommand {
public override usage() {
@@ -39,7 +39,7 @@ class Command extends BaseCommand {
const title = args['note'];
if (!app().currentFolder()) throw new Error(_('No active notebook.'));
let note = await app().loadItem(BaseModel.TYPE_NOTE, title);
let note = await app().loadItem(ModelType.Note, title);
this.encryptionCheck(note);

View File

@@ -1,6 +1,6 @@
import BaseCommand from './base-command';
import InteropService from '@joplin/lib/services/interop/InteropService';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import app from './app';
import { _ } from '@joplin/lib/locale';
import { ExportOptions } from '@joplin/lib/services/interop/types';
@@ -34,12 +34,12 @@ class Command extends BaseCommand {
if (exportOptions.format === 'html') throw new Error('HTML export is not supported. Please use the desktop application.');
if (args.options.note) {
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args.options.note, { parent: app().currentFolder() });
const notes = await app().loadItems(ModelType.Note, args.options.note, { parent: app().currentFolder() });
if (!notes.length) throw new Error(_('Cannot find "%s".', args.options.note));
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
exportOptions.sourceNoteIds = notes.map((n: any) => n.id);
} else if (args.options.notebook) {
const folders = await app().loadItems(BaseModel.TYPE_FOLDER, args.options.notebook);
const folders = await app().loadItems(ModelType.Folder, args.options.notebook);
if (!folders.length) throw new Error(_('Cannot find "%s".', args.options.notebook));
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
exportOptions.sourceFolderIds = folders.map((n: any) => n.id);

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note';
class Command extends BaseCommand {
@@ -17,7 +17,7 @@ class Command extends BaseCommand {
public override async action(args: any) {
const title = args['note'];
const item = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
const item = await app().loadItem(ModelType.Note, title, { parent: app().currentFolder() });
if (!item) throw new Error(_('Cannot find "%s".', title));
const url = Note.geolocationUrl(item);
this.stdout(url);

View File

@@ -1,6 +1,6 @@
import BaseCommand from './base-command';
import InteropService from '@joplin/lib/services/interop/InteropService';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
const { cliUtils } = require('./cli-utils.js');
import app from './app';
import { _ } from '@joplin/lib/locale';
@@ -33,7 +33,7 @@ class Command extends BaseCommand {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public override async action(args: any) {
let destinationFolder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
let destinationFolder = await app().loadItem(ModelType.Folder, args.notebook);
if (args.notebook && !destinationFolder) throw new Error(_('Cannot find "%s".', args.notebook));

View File

@@ -1,7 +1,7 @@
const BaseCommand = require('./base-command').default;
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import { FolderEntity } from '@joplin/lib/services/database/types';
@@ -23,7 +23,7 @@ class Command extends BaseCommand {
// validDestinationFolder check for presents and ambiguous folders
public async validDestinationFolder(targetFolder: string) {
const destinationFolder = await app().loadItem(BaseModel.TYPE_FOLDER, targetFolder);
const destinationFolder = await app().loadItem(ModelType.Folder, targetFolder);
if (!destinationFolder) {
throw new Error(_('Cannot find: "%s"', targetFolder));
}

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import Note from '@joplin/lib/models/Note';
@@ -21,7 +21,7 @@ class Command extends BaseCommand {
let folder = null;
if (destination !== 'root') {
folder = await app().loadItem(BaseModel.TYPE_FOLDER, destination);
folder = await app().loadItem(ModelType.Folder, destination);
if (!folder) throw new Error(_('Cannot find "%s".', destination));
}
@@ -30,7 +30,7 @@ class Command extends BaseCommand {
throw new Error(_('Ambiguous notebook "%s". Please use short notebook id instead - press "ti" to see the short notebook id', destination));
}
const itemFolder = await app().loadItem(BaseModel.TYPE_FOLDER, pattern);
const itemFolder = await app().loadItem(ModelType.Folder, pattern);
if (itemFolder) {
const sourceDuplicates = await Folder.search({ titlePattern: pattern, limit: 2 });
if (sourceDuplicates.length > 1) {
@@ -42,7 +42,7 @@ class Command extends BaseCommand {
await Folder.moveToFolder(itemFolder.id, folder.id);
}
} else {
const notes = await app().loadItems(BaseModel.TYPE_NOTE, pattern);
const notes = await app().loadItems(ModelType.Note, pattern);
if (notes.length === 0) throw new Error(_('Cannot find "%s".', pattern));
for (let i = 0; i < notes.length; i++) {
await Note.moveToFolder(notes[i].id, folder.id);

View File

@@ -2,7 +2,7 @@ import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import Folder from '@joplin/lib/models/Folder';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import { substrWithEllipsis } from '@joplin/lib/string-utils';
class Command extends BaseCommand {
@@ -26,7 +26,7 @@ class Command extends BaseCommand {
const pattern = args['notebook'];
const force = args.options && args.options.force === true;
const folder = await app().loadItemOrFail(BaseModel.TYPE_FOLDER, pattern);
const folder = await app().loadItemOrFail(ModelType.Folder, pattern);
const permanent = args.options?.permanent === true || !!folder.deleted_time;
const ellipsizedFolderTitle = substrWithEllipsis(folder.title, 0, 32);

View File

@@ -2,7 +2,7 @@ import BaseCommand from './base-command';
import app from './app';
import { _, _n } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import BaseModel, { DeleteOptions } from '@joplin/lib/BaseModel';
import { DeleteOptions, ModelType } from '@joplin/lib/BaseModel';
import { NoteEntity } from '@joplin/lib/services/database/types';
class Command extends BaseCommand {
@@ -26,7 +26,7 @@ class Command extends BaseCommand {
const pattern = args['note-pattern'];
const force = args.options && args.options.force === true;
const notes: NoteEntity[] = await app().loadItems(BaseModel.TYPE_NOTE, pattern);
const notes: NoteEntity[] = await app().loadItems(ModelType.Note, pattern);
if (!notes.length) throw new Error(_('Cannot find "%s".', pattern));
let ok = true;

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Database from '@joplin/lib/database';
import Note from '@joplin/lib/models/Note';
@@ -29,7 +29,7 @@ class Command extends BaseCommand {
let propValue = args['value'];
if (!propValue) propValue = '';
const notes = await app().loadItems(BaseModel.TYPE_NOTE, title);
const notes = await app().loadItems(ModelType.Note, title);
if (!notes.length) throw new Error(_('Cannot find "%s".', title));
for (let i = 0; i < notes.length; i++) {

View File

@@ -8,7 +8,7 @@ import { masterKeysWithoutPassword } from '@joplin/lib/services/e2ee/utils';
import { appTypeToLockType } from '@joplin/lib/services/synchronizer/LockHandler';
const BaseCommand = require('./base-command').default;
import app from './app';
import OneDriveApiNodeUtils from '@joplin/lib/onedrive-api-node-utils';
const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js');
import { reg } from '@joplin/lib/registry';
const { cliUtils } = require('./cli-utils.js');
const md5 = require('md5');

View File

@@ -17,17 +17,11 @@ type Args = {
class Command extends BaseCommand {
public usage() {
return 'publish [note]';
return 'unpublish [note]';
}
public description() {
return _('Publishes a note to Joplin Server or Joplin Cloud');
}
public options() {
return [
['-f, --force', _('Do not ask for user confirmation.')],
];
return _('Unpublishes a note from Joplin Server or Joplin Cloud');
}
public enabled() {

View File

@@ -1,7 +1,7 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import { ModelType } from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
class Command extends BaseCommand {
@@ -19,7 +19,7 @@ class Command extends BaseCommand {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public override async action(args: any) {
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, args['notebook']);
const folder = await app().loadItem(ModelType.Folder, args['notebook']);
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
// Auto-expand parent folders in GUI if present

View File

@@ -34,6 +34,12 @@ class ConsoleWidget extends TextWidget {
super.onBlur();
}
clear() {
this.lines_ = [];
this.updateText_ = true;
this.invalidate();
}
render() {
if (this.updateText_) {
if (this.lines_.length > this.maxLines_) {

View File

@@ -48,7 +48,7 @@
"chalk": "4.1.2",
"compare-version": "0.1.2",
"file-type": "16.5.4",
"fs-extra": "11.3.2",
"fs-extra": "11.3.3",
"html-entities": "1.4.0",
"keytar": "7.9.0",
"md5": "2.3.0",

View File

@@ -45,6 +45,10 @@ describe('HtmlToMd', () => {
htmlToMdOptions.preserveColorStyles = true;
}
if (htmlFilename.indexOf('table_with') === 0 || htmlFilename.indexOf('table_default') === 0) {
htmlToMdOptions.preserveTableStyles = true;
}
const html = await readFile(htmlPath, 'utf8');
let expectedMd = await readFile(mdPath, 'utf8');
@@ -96,4 +100,34 @@ describe('HtmlToMd', () => {
expect(htmlToMd.parse('> 1 _2_ 3.pdf', { disableEscapeContent: false })).toBe('\\> 1 \\_2_ 3.pdf');
});
it('should support tightLists option', async () => {
const htmlToMd = new HtmlToMd();
const html = '<ul><li><p><strong>Item 1</strong></p></li><li><p><strong>Item 2</strong></p></li><li><p><strong>Item 3</strong></p></li></ul>';
// Without tightLists, paragraphs inside list items produce extra blank lines
const looseResult = htmlToMd.parse(html, { tightLists: false });
expect(looseResult).toContain('\n \n');
// With tightLists, list items are compact without blank lines
const tightResult = htmlToMd.parse(html, { tightLists: true });
expect(tightResult).toBe('- **Item 1**\n- **Item 2**\n- **Item 3**');
});
it('should support collapseMultipleBlankLines option', async () => {
const htmlToMd = new HtmlToMd();
const html = '<p>First</p><br><br><br><p>Second</p>';
// Without collapseMultipleBlankLines, multiple blank lines are preserved
const looseResult = htmlToMd.parse(html, { collapseMultipleBlankLines: false });
expect(looseResult).toContain('\n\n \n');
// With collapseMultipleBlankLines, multiple blank lines are collapsed into one
const collapsedResult = htmlToMd.parse(html, { collapseMultipleBlankLines: true });
expect(collapsedResult).not.toContain('\n\n\n');
expect(collapsedResult).not.toContain('\n\n \n');
// Verify that a single blank line is preserved (not fully removed)
expect(collapsedResult).toContain('\n\n');
});
});

View File

@@ -99,6 +99,10 @@ describe('MdToHtml', () => {
'',
];
// Use this to generate the needed file:
// await writeFile('/path/to/actual.html', actualHtml, 'utf-8');
// eslint-disable-next-line no-console
console.info(msg.join('\n'));

View File

@@ -0,0 +1,7 @@
<ul>
<li>First line<br/>Second line</li>
<li>Normal item</li>
<li>With sub-list<ul>
<li>Sub-list<br/>Paragraph<br/>Also another line</li>
</ul></li>
</ul>

View File

@@ -0,0 +1,8 @@
- First line
Second line
- Normal item
- With sub-list
- Sub-list
Paragraph
Also another line

View File

@@ -0,0 +1 @@
<a href="#section" style="text-decoration: underline">Section Link</a>

View File

@@ -0,0 +1 @@
[Section Link](#section)

View File

@@ -0,0 +1,18 @@
<table style="border-collapse: collapse; width: 100%;">
<thead>
<tr>
<th style="width: 50%;">Name</th>
<th style="width: 50%;">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 50%;">Cell A</td>
<td style="width: 50%;">Cell B</td>
</tr>
<tr>
<td style="width: 50%;">Cell C</td>
<td style="width: 50%;">Cell D</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,4 @@
| Name | Value |
| --- | --- |
| Cell A | Cell B |
| Cell C | Cell D |

View File

@@ -0,0 +1,18 @@
<table bgcolor="#f0f0f0" cellpadding="8">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell A</td>
<td>Cell B</td>
</tr>
<tr>
<td>Cell C</td>
<td>Cell D</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1 @@
<div class="joplin-table-wrapper"><table bgcolor="#f0f0f0" cellpadding="8"><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td>Cell A</td><td>Cell B</td></tr><tr><td>Cell C</td><td>Cell D</td></tr></tbody></table></div>

View File

@@ -0,0 +1,18 @@
<table style="border-collapse: collapse">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td style="background-color: #e03e2d">Red cell</td>
<td style="padding: 10px 15px">Padded cell</td>
</tr>
<tr>
<td style="border-color: #2dc26b; border-style: solid">Green border</td>
<td>Normal cell</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1 @@
<div class="joplin-table-wrapper"><table style="border-collapse: collapse"><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td style="background-color: #e03e2d">Red cell</td><td style="padding: 10px 15px">Padded cell</td></tr><tr><td style="border-color: #2dc26b; border-style: solid">Green border</td><td>Normal cell</td></tr></tbody></table></div>

View File

@@ -0,0 +1,10 @@
<p>Link: <a data-from-md title='https://www.youtube.com/watch?v=iJqe9pC-z-Y' href='https://www.youtube.com/watch?v=iJqe9pC-z-Y' onclick='postMessage(&quot;https://www.youtube.com/watch?v=iJqe9pC-z-Y&quot;, { resourceId: &quot;&quot; }); return false;'>https://www.youtube.com/watch?v=iJqe9pC-z-Y</a></p>
<p>
<div class="joplin-editable">
<span class="joplin-source" data-joplin-source-open="" data-joplin-source-close="">https://www.youtube.com/watch?v=iJqe9pC-z-Y</span>
<div class="joplin-youtube-player-rendered">
<iframe src="https://www.youtube-nocookie.com/embed/iJqe9pC-z-Y" title="YouTube video player" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</p>
<p>Test</p>

View File

@@ -0,0 +1,5 @@
Link: https://www.youtube.com/watch?v=iJqe9pC-z-Y
https://www.youtube.com/watch?v=iJqe9pC-z-Y
Test

View File

@@ -10,6 +10,7 @@ import Folder from '@joplin/lib/models/Folder';
import { expectNotThrow, setupDatabaseAndSynchronizer, switchClient, expectThrow, createTempDir, supportDir, mockMobilePlatform } from '@joplin/lib/testing/test-utils';
import { newPluginScript } from '../../testUtils';
import { join } from 'path';
import { PluginManifest } from '@joplin/lib/services/plugins/utils/types';
const testPluginDir = `${supportDir}/plugins`;
@@ -472,4 +473,18 @@ describe('services_PluginService', () => {
await fs.remove(testDir);
}
});
it('should report a missing app_min_version field specifically', () => {
const service = newPluginService();
const manifest = {
manifest_version: 1,
id: 'test.plugin',
name: 'Test Plugin',
version: '1.0.0',
// Missing app_min_version
};
const error = service.describeIncompatibility(manifest as unknown as PluginManifest);
expect(error).toContain('Invalid plugin manifest: Missing required field: app_min_version');
});
});

Binary file not shown.

View File

@@ -1,27 +1,22 @@
# generator-joplin
# Plugin development
Scaffolds out a new Joplin plugin
This documentation describes how to create a plugin, and how to work with the plugin builder framework and API.
## Installation
First, install [Yeoman](http://yeoman.io) and generator-joplin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)).
```bash
npm install -g yo
npm install -g yo@4.3.1
npm install -g generator-joplin
```
Then generate your new project:
```bash
yo joplin
yo --node-package-manager npm joplin
```
## Development
To test the generator for development purposes, follow the instructions there: https://yeoman.io/authoring/#running-the-generator
This is a template to create a new Joplin plugin.
## Structure
The main two files you will want to look at are:
@@ -39,6 +34,10 @@ To build the plugin, simply run `npm run dist`.
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
## Updating the manifest version number
You can run `npm run updateVersion` to bump the patch part of the version number, so for example 1.0.3 will become 1.0.4. This script will update both the package.json and manifest.json version numbers so as to keep them in sync.
## Publishing the plugin
To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
@@ -67,6 +66,13 @@ By default, the compiler (webpack) is going to compile `src/index.ts` only (as w
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
## More information
- [Joplin Plugin API](https://joplinapp.org/api/references/plugin_api/classes/joplin.html)
- [Joplin Data API](https://joplinapp.org/help/api/references/rest_api)
- [Joplin Plugin Manifest](https://joplinapp.org/api/references/plugin_manifest/)
- Ask for help on the [forum](https://discourse.joplinapp.org/) or our [Discord channel](https://discord.gg/VSj7AFHvpq)
## License
MIT © Laurent Cozic

View File

@@ -73,4 +73,8 @@ export default class Joplin {
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;
/**
* Tells whether the current theme is a dark one or not.
*/
shouldUseDarkColors(): Promise<boolean>;
}

View File

@@ -1,3 +1,4 @@
import { ClipboardContent } from './types';
export default class JoplinClipboard {
private electronClipboard_;
private electronNativeImage_;
@@ -26,4 +27,19 @@ export default class JoplinClipboard {
* For example [ 'text/plain', 'text/html' ]
*/
availableFormats(): Promise<string[]>;
/**
* Writes multiple formats to the clipboard simultaneously.
* This allows setting both text/plain and text/html at the same time.
*
* <span class="platform-desktop">desktop</span>
*
* @example
* ```typescript
* await joplin.clipboard.write({
* text: 'Plain text version',
* html: '<strong>HTML version</strong>'
* });
* ```
*/
write(content: ClipboardContent): Promise<void>;
}

View File

@@ -14,7 +14,7 @@ import Plugin from '../Plugin';
* now, are not well documented. You can find the list directly on GitHub
* though at the following locations:
*
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/MainScreen/commands)
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/WindowCommandsAndDialogs/commands)
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/commands)
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts)
*
@@ -25,8 +25,13 @@ import Plugin from '../Plugin';
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Note screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/components/screens/Note/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* Additionally, certain global commands have the same implementation on both platforms:
*
* * [Shared global commands](https://github.com/laurent22/joplin/tree/dev/packages/lib/commands)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands

View File

@@ -42,9 +42,11 @@ export default class JoplinSettings {
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
* Gets a setting value (only applies to setting you registered from your plugin).
*
* Gets a setting value (only applies to setting you registered from your plugin)
* Note: If you want to retrieve all your plugin settings, for example when the plugin starts,
* it is recommended to use the `values()` function instead - it will be much faster than
* calling `value()` multiple times.
*/
value(key: string): Promise<any>;
/**
@@ -52,11 +54,15 @@ export default class JoplinSettings {
*/
setValue(key: string, value: any): Promise<void>;
/**
* Gets a global setting value, including app-specific settings and those set by other plugins.
* Gets global setting values, including app-specific settings and those set by other plugins.
*
* The list of available settings is not documented yet, but can be found by looking at the source code:
*
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/settings/builtInMetadata.ts
*/
globalValues(keys: string[]): Promise<any[]>;
/**
* @deprecated Use joplin.settings.globalValues()
*/
globalValue(key: string): Promise<any>;
/**

View File

@@ -9,8 +9,17 @@ import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
* All view services provide a `create()` method which you would use to create the view object, whether it's a dialog, a toolbar button or a menu item.
* In some cases, the `create()` method will return a [[ViewHandle]], which you would use to act on the view, for example to set certain properties or call some methods.
* ## Creating a view
*
* All view services provide a `create()` method which you would use to create the view object,
* whether it's a dialog, a toolbar button or a menu item. In some cases, the `create()` method will
* return a [[ViewHandle]], which you would use to act on the view, for example to set certain
* properties or call some methods.
*
* ## The `webviewApi` object
*
* Within a view, you can use the global object `webviewApi` for various utility functions, such as
* sending messages or displaying context menu. Refer to [[WebviewApi]] for the full documentation.
*/
export default class JoplinViews {
private store;

View File

@@ -1,5 +1,5 @@
import Plugin from '../Plugin';
import { ButtonSpec, ViewHandle, DialogResult } from './types';
import { ButtonSpec, ViewHandle, DialogResult, Toast } from './types';
/**
* Allows creating and managing dialogs. A dialog is modal window that
* contains a webview and a row of buttons. You can update the
@@ -43,6 +43,10 @@ export default class JoplinViewsDialogs {
* Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel"
*/
showMessageBox(message: string): Promise<number>;
/**
* Displays a Toast notification in the corner of the application screen.
*/
showToast(toast: Toast): Promise<void>;
/**
* Displays a dialog to select a file or a directory. Same options and
* output as

View File

@@ -1,5 +1,18 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
import { ActivationCheckCallback, ViewHandle, UpdateCallback, EditorPluginCallbacks } from './types';
interface SaveNoteOptions {
/**
* The ID of the note to save. This should match either:
* - The ID of the note currently being edited
* - The ID of a note that was very recently open in the editor.
*
* This property is present to ensure that the note editor doesn't write
* to the wrong note just after switching notes.
*/
noteId: string;
/** The note's new content. */
body: string;
}
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
@@ -41,10 +54,18 @@ export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
private unhandledActivationCheck_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Registers a new editor plugin. Joplin will call the provided callback to create new editor views
* associated with the plugin as necessary (e.g. when a new editor is created in a new window).
*/
register(viewId: string, callbacks: EditorPluginCallbacks): Promise<void>;
/**
* Creates a new editor view
*
* @deprecated
*/
create(id: string): Promise<ViewHandle>;
/**
@@ -60,14 +81,21 @@ export default class JoplinViewsEditors {
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
* Saves the content of the editor, without calling `onUpdate` for editors in the same window.
*/
saveNote(handle: ViewHandle, props: SaveNoteOptions): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this is for example when the current
* note is changed, or when the application is opened. At that point you should check the
* current note and decide whether your editor should be activated or not. If it should, return
* `true`, otherwise return `false`.
*
* @deprecated - `onActivationCheck` should be provided when the editor is first created with
* `editor.register`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* Emitted when your editor content should be updated. This is for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
@@ -86,3 +114,4 @@ export default class JoplinViewsEditors {
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}
export {};

View File

@@ -80,5 +80,9 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
/**
* Assuming that the current panel is an editor plugin view, returns
* whether the editor plugin view supports editing the current note.
*/
isActive(handle: ViewHandle): Promise<boolean>;
}

View File

@@ -80,6 +80,8 @@ export default class JoplinWorkspace {
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
/**
* Gets the currently selected note. Will be `null` if no note is selected.
*
* On desktop, this returns the selected note in the focused window.
*/
selectedNote(): Promise<any>;
/**
@@ -93,5 +95,12 @@ export default class JoplinWorkspace {
* Gets the IDs of the selected notes (can be zero, one, or many). Use the data API to retrieve information about these notes.
*/
selectedNoteIds(): Promise<string[]>;
/**
* Gets the last hash (note section ID) from cross-note link targeting specific section.
* New hash is available after `onNoteSelectionChange()` is triggered.
* Example of cross-note link where `hello-world` is a hash: [Other Note Title](:/9bc9a5cb83f04554bf3fd3e41b4bb415#hello-world).
* Method returns empty value when a note was navigated with method other than cross-note link containing valid hash.
*/
selectedNoteHash(): Promise<string>;
}
export {};

View File

@@ -372,6 +372,19 @@ export interface DialogResult {
formData?: any;
}
export enum ToastType {
Info = 'info',
Success = 'success',
Error = 'error',
}
export interface Toast {
message: string;
type?: ToastType;
duration?: number;
timestamp?: number;
}
export interface Size {
width?: number;
height?: number;
@@ -384,9 +397,40 @@ export interface Rectangle {
height?: number;
}
export type ActivationCheckCallback = ()=> Promise<boolean>;
export interface EditorUpdateEvent {
newBody: string;
noteId: string;
}
export type UpdateCallback = (event: EditorUpdateEvent)=> Promise<void>;
export type UpdateCallback = ()=> Promise<void>;
export interface ActivationCheckEvent {
handle: ViewHandle;
noteId: string;
}
export type ActivationCheckCallback = (event: ActivationCheckEvent)=> Promise<boolean>;
/**
* Required callbacks for creating an editor plugin.
*/
export interface EditorPluginCallbacks {
/**
* Emitted when the editor can potentially be activated - this is for example when the current
* note is changed, or when the application is opened. At that point you should check the
* current note and decide whether your editor should be activated or not. If it should, return
* `true`, otherwise return `false`.
*/
onActivationCheck: ActivationCheckCallback;
/**
* Emitted when an editor view is created. This happens, for example, when a new window containing
* a new editor is created.
*
* This callback should set the editor plugin's HTML using `editors.setHtml`, add scripts to the editor
* with `editors.addScript`, and optionally listen for external changes using `editors.onUpdate`.
*/
onSetup: (handle: ViewHandle)=> Promise<void>;
}
export type VisibleHandler = ()=> Promise<void>;
@@ -395,6 +439,8 @@ export interface EditContextMenuFilterObject {
}
export interface EditorActivationCheckFilterObject {
effectiveNoteId: string;
windowId: string;
activatedEditors: {
pluginId: string;
viewId: string;
@@ -404,6 +450,20 @@ export interface EditorActivationCheckFilterObject {
export type FilterHandler<T> = (object: T)=> Promise<T>;
export type CommandArgument = string|number|object|boolean|null;
export interface MenuTemplateItem {
label?: string;
command?: string;
commandArgs?: CommandArgument[];
}
export interface WebviewApi {
postMessage: (message: object)=> unknown;
onMessage: (message: object)=> void;
menuPopupFromTemplate: (template: MenuTemplateItem[])=> void;
}
// =================================================================
// Settings types
// =================================================================
@@ -528,6 +588,30 @@ export interface SettingSection {
*/
export type Path = string[];
// =================================================================
// Clipboard API types
// =================================================================
/**
* Represents content that can be written to the clipboard in multiple formats.
*/
export interface ClipboardContent {
/**
* Plain text representation of the content
*/
text?: string;
/**
* HTML representation of the content
*/
html?: string;
/**
* Image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format
*/
image?: string;
}
// =================================================================
// Content Script types
// =================================================================
@@ -609,6 +693,27 @@ export interface CodeMirrorControl {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
enableLanguageDataAutocomplete: { of: (enabled: boolean)=> any };
/**
* A CodeMirror [facet](https://codemirror.net/docs/ref/#state.EditorState.facet) that contains
* the ID of the note currently open in the editor.
*
* Access the value of this facet using
* ```ts
* const noteIdFacet = editorControl.joplinExtensions.noteIdFacet;
* const editorState = editorControl.editor.state;
* const noteId = editorState.facet(noteIdFacet);
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- No better type available
noteIdFacet: any;
/**
* A CodeMirror [StateEffect](https://codemirror.net/docs/ref/#state.StateEffect) that is
* included in a [Transaction](https://codemirror.net/docs/ref/#state.Transaction) when the
* note ID changes.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- No better type available
setNoteIdEffect: any;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,25 +3,26 @@
"version": "1.0.0",
"description": "",
"scripts": {
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"dist": "webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && webpack --env joplin-plugin-config=createArchive",
"prepare": "npm run dist",
"update": "npm install -g generator-joplin && yo joplin --update"
"update": "npm install -g generator-joplin && yo joplin --node-package-manager npm --update --force",
"updateVersion": "webpack --env joplin-plugin-config=updateVersion"
},
"keywords": [
"joplin-plugin"
],
"license": "MIT",
"devDependencies": {
"@types/node": "^14.0.14",
"copy-webpack-plugin": "^6.1.0",
"fs-extra": "^9.0.1",
"glob": "^7.1.6",
"@types/node": "^18.7.13",
"copy-webpack-plugin": "^11.0.0",
"fs-extra": "^10.1.0",
"glob": "^8.0.3",
"on-build-webpack": "^0.1.0",
"tar": "^6.0.5",
"ts-loader": "^7.0.5",
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"tar": "^6.1.11",
"ts-loader": "^9.3.1",
"typescript": "^4.8.2",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"chalk": "^4.1.0",
"yargs": "^16.2.0"
},

View File

@@ -1,4 +1,5 @@
import joplin from 'api';
import { MenuItem } from 'api/types';
joplin.plugins.register({
onStart: async function() {
@@ -21,5 +22,29 @@ joplin.plugins.register({
],
},
]);
await joplin.workspace.filterEditorContextMenu(async (object: any) => {
const newItems: MenuItem[] = [];
newItems.push({
label: 'filterEditorContextMenu test 1',
commandName: 'newNote',
commandArgs: ['Created from context menu 1'],
});
newItems.push({
type: 'separator',
});
newItems.push({
label: 'filterEditorContextMenu test 2',
commandName: 'newNote',
commandArgs: ['Created from context menu 2'],
});
object.items = object.items.concat(newItems);
return object;
});
},
});

View File

@@ -5,9 +5,6 @@
"target": "es2015",
"jsx": "react",
"allowJs": true,
"baseUrl": ".",
"typeRoots": [
"./node_modules/@types"
]
"baseUrl": "."
}
}

View File

@@ -6,16 +6,21 @@
// update, you can easily restore the functionality you've added.
// -----------------------------------------------------------------------------
/* eslint-disable no-console */
const path = require('path');
const crypto = require('crypto');
const fs = require('fs-extra');
const chalk = require('chalk');
const CopyPlugin = require('copy-webpack-plugin');
const WebpackOnBuildPlugin = require('on-build-webpack');
const tar = require('tar');
const glob = require('glob');
const execSync = require('child_process').execSync;
// AUTO-GENERATED by updateCategories
const allPossibleCategories = [{ 'name': 'appearance' }, { 'name': 'developer tools' }, { 'name': 'productivity' }, { 'name': 'themes' }, { 'name': 'integrations' }, { 'name': 'viewer' }, { 'name': 'search' }, { 'name': 'tags' }, { 'name': 'editor' }, { 'name': 'files' }, { 'name': 'personal knowledge management' }];
// AUTO-GENERATED by updateCategories
const rootDir = path.resolve(__dirname);
const userConfigFilename = './plugin.config.json';
const userConfigPath = path.resolve(rootDir, userConfigFilename);
@@ -23,19 +28,34 @@ const distDir = path.resolve(rootDir, 'dist');
const srcDir = path.resolve(rootDir, 'src');
const publishDir = path.resolve(rootDir, 'publish');
const userConfig = Object.assign({}, {
const userConfig = {
extraScripts: [],
}, fs.pathExistsSync(userConfigPath) ? require(userConfigFilename) : {});
...(fs.pathExistsSync(userConfigPath) ? require(userConfigFilename) : {}),
};
const manifestPath = `${srcDir}/manifest.json`;
const packageJsonPath = `${rootDir}/package.json`;
const allPossibleCategories = ['appearance', 'developer tools', 'productivity', 'themes', 'integrations', 'viewer', 'search', 'tags', 'editor', 'files', 'personal knowledge management'];
const allPossibleScreenshotsType = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
const manifest = readManifest(manifestPath);
const pluginArchiveFilePath = path.resolve(publishDir, `${manifest.id}.jpl`);
const pluginInfoFilePath = path.resolve(publishDir, `${manifest.id}.json`);
const { builtinModules } = require('node:module');
// Webpack5 doesn't polyfill by default and displays a warning when attempting to require() built-in
// node modules. Set these to false to prevent Webpack from warning about not polyfilling these modules.
// We don't need to polyfill because the plugins run in Electron's Node environment.
const moduleFallback = {};
for (const moduleName of builtinModules) {
moduleFallback[moduleName] = false;
}
const getPackageJson = () => {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
};
function validatePackageJson() {
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const content = getPackageJson();
if (!content.name || content.name.indexOf('joplin-plugin-') !== 0) {
console.warn(chalk.yellow(`WARNING: To publish the plugin, the package name should start with "joplin-plugin-" (found "${content.name}") in ${packageJsonPath}`));
}
@@ -71,21 +91,45 @@ function currentGitInfo() {
function validateCategories(categories) {
if (!categories) return null;
if ((categories.length !== new Set(categories).size)) throw new Error('Repeated categories are not allowed');
// eslint-disable-next-line github/array-foreach -- Old code before rule was applied
categories.forEach(category => {
if (!allPossibleCategories.includes(category)) throw new Error(`${category} is not a valid category. Please make sure that the category name is lowercase. Valid Categories are: \n${allPossibleCategories}\n`);
if (!allPossibleCategories.map(category => { return category.name; }).includes(category)) throw new Error(`${category} is not a valid category. Please make sure that the category name is lowercase. Valid categories are: \n${allPossibleCategories.map(category => { return category.name; })}\n`);
});
}
function validateScreenshots(screenshots) {
if (!screenshots) return null;
for (const screenshot of screenshots) {
if (!screenshot.src) throw new Error('You must specify a src for each screenshot');
// Avoid attempting to download and verify URL screenshots.
if (screenshot.src.startsWith('https://') || screenshot.src.startsWith('http://')) {
continue;
}
const screenshotType = screenshot.src.split('.').pop();
if (!allPossibleScreenshotsType.includes(screenshotType)) throw new Error(`${screenshotType} is not a valid screenshot type. Valid types are: \n${allPossibleScreenshotsType}\n`);
const screenshotPath = path.resolve(rootDir, screenshot.src);
// Max file size is 1MB
const fileMaxSize = 1024;
const fileSize = fs.statSync(screenshotPath).size / 1024;
if (fileSize > fileMaxSize) throw new Error(`Max screenshot file size is ${fileMaxSize}KB. ${screenshotPath} is ${fileSize}KB`);
}
}
function readManifest(manifestPath) {
const content = fs.readFileSync(manifestPath, 'utf8');
const output = JSON.parse(content);
if (!output.id) throw new Error(`Manifest plugin ID is not set in ${manifestPath}`);
validateCategories(output.categories);
validateScreenshots(output.screenshots);
return output;
}
function createPluginArchive(sourceDir, destPath) {
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true, windowsPathsNoEscape: true })
.map(f => f.substr(sourceDir.length + 1));
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
@@ -99,18 +143,22 @@ function createPluginArchive(sourceDir, destPath) {
cwd: sourceDir,
sync: true,
},
distFiles
distFiles,
);
console.info(chalk.cyan(`Plugin archive has been created in ${destPath}`));
}
const writeManifest = (manifestPath, content) => {
fs.writeFileSync(manifestPath, JSON.stringify(content, null, '\t'), 'utf8');
};
function createPluginInfo(manifestPath, destPath, jplFilePath) {
const contentText = fs.readFileSync(manifestPath, 'utf8');
const content = JSON.parse(contentText);
content._publish_hash = `sha256:${fileSha256(jplFilePath)}`;
content._publish_commit = currentGitInfo();
fs.writeFileSync(destPath, JSON.stringify(content, null, '\t'), 'utf8');
writeManifest(destPath, content);
}
function onBuildCompleted() {
@@ -137,14 +185,15 @@ const baseConfig = {
},
],
},
...userConfig.webpackOverrides,
};
const pluginConfig = Object.assign({}, baseConfig, {
entry: './src/index.ts',
const pluginConfig = { ...baseConfig, entry: './src/index.ts',
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
},
fallback: moduleFallback,
// JSON files can also be required from scripts so we include this.
// https://github.com/joplin/plugin-bibtex/pull/2
extensions: ['.js', '.tsx', '.ts', '.json'],
@@ -171,26 +220,63 @@ const pluginConfig = Object.assign({}, baseConfig, {
},
],
}),
],
});
] };
const extraScriptConfig = Object.assign({}, baseConfig, {
// These libraries can be included with require(...) or
// joplin.require(...) from content scripts.
const externalContentScriptLibraries = [
'@codemirror/view',
'@codemirror/state',
'@codemirror/search',
'@codemirror/language',
'@codemirror/autocomplete',
'@codemirror/commands',
'@codemirror/highlight',
'@codemirror/lint',
'@codemirror/lang-html',
'@codemirror/lang-markdown',
'@codemirror/language-data',
'@lezer/common',
'@lezer/markdown',
'@lezer/highlight',
];
const extraScriptExternals = {};
for (const library of externalContentScriptLibraries) {
extraScriptExternals[library] = { commonjs: library };
}
const extraScriptConfig = {
...baseConfig,
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
},
fallback: moduleFallback,
extensions: ['.js', '.tsx', '.ts', '.json'],
},
});
// We support requiring @codemirror/... libraries through require('@codemirror/...')
externalsType: 'commonjs',
externals: extraScriptExternals,
};
const createArchiveConfig = {
stats: 'errors-only',
entry: './dist/index.js',
resolve: {
fallback: moduleFallback,
},
output: {
filename: 'index.js',
path: publishDir,
},
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
plugins: [{
apply(compiler) {
compiler.hooks.done.tap('archiveOnBuildListener', onBuildCompleted);
},
}],
};
function resolveExtraScriptPath(name) {
@@ -222,20 +308,43 @@ function buildExtraScriptConfigs(userConfig) {
for (const scriptName of userConfig.extraScripts) {
const scriptPaths = resolveExtraScriptPath(scriptName);
output.push(Object.assign({}, extraScriptConfig, {
entry: scriptPaths.entry,
output: scriptPaths.output,
}));
output.push({ ...extraScriptConfig, entry: scriptPaths.entry,
output: scriptPaths.output });
}
return output;
}
function main(processArgv) {
const yargs = require('yargs/yargs');
const argv = yargs(processArgv).argv;
const increaseVersion = version => {
try {
const s = version.split('.');
const d = Number(s[s.length - 1]) + 1;
s[s.length - 1] = `${d}`;
return s.join('.');
} catch (error) {
error.message = `Could not parse version number: ${version}: ${error.message}`;
throw error;
}
};
const configName = argv['joplin-plugin-config'];
const updateVersion = () => {
const packageJson = getPackageJson();
packageJson.version = increaseVersion(packageJson.version);
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8');
const manifest = readManifest(manifestPath);
manifest.version = increaseVersion(manifest.version);
writeManifest(manifestPath, manifest);
if (packageJson.version !== manifest.version) {
console.warn(chalk.yellow(`Version numbers have been updated but they do not match: package.json (${packageJson.version}), manifest.json (${manifest.version}). Set them to the required values to get them in sync.`));
} else {
console.info(packageJson.version);
}
};
function main(environ) {
const configName = environ['joplin-plugin-config'];
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
// Webpack configurations run in parallel, while we need them to run in
@@ -270,22 +379,30 @@ function main(processArgv) {
fs.mkdirpSync(publishDir);
}
if (configName === 'updateVersion') {
updateVersion();
return [];
}
return configs[configName];
}
let exportedConfigs = [];
try {
exportedConfigs = main(process.argv);
} catch (error) {
console.error(chalk.red(error.message));
process.exit(1);
}
module.exports = (env) => {
let exportedConfigs = [];
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
try {
exportedConfigs = main(env);
} catch (error) {
console.error(error.message);
process.exit(1);
}
module.exports = exportedConfigs;
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
return exportedConfigs;
};

View File

@@ -297,7 +297,11 @@ class AppComponent extends Component {
if (!this.state.contentScriptLoaded) {
let msg = 'Loading...';
if (this.state.contentScriptError) msg = `The Joplin extension is not available on this tab due to: ${this.state.contentScriptError}`;
return <div style={{ padding: 10, fontSize: 12, maxWidth: 200 }}>{msg}</div>;
return (
<div className="App Startup">
{msg}
</div>
);
}
const warningComponent = !this.props.warning ? null : <div className="Warning">{ this.props.warning }</div>;

View File

@@ -6,7 +6,7 @@ const shim: typeof ShimType = require('@joplin/lib/shim').default;
import { isCallbackUrl } from '@joplin/lib/callbackUrlUtils';
import { FileLocker } from '@joplin/utils/fs';
import { IpcMessageHandler, IpcServer, Message, newHttpError, sendMessage, SendMessageOptions, startServer, stopServer } from '@joplin/utils/ipc';
import { BrowserWindow, Tray, WebContents, screen, App, nativeTheme } from 'electron';
import { BrowserWindow, Tray, WebContents, screen, App, nativeTheme, Menu, session as electronSession, Session } from 'electron';
import bridge from './bridge';
import * as url from 'url';
const path = require('path');
@@ -16,7 +16,7 @@ const fs = require('fs-extra');
import { dialog, ipcMain } from 'electron';
import { _ } from '@joplin/lib/locale';
import restartInSafeModeFromMain from './utils/restartInSafeModeFromMain';
import handleCustomProtocols, { CustomProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
import handleCustomProtocols, { CustomProtocolHandlers } from './utils/customProtocols/handleCustomProtocols';
import { clearTimeout, setTimeout } from 'timers';
import { resolve } from 'path';
import { defaultWindowId } from '@joplin/lib/reducer';
@@ -30,8 +30,7 @@ interface RendererProcessQuitReply {
}
interface PluginWindows {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
[key: string]: any;
[key: string]: BrowserWindow;
}
type SecondaryWindowId = string;
@@ -48,7 +47,6 @@ export interface Options {
}
export default class ElectronAppWrapper {
private logger_: Logger = null;
private electronApp_: App;
private env_: string;
private isDebugMode_: boolean;
@@ -61,22 +59,23 @@ export default class ElectronAppWrapper {
private secondaryWindows_: Map<SecondaryWindowId, SecondaryWindowData> = new Map();
private willQuitApp_ = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
private tray_: any = null;
private tray_: Tray = null;
private buildDir_: string = null;
private rendererProcessQuitReply_: RendererProcessQuitReply = null;
private initialCallbackUrl_: string = null;
private updaterService_: AutoUpdaterService = null;
private customProtocolHandler_: CustomProtocolHandler = null;
private customProtocolHandlers_: CustomProtocolHandlers|null = null;
private updatePollInterval_: ReturnType<typeof setTimeout>|null = null;
private joplinSession_: Session|null = null;
private profileLocker_: FileLocker|null = null;
private ipcServer_: IpcServer|null = null;
private ipcStartPort_ = 2658;
private ipcLogger_: Logger;
private ipcLoggerFilePath_: string;
private mainProcessLoggerFilePath_: string;
private ipcLogger_: LoggerWrapper;
private appLogger_: LoggerWrapper;
public constructor(electronApp: App, { env, profilePath, isDebugMode, initialCallbackUrl, isEndToEndTesting }: Options) {
this.electronApp_ = electronApp;
@@ -88,28 +87,20 @@ export default class ElectronAppWrapper {
this.profileLocker_ = new FileLocker(`${this.profilePath_}/lock`);
// Note: in certain contexts `this.logger_` doesn't seem to be available, especially for IPC
// calls, either because it hasn't been set or other issue. So we set one here specifically
// for this.
this.ipcLogger_ = new Logger();
this.ipcLoggerFilePath_ = `${profilePath}/log-cross-app-ipc.txt`;
this.ipcLogger_.addTarget(TargetType.File, {
path: this.ipcLoggerFilePath_,
const mainProcessLogger = new Logger();
this.mainProcessLoggerFilePath_ = `${profilePath}/log-main-process.txt`;
mainProcessLogger.addTarget(TargetType.File, {
path: this.mainProcessLoggerFilePath_,
});
this.ipcLogger_ = Logger.create('IPC', mainProcessLogger);
this.appLogger_ = Logger.create('App', mainProcessLogger);
}
public electronApp() {
return this.electronApp_;
}
public setLogger(v: Logger) {
this.logger_ = v;
}
public logger() {
return this.logger_;
}
public mainWindow() {
return this.win_;
}
@@ -122,8 +113,8 @@ export default class ElectronAppWrapper {
return !!this.ipcServer_;
}
public ipcLoggerFilePath() {
return this.ipcLoggerFilePath_;
public mainProcessLogFilePath() {
return this.mainProcessLoggerFilePath_;
}
public windowById(joplinId: string) {
@@ -176,6 +167,10 @@ export default class ElectronAppWrapper {
public async handleAppFailure(errorMessage: string, canIgnore: boolean, isTesting?: boolean) {
await bridge().captureException(new Error(errorMessage));
if (this.win_ && this.win_.isDestroyed()) {
return;
}
const buttons = [];
buttons.push(_('Quit'));
const exitIndex = 0;
@@ -199,7 +194,7 @@ export default class ElectronAppWrapper {
//
// Also only run this if not testing (crashing the renderer breaks automated
// tests).
if (this.win_ && !this.win_.webContents.isCrashed() && !isTesting) {
if (this.win_ && !this.win_.isDestroyed() && !this.win_.webContents.isCrashed() && !isTesting) {
this.win_.webContents.forcefullyCrashRenderer();
}
} else if (response === exitIndex) {
@@ -207,13 +202,46 @@ export default class ElectronAppWrapper {
}
}
private createJoplinSession_() {
const sessionPath = path.join(this.profilePath_, 'internal');
const joplinSession = electronSession.fromPath(sessionPath, { cache: false });
// One-time migration: copy existing dictionary words from the old Electron userData location into the new session.
const migrationFlagPath = path.join(this.profilePath_, 'spell-checker-migration-done');
if (!fs.existsSync(migrationFlagPath)) {
try {
const wordsToMigrate = new Set<string>();
const oldElectronDictPath = path.join(this.electronApp_.getPath('userData'), 'Custom Dictionary.txt');
if (fs.existsSync(oldElectronDictPath)) {
const content = fs.readFileSync(oldElectronDictPath, 'utf8');
const words = content.split('\n')
.map((w: string) => w.trim())
.filter((w: string) => w.length > 0 && !/^checksum_v1\s*=/.test(w));
for (const word of words) {
wordsToMigrate.add(word);
}
}
for (const word of wordsToMigrate) {
joplinSession.addWordToSpellCheckerDictionary(word);
}
fs.writeFileSync(migrationFlagPath, '', 'utf8');
} catch (error) {
console.warn('Failed to migrate spell-check dictionary:', error);
}
}
return joplinSession;
}
public createWindow() {
// Set to true to view errors if the application does not start
const debugEarlyBugs = this.env_ === 'dev' || this.isDebugMode_;
const windowStateKeeper = require('electron-window-state');
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const stateOptions: any = {
defaultWidth: Math.round(0.8 * screen.getPrimaryDisplay().workArea.width),
@@ -239,6 +267,7 @@ export default class ElectronAppWrapper {
// this needs to be a non-transparent color:
backgroundColor: nativeTheme.shouldUseDarkColors ? '#333' : '#fff',
webPreferences: {
session: this.joplinSession_,
nodeIntegration: true,
contextIsolation: false,
spellcheck: true,
@@ -348,7 +377,7 @@ export default class ElectronAppWrapper {
} catch (error) {
// This will throw an exception "Object has been destroyed" if the app is closed
// in less that the timeout interval. It can be ignored.
console.warn('Error opening dev tools', error);
this.appLogger_.warn('Error opening dev tools', error);
}
}, 1000);
}
@@ -410,12 +439,15 @@ export default class ElectronAppWrapper {
// On Windows and Linux, the app is closed when the window is closed *except* if the tray icon is used. In which
// case the app must be explicitly closed with Ctrl+Q or by right-clicking on the tray icon and selecting "Exit".
this.appLogger_.info('[appClose] Window close event - willQuitApp_:', this.willQuitApp_, 'rendererProcessQuitReply_:', this.rendererProcessQuitReply_, 'secondaryWindows:', this.secondaryWindows_.size, 'trayShown:', this.trayShown());
let isGoingToExit = false;
if (process.platform === 'darwin') {
if (this.willQuitApp_) {
isGoingToExit = true;
} else {
this.appLogger_.info('[appClose] macOS: willQuitApp_ is false, hiding window instead of closing');
event.preventDefault();
const w = this.win_;
@@ -439,21 +471,27 @@ export default class ElectronAppWrapper {
}
}
this.appLogger_.info('[appClose] isGoingToExit:', isGoingToExit);
if (isGoingToExit) {
if (!this.rendererProcessQuitReply_) {
// If we haven't notified the renderer process yet, do it now
// so that it can tell us if we can really close the app or not.
// Search for "appClose" event for closing logic on renderer side.
this.appLogger_.info('[appClose] Sending appClose to renderer, waiting for reply...');
event.preventDefault();
if (this.win_) this.win_.webContents.send('appClose');
} else {
// If the renderer process has responded, check if we can close or not
this.appLogger_.info('[appClose] Got renderer reply - canClose:', this.rendererProcessQuitReply_.canClose);
if (this.rendererProcessQuitReply_.canClose) {
// Really quit the app
this.appLogger_.info('[appClose] Closing app now');
this.rendererProcessQuitReply_ = null;
this.win_ = null;
} else {
// Wait for renderer to finish task
this.appLogger_.info('[appClose] Renderer says cannot close yet, waiting...');
event.preventDefault();
this.rendererProcessQuitReply_ = null;
}
@@ -469,8 +507,31 @@ export default class ElectronAppWrapper {
// Match the main window's zoom:
window.webContents.setZoomFactor(this.mainWindow().webContents.getZoomFactor());
window.once('close', () => {
this.secondaryWindows_.delete(windowId);
window.once('close', (event) => {
// Check both: BrowserWindow and webContents can be destroyed independently
if (this.win_ && !this.win_.isDestroyed() && !this.win_.webContents.isDestroyed()) {
this.win_.webContents.send('secondary-window-closing', windowId);
}
if (this.secondaryWindows_.has(windowId)) {
this.secondaryWindows_.delete(windowId);
// Avoid closing a destroyed window. Closing a destroyed window results in the following error:
// Error: Render frame was disposed before WebFrameMain could be accessed
const stillOpen = !window.isDestroyed();
if (stillOpen) {
event.preventDefault();
// As of March 2026, Electron crashes with "Assertion failed: (Environment::GetCurrent(isolate)) == (env)" if the native 'close'
// event is allowed to close a secondary window. As a workaround, briefly hide the window and .close() it later.
// See https://github.com/laurent22/joplin/issues/14628.
window.hide();
setTimeout(() => {
if (!window.isDestroyed()) {
window.close();
}
}, 100);
}
}
const allSecondaryWindowsClosed = this.secondaryWindows_.size === 0;
const mainWindowVisuallyClosed = this.mainWindowHidden_;
@@ -518,8 +579,8 @@ export default class ElectronAppWrapper {
// sends a message. In which case, the above code would try to
// access a destroyed webview.
// https://github.com/laurent22/joplin/issues/4570
console.error('Could not process plugin message:', message);
console.error(error);
this.appLogger_.error('Could not process plugin message:', message);
this.appLogger_.error(error);
}
});
@@ -544,8 +605,7 @@ export default class ElectronAppWrapper {
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public registerPluginWindow(pluginId: string, window: any) {
public registerPluginWindow(pluginId: string, window: BrowserWindow) {
this.pluginWindows_[pluginId] = window;
}
@@ -574,10 +634,23 @@ export default class ElectronAppWrapper {
}
public quit() {
this.appLogger_.info('[appClose] quit() called');
this.onExit();
this.electronApp_.quit();
}
public quitWithSyncCheck(
dispatch: (action: { type: string; [key: string]: unknown })=> void,
syncPending: boolean,
) {
this.appLogger_.info('[appClose] quitWithSyncCheck() called - syncPending:', syncPending);
if (syncPending) {
dispatch({ type: 'QUIT_SYNC_DIALOG_OPEN' });
} else {
this.quit();
}
}
public exit(errorCode = 0) {
this.onExit();
this.electronApp_.exit(errorCode);
@@ -620,8 +693,7 @@ export default class ElectronAppWrapper {
}
// Note: this must be called only after the "ready" event of the app has been dispatched
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public createTray(contextMenu: any) {
public createTray(contextMenu: Menu) {
try {
this.tray_ = new Tray(`${this.buildDir()}/icons/${this.trayIconFilename_()}`);
this.tray_.setToolTip(this.electronApp_.name);
@@ -629,7 +701,7 @@ export default class ElectronAppWrapper {
this.tray_.on('click', () => {
if (!this.mainWindow()) {
console.warn('The window object was not available during the click event from tray icon');
this.appLogger_.warn('The window object was not available during the click event from tray icon');
return;
}
if (!this.mainWindow().isVisible()) {
@@ -639,7 +711,7 @@ export default class ElectronAppWrapper {
}
});
} catch (error) {
console.error('Cannot create tray', error);
this.appLogger_.error('Cannot create tray', error);
}
}
@@ -786,7 +858,7 @@ export default class ElectronAppWrapper {
}
this.quit();
if (this.env() === 'dev') console.warn(`Closing the application because another instance is already running, or the previous instance was force-quit within the last ${Math.round(this.profileLocker_.options.interval / Second)} seconds.`);
if (this.env() === 'dev') this.appLogger_.warn(`Closing the application because another instance is already running, or the previous instance was force-quit within the last ${Math.round(this.profileLocker_.options.interval / Second)} seconds.`);
return true;
}
@@ -816,8 +888,12 @@ export default class ElectronAppWrapper {
}
};
public getCustomProtocolHandler() {
return this.customProtocolHandler_;
public getContentProtocolHandler() {
return this.customProtocolHandlers_.appContent;
}
public getPluginProtocolHandler() {
return this.customProtocolHandlers_.pluginContent;
}
private async fixLinuxAccessibility_() {
@@ -830,8 +906,7 @@ export default class ElectronAppWrapper {
return matchingProcesses.trim().length > 0;
} catch (error) {
if (error.stderr || error.exitCode !== 1) {
// eslint-disable-next-line no-console -- The main logger is not available at this point.
console.error('Failed to check for and enable accessibility support:', error.stderr);
this.appLogger_.error('Failed to check for and enable accessibility support:', error.stderr);
}
return false;
@@ -841,8 +916,7 @@ export default class ElectronAppWrapper {
// Work around https://issues.chromium.org/issues/431257156 by force-enabling accessibility
// when Orca (a screen reader) is running:
if (await isOrcaRunning()) {
// eslint-disable-next-line no-console -- The main logger is not available at this point.
console.log('Linux accessibility: Enabling full accessibility support.');
this.appLogger_.info('Linux accessibility: Enabling full accessibility support.');
this.electronApp().setAccessibilitySupportEnabled(true);
}
}
@@ -857,14 +931,18 @@ export default class ElectronAppWrapper {
await this.fixLinuxAccessibility_();
this.customProtocolHandler_ = handleCustomProtocols();
// Session must be created before handleCustomProtocols() so both use the same object.
this.joplinSession_ = this.createJoplinSession_();
this.customProtocolHandlers_ = handleCustomProtocols(this.joplinSession_);
this.createWindow();
this.electronApp_.on('before-quit', () => {
this.appLogger_.info('[appClose] before-quit event fired, setting willQuitApp_ = true');
this.willQuitApp_ = true;
});
this.electronApp_.on('window-all-closed', () => {
this.appLogger_.info('[appClose] window-all-closed event fired');
this.quit();
});

View File

@@ -11,8 +11,7 @@ const logger = Logger.create('app.reducer');
export interface AppStateRoute {
type: string;
routeName: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
props: any;
props: Record<string, unknown>;
}
export enum AppStateDialogName {
@@ -22,8 +21,7 @@ export enum AppStateDialogName {
export interface AppStateDialog {
name: AppStateDialogName;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
props: Record<string, any>;
props: Record<string, unknown>;
}
export interface NoteIdToScrollPercent {

View File

@@ -43,7 +43,7 @@ const electronContextMenu = require('./services/electron-context-menu');
// Commands that are not tied to any particular component.
// The runtime for these commands can be loaded when the app starts.
import PerFolderSortOrderService from './services/sortOrder/PerFolderSortOrderService';
import PerFolderSortOrderService from '@joplin/lib/services/sortOrder/PerFolderSortOrderService';
import ShareService from '@joplin/lib/services/share/ShareService';
import checkForUpdates from './checkForUpdates';
import { AppState } from './app.reducer';
@@ -58,7 +58,7 @@ import OcrDriverTesseract from '@joplin/lib/services/ocr/drivers/OcrDriverTesser
import OcrDriverTranscribe from '@joplin/lib/services/ocr/drivers/OcrDriverTranscribe';
import SearchEngine from '@joplin/lib/services/search/SearchEngine';
import { PackageInfo } from '@joplin/lib/versionInfo';
import { CustomProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
import { CustomContentProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
import { refreshFolders } from '@joplin/lib/folders-screen-utils';
import initializeCommandService from './utils/initializeCommandService';
import OcrDriverBase from '@joplin/lib/services/ocr/OcrDriverBase';
@@ -78,11 +78,10 @@ type StartupTask = { label: string; task: ()=> void|Promise<void> };
class Application extends BaseApplication {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
private checkAllPluginStartedIID_: any = null;
private checkAllPluginStartedIID_: ReturnType<typeof setInterval> = null;
private initPluginServiceDone_ = false;
private ocrService_: OcrService;
private protocolHandler_: CustomProtocolHandler;
private protocolHandler_: CustomContentProtocolHandler;
public constructor() {
super();
@@ -130,7 +129,7 @@ class Application extends BaseApplication {
}
if (action.type === 'SETTING_UPDATE_ONE' && action.key === 'renderer.fileUrls' || action.type === 'SETTING_UPDATE_ALL') {
bridge().electronApp().getCustomProtocolHandler().setMediaAccessEnabled(
bridge().electronApp().getContentProtocolHandler().setMediaAccessEnabled(
Setting.value('renderer.fileUrls'),
);
}
@@ -212,7 +211,12 @@ class Application extends BaseApplication {
const contextMenu = Menu.buildFromTemplate([
{ label: _('Open %s', app.electronApp().name), click: () => { app.mainWindow().show(); } },
{ type: 'separator' },
{ label: _('Quit'), click: () => { void app.quit(); } },
{ label: _('Quit'), click: () => {
app.quitWithSyncCheck(
(action: { type: string; [key: string]: unknown }) => this.store().dispatch(action),
this.store().getState().syncPending,
);
} },
]);
app.createTray(contextMenu);
}
@@ -477,7 +481,7 @@ class Application extends BaseApplication {
}
addTask('app/set up custom protocol handler', async () => {
this.protocolHandler_ = bridge().electronApp().getCustomProtocolHandler();
this.protocolHandler_ = bridge().electronApp().getContentProtocolHandler();
this.protocolHandler_.allowReadAccessToDirectory(__dirname); // App bundle directory
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('cacheDir'));
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('resourceDir'));
@@ -633,18 +637,23 @@ class Application extends BaseApplication {
if (Setting.value('env') === 'dev') {
void AlarmService.updateAllNotifications();
RevisionService.instance().runInBackground();
} else {
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
void reg.scheduleSync(1000).then(() => {
// Wait for the first sync before updating the notifications, since synchronisation
// might change the notifications.
void AlarmService.updateAllNotifications();
setTimeout(() => {
// Schedule sync with a delay of 0 and wrap with the desired timeout, as shim.setTimeout may not fire on first run or after an upgrade
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
void reg.scheduleSync(0).then(() => {
// Wait for the first sync before updating the notifications, since synchronisation
// might change the notifications.
void AlarmService.updateAllNotifications();
void DecryptionWorker.instance().scheduleStart();
});
void DecryptionWorker.instance().scheduleStart();
RevisionService.instance().runInBackground();
});
}, 1000);
}
RevisionService.instance().runInBackground();
this.startRotatingLogMaintenance(Setting.value('profileDir'));
});
@@ -723,6 +732,10 @@ class Application extends BaseApplication {
});
}
});
ipcRenderer.on('secondary-window-closing', (_event, windowId: string) => {
this.dispatch({ type: 'WINDOW_CLOSE', windowId });
});
});
addTask('app/initPluginService', () => this.initPluginService());

View File

@@ -1,7 +1,7 @@
import ElectronAppWrapper from './ElectronAppWrapper';
import shim, { MessageBoxType } from '@joplin/lib/shim';
import { _, setLocale } from '@joplin/lib/locale';
import { BrowserWindow, nativeTheme, nativeImage, shell, dialog, MessageBoxSyncOptions, safeStorage, Menu, MenuItemConstructorOptions, MenuItem } from 'electron';
import { BrowserWindow, nativeTheme, nativeImage, shell, dialog, MessageBoxSyncOptions, safeStorage, Menu, MenuItemConstructorOptions, MenuItem, BrowserWindowConstructorOptions, FileFilter, SaveDialogOptions } from 'electron';
import { dirname, toSystemSlashes } from '@joplin/lib/path-utils';
import { fileUriToPath } from '@joplin/utils/url';
import { urlDecode } from '@joplin/lib/string-utils';
@@ -25,8 +25,7 @@ interface OpenDialogOptions {
properties?: string[];
defaultPath?: string;
createDirectory?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
filters?: any[];
filters?: FileFilter[];
}
type OnAllowedExtensionsChange = (newExtensions: string[])=> void;
@@ -208,8 +207,7 @@ export class Bridge {
this.onAllowedExtensionsChangeListener_ = listener;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async captureException(error: any) {
public async captureException(error: unknown) {
Sentry.captureException(error);
// We wait to give the "beforeSend" event handler time to process the crash dump and write
// it to file.
@@ -335,8 +333,7 @@ export class Bridge {
return require('electron').shell.showItemInFolder(toSystemSlashes(fullPath));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public newBrowserWindow(options: any) {
public newBrowserWindow(options: BrowserWindowConstructorOptions) {
return new BrowserWindow(options);
}
@@ -353,8 +350,7 @@ export class Bridge {
return this.activeWindow().webContents.closeDevTools();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async showSaveDialog(options: any) {
public async showSaveDialog(options: SaveDialogOptions) {
if (!options) options = {};
if (!('defaultPath' in options) && this.lastSelectedPaths_.file) options.defaultPath = this.lastSelectedPaths_.file;
const { filePath } = await dialog.showSaveDialog(this.activeWindow(), options);
@@ -381,8 +377,7 @@ export class Bridge {
}
// Don't use this directly - call one of the showXxxxxxxMessageBox() instead
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
private showMessageBox_(window: any, options: MessageDialogOptions): number {
private showMessageBox_(window: BrowserWindow, options: MessageDialogOptions): number {
if (!window) window = this.activeWindow();
return dialog.showMessageBoxSync(window, { message: '', ...options });
}
@@ -428,8 +423,7 @@ export class Bridge {
return result;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public showInfoMessageBox(message: string, options: any = {}) {
public showInfoMessageBox(message: string, options: MessageDialogOptions = {}) {
const result = this.showMessageBox_(this.activeWindow(), { type: 'info',
message: message,
buttons: [_('OK')], ...options });
@@ -441,11 +435,11 @@ export class Bridge {
}
public get Menu() {
return require('electron').Menu;
return Menu;
}
public get MenuItem() {
return require('electron').MenuItem;
return MenuItem;
}
public async openExternal(url: string) {
@@ -559,7 +553,7 @@ export class Bridge {
});
if (buttonIndex === 1) {
void this.openItem(this.electronApp().ipcLoggerFilePath());
void this.openItem(this.electronApp().mainProcessLogFilePath());
}
}
}
@@ -583,6 +577,11 @@ export class Bridge {
execPath: process.env.PORTABLE_EXECUTABLE_FILE,
};
app.relaunch(options);
} else if (process.env.APPIMAGE && !this.altInstanceId_) {
app.relaunch({
execPath: process.env.APPIMAGE,
args: ['--appimage-extract-and-run'],
});
} else if (this.altInstanceId_) {
// Couldn't get it to work using relaunch() - it would just "close" the app, but it
// would still be open in the tray except unusable. Or maybe it reopens it quickly but

View File

@@ -4,7 +4,7 @@ import { _ } from '@joplin/lib/locale';
import bridge from './services/bridge';
import KvStore from '@joplin/lib/services/KvStore';
import * as ArrayUtils from '@joplin/lib/ArrayUtils';
import { CheckForUpdateOptions, extractVersionInfo, GitHubRelease } from './utils/checkForUpdatesUtils';
import { CheckForUpdateOptions, extractVersionInfo, GitHubRelease, handleReleaseResponseError } from './utils/checkForUpdatesUtils';
import { PackageInfo } from '@joplin/lib/versionInfo';
import { compareVersions } from 'compare-versions';
const packageInfo: PackageInfo = require('./packageInfo.js');
@@ -29,7 +29,8 @@ async function fetchLatestReleases() {
if (!response.ok) {
const responseText = await response.text();
throw new Error(`Cannot get latest release info: ${responseText.substr(0, 500)}`);
logger.error(`Cannot get latest release info (${response.status}): ${responseText.substr(0, 500)}`);
handleReleaseResponseError(response.status, responseText);
}
return (await response.json()) as GitHubRelease[];
@@ -48,8 +49,8 @@ function truncateText(text: string, length: number) {
}
async function getSkippedVersions(): Promise<string[]> {
const r = await KvStore.instance().value<string>('updateCheck::skippedVersions');
return r ? JSON.parse(r) : [];
const r = await KvStore.instance().value('updateCheck::skippedVersions');
return r && typeof r === 'string' ? JSON.parse(r) : [];
}
async function isSkippedVersion(v: string): Promise<boolean> {

Some files were not shown because too many files have changed in this diff Show More