1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-14 23:26:58 +02:00

Compare commits

...

166 Commits

Author SHA1 Message Date
palerdot
357277cda0 pass handleEscape as false in splitCommand for bundleDefaultPlugins 2023-04-11 15:27:02 +05:30
palerdot
8c1568ae81 pass options to splitCommand for bundleDefaultPlugins 2023-04-11 15:07:47 +05:30
palerdot
66e479d13d Revert "fix path separator in windows for default plugins"
This reverts commit 700c1410fa.
2023-04-11 15:05:51 +05:30
palerdot
700c1410fa fix path separator in windows for default plugins 2023-04-11 13:05:11 +05:30
palerdot
3873e15a21 fix __dirname in windows for default plugins 2023-04-11 12:27:43 +05:30
palerdot
72ec2d3b1e desktop: add jest types for tsconfig 2023-04-11 11:48:57 +05:30
palerdot
7eddbc7002 CI: run tsc task before build task in workspaces 2023-04-11 11:35:18 +05:30
palerdot
d593ed130e fix(CI): --topological-dev for building the project
ref: https://yarnpkg.com/cli/workspaces/foreach#options-topological-dev
@joplin/tools is a devDependency for lots of packages including
app-desktop. The build fails since this dev dependency was not
built as a required dependency in node_modules of desktop
2023-04-11 11:11:02 +05:30
palerdot
b2eabb3836 running updateIgnored at root 2023-04-11 10:54:44 +05:30
palerdot
5e1c789926 chore(desktop): move gulpfile to typescript 2023-04-10 17:46:37 +05:30
palerdot
4f552b396c fix(ci): bundleDefaultPlugins task fixes 2023-04-10 15:15:59 +05:30
palerdot
132bcbd477 chore: auto newline insert for package json 2023-04-10 12:46:50 +05:30
palerdot
8f6192464b Merge remote-tracking branch 'origin/dev' into mac-binary-signing-osxsign-upgrade 2023-04-10 11:24:44 +05:30
palerdot
897addec4e gulp: bundleDefaultPlugins task for desktop 2023-04-10 10:45:17 +05:30
github-actions[bot]
f3eea43d24 @tbjers has signed the CLA in laurent22/joplin#8036 2023-04-10 02:35:07 +00:00
Joplin Bot
8babaddbcb Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-04-09 12:21:18 +00:00
Laurent Cozic
13cdaabb17 Android 2.11.2 2023-04-09 14:07:14 +02:00
renovate[bot]
a94aa21088 Update dependency slugify to v1.6.6 (#8019)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2023-04-09 12:56:05 +01:00
Henry Heino
6116bed4e3 Mobile: Resolve #8022: Editor syntax highlighting was broken (#8023) 2023-04-09 12:55:47 +01:00
Arun Kumar
fabd0b4dda Desktop, Mobile: Fixes #7940: Removed MasterKey from Sync Status report (#8026) 2023-04-09 12:54:48 +01:00
Laurent Cozic
6b72f86e7b Mobile: Security: Prevent bypassing fingerprint lock on certain devices 2023-04-09 11:29:33 +02:00
Joplin Bot
02cf546124 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-04-09 06:17:13 +00:00
renovate[bot]
eecb012d64 Update dependency @react-native-community/netinfo to v9.3.8 (#8033)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-09 03:02:24 +00:00
Laurent Cozic
04e9b40769 Android 2.11.1 2023-04-08 10:51:00 +02:00
Laurent Cozic
efdbaeb397 Mobile: Add log info for biometrics feature 2023-04-08 10:40:53 +02:00
Laurent Cozic
46425b920c Doc: Added some doc about Joplin Server items 2023-04-07 16:49:54 +02:00
Laurent Cozic
f5be43c2ac Doc: Add info about synchronisation process 2023-04-07 16:36:59 +02:00
palerdot
51e865c467 change back to desktop directory after bundleDefaultPlugins 2023-04-07 15:50:22 +05:30
github-actions[bot]
080541a2fe @Letty has signed the CLA in laurent22/joplin#8029 2023-04-07 10:05:21 +00:00
palerdot
ac8b3ae0cc Merge remote-tracking branch 'origin/mac-binary-signing-osxsign-upgrade' into mac-binary-signing-osxsign-upgrade 2023-04-07 15:04:21 +05:30
palerdot
0b3919fd62 desktop: bundleDefaultPlugins task added to dist 2023-04-07 15:02:28 +05:30
github-actions[bot]
7dc638edf4 @gitstart has signed the CLA in laurent22/joplin#8024 2023-04-06 21:46:34 +00:00
Laurent Cozic
db69125e8f Merge branch 'dev' into mac-binary-signing-osxsign-upgrade 2023-04-06 14:03:08 +02:00
Laurent Cozic
3b686194d8 Tools: Pass APPLE_APP_SPECIFIC_PASSWORD to CI 2023-04-06 14:02:45 +02:00
Laurent Cozic
ccabc778f6 Merge branch 'dev' into mac-binary-signing-osxsign-upgrade 2023-04-06 12:13:35 +02:00
Laurent Cozic
5c2640f88f Tools: Simplify root workspace build 2023-04-06 12:11:45 +02:00
Laurent Cozic
eca0f92dff Disable again 2023-04-06 11:46:06 +02:00
Laurent Cozic
260fa6c038 Clipper release v2.11.2 2023-04-06 11:44:55 +02:00
Laurent Cozic
8ec6bc9138 Tools: Simplify dependencies of root package 2023-04-06 11:29:59 +02:00
Laurent Cozic
93fa92369b Tools: Removing packages/tools dependency from root workspace 2023-04-06 11:02:22 +02:00
Laurent Cozic
56b9c9fbc9 Merge branch 'dev' into mac-binary-signing-osxsign-upgrade 2023-04-06 10:03:12 +02:00
Laurent Cozic
bc6c5ab7a7 Chore: Make utils package a fixed version again (too many problems otherwise) 2023-04-06 10:02:49 +02:00
Laurent Cozic
c68d196baa Merge branch 'dev' into mac-binary-signing-osxsign-upgrade 2023-04-06 09:46:37 +02:00
Laurent Cozic
1826625e4f lock file 2023-04-05 23:19:25 +02:00
Laurent Cozic
20b8fb2719 Missing package 2023-04-05 22:48:17 +02:00
Laurent Cozic
f813e71b29 Chore: Access utils lib with relative path 2023-04-05 22:35:47 +02:00
Laurent Cozic
02422a6e31 Chore: Access utils lib with relative path 2023-04-05 22:35:46 +02:00
renovate[bot]
69a34e87f3 Update dependency nanoid to v3.3.6 (#7973)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 21:16:55 +01:00
Joplin Bot
cbeaa16b61 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-04-05 18:18:02 +00:00
Joplin Bot
05917ac142 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-04-05 12:24:26 +00:00
palerdot
897fd0f727 trying binary signing with plugin jpl path 2023-04-05 16:16:25 +05:30
palerdot
9edb402b18 fix mac app binary signing not a directory error 2023-04-05 15:38:02 +05:30
palerdot
36ae58ffe1 fix mac app binary signing by giving the directory path 2023-04-05 15:02:18 +05:30
palerdot
5ef8b86957 fix(ci): provide extraResources path for mac binary signing 2023-04-05 13:11:39 +05:30
palerdot
c7228cfcd6 fix(ci): desktop package directory navigation fix
correctly navigate to desktop directory for CI building after
building default plugins for CI
2023-04-05 12:40:02 +05:30
palerdot
7a791dbf98 Merge remote-tracking branch 'origin/dev' into mac-binary-signing-osxsign-upgrade 2023-04-05 12:23:28 +05:30
palerdot
a543588527 fix(ci): raw binary path before copying as extraResources 2023-04-05 11:39:58 +05:30
palerdot
998ad142a6 Revert "fix(ci): checking with binary path before copying as extraResources"
This reverts commit b6a53f96f7.
2023-04-05 11:39:08 +05:30
palerdot
b6a53f96f7 fix(ci): checking with binary path before copying as extraResources 2023-04-05 11:38:24 +05:30
palerdot
841a9c6e09 fix(ci): build default plugins for CI check and mac app signing 2023-04-05 11:34:35 +05:30
palerdot
d25c078ef0 fix: mac app correct extraResources path for binaries 2023-04-05 10:53:12 +05:30
Laurent Cozic
0c8de68b80 Desktop: Fixed issue with text disappearing within plugin-created zones when searching for text
Ref: https://github.com/joplin/plugin-abc-sheet-music/issues/5
2023-04-04 21:09:58 +02:00
Joplin Bot
44d93d52d3 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-04-04 18:30:09 +00:00
Laurent Cozic
073bec9e8c CI: Trying to fix website builder 2023-04-04 20:16:35 +02:00
Laurent Cozic
e6a8c2bea5 CI: Trying to fix website builder 2023-04-04 19:47:54 +02:00
Laurent Cozic
81c316cd2c CI: Trying to fix website builder 2023-04-04 19:24:03 +02:00
Laurent Cozic
659c851960 CI: Trying to fix website builder 2023-04-04 17:01:34 +02:00
Laurent Cozic
572701d9a0 Tools: Fix website builder 2023-04-04 12:04:42 +02:00
palerdot
ff69ac17be include default plugins and binary path for mac signing 2023-04-04 13:17:10 +05:30
palerdot
b44945b3a0 chore: electron-builder v24 update for @electron/osx-sign 2023-04-04 12:37:25 +05:30
palerdot
2584224026 chore: upgrade to @electron/notarize namespace 2023-04-04 12:29:44 +05:30
palerdot
46136871bf chore: upgrade to @electron/rebuild namespace 2023-04-04 11:44:02 +05:30
Laurent Cozic
66ef37bd4e Chore: Disable flaky test 2023-04-03 20:42:31 +02:00
Laurent Cozic
9ddf75604d Doc: Remove sponsor 2023-04-03 20:39:31 +02:00
Laurent Cozic
3ed7e1d7e8 Doc: Fix sponsor thumbnails 2023-04-03 20:39:31 +02:00
Laurent Cozic
b2b412105a Merge branch 'release-2.10' into dev 2023-04-03 18:30:55 +02:00
Laurent Cozic
60a3c4f65e lock file 2023-04-03 18:26:04 +02:00
Laurent Cozic
9645414c17 Desktop release v2.10.13 2023-04-03 18:10:54 +02:00
Henry Heino
af0136ef39 All: Fixes #7986: Fix OneDrive sync attempting to call method on null variable (#7987) 2023-04-03 18:09:52 +02:00
Self Not Found
b76586c4fd All: Fixes #7851: Encode the non-ASCII characters in OneDrive URI (#7868) 2023-04-03 18:09:10 +02:00
Laurent Cozic
376e4ebde0 Desktop: Fixed display of installed plugins in About box 2023-04-03 18:01:06 +02:00
renovate[bot]
1439b8787f Update dependency react-native-image-picker to v5.3.1 (#8015)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 11:51:02 +01:00
renovate[bot]
b8854a99be Update dependency @lezer/highlight to v1.1.4 (#8014)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 10:46:19 +00:00
renovate[bot]
6cf02173dc Update dependency gettext-extractor to v3.7.0 (#8012)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 10:56:44 +01:00
renovate[bot]
4d8a53d8c9 Update dependency react-native-image-picker to v5.3.0 (#8010)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 10:56:25 +01:00
renovate[bot]
7f43718e1d Update dependency react-select to v5.7.2 (#8009)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-02 07:09:26 +00:00
renovate[bot]
690ce637b1 Update dependency nodemon to v2.0.22 (#8008)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-02 03:42:02 +00:00
renovate[bot]
4d023e679e Update dependency turndown to v7.1.2 (#8006)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-01 16:46:25 +00:00
renovate[bot]
6e220a978f Update dependency jsdom to v21.1.1 (#8007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-01 16:00:34 +02:00
renovate[bot]
39757cd90e Update dependency sass to v1.59.3 (#8005)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-01 05:46:20 +00:00
renovate[bot]
5ccbbea757 Update dependency react-native-paper to v5.4.1 (#8004)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 22:56:15 +00:00
Arun Kumar
309222c082 Desktop: Fixes #8000: Fixed Linux tag display issues (#8002) 2023-03-31 23:13:59 +02:00
renovate[bot]
50f5fe2c91 Update dependency sass to v1.59.2 (#8001)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 23:12:25 +02:00
renovate[bot]
eacae83182 Update dependency react-native-paper to v5.4.0 (#7997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 23:12:05 +02:00
Laurent Cozic
403d770b1d Tools: Trying to prevent CI from running on forks 2023-03-30 22:57:58 +01:00
Laurent Cozic
a481bf1b53 Tools: Trying to prevent CI from running on forks 2023-03-30 22:55:14 +01:00
renovate[bot]
0d32570c9e Update dependency fs-extra to v11.1.1 (#7996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 20:11:29 +00:00
Fejby
f017e99b02 All: Translation: Update cs_CZ.po (#7999) 2023-03-30 14:40:05 -04:00
github-actions[bot]
a89d64d435 @Fejby has signed the CLA in laurent22/joplin#7999 2023-03-30 18:21:47 +00:00
github-actions[bot]
3a27086534 @TahaNw has signed the CLA in laurent22/joplin#7998 2023-03-30 17:33:50 +00:00
Laurent Cozic
413c1e41b5 Revert "Chore: Mac binary signing tweaks for embedded plugins (#7988)"
This reverts commit cf4008951d.

Not working.

Ref: https://github.com/laurent22/joplin/issues/7934#issuecomment-1490632038
2023-03-30 18:24:25 +01:00
Henry Heino
8b879464b8 All: Fixes #7986: Fix OneDrive sync attempting to call method on null variable (#7987) 2023-03-30 17:41:29 +01:00
renovate[bot]
97c9bbc1fe Update dependency react-native-paper to v5.3.1 (#7977) 2023-03-30 17:38:18 +01:00
renovate[bot]
e5bebef7b2 Update dependency lint-staged to v13.2.0 (#7994) 2023-03-30 17:38:06 +01:00
renovate[bot]
73752c4b3f Update dependency pg to v8.10.0 (#7978) 2023-03-30 17:37:46 +01:00
Laurent Cozic
dcf7c9838d Desktop release v2.11.1 2023-03-30 17:13:20 +01:00
Laurent Cozic
f325e7694b Chore: Prepare v2.11 2023-03-30 17:13:06 +01:00
Arun Kumar
75d204c9ca Desktop: Resolves #6101: Added export graph button for Mermaid (#7958) 2023-03-30 16:58:48 +01:00
Arun Kumar
cf4008951d Chore: Mac binary signing tweaks for embedded plugins (#7988) 2023-03-30 16:57:22 +01:00
renovate[bot]
d67818d096 Update dependency react-select to v5.7.1 (#7993)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 14:30:20 +00:00
Laurent Cozic
6aaea8ad4f Renovate conf 2023-03-26 16:58:29 +01:00
github-actions[bot]
de41278096 @HelpdeskThisIsJohn has signed the CLA in laurent22/joplin#7969 2023-03-26 03:41:02 +00:00
renovate[bot]
f01ab70907 Update dependency sqlite3 to v5.1.6 (#7967) 2023-03-25 14:27:19 +00:00
renovate[bot]
bbdb221a67 Update dependency react-native-document-picker to v8.1.4 (#7966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 18:21:01 +00:00
renovate[bot]
7d053f8c79 Update dependency styled-components to v5.3.9 (#7965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 14:17:40 +00:00
renovate[bot]
fcad0bf3ca Update dependency style-loader to v3.3.2 (#7964)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 10:04:32 +00:00
renovate[bot]
58f929f6b5 Update dependency sqlite3 to v5.1.5 (#7963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 05:40:51 +00:00
renovate[bot]
943198c56e Update dependency node-mocks-http to v1.12.2 (#7962)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 01:51:21 +00:00
renovate[bot]
2112ad4004 Update dependency markdown-it-multimd-table to v4.2.1 (#7928) 2023-03-23 21:07:41 +00:00
Laurent Cozic
5995dc81f3 Doc: Added info about data escaping in coding style 2023-03-23 16:10:52 +00:00
Laurent Cozic
104e752634 Merge branch 'release-2.10' into dev 2023-03-23 11:35:21 +00:00
Laurent Cozic
fc335cd15d Desktop release v2.10.12 2023-03-23 11:34:42 +00:00
Julien
45923ba0d3 Desktop: Adjusted New Note and New to-do buttons' breakpoints to happen earlier (#7961) 2023-03-23 11:32:36 +00:00
Julien
8fefa99d81 Desktop: Adjusted New Note and New to-do buttons' breakpoints to happen earlier (#7961) 2023-03-23 11:31:22 +00:00
Laurent Cozic
85d652cd67 Removed unused conf 2023-03-23 11:05:15 +00:00
github-actions[bot]
88e41e9c7d @chenqy9 has signed the CLA in laurent22/joplin#7955 2023-03-23 07:04:32 +00:00
Laurent Cozic
26750488d0 Merge branch 'release-2.10' into dev 2023-03-22 18:46:42 +00:00
Laurent Cozic
a0f582b2b9 Android 2.10.9 2023-03-22 18:45:52 +00:00
Laurent Cozic
917b53bec2 lock file 2023-03-22 18:33:19 +00:00
Laurent Cozic
e44a93422a Mobile: Mark biometrics feature as beta and ensure no call is made if it is not enabled 2023-03-22 18:24:10 +00:00
Laurent Cozic
e115ef4259 Mobile: Mark biometrics feature as beta and ensure no call is made if it is not enabled 2023-03-22 18:22:58 +00:00
Laurent Cozic
bcec699124 Doc: Fixed sponsor avatars 2023-03-21 17:31:43 +00:00
github-actions[bot]
d23c728a1a @jcgurango has signed the CLA in laurent22/joplin#7953 2023-03-21 17:20:42 +00:00
Milo Ivir
0a2d507dec All: Translation: Update hr_HR.po (#7947) 2023-03-20 17:32:52 -04:00
Laurent Cozic
0c08617606 Fix CI 2023-03-20 13:43:25 +00:00
Laurent Cozic
29fba45c33 Fix CI 2023-03-20 12:24:17 +00:00
Laurent Cozic
1071a455b6 Revert "Update Croatian translation (#7937)"
This reverts commit ffeeff260f.

Ref: https://github.com/laurent22/joplin/pull/7937#issuecomment-1475058291
2023-03-20 10:20:46 +00:00
Laurent Cozic
57e4b36fd7 Revert "Revert "All: Translation: Update fi_FI.po (#7945)""
This reverts commit d18a4be31f.

Restore FI translation.

Ref: d18a4be31f (commitcomment-105121959)
2023-03-20 10:19:56 +00:00
Joplin Bot
f08fa92294 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-03-19 18:19:35 +00:00
Laurent Cozic
3a8d87d292 Tools: Export rootDir from utils 2023-03-19 17:31:37 +00:00
Laurent Cozic
53302c9e90 lock file 2023-03-19 17:05:31 +00:00
Laurent Cozic
28a24d8c03 Chore: Fixed build 2023-03-19 17:03:04 +00:00
Laurent Cozic
3e52411bc4 Tools: Moved some utility functions to @joplin/utils to reduce dependencies between packages 2023-03-19 15:38:09 +00:00
Joplin Bot
1548ea18e1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-03-19 12:21:16 +00:00
Laurent Cozic
f8cd1ba8e5 Revert "Tools: Switch Joplin Server image location to laurent22/joplin-server"
This reverts commit 6729a3d51f.

Ref: https://discourse.joplinapp.org/t/docker-image-doesnt-exist/30103/5
2023-03-19 09:07:19 +00:00
Laurent Cozic
d18a4be31f Revert "All: Translation: Update fi_FI.po (#7945)"
This reverts commit c56f270ed6.

Ref: https://github.com/laurent22/joplin/pull/7937#issuecomment-1475058291
2023-03-19 08:59:16 +00:00
mrkaato0
c56f270ed6 All: Translation: Update fi_FI.po (#7945) 2023-03-18 21:16:42 -04:00
github-actions[bot]
2bca3d1032 @mrkaato0 has signed the CLA in laurent22/joplin#7945 2023-03-18 18:25:42 +00:00
renovate[bot]
9f81d69c5e Update dependency jquery to v3.6.4 (#7944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-18 16:33:08 +00:00
Laurent Cozic
815419260d Server v2.10.11 2023-03-17 17:50:34 +00:00
Laurent Cozic
6729a3d51f Tools: Switch Joplin Server image location to laurent22/joplin-server 2023-03-17 17:49:34 +00:00
Joplin Bot
6d8ce280dd Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-03-17 12:20:34 +00:00
Laurent Cozic
9e5b455065 Merge branch 'release-2.10' into dev 2023-03-17 08:56:39 +00:00
Laurent Cozic
09cbac3019 Desktop release v2.10.11 2023-03-17 08:55:09 +00:00
Julien
5354ad3934 Desktop: Fixes text wrap on new buttons (#7938) 2023-03-17 08:53:19 +00:00
Julien
7754048b80 Desktop: Fixes text wrap on new buttons (#7938) 2023-03-17 08:51:46 +00:00
Milo Ivir
ffeeff260f Update Croatian translation (#7937) 2023-03-17 08:51:22 +00:00
Julien
71ea74d273 Desktop: Fixes #4801: Do not allow update for plugins incompatible with current version (#7936) 2023-03-17 08:50:51 +00:00
Julien
3a744c79ae Desktop: Fixes #7920: List enabled plugins only in About Joplin and in alphabetical order (#7923) 2023-03-17 08:41:33 +00:00
renovate[bot]
d9ba27a1ec Update dependency lint-staged to v13.1.4 (#7935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 20:26:38 +00:00
github-actions[bot]
0a3540049c @milotype has signed the CLA in laurent22/joplin#7937 2023-03-16 18:51:53 +00:00
Henry Heino
ab50ca9bbd Mobile: Add setting to enable/disable the markdown toolbar (#7929) 2023-03-16 11:12:56 +00:00
renovate[bot]
0bee793ab8 Update dependency lint-staged to v13.1.3 (#7927)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-15 20:36:26 +00:00
Arun Kumar
89fc5e19d9 Desktop: Fixes #7881: Fixed icon when note is dragged across notebooks (#7924) 2023-03-15 14:33:59 +00:00
Arun Kumar
6a3bf51084 Desktop: Resolves #7889: Add support for --safe-mode command line flag (#7919) 2023-03-14 11:46:21 +00:00
Laurent Cozic
df1e298c84 Doc: Mentioned Safe Mode in debugging doc 2023-03-14 11:41:30 +00:00
123 changed files with 3319 additions and 1828 deletions

View File

@@ -66,6 +66,7 @@ packages/lib/welcomeAssets.js
packages/plugins/**/api packages/plugins/**/api
packages/plugins/**/dist packages/plugins/**/dist
packages/server/dist/ packages/server/dist/
packages/utils/dist/
packages/tools/node_modules packages/tools/node_modules
packages/tools/PortableAppsLauncher packages/tools/PortableAppsLauncher
packages/turndown-plugin-gfm/ packages/turndown-plugin-gfm/
@@ -329,6 +330,7 @@ packages/app-desktop/gui/style/StyledTextInput.js
packages/app-desktop/gui/utils/NoteListUtils.js packages/app-desktop/gui/utils/NoteListUtils.js
packages/app-desktop/gui/utils/convertToScreenCoordinates.js packages/app-desktop/gui/utils/convertToScreenCoordinates.js
packages/app-desktop/gui/utils/loadScript.js packages/app-desktop/gui/utils/loadScript.js
packages/app-desktop/gulpfile.js
packages/app-desktop/plugins/GotoAnything.js packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/bridge.js packages/app-desktop/services/bridge.js
packages/app-desktop/services/commands/stateToWhenClauseContext.js packages/app-desktop/services/commands/stateToWhenClauseContext.js
@@ -404,6 +406,7 @@ packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/TextInput.js packages/app-mobile/components/TextInput.js
packages/app-mobile/components/app-nav.js packages/app-mobile/components/app-nav.js
packages/app-mobile/components/biometrics/BiometricPopup.js packages/app-mobile/components/biometrics/BiometricPopup.js
packages/app-mobile/components/biometrics/biometricAuthenticate.js
packages/app-mobile/components/biometrics/sensorInfo.js packages/app-mobile/components/biometrics/sensorInfo.js
packages/app-mobile/components/getResponsiveValue.js packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/getResponsiveValue.test.js packages/app-mobile/components/getResponsiveValue.test.js
@@ -862,6 +865,7 @@ packages/tools/update-readme-download.js
packages/tools/update-readme-sponsors.js packages/tools/update-readme-sponsors.js
packages/tools/updateMarkdownDoc.js packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.js packages/tools/utils/discourse.js
packages/tools/utils/loadSponsors.js
packages/tools/utils/translation.js packages/tools/utils/translation.js
packages/tools/website/build.js packages/tools/website/build.js
packages/tools/website/buildTranslations.js packages/tools/website/buildTranslations.js

View File

@@ -180,9 +180,6 @@ cd "$ROOT_DIR/packages/app-desktop"
if [[ $GIT_TAG_NAME = v* ]]; then if [[ $GIT_TAG_NAME = v* ]]; then
echo "Step: Building and publishing desktop application..." echo "Step: Building and publishing desktop application..."
# cd "$ROOT_DIR/packages/tools"
# node bundleDefaultPlugins.js
cd "$ROOT_DIR/packages/app-desktop"
USE_HARD_LINKS=false yarn run dist USE_HARD_LINKS=false yarn run dist
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
echo "Step: Building Docker Image..." echo "Step: Building Docker Image..."

View File

@@ -6,6 +6,7 @@ on: [push, pull_request]
jobs: jobs:
pre_job: pre_job:
if: github.repository == 'laurent22/joplin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }} should_skip: ${{ steps.skip_check.outputs.should_skip }}
@@ -16,6 +17,7 @@ jobs:
concurrent_skipping: 'same_content_newer' concurrent_skipping: 'same_content_newer'
BuildAndroidDebug: BuildAndroidDebug:
if: github.repository == 'laurent22/joplin'
needs: pre_job needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true' if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -7,6 +7,7 @@ on:
jobs: jobs:
CLAAssistant: CLAAssistant:
if: github.repository == 'laurent22/joplin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "CLA Assistant" - name: "CLA Assistant"

View File

@@ -6,6 +6,7 @@ permissions:
issues: write issues: write
jobs: jobs:
ProcessStaleIssues: ProcessStaleIssues:
if: github.repository == 'laurent22/joplin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v4 - uses: actions/stale@v4

View File

@@ -2,6 +2,7 @@ name: Joplin Continuous Integration
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
pre_job: pre_job:
if: github.repository == 'laurent22/joplin'
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }} should_skip: ${{ steps.skip_check.outputs.should_skip }}
@@ -14,7 +15,7 @@ jobs:
Main: Main:
needs: pre_job needs: pre_job
# We always process server or desktop release tags, because they also publish the release # We always process server or desktop release tags, because they also publish the release
if: needs.pre_job.outputs.should_skip != 'true' || startsWith(github.ref, 'refs/tags/server-v') || startsWith(github.ref, 'refs/tags/v') if: github.repository == 'laurent22/joplin' && (needs.pre_job.outputs.should_skip != 'true' || startsWith(github.ref, 'refs/tags/server-v') || startsWith(github.ref, 'refs/tags/v'))
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
@@ -92,6 +93,7 @@ jobs:
APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }} APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }}
APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }} CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
GH_TOKEN: ${{ secrets.GH_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
@@ -129,7 +131,7 @@ jobs:
ServerDockerImage: ServerDockerImage:
needs: pre_job needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true' if: github.repository == 'laurent22/joplin' && needs.pre_job.outputs.should_skip != 'true'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:

3
.gitignore vendored
View File

@@ -317,6 +317,7 @@ packages/app-desktop/gui/style/StyledTextInput.js
packages/app-desktop/gui/utils/NoteListUtils.js packages/app-desktop/gui/utils/NoteListUtils.js
packages/app-desktop/gui/utils/convertToScreenCoordinates.js packages/app-desktop/gui/utils/convertToScreenCoordinates.js
packages/app-desktop/gui/utils/loadScript.js packages/app-desktop/gui/utils/loadScript.js
packages/app-desktop/gulpfile.js
packages/app-desktop/plugins/GotoAnything.js packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/bridge.js packages/app-desktop/services/bridge.js
packages/app-desktop/services/commands/stateToWhenClauseContext.js packages/app-desktop/services/commands/stateToWhenClauseContext.js
@@ -392,6 +393,7 @@ packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/TextInput.js packages/app-mobile/components/TextInput.js
packages/app-mobile/components/app-nav.js packages/app-mobile/components/app-nav.js
packages/app-mobile/components/biometrics/BiometricPopup.js packages/app-mobile/components/biometrics/BiometricPopup.js
packages/app-mobile/components/biometrics/biometricAuthenticate.js
packages/app-mobile/components/biometrics/sensorInfo.js packages/app-mobile/components/biometrics/sensorInfo.js
packages/app-mobile/components/getResponsiveValue.js packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/getResponsiveValue.test.js packages/app-mobile/components/getResponsiveValue.test.js
@@ -850,6 +852,7 @@ packages/tools/update-readme-download.js
packages/tools/update-readme-sponsors.js packages/tools/update-readme-sponsors.js
packages/tools/updateMarkdownDoc.js packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.js packages/tools/utils/discourse.js
packages/tools/utils/loadSponsors.js
packages/tools/utils/translation.js packages/tools/utils/translation.js
packages/tools/website/build.js packages/tools/website/build.js
packages/tools/website/buildTranslations.js packages/tools/website/buildTranslations.js

View File

@@ -14,7 +14,8 @@
"@joplin/turndown-plugin-gfm", "@joplin/turndown-plugin-gfm",
"@joplin/tools", "@joplin/tools",
"@joplin/react-native-saf-x", "@joplin/react-native-saf-x",
"@joplin/react-native-alarm-notification" "@joplin/react-native-alarm-notification",
"@joplin/utils"
] ]
} }
] ]

View File

@@ -30,6 +30,7 @@ COPY packages/fork-uslug ./packages/fork-uslug
COPY packages/htmlpack ./packages/htmlpack COPY packages/htmlpack ./packages/htmlpack
COPY packages/renderer ./packages/renderer COPY packages/renderer ./packages/renderer
COPY packages/tools ./packages/tools COPY packages/tools ./packages/tools
COPY packages/utils ./packages/utils
COPY packages/lib ./packages/lib COPY packages/lib ./packages/lib
COPY packages/server ./packages/server COPY packages/server ./packages/server

View File

@@ -64,7 +64,7 @@ A community maintained list of these distributions can be found here: [Unofficia
# Sponsors # Sponsors
<!-- SPONSORS-ORG --> <!-- 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://usrigging.com/"><img title="U.S. Ringing Supply" width="256" src="https://joplinapp.org/images/sponsors/RingingSupply.svg"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&amp;mtm_kwd=joplinapp&amp;mtm_source=joplinapp-github&amp;mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></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://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&amp;mtm_kwd=joplinapp&amp;mtm_source=joplinapp-webseite&amp;mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a>
<!-- SPONSORS-ORG --> <!-- SPONSORS-ORG -->
* * * * * *
@@ -126,6 +126,7 @@ A community maintained list of these distributions can be found here: [Unofficia
- [Writing a technical spec](https://github.com/laurent22/joplin/blob/dev/readme/technical_spec.md) - [Writing a technical spec](https://github.com/laurent22/joplin/blob/dev/readme/technical_spec.md)
- [Desktop application styling](https://github.com/laurent22/joplin/blob/dev/readme/spec/desktop_styling.md) - [Desktop application styling](https://github.com/laurent22/joplin/blob/dev/readme/spec/desktop_styling.md)
- [Note History spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/history.md) - [Note History spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/history.md)
- [Synchronisation spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync.md)
- [Sync Lock spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_lock.md) - [Sync Lock spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_lock.md)
- [Synchronous Scroll spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_scroll.md) - [Synchronous Scroll spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_scroll.md)
- [Plugin Architecture spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/plugins.md) - [Plugin Architecture spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/plugins.md)

View File

@@ -1,26 +1,52 @@
const gulp = require('gulp'); const gulp = require('gulp');
const utils = require('./packages/tools/gulp/utils'); const execa = require('execa');
const { stdout } = require('process');
const execCommand = async (executableName, args, options = null) => {
options = {
showInput: true,
showStdout: true,
showStderr: true,
quiet: false,
...options,
};
if (options.quiet) {
options.showInput = false;
options.showStdout = false;
options.showStderr = false;
}
if (options.showInput) {
stdout.write(`> ${executableName} ${args.join(' ')}\n`);
}
const promise = execa(executableName, args);
if (options.showStdout && promise.stdout) promise.stdout.pipe(process.stdout);
if (options.showStderr && promise.stderr) promise.stderr.pipe(process.stderr);
const result = await promise;
return result.stdout.trim();
};
const tasks = { const tasks = {
updateIgnoredTypeScriptBuild: require('./packages/tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
buildCommandIndex: require('./packages/tools/gulp/tasks/buildCommandIndex'),
completePublishAll: { completePublishAll: {
fn: async () => { fn: async () => {
await utils.execCommandVerbose('git', ['add', '-A']); await execCommand('git', ['add', '-A']);
await utils.execCommandVerbose('git', ['commit', '-m', 'Releasing sub-packages']); await execCommand('git', ['commit', '-m', 'Releasing sub-packages']);
// Lerna does some unnecessary auth check that doesn't work with // Lerna does some unnecessary auth check that doesn't work with
// automation tokens, thus the --no-verify-access. Automation token // automation tokens, thus the --no-verify-access. Automation token
// is still used for access when publishing even with this flag // is still used for access when publishing even with this flag
// (publishing would fail otherwise). // (publishing would fail otherwise).
// https://github.com/lerna/lerna/issues/2788 // https://github.com/lerna/lerna/issues/2788
await utils.execCommandVerbose('lerna', ['publish', 'from-package', '-y', '--no-verify-access']); await execCommand('lerna', ['publish', 'from-package', '-y', '--no-verify-access']);
await utils.execCommandVerbose('yarn', ['install']); await execCommand('yarn', ['install']);
await utils.execCommandVerbose('git', ['add', '-A']); await execCommand('git', ['add', '-A']);
await utils.execCommandVerbose('git', ['commit', '-m', 'Lock file']); await execCommand('git', ['commit', '-m', 'Lock file']);
await utils.execCommandVerbose('git', ['push']); await execCommand('git', ['push']);
}, },
}, },
build: { build: {
@@ -33,12 +59,14 @@ const tasks = {
// faster, especially when having to rebuild after adding a // faster, especially when having to rebuild after adding a
// dependency. // dependency.
if (process.env.BUILD_SEQUENCIAL === '1') { if (process.env.BUILD_SEQUENCIAL === '1') {
await utils.execCommandVerbose('yarn', ['run', 'buildSequential']); await execCommand('yarn', ['run', 'buildSequential']);
} else { } else {
await utils.execCommandVerbose('yarn', ['run', 'buildParallel']); await execCommand('yarn', ['run', 'buildParallel']);
} }
}, },
}, },
}; };
utils.registerGulpTasks(gulp, tasks); for (const taskName in tasks) {
gulp.task(taskName, tasks[taskName].fn);
}

View File

@@ -329,6 +329,7 @@
"packages/renderer/MdToHtml/rules/sanitize_html.js": true, "packages/renderer/MdToHtml/rules/sanitize_html.js": true,
"packages/server/db-*.sqlite": true, "packages/server/db-*.sqlite": true,
"packages/server/dist/": true, "packages/server/dist/": true,
"packages/utils/dist/": true,
"packages/server/temp": true, "packages/server/temp": true,
"packages/server/test.pid": true, "packages/server/test.pid": true,
"phpunit.xml": true, "phpunit.xml": true,

View File

@@ -13,9 +13,9 @@
}, },
"scripts": { "scripts": {
"buildParallel": "yarn workspaces foreach --verbose --interlaced --parallel --jobs 2 --topological run build && yarn run tsc", "buildParallel": "yarn workspaces foreach --verbose --interlaced --parallel --jobs 2 --topological run build && yarn run tsc",
"buildSequential": "yarn workspaces foreach --verbose --interlaced --topological run build && yarn run tsc", "buildSequential": "yarn run tsc && yarn workspaces foreach --verbose --interlaced --topological-dev run build",
"buildApiDoc": "yarn workspace joplin start apidoc ../../readme/api/references/rest_api.md", "buildApiDoc": "yarn workspace joplin start apidoc ../../readme/api/references/rest_api.md",
"buildCommandIndex": "gulp buildCommandIndex", "buildCommandIndex": "node packages/tools/gulp/tasks/buildCommandIndexRun.js",
"buildPluginDoc": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme './Assets/PluginDocTheme/' --readme './Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../joplin-website/docs/api/references/plugin_api packages/lib/services/plugins/api/", "buildPluginDoc": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme './Assets/PluginDocTheme/' --readme './Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../joplin-website/docs/api/references/plugin_api packages/lib/services/plugins/api/",
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc", "updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
"updateNews": "node ./packages/tools/website/updateNews", "updateNews": "node ./packages/tools/website/updateNews",
@@ -53,7 +53,7 @@
"test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci", "test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci",
"test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test", "test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test",
"tsc": "yarn workspaces foreach --parallel --verbose --interlaced run tsc", "tsc": "yarn workspaces foreach --parallel --verbose --interlaced run tsc",
"updateIgnored": "gulp updateIgnoredTypeScriptBuild", "updateIgnored": "node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js",
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh", "updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
"watch": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 999 run watch", "watch": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 999 run watch",
"watchWebsite": "nodemon --verbose --watch Assets/WebsiteAssets --watch packages/tools/website --watch packages/tools/website/utils --ext md,ts,js,mustache,css,tsx,gif,png,svg --exec \"node packages/tools/website/build.js && http-server --port 8077 ../joplin-website/docs -a localhost\"" "watchWebsite": "nodemon --verbose --watch Assets/WebsiteAssets --watch packages/tools/website --watch packages/tools/website/utils --ext md,ts,js,mustache,css,tsx,gif,png,svg --exec \"node packages/tools/website/build.js && http-server --port 8077 ../joplin-website/docs -a localhost\""
@@ -64,6 +64,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@joplin/utils": "~2.11",
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0", "@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.48.2",
"@typescript-eslint/parser": "5.48.2", "@typescript-eslint/parser": "5.48.2",
@@ -74,12 +75,13 @@
"eslint-plugin-jest": "27.2.1", "eslint-plugin-jest": "27.2.1",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.32.0", "eslint-plugin-react": "7.32.0",
"fs-extra": "11.1.0", "execa": "5.1.1",
"fs-extra": "11.1.1",
"glob": "8.1.0", "glob": "8.1.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"husky": "3.1.0", "husky": "3.1.0",
"lerna": "3.22.1", "lerna": "3.22.1",
"lint-staged": "13.1.2", "lint-staged": "13.2.0",
"madge": "6.0.0", "madge": "6.0.0",
"npm-package-json-lint": "6.4.0", "npm-package-json-lint": "6.4.0",
"typedoc": "0.17.8", "typedoc": "0.17.8",
@@ -89,7 +91,7 @@
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
"http-server": "14.1.1", "http-server": "14.1.1",
"node-gyp": "9.3.1", "node-gyp": "9.3.1",
"nodemon": "2.0.21" "nodemon": "2.0.22"
}, },
"packageManager": "yarn@3.3.1", "packageManager": "yarn@3.3.1",
"resolutions": { "resolutions": {

View File

@@ -8,7 +8,7 @@ const Resource = require('@joplin/lib/models/Resource').default;
const Setting = require('@joplin/lib/models/Setting').default; const Setting = require('@joplin/lib/models/Setting').default;
const reducer = require('@joplin/lib/reducer').default; const reducer = require('@joplin/lib/reducer').default;
const { defaultState } = require('@joplin/lib/reducer'); const { defaultState } = require('@joplin/lib/reducer');
const { splitCommandString } = require('@joplin/lib/string-utils.js'); const { splitCommandString } = require('@joplin/utils');
const { reg } = require('@joplin/lib/registry.js'); const { reg } = require('@joplin/lib/registry.js');
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;

View File

@@ -9,7 +9,8 @@ const Tag = require('@joplin/lib/models/Tag').default;
const Setting = require('@joplin/lib/models/Setting').default; const Setting = require('@joplin/lib/models/Setting').default;
const { reg } = require('@joplin/lib/registry.js'); const { reg } = require('@joplin/lib/registry.js');
const { fileExtension } = require('@joplin/lib/path-utils'); const { fileExtension } = require('@joplin/lib/path-utils');
const { splitCommandString, splitCommandBatch } = require('@joplin/lib/string-utils'); const { splitCommandString } = require('@joplin/utils');
const { splitCommandBatch } = require('@joplin/lib/string-utils');
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const fs = require('fs-extra'); const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js'); const { cliUtils } = require('./cli-utils.js');

View File

@@ -1,6 +1,6 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { splitCommandString } = require('@joplin/lib/string-utils.js'); const { splitCommandString } = require('@joplin/utils');
const uuid = require('@joplin/lib/uuid').default; const uuid = require('@joplin/lib/uuid').default;
const { app } = require('./app.js'); const { app } = require('./app.js');
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');

View File

@@ -30,22 +30,24 @@
2019, 2019,
2020, 2020,
2021, 2021,
2022 2022,
2023
], ],
"owner": "Laurent Cozic" "owner": "Laurent Cozic"
}, },
"version": "2.10.3", "version": "2.11.0",
"bin": "./main.js", "bin": "./main.js",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },
"dependencies": { "dependencies": {
"@joplin/lib": "~2.10", "@joplin/lib": "~2.11",
"@joplin/renderer": "~2.10", "@joplin/renderer": "~2.11",
"@joplin/utils": "~2.11",
"aws-sdk": "2.1290.0", "aws-sdk": "2.1290.0",
"chalk": "4.1.2", "chalk": "4.1.2",
"compare-version": "0.1.2", "compare-version": "0.1.2",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"image-type": "3.1.0", "image-type": "3.1.0",
"keytar": "7.9.0", "keytar": "7.9.0",
@@ -57,7 +59,7 @@
"server-destroy": "1.0.1", "server-destroy": "1.0.1",
"sharp": "0.31.3", "sharp": "0.31.3",
"sprintf-js": "1.1.2", "sprintf-js": "1.1.2",
"sqlite3": "5.1.4", "sqlite3": "5.1.6",
"string-padding": "1.0.2", "string-padding": "1.0.2",
"strip-ansi": "6.0.1", "strip-ansi": "6.0.1",
"tcp-port-used": "1.0.2", "tcp-port-used": "1.0.2",
@@ -68,7 +70,7 @@
"yargs-parser": "21.1.1" "yargs-parser": "21.1.1"
}, },
"devDependencies": { "devDependencies": {
"@joplin/tools": "~2.10", "@joplin/tools": "~2.11",
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
"@types/jest": "29.2.6", "@types/jest": "29.2.6",
"@types/node": "18.11.18", "@types/node": "18.11.18",

View File

@@ -47,9 +47,11 @@ describe('services_plugins_RepositoryApi', () => {
it('should tell if a plugin can be updated', (async () => { it('should tell if a plugin can be updated', (async () => {
const api = await newRepoApi(); const api = await newRepoApi();
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0')).toBe(true);
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.2')).toBe(false); expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0', '3.0.0')).toBe(true);
expect(await api.pluginCanBeUpdated('does.not.exist', '1.0.0')).toBe(false); expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0', '1.0.0')).toBe(false);
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.2', '3.0.0')).toBe(false);
expect(await api.pluginCanBeUpdated('does.not.exist', '1.0.0', '3.0.0')).toBe(false);
})); }));
}); });

View File

@@ -19,7 +19,7 @@
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import { homedir } from 'os'; import { homedir } from 'os';
import { execCommand2 } from '@joplin/tools/tool-utils'; import { execCommand } from '@joplin/utils';
import { chdir } from 'process'; import { chdir } from 'process';
const minUserNum = 1; const minUserNum = 1;
@@ -66,7 +66,7 @@ const processUser = async (userNum: number) => {
await chdir(cliDir); await chdir(cliDir);
await execCommand2(['yarn', 'run', 'start-no-build', '--', '--profile', profileDir, 'batch', commandFile]); await execCommand(['yarn', 'run', 'start-no-build', '--', '--profile', profileDir, 'batch', commandFile]);
} catch (error) { } catch (error) {
console.error(`Could not process user ${userNum}:`, error); console.error(`Could not process user ${userNum}:`, error);
} finally { } finally {
@@ -90,7 +90,7 @@ const main = async () => {
// Build the app once before starting, because we'll use start-no-build to // Build the app once before starting, because we'll use start-no-build to
// run the scripts (faster) // run the scripts (faster)
await execCommand2(['yarn', 'run', 'build']); await execCommand(['yarn', 'run', 'build']);
const focusUserNum = 0; const focusUserNum = 0;

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Joplin Web Clipper [DEV]", "name": "Joplin Web Clipper [DEV]",
"version": "2.10.0", "version": "2.11.2",
"description": "Capture and save web pages and screenshots from your browser to Joplin.", "description": "Capture and save web pages and screenshots from your browser to Joplin.",
"homepage_url": "https://joplinapp.org", "homepage_url": "https://joplinapp.org",
"content_security_policy": "script-src 'self'; object-src 'self'", "content_security_policy": "script-src 'self'; object-src 'self'",

View File

@@ -126,4 +126,4 @@
"react-app" "react-app"
] ]
} }
} }

View File

@@ -143,7 +143,7 @@ export default function(props: Props) {
let cancelled = false; let cancelled = false;
async function fetchPluginIds() { async function fetchPluginIds() {
const pluginIds = await repoApi().canBeUpdatedPlugins(pluginItems.map(p => p.manifest)); const pluginIds = await repoApi().canBeUpdatedPlugins(pluginItems.map(p => p.manifest), pluginService.appVersion);
if (cancelled) return; if (cancelled) return;
const conv: Record<string, boolean> = {}; const conv: Record<string, boolean> = {};
pluginIds.forEach(id => conv[id] = true); pluginIds.forEach(id => conv[id] = true);
@@ -155,7 +155,7 @@ export default function(props: Props) {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [manifestsLoaded, pluginItems]); }, [manifestsLoaded, pluginItems, pluginService.appVersion]);
const onDelete = useCallback(async (event: ItemEvent) => { const onDelete = useCallback(async (event: ItemEvent) => {
const item = event.item; const item = event.item;

View File

@@ -21,7 +21,7 @@ import checkForUpdates from '../checkForUpdates';
const { connect } = require('react-redux'); const { connect } = require('react-redux');
import { reg } from '@joplin/lib/registry'; import { reg } from '@joplin/lib/registry';
import { ProfileConfig } from '@joplin/lib/services/profileConfig/types'; import { ProfileConfig } from '@joplin/lib/services/profileConfig/types';
import PluginService from '@joplin/lib/services/plugins/PluginService'; import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService';
const packageInfo = require('../packageInfo.js'); const packageInfo = require('../packageInfo.js');
const { clipboard } = require('electron'); const { clipboard } = require('electron');
const Menu = bridge().Menu; const Menu = bridge().Menu;
@@ -128,6 +128,7 @@ interface Props {
customCss: string; customCss: string;
locale: string; locale: string;
profileConfig: ProfileConfig; profileConfig: ProfileConfig;
pluginSettings: PluginSettings;
} }
const commandNames: string[] = menuCommandNames(); const commandNames: string[] = menuCommandNames();
@@ -487,8 +488,7 @@ function useMenu(props: Props) {
} }
function _showAbout() { function _showAbout() {
const v = versionInfo(packageInfo, PluginService.instance().plugins); const v = versionInfo(packageInfo, PluginService.instance().enabledPlugins(props.pluginSettings));
const copyToClipboard = bridge().showMessageBox(v.message, { const copyToClipboard = bridge().showMessageBox(v.message, {
icon: `${bridge().electronApp().buildDir()}/icons/128x128.png`, icon: `${bridge().electronApp().buildDir()}/icons/128x128.png`,
@@ -931,6 +931,7 @@ function useMenu(props: Props) {
props['spellChecker.languages'], props['spellChecker.languages'],
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['spellChecker.enabled'], props['spellChecker.enabled'],
props.pluginSettings,
props.customCss, props.customCss,
props.locale, props.locale,
props.profileConfig, props.profileConfig,
@@ -986,6 +987,7 @@ const mapStateToProps = (state: AppState) => {
['folders.sortOrder.field']: state.settings['folders.sortOrder.field'], ['folders.sortOrder.field']: state.settings['folders.sortOrder.field'],
['notes.sortOrder.reverse']: state.settings['notes.sortOrder.reverse'], ['notes.sortOrder.reverse']: state.settings['notes.sortOrder.reverse'],
['folders.sortOrder.reverse']: state.settings['folders.sortOrder.reverse'], ['folders.sortOrder.reverse']: state.settings['folders.sortOrder.reverse'],
pluginSettings: state.settings['plugins.states'],
showNoteCounts: state.settings.showNoteCounts, showNoteCounts: state.settings.showNoteCounts,
uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop, uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
showCompletedTodos: state.settings.showCompletedTodos, showCompletedTodos: state.settings.showCompletedTodos,

View File

@@ -3,6 +3,7 @@ import { useCallback, useMemo } from 'react';
import { ResourceInfos } from './types'; import { ResourceInfos } from './types';
import markupLanguageUtils from '../../../utils/markupLanguageUtils'; import markupLanguageUtils from '../../../utils/markupLanguageUtils';
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';
import shim from '@joplin/lib/shim';
const { themeStyle } = require('@joplin/lib/theme'); const { themeStyle } = require('@joplin/lib/theme');
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';
@@ -23,6 +24,7 @@ export interface MarkupToHtmlOptions {
useCustomPdfViewer?: boolean; useCustomPdfViewer?: boolean;
noteId?: string; noteId?: string;
vendorDir?: string; vendorDir?: string;
platformName?: string;
} }
export default function useMarkupToHtml(deps: HookDependencies) { export default function useMarkupToHtml(deps: HookDependencies) {
@@ -40,6 +42,7 @@ export default function useMarkupToHtml(deps: HookDependencies) {
options = { options = {
replaceResourceInternalToExternalLinks: false, replaceResourceInternalToExternalLinks: false,
resourceInfos: {}, resourceInfos: {},
platformName: shim.platformName(),
...options, ...options,
}; };

View File

@@ -241,6 +241,7 @@ const NoteListComponent = (props: Props) => {
event.dataTransfer.setDragImage(new Image(), 1, 1); event.dataTransfer.setDragImage(new Image(), 1, 1);
event.dataTransfer.clearData(); event.dataTransfer.clearData();
event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds)); event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds));
event.dataTransfer.effectAllowed = 'move';
}; };
const renderItem = useCallback((item: any, index: number) => { const renderItem = useCallback((item: any, index: number) => {

View File

@@ -12,9 +12,9 @@ const { connect } = require('react-redux');
const styled = require('styled-components').default; const styled = require('styled-components').default;
enum BaseBreakpoint { enum BaseBreakpoint {
Sm = 160, Sm = 75,
Md = 190, Md = 80,
Lg = 40, Lg = 120,
Xl = 474, Xl = 474,
} }
@@ -50,7 +50,9 @@ const StyledButton = styled(Button)`
width: auto; width: auto;
height: 26px; height: 26px;
min-height: 26px; min-height: 26px;
min-width: 37px;
max-width: none; max-width: none;
white-space: nowrap;
.fa, .fas { .fa, .fas {
font-size: 11px; font-size: 11px;

View File

@@ -48,6 +48,15 @@ const StyledFoldersHolder = styled.div`
}} }}
} }
`; `;
const TagsHolder = styled.div`
// linux bug: https://github.com/laurent22/joplin/issues/8000
// solution ref: https://github.com/laurent22/joplin/issues/7506#issuecomment-1447101057
& a.list-item {
${shim.isLinux() && {
opacity: 1,
}}
}
`;
interface Props { interface Props {
themeId: number; themeId: number;
@@ -738,9 +747,9 @@ const SidebarComponent = (props: Props) => {
tagItemsOrder_.current = result.order; tagItemsOrder_.current = result.order;
items.push( items.push(
<div className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}> <TagsHolder className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}>
{tagItems} {tagItems}
</div> </TagsHolder>
); );
} }

View File

@@ -56,6 +56,19 @@ if (typeof module !== 'undefined') {
const markJsUtils = {}; const markJsUtils = {};
const isInsideContainer = (node, tagName) => {
if (!node) return false;
tagName = tagName.toLowerCase();
while (node) {
if (node.tagName && node.tagName.toLowerCase() === tagName) return true;
node = node.parentNode;
}
return false;
};
markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => { markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
if (typeof keyword === 'string') { if (typeof keyword === 'string') {
keyword = { keyword = {
@@ -71,12 +84,13 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
if (isBasicSearch) accuracy = 'partially'; if (isBasicSearch) accuracy = 'partially';
if (keyword.type === 'regex') { if (keyword.type === 'regex') {
accuracy = 'complementary'; accuracy = 'complementary';
// Remove the trailing wildcard and "accuracy = complementary" will take care of // Remove the trailing wildcard and "accuracy = complementary" will take
// highlighting the relevant keywords. // care of highlighting the relevant keywords.
// Known bug: it will also highlight word that contain the term as a suffix for example for "ent*", it will highlight "present" // Known bug: it will also highlight word that contain the term as a
// which is incorrect (it should only highlight what starts with "ent") but for now will do. Mark.js doesn't have an option // suffix for example for "ent*", it will highlight "present" which is
// to tweak this behaviour. // incorrect (it should only highlight what starts with "ent") but for
// now will do. Mark.js doesn't have an option to tweak this behaviour.
value = keyword.value.substr(0, keyword.value.length - 1); value = keyword.value.substr(0, keyword.value.length - 1);
} }
@@ -86,6 +100,18 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
{}, {},
{ {
accuracy: accuracy, accuracy: accuracy,
filter: (node, _term, _totalCounter, _counter) => {
// We exclude SVG because it creates a "<mark>" tag inside
// the document, which is not a valid SVG tag. As a result
// the content within that tag disappears.
//
// mark.js has an "exclude" parameter, but it doesn't work
// so we use "filter" instead.
//
// https://github.com/joplin/plugin-abc-sheet-music
if (isInsideContainer(node, 'SVG')) return false;
return true;
},
}, },
extraOptions extraOptions
) )

View File

@@ -2,6 +2,7 @@ const gulp = require('gulp');
const utils = require('@joplin/tools/gulp/utils'); const utils = require('@joplin/tools/gulp/utils');
const compileSass = require('@joplin/tools/compileSass'); const compileSass = require('@joplin/tools/compileSass');
const compilePackageInfo = require('@joplin/tools/compilePackageInfo'); const compilePackageInfo = require('@joplin/tools/compilePackageInfo');
const bundleDefaultPlugins = require('@joplin/tools/bundleDefaultPlugins');
const tasks = { const tasks = {
compileScripts: { compileScripts: {
@@ -35,6 +36,11 @@ const tasks = {
); );
}, },
}, },
bundleDefaultPlugins: {
fn: async () => {
await bundleDefaultPlugins();
},
},
}; };
utils.registerGulpTasks(gulp, tasks); utils.registerGulpTasks(gulp, tasks);

View File

@@ -1,11 +1,12 @@
{ {
"name": "@joplin/app-desktop", "name": "@joplin/app-desktop",
"version": "2.10.10", "version": "2.11.1",
"description": "Joplin for Desktop", "description": "Joplin for Desktop",
"main": "main.js", "main": "main.js",
"private": true, "private": true,
"scripts": { "scripts": {
"dist": "yarn run electronRebuild && npx electron-builder", "dist": "yarn run bundleDefaultPlugins && yarn run electronRebuild && npx electron-builder",
"bundleDefaultPlugins": "gulp bundleDefaultPlugins",
"build": "gulp build", "build": "gulp build",
"postinstall": "yarn run build", "postinstall": "yarn run build",
"electronBuilder": "gulp electronBuilder", "electronBuilder": "gulp electronBuilder",
@@ -90,7 +91,10 @@
"CFBundleURLName": "org.joplinapp.x-callback-url" "CFBundleURLName": "org.joplinapp.x-callback-url"
} }
] ]
} },
"binaries": [
"Contents/Resources/build/defaultPlugins/io.github.jackgruber.backup/plugin.jpl"
]
}, },
"linux": { "linux": {
"icon": "../../Assets/LinuxIcons", "icon": "../../Assets/LinuxIcons",
@@ -107,7 +111,9 @@
}, },
"homepage": "https://github.com/laurent22/joplin#readme", "homepage": "https://github.com/laurent22/joplin#readme",
"devDependencies": { "devDependencies": {
"@joplin/tools": "~2.10", "@electron/notarize": "1.2.3",
"@electron/rebuild": "3.2.10",
"@joplin/tools": "~2.11",
"@testing-library/react-hooks": "8.0.1", "@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.2.6", "@types/jest": "29.2.6",
"@types/node": "18.11.18", "@types/node": "18.11.18",
@@ -115,9 +121,7 @@
"@types/react-redux": "7.1.25", "@types/react-redux": "7.1.25",
"@types/styled-components": "5.1.26", "@types/styled-components": "5.1.26",
"electron": "19.1.4", "electron": "19.1.4",
"electron-builder": "23.6.0", "electron-builder": "24.1.2",
"electron-notarize": "1.2.2",
"electron-rebuild": "3.2.9",
"glob": "8.1.0", "glob": "8.1.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"jest": "29.4.3", "jest": "29.4.3",
@@ -125,6 +129,7 @@
"js-sha512": "0.8.0", "js-sha512": "0.8.0",
"nan": "2.17.0", "nan": "2.17.0",
"react-test-renderer": "18.2.0", "react-test-renderer": "18.2.0",
"ts-node": "^10.9.1",
"typescript": "4.9.4" "typescript": "4.9.4"
}, },
"optionalDependencies": { "optionalDependencies": {
@@ -136,9 +141,9 @@
"@electron/remote": "2.0.9", "@electron/remote": "2.0.9",
"@fortawesome/fontawesome-free": "5.15.4", "@fortawesome/fontawesome-free": "5.15.4",
"@joeattardi/emoji-button": "4.6.4", "@joeattardi/emoji-button": "4.6.4",
"@joplin/lib": "~2.10", "@joplin/lib": "~2.11",
"@joplin/pdf-viewer": "~2.10", "@joplin/pdf-viewer": "~2.11",
"@joplin/renderer": "~2.10", "@joplin/renderer": "~2.11",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"codemirror": "5.65.9", "codemirror": "5.65.9",
"color": "3.2.1", "color": "3.2.1",
@@ -147,7 +152,7 @@
"debounce": "1.2.1", "debounce": "1.2.1",
"electron-window-state": "5.0.3", "electron-window-state": "5.0.3",
"formatcoords": "1.1.3", "formatcoords": "1.1.3",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"highlight.js": "11.7.0", "highlight.js": "11.7.0",
"immer": "7.0.15", "immer": "7.0.15",
"keytar": "7.9.0", "keytar": "7.9.0",
@@ -163,15 +168,15 @@
"react-datetime": "3.2.0", "react-datetime": "3.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-redux": "8.0.5", "react-redux": "8.0.5",
"react-select": "5.7.0", "react-select": "5.7.2",
"react-toggle-button": "2.2.0", "react-toggle-button": "2.2.0",
"react-tooltip": "4.5.1", "react-tooltip": "4.5.1",
"redux": "4.2.1", "redux": "4.2.1",
"reselect": "4.1.7", "reselect": "4.1.7",
"roboto-fontface": "0.10.0", "roboto-fontface": "0.10.0",
"smalltalk": "2.5.1", "smalltalk": "2.5.1",
"sqlite3": "5.1.4", "sqlite3": "5.1.6",
"styled-components": "5.3.8", "styled-components": "5.3.9",
"styled-system": "5.1.5", "styled-system": "5.1.5",
"taboverride": "4.0.3", "taboverride": "4.0.3",
"tinymce": "5.10.6" "tinymce": "5.10.6"

View File

@@ -1,6 +1,6 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const electron_notarize = require('electron-notarize'); const electron_notarize = require('@electron/notarize');
const execCommand = require('./execCommand'); const execCommand = require('./execCommand');
function isDesktopAppTag(tagName) { function isDesktopAppTag(tagName) {

View File

@@ -1,11 +1,18 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"include": [ "include": [
"**/*.ts", "**/*.ts",
"**/*.tsx", "**/*.tsx",
], ],
"exclude": [ "exclude": [
"**/node_modules", "**/node_modules",
"**/dist", "**/dist",
"gulpfile.ts",
], ],
"compilerOptions": {
"types": [
"jest",
"node"
]
}
} }

View File

@@ -1,6 +0,0 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};

View File

@@ -150,8 +150,8 @@ android {
applicationId "net.cozic.joplin" applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097684 versionCode 2097687
versionName "2.10.8" versionName "2.11.2"
// ndk { // ndk {
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" // abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
// } // }

View File

@@ -2,6 +2,7 @@
* @jest-environment jsdom * @jest-environment jsdom
*/ */
import { EditorSettings } from '../types'; import { EditorSettings } from '../types';
import { initCodeMirror } from './CodeMirror'; import { initCodeMirror } from './CodeMirror';
import { themeStyle } from '@joplin/lib/theme'; import { themeStyle } from '@joplin/lib/theme';
@@ -9,6 +10,8 @@ import Setting from '@joplin/lib/models/Setting';
import { forceParsing } from '@codemirror/language'; import { forceParsing } from '@codemirror/language';
import loadLangauges from './testUtil/loadLanguages'; import loadLangauges from './testUtil/loadLanguages';
import { expect, describe, it } from '@jest/globals';
const createEditorSettings = (themeId: number) => { const createEditorSettings = (themeId: number) => {
const themeData = themeStyle(themeId); const themeData = themeStyle(themeId);
@@ -23,6 +26,14 @@ const createEditorSettings = (themeId: number) => {
}; };
describe('CodeMirror', () => { describe('CodeMirror', () => {
// This checks for a regression -- occasionally, when updating packages,
// syntax highlighting in the CodeMirror editor stops working. This is usually
// fixed by
// 1. removing all `@codemirror/` and `@lezer/` dependencies from yarn.lock,
// 2. upgrading all CodeMirror packages to the latest versions in package.json, and
// 3. re-running `yarn install`.
//
// See https://github.com/laurent22/joplin/issues/7253
it('should give headings a different style', async () => { it('should give headings a different style', async () => {
const headerLineText = '# Testing...'; const headerLineText = '# Testing...';
const initialText = `${headerLineText}\nThis is a test.`; const initialText = `${headerLineText}\nThis is a test.`;

View File

@@ -30,6 +30,7 @@ interface Props {
initialSelection?: Selection; initialSelection?: Selection;
style: ViewStyle; style: ViewStyle;
contentStyle?: ViewStyle; contentStyle?: ViewStyle;
toolbarEnabled: boolean;
onChange: ChangeEventHandler; onChange: ChangeEventHandler;
onSelectionChange: SelectionChangeEventHandler; onSelectionChange: SelectionChangeEventHandler;
@@ -364,6 +365,19 @@ function NoteEditor(props: Props, ref: any) {
console.error('NoteEditor: webview error'); console.error('NoteEditor: webview error');
}, []); }, []);
const toolbar = <MarkdownToolbar
style={{
// Don't show the markdown toolbar if there isn't enough space
// for it:
flexShrink: 1,
}}
editorSettings={editorSettings}
editorControl={editorControl}
selectionState={selectionState}
searchState={searchState}
onAttach={props.onAttach}
/>;
// - `scrollEnabled` prevents iOS from scrolling the document (has no effect on Android) // - `scrollEnabled` prevents iOS from scrolling the document (has no effect on Android)
// when an editable region (e.g. a the full-screen NoteEditor) is focused. // when an editable region (e.g. a the full-screen NoteEditor) is focused.
return ( return (
@@ -401,18 +415,7 @@ function NoteEditor(props: Props, ref: any) {
searchState={searchState} searchState={searchState}
/> />
<MarkdownToolbar {props.toolbarEnabled ? toolbar : null}
style={{
// Don't show the markdown toolbar if there isn't enough space
// for it:
flexShrink: 1,
}}
editorSettings={editorSettings}
editorControl={editorControl}
selectionState={selectionState}
searchState={searchState}
onAttach={props.onAttach}
/>
</View> </View>
); );
} }

View File

@@ -2,9 +2,12 @@ const React = require('react');
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { View, Dimensions, Alert, Button } from 'react-native'; import { View, Dimensions, Alert, Button } from 'react-native';
import FingerprintScanner from 'react-native-fingerprint-scanner';
import { SensorInfo } from './sensorInfo'; import { SensorInfo } from './sensorInfo';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import Logger from '@joplin/lib/Logger';
import biometricAuthenticate from './biometricAuthenticate';
const logger = Logger.create('BiometricPopup');
interface Props { interface Props {
themeId: number; themeId: number;
@@ -13,24 +16,36 @@ interface Props {
} }
export default (props: Props) => { export default (props: Props) => {
const [initialPromptDone, setInitialPromptDone] = useState(Setting.value('security.biometricsInitialPromptDone')); // The initial prompt is there so that the user can choose to opt-in to
const [display, setDisplay] = useState(!!props.sensorInfo.supportedSensors && (props.sensorInfo.enabled || !initialPromptDone)); // biometrics auth the first time the app is launched. However since it
// doesn't work properly, we disable it. We only want the user to enable the
// feature after they've read the description in the config screen.
const [initialPromptDone, setInitialPromptDone] = useState(true); // useState(Setting.value('security.biometricsInitialPromptDone'));
const [display, setDisplay] = useState(props.sensorInfo.enabled || !initialPromptDone);
const [tryBiometricsCheck, setTryBiometricsCheck] = useState(initialPromptDone); const [tryBiometricsCheck, setTryBiometricsCheck] = useState(initialPromptDone);
logger.info('Render start');
logger.info('initialPromptDone', initialPromptDone);
logger.info('display', display);
logger.info('tryBiometricsCheck', tryBiometricsCheck);
logger.info('props.sensorInfo', props.sensorInfo);
useEffect(() => { useEffect(() => {
if (!display || !tryBiometricsCheck) return; if (!display || !tryBiometricsCheck) return;
const biometricsCheck = async () => { const biometricsCheck = async () => {
logger.info('biometricsCheck: start');
try { try {
await FingerprintScanner.authenticate({ description: _('Verify your identity') }); await biometricAuthenticate();
setTryBiometricsCheck(false);
setDisplay(false); setDisplay(false);
} catch (error) { } catch (error) {
Alert.alert(_('Could not verify your identify'), error.message); Alert.alert(error.message);
setTryBiometricsCheck(false);
} finally {
FingerprintScanner.release();
} }
setTryBiometricsCheck(false);
logger.info('biometricsCheck: end');
}; };
void biometricsCheck(); void biometricsCheck();
@@ -41,6 +56,9 @@ export default (props: Props) => {
if (!display) return; if (!display) return;
const complete = (enableBiometrics: boolean) => { const complete = (enableBiometrics: boolean) => {
logger.info('complete: start');
logger.info('complete: enableBiometrics:', enableBiometrics);
setInitialPromptDone(true); setInitialPromptDone(true);
Setting.setValue('security.biometricsInitialPromptDone', true); Setting.setValue('security.biometricsInitialPromptDone', true);
Setting.setValue('security.biometricsEnabled', enableBiometrics); Setting.setValue('security.biometricsEnabled', enableBiometrics);
@@ -55,6 +73,8 @@ export default (props: Props) => {
type: 'BIOMETRICS_DONE_SET', type: 'BIOMETRICS_DONE_SET',
value: true, value: true,
}); });
logger.info('complete: end');
}; };
Alert.alert( Alert.alert(
@@ -73,7 +93,7 @@ export default (props: Props) => {
}, },
] ]
); );
}, [initialPromptDone, props.sensorInfo.supportedSensors, display, props.dispatch]); }, [initialPromptDone, display, props.dispatch]);
const windowSize = useMemo(() => { const windowSize = useMemo(() => {
return { return {
@@ -83,12 +103,18 @@ export default (props: Props) => {
}, []); }, []);
useEffect(() => { useEffect(() => {
logger.info('effect 1: start');
if (!display) { if (!display) {
logger.info('effect 1: display', display);
props.dispatch({ props.dispatch({
type: 'BIOMETRICS_DONE_SET', type: 'BIOMETRICS_DONE_SET',
value: true, value: true,
}); });
} }
logger.info('effect 1: end');
}, [display, props.dispatch]); }, [display, props.dispatch]);
const renderTryAgainButton = () => { const renderTryAgainButton = () => {

View File

@@ -0,0 +1,28 @@
import Logger from '@joplin/lib/Logger';
import FingerprintScanner, { Errors } from 'react-native-fingerprint-scanner';
import { _ } from '@joplin/lib/locale';
const logger = Logger.create('biometricAuthenticate');
export default async () => {
try {
logger.info('Authenticate...');
await FingerprintScanner.authenticate({ description: _('Verify your identity') });
logger.info('Authenticate done');
} catch (error) {
const errorName = (error as Errors).name;
let errorMessage = error.message;
if (errorName === 'FingerprintScannerNotEnrolled' || errorName === 'FingerprintScannerNotAvailable') {
errorMessage = _('Biometric unlock is not setup on the device. Please set it up in order to unlock Joplin. If the device is on lockout, consider switching it off and on to reset biometrics scanning.');
}
error.message = _('Could not verify your identify: %s', errorMessage);
logger.warn(error);
throw error;
} finally {
FingerprintScanner.release();
}
};

View File

@@ -1,5 +1,7 @@
import Logger from '@joplin/lib/Logger';
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';
import FingerprintScanner from 'react-native-fingerprint-scanner'; import FingerprintScanner from 'react-native-fingerprint-scanner';
const logger = Logger.create('sensorInfo');
export interface SensorInfo { export interface SensorInfo {
enabled: boolean; enabled: boolean;
@@ -8,11 +10,40 @@ export interface SensorInfo {
} }
export default async (): Promise<SensorInfo> => { export default async (): Promise<SensorInfo> => {
// Early exit if the feature is disabled, so that we don't make any
// FingerprintScanner scanner calls, since it seems they can fail and freeze
// the app.
logger.info('Start');
logger.info('security.biometricsEnabled', Setting.value('security.biometricsEnabled'));
if (!Setting.value('security.biometricsEnabled')) {
return {
enabled: false,
sensorsHaveChanged: false,
supportedSensors: '',
};
}
let hasChanged = false; let hasChanged = false;
let supportedSensors = ''; let supportedSensors = '';
try { try {
logger.info('Getting isSensorAvailable...');
// Note: If `isSensorAvailable()` doesn't return anything, it seems we
// could assume that biometrics are not setup on the device, and thus we
// can unlock the app. However that's not always correct - on some
// devices (eg Galaxy S22), `isSensorAvailable()` will return nothing if
// the device is on lockout - i.e. if the user gave the wrong
// fingerprint multiple times.
//
// So we definitely can't unlock the app in that case, and it means
// `isSensorAvailable()` is pretty much useless. Instead we ask for
// fingerprint when the user turns on the feature and at that point we
// know if the device supports biometrics or not.
const result = await FingerprintScanner.isSensorAvailable(); const result = await FingerprintScanner.isSensorAvailable();
logger.info('isSensorAvailable result', result);
supportedSensors = result; supportedSensors = result;
if (result) { if (result) {
@@ -22,7 +53,7 @@ export default async (): Promise<SensorInfo> => {
} }
} }
} catch (error) { } catch (error) {
console.warn('Could not check for biometrics sensor:', error); logger.warn('Could not check for biometrics sensor:', error);
Setting.setValue('security.biometricsSupportedSensors', ''); Setting.setValue('security.biometricsSupportedSensors', '');
} }

View File

@@ -23,6 +23,7 @@ const { themeStyle } = require('../global-style.js');
const shared = require('@joplin/lib/components/shared/config-shared.js'); const shared = require('@joplin/lib/components/shared/config-shared.js');
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry'; import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
import { openDocumentTree } from '@joplin/react-native-saf-x'; import { openDocumentTree } from '@joplin/react-native-saf-x';
import biometricAuthenticate from '../biometrics/biometricAuthenticate';
class ConfigScreenComponent extends BaseScreenComponent { class ConfigScreenComponent extends BaseScreenComponent {
public static navigationOptions(): any { public static navigationOptions(): any {
@@ -463,7 +464,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
<Text key="label" style={this.styles().switchSettingText}> <Text key="label" style={this.styles().switchSettingText}>
{label} {label}
</Text> </Text>
<Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value: any) => updateSettingValue(key, value)} /> <Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value: any) => void updateSettingValue(key, value)} />
</View> </View>
{descriptionComp} {descriptionComp}
</View> </View>
@@ -474,13 +475,39 @@ class ConfigScreenComponent extends BaseScreenComponent {
return !hasDescription ? this.styles().settingContainer : this.styles().settingContainerNoBottomBorder; return !hasDescription ? this.styles().settingContainer : this.styles().settingContainerNoBottomBorder;
} }
private async handleSetting(key: string, value: any): Promise<boolean> {
// When the user tries to enable biometrics unlock, we ask for the
// fingerprint or Face ID, and if it's correct we save immediately. If
// it's not, we don't turn on the setting.
if (key === 'security.biometricsEnabled' && !!value) {
try {
await biometricAuthenticate();
shared.updateSettingValue(this, key, value);
await this.saveButton_press();
} catch (error) {
shared.updateSettingValue(this, key, false);
Alert.alert(error.message);
}
return true;
}
if (key === 'security.biometricsEnabled' && !value) {
shared.updateSettingValue(this, key, value);
await this.saveButton_press();
return true;
}
return false;
}
public settingToComponent(key: string, value: any) { public settingToComponent(key: string, value: any) {
const themeId = this.props.themeId; const themeId = this.props.themeId;
const theme = themeStyle(themeId); const theme = themeStyle(themeId);
const output: any = null; const output: any = null;
const updateSettingValue = (key: string, value: any) => { const updateSettingValue = async (key: string, value: any) => {
return shared.updateSettingValue(this, key, value); const handled = await this.handleSetting(key, value);
if (!handled) shared.updateSettingValue(this, key, value);
}; };
const md = Setting.settingMetadata(key); const md = Setting.settingMetadata(key);
@@ -517,7 +544,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
fontSize: theme.fontSize, fontSize: theme.fontSize,
}} }}
onValueChange={(itemValue: string) => { onValueChange={(itemValue: string) => {
updateSettingValue(key, itemValue); void updateSettingValue(key, itemValue);
}} }}
/> />
</View> </View>
@@ -553,7 +580,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
</Text> </Text>
<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', flex: 1 }}> <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', flex: 1 }}>
<Text style={this.styles().sliderUnits}>{unitLabel}</Text> <Text style={this.styles().sliderUnits}>{unitLabel}</Text>
<Slider key="control" style={{ flex: 1 }} step={md.step} minimumValue={minimum} maximumValue={maximum} value={value} onValueChange={value => updateSettingValue(key, value)} /> <Slider key="control" style={{ flex: 1 }} step={md.step} minimumValue={minimum} maximumValue={maximum} value={value} onValueChange={value => void updateSettingValue(key, value)} />
</View> </View>
</View> </View>
); );
@@ -577,7 +604,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
<Text key="label" style={this.styles().settingText}> <Text key="label" style={this.styles().settingText}>
{md.label()} {md.label()}
</Text> </Text>
<TextInput autoCorrect={false} autoComplete="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={(value: any) => updateSettingValue(key, value)} secureTextEntry={!!md.secure} /> <TextInput autoCorrect={false} autoComplete="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={(value: any) => void updateSettingValue(key, value)} secureTextEntry={!!md.secure} />
</View> </View>
); );
} else { } else {

View File

@@ -1118,6 +1118,7 @@ class NoteScreenComponent extends BaseScreenComponent {
bodyComponent = <NoteEditor bodyComponent = <NoteEditor
ref={this.editorRef} ref={this.editorRef}
toolbarEnabled={this.props.toolbarEnabled}
themeId={this.props.themeId} themeId={this.props.themeId}
initialText={note.body} initialText={note.body}
initialSelection={this.selection} initialSelection={this.selection}
@@ -1231,6 +1232,7 @@ const NoteScreen = connect((state: any) => {
themeId: state.settings.theme, themeId: state.settings.theme,
editorFont: [state.settings['style.editor.fontFamily']], editorFont: [state.settings['style.editor.fontFamily']],
editorFontSize: state.settings['style.editor.fontSize'], editorFontSize: state.settings['style.editor.fontSize'],
toolbarEnabled: state.settings['editor.mobile.toolbarEnabled'],
ftsEnabled: state.settings['db.ftsEnabled'], ftsEnabled: state.settings['db.ftsEnabled'],
sharedData: state.sharedData, sharedData: state.sharedData,
showSideMenu: state.showSideMenu, showSideMenu: state.showSideMenu,

View File

@@ -523,7 +523,7 @@
INFOPLIST_FILE = Joplin/Info.plist; INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.10.5; MARKETING_VERSION = 12.11.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"$(inherited)", "$(inherited)",
"-ObjC", "-ObjC",
@@ -551,7 +551,7 @@
INFOPLIST_FILE = Joplin/Info.plist; INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.10.5; MARKETING_VERSION = 12.11.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"$(inherited)", "$(inherited)",
"-ObjC", "-ObjC",
@@ -705,7 +705,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.10.5; MARKETING_VERSION = 12.11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
@@ -736,7 +736,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.10.5; MARKETING_VERSION = 12.11.0;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -306,7 +306,7 @@ PODS:
- React-jsinspector (0.70.6) - React-jsinspector (0.70.6)
- React-logger (0.70.6): - React-logger (0.70.6):
- glog - glog
- react-native-alarm-notification (2.10.0): - react-native-alarm-notification (2.11.0):
- React - React
- react-native-camera (4.2.1): - react-native-camera (4.2.1):
- React-Core - React-Core
@@ -316,7 +316,7 @@ PODS:
- React-Core - React-Core
- react-native-camera/RN (4.2.1): - react-native-camera/RN (4.2.1):
- React-Core - React-Core
- react-native-document-picker (8.1.3): - react-native-document-picker (8.1.4):
- React-Core - React-Core
- react-native-fingerprint-scanner (6.0.0): - react-native-fingerprint-scanner (6.0.0):
- React - React
@@ -324,15 +324,15 @@ PODS:
- React-Core - React-Core
- react-native-get-random-values (1.8.0): - react-native-get-random-values (1.8.0):
- React-Core - React-Core
- react-native-image-picker (5.0.2): - react-native-image-picker (5.3.1):
- React-Core - React-Core
- react-native-image-resizer (1.4.5): - react-native-image-resizer (1.4.5):
- React-Core - React-Core
- react-native-netinfo (9.3.7): - react-native-netinfo (9.3.8):
- React-Core - React-Core
- react-native-rsa-native (2.0.5): - react-native-rsa-native (2.0.5):
- React - React
- react-native-saf-x (2.10.2): - react-native-saf-x (2.11.0):
- React-Core - React-Core
- react-native-safe-area-context (4.5.0): - react-native-safe-area-context (4.5.0):
- RCT-Folly - RCT-Folly
@@ -432,7 +432,7 @@ PODS:
- React - React
- RNSecureRandom (1.0.1): - RNSecureRandom (1.0.1):
- React - React
- RNShare (8.2.0): - RNShare (8.2.1):
- React-Core - React-Core
- RNVectorIcons (9.2.0): - RNVectorIcons (9.2.0):
- React-Core - React-Core
@@ -714,17 +714,17 @@ SPEC CHECKSUMS:
React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f
React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0 React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
react-native-alarm-notification: 0f58eaa37a4188480536fd7ab62db9b1dfba392f react-native-alarm-notification: 26527410a6162d07a9dc57f4bbc62e94ff48e65d
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
react-native-document-picker: 958e2bc82e128be69055be261aeac8d872c8d34c react-native-document-picker: a9bd26996d1b2e4f412dd186041714c79af381d0
react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe
react-native-geolocation: 69f4fd37650b8e7fee91816d395e62dd16f5ab8d react-native-geolocation: 69f4fd37650b8e7fee91816d395e62dd16f5ab8d
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
react-native-image-picker: a5dddebb4d2955ac4712a4ed66b00a85f62a63ac react-native-image-picker: ec9b713e248760bfa0f879f0715391de4651a7cb
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983 react-native-netinfo: fbc23bc2fe217155d85f2f7e0644b1654df8029b
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
react-native-saf-x: db5a33862e7aec0f9f2d4cccfe7264b09b234e2e react-native-saf-x: 9bd5238d3b43d76bbec64aa82c173ac20a4bce9f
react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc
react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261 react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
@@ -751,7 +751,7 @@ SPEC CHECKSUMS:
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
RNShare: b089c33619bbfb0a32bc4069c858b9274e694187 RNShare: eaee3dd5a06dad397c7d3b14762007035c5de405
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc

View File

@@ -2,7 +2,7 @@
"name": "@joplin/app-mobile", "name": "@joplin/app-mobile",
"description": "Joplin for Mobile", "description": "Joplin for Mobile",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"version": "2.10.0", "version": "2.11.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start --reset-cache", "start": "react-native start --reset-cache",
@@ -18,14 +18,14 @@
"postinstall": "jetify && yarn run build" "postinstall": "jetify && yarn run build"
}, },
"dependencies": { "dependencies": {
"@joplin/lib": "~2.10", "@joplin/lib": "~2.11",
"@joplin/react-native-alarm-notification": "~2.10", "@joplin/react-native-alarm-notification": "~2.11",
"@joplin/react-native-saf-x": "~2.10", "@joplin/react-native-saf-x": "~2.11",
"@joplin/renderer": "~2.10", "@joplin/renderer": "~2.11",
"@react-native-community/clipboard": "1.5.1", "@react-native-community/clipboard": "1.5.1",
"@react-native-community/datetimepicker": "6.7.5", "@react-native-community/datetimepicker": "6.7.5",
"@react-native-community/geolocation": "2.1.0", "@react-native-community/geolocation": "2.1.0",
"@react-native-community/netinfo": "9.3.7", "@react-native-community/netinfo": "9.3.8",
"@react-native-community/push-notification-ios": "1.10.1", "@react-native-community/push-notification-ios": "1.10.1",
"@react-native-community/slider": "4.4.2", "@react-native-community/slider": "4.4.2",
"assert-browserify": "2.0.0", "assert-browserify": "2.0.0",
@@ -44,17 +44,17 @@
"react-native-action-button": "2.8.5", "react-native-action-button": "2.8.5",
"react-native-camera": "4.2.1", "react-native-camera": "4.2.1",
"react-native-dialogbox": "0.6.10", "react-native-dialogbox": "0.6.10",
"react-native-document-picker": "8.1.3", "react-native-document-picker": "8.1.4",
"react-native-dropdownalert": "4.5.1", "react-native-dropdownalert": "4.5.1",
"react-native-exit-app": "1.1.0", "react-native-exit-app": "1.1.0",
"react-native-file-viewer": "2.1.5", "react-native-file-viewer": "2.1.5",
"react-native-fingerprint-scanner": "6.0.0", "react-native-fingerprint-scanner": "6.0.0",
"react-native-fs": "2.20.0", "react-native-fs": "2.20.0",
"react-native-get-random-values": "1.8.0", "react-native-get-random-values": "1.8.0",
"react-native-image-picker": "5.1.0", "react-native-image-picker": "5.3.1",
"react-native-image-resizer": "1.4.5", "react-native-image-resizer": "1.4.5",
"react-native-modal-datetime-picker": "14.0.1", "react-native-modal-datetime-picker": "14.0.1",
"react-native-paper": "5.2.0", "react-native-paper": "5.4.1",
"react-native-popup-menu": "0.16.1", "react-native-popup-menu": "0.16.1",
"react-native-quick-actions": "0.3.13", "react-native-quick-actions": "0.3.13",
"react-native-rsa-native": "2.0.5", "react-native-rsa-native": "2.0.5",
@@ -79,36 +79,36 @@
"devDependencies": { "devDependencies": {
"@babel/core": "7.16.0", "@babel/core": "7.16.0",
"@babel/runtime": "7.16.3", "@babel/runtime": "7.16.3",
"@codemirror/commands": "6.1.2", "@codemirror/commands": "6.2.2",
"@codemirror/lang-cpp": "6.0.2", "@codemirror/lang-cpp": "6.0.2",
"@codemirror/lang-html": "6.4.0", "@codemirror/lang-html": "6.4.3",
"@codemirror/lang-java": "6.0.1", "@codemirror/lang-java": "6.0.1",
"@codemirror/lang-javascript": "6.1.1", "@codemirror/lang-javascript": "6.1.5",
"@codemirror/lang-markdown": "6.0.5", "@codemirror/lang-markdown": "6.1.0",
"@codemirror/lang-php": "6.0.1", "@codemirror/lang-php": "6.0.1",
"@codemirror/lang-rust": "6.0.1", "@codemirror/lang-rust": "6.0.1",
"@codemirror/language": "6.3.2", "@codemirror/language": "6.6.0",
"@codemirror/legacy-modes": "6.3.1", "@codemirror/legacy-modes": "6.3.2",
"@codemirror/search": "6.2.3", "@codemirror/search": "6.3.0",
"@codemirror/state": "6.1.4", "@codemirror/state": "6.2.0",
"@codemirror/view": "6.7.1", "@codemirror/view": "6.9.3",
"@joplin/tools": "~2.10", "@joplin/tools": "~2.11",
"@lezer/highlight": "1.1.3", "@lezer/highlight": "1.1.4",
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
"@types/jest": "29.2.6", "@types/jest": "29.2.6",
"@types/react-native": "0.70.6", "@types/react-native": "0.70.6",
"@types/react-redux": "7.1.25", "@types/react-redux": "7.1.25",
"babel-plugin-module-resolver": "4.1.0", "babel-plugin-module-resolver": "4.1.0",
"execa": "4.1.0", "execa": "4.1.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"gulp": "4.0.2", "gulp": "4.0.2",
"jest": "29.4.3", "jest": "29.4.3",
"jest-environment-jsdom": "29.4.3", "jest-environment-jsdom": "29.4.3",
"jetifier": "2.0.0", "jetifier": "2.0.0",
"jsdom": "21.0.0", "jsdom": "21.1.1",
"md5-file": "5.0.0", "md5-file": "5.0.0",
"metro-react-native-babel-preset": "0.72.3", "metro-react-native-babel-preset": "0.72.3",
"nodemon": "2.0.21", "nodemon": "2.0.22",
"ts-jest": "29.0.5", "ts-jest": "29.0.5",
"ts-loader": "9.4.2", "ts-loader": "9.4.2",
"ts-node": "10.9.1", "ts-node": "10.9.1",

View File

@@ -501,7 +501,7 @@ async function initialize(dispatch: Function) {
if (Setting.value('env') === 'prod') { if (Setting.value('env') === 'prod') {
await db.open({ name: getDatabaseName(currentProfile, isSubProfile) }); await db.open({ name: getDatabaseName(currentProfile, isSubProfile) });
} else { } else {
await db.open({ name: getDatabaseName(currentProfile, isSubProfile) }); await db.open({ name: getDatabaseName(currentProfile, isSubProfile, '-3') });
// await db.clearForTesting(); // await db.clearForTesting();
} }
@@ -984,6 +984,10 @@ class AppComponent extends React.Component {
const biometricIsEnabled = !!this.state.sensorInfo && this.state.sensorInfo.enabled; const biometricIsEnabled = !!this.state.sensorInfo && this.state.sensorInfo.enabled;
const shouldShowMainContent = !biometricIsEnabled || this.props.biometricsDone; const shouldShowMainContent = !biometricIsEnabled || this.props.biometricsDone;
logger.info('root.biometrics: biometricIsEnabled', biometricIsEnabled);
logger.info('root.biometrics: shouldShowMainContent', shouldShowMainContent);
logger.info('root.biometrics: this.state.sensorInfo', this.state.sensorInfo);
const mainContent = ( const mainContent = (
<View style={{ flex: 1, backgroundColor: theme.backgroundColor }}> <View style={{ flex: 1, backgroundColor: theme.backgroundColor }}>
<SideMenu <SideMenu

View File

@@ -24,9 +24,10 @@ export const getResourceDir = (profile: Profile, isSubProfile: boolean) => {
return `${getProfilesRootDir()}/resources-${profile.id}`; return `${getProfilesRootDir()}/resources-${profile.id}`;
}; };
export const getDatabaseName = (profile: Profile, isSubProfile: boolean) => { // The suffix is for debugging only
if (!isSubProfile) return 'joplin.sqlite'; export const getDatabaseName = (profile: Profile, isSubProfile: boolean, suffix: string = '') => {
return `joplin-${profile.id}.sqlite`; if (!isSubProfile) return `joplin${suffix}.sqlite`;
return `joplin-${profile.id}${suffix}.sqlite`;
}; };
export const loadProfileConfig = async () => { export const loadProfileConfig = async () => {

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 1, "manifest_version": 1,
"id": "<%= pluginId %>", "id": "<%= pluginId %>",
"app_min_version": "2.10", "app_min_version": "2.11",
"version": "1.0.0", "version": "1.0.0",
"name": "<%= pluginName %>", "name": "<%= pluginName %>",
"description": "<%= pluginDescription %>", "description": "<%= pluginDescription %>",

View File

@@ -1,6 +1,6 @@
{ {
"name": "generator-joplin", "name": "generator-joplin",
"version": "2.10.0", "version": "2.11.0",
"description": "Scaffolds out a new Joplin plugin", "description": "Scaffolds out a new Joplin plugin",
"homepage": "https://github.com/laurent22/joplin/tree/dev/packages/generator-joplin", "homepage": "https://github.com/laurent22/joplin/tree/dev/packages/generator-joplin",
"author": { "author": {
@@ -24,7 +24,7 @@
}, },
"dependencies": { "dependencies": {
"chalk": "2.4.2", "chalk": "2.4.2",
"slugify": "1.6.5", "slugify": "1.6.6",
"yeoman-generator": "5.8.0", "yeoman-generator": "5.8.0",
"yosay": "2.0.2" "yosay": "2.0.2"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/htmlpack", "name": "@joplin/htmlpack",
"version": "2.10.2", "version": "2.11.0",
"description": "Pack an HTML file and all its linked resources into a single HTML file", "description": "Pack an HTML file and all its linked resources into a single HTML file",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.ts", "types": "src/index.ts",
@@ -17,7 +17,7 @@
"@joplin/fork-htmlparser2": "^4.1.43", "@joplin/fork-htmlparser2": "^4.1.43",
"css": "3.0.0", "css": "3.0.0",
"datauri": "4.1.0", "datauri": "4.1.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"html-entities": "1.4.0" "html-entities": "1.4.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -20,7 +20,7 @@ import Folder from './models/Folder';
import BaseItem from './models/BaseItem'; import BaseItem from './models/BaseItem';
import Note from './models/Note'; import Note from './models/Note';
import Tag from './models/Tag'; import Tag from './models/Tag';
const { splitCommandString } = require('./string-utils.js'); import { splitCommandString } from '@joplin/utils';
import { reg } from './registry'; import { reg } from './registry';
import time from './time'; import time from './time';
import BaseSyncTarget from './BaseSyncTarget'; import BaseSyncTarget from './BaseSyncTarget';
@@ -192,6 +192,12 @@ export default class BaseApplication {
continue; continue;
} }
if (arg === '--safe-mode') {
matched.isSafeMode = true;
argv.splice(0, 1);
continue;
}
if (arg === '--open-dev-tools') { if (arg === '--open-dev-tools') {
Setting.setConstant('flagOpenDevTools', true); Setting.setConstant('flagOpenDevTools', true);
argv.splice(0, 1); argv.splice(0, 1);
@@ -700,7 +706,7 @@ export default class BaseApplication {
flagContent = flagContent.trim(); flagContent = flagContent.trim();
let flags = splitCommandString(flagContent); let flags: any = splitCommandString(flagContent);
flags.splice(0, 0, 'cmd'); flags.splice(0, 0, 'cmd');
flags.splice(0, 0, 'node'); flags.splice(0, 0, 'node');
@@ -829,6 +835,10 @@ export default class BaseApplication {
appLogger.info(`Client ID: ${Setting.value('clientId')}`); appLogger.info(`Client ID: ${Setting.value('clientId')}`);
if (initArgs?.isSafeMode) {
Setting.setValue('isSafeMode', true);
}
if (Setting.value('firstStart')) { if (Setting.value('firstStart')) {
// If it's a sub-profile, the locale must come from the root // If it's a sub-profile, the locale must come from the root
// profile. // profile.

View File

@@ -96,12 +96,14 @@ export default class SyncTargetOneDrive extends BaseSyncTarget {
let context = Setting.value(`sync.${this.syncTargetId()}.context`); let context = Setting.value(`sync.${this.syncTargetId()}.context`);
context = context === '' ? null : JSON.parse(context); context = context === '' ? null : JSON.parse(context);
let accountProperties = context ? context.accountProperties : null; let accountProperties = context ? context.accountProperties : null;
const api = this.api();
if (!accountProperties) { if (!accountProperties) {
accountProperties = await this.api_.execAccountPropertiesRequest(); accountProperties = await api.execAccountPropertiesRequest();
context ? context.accountProperties = accountProperties : context = { accountProperties: accountProperties }; context ? context.accountProperties = accountProperties : context = { accountProperties: accountProperties };
Setting.setValue(`sync.${this.syncTargetId()}.context`, JSON.stringify(context)); Setting.setValue(`sync.${this.syncTargetId()}.context`, JSON.stringify(context));
} }
this.api_.setAccountProperties(accountProperties); api.setAccountProperties(accountProperties);
const appDir = await this.api().appDirectory(); const appDir = await this.api().appDirectory();
// the appDir might contain non-ASCII characters // the appDir might contain non-ASCII characters
// /[^\u0021-\u00ff]/ is used in Node.js to detect the unescaped characters. // /[^\u0021-\u00ff]/ is used in Node.js to detect the unescaped characters.

View File

@@ -1,5 +1,18 @@
const markJsUtils = {}; const markJsUtils = {};
const isInsideContainer = (node, tagName) => {
if (!node) return false;
tagName = tagName.toLowerCase();
while (node) {
if (node.tagName && node.tagName.toLowerCase() === tagName) return true;
node = node.parentNode;
}
return false;
};
markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => { markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
if (typeof keyword === 'string') { if (typeof keyword === 'string') {
keyword = { keyword = {
@@ -15,12 +28,13 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
if (isBasicSearch) accuracy = 'partially'; if (isBasicSearch) accuracy = 'partially';
if (keyword.type === 'regex') { if (keyword.type === 'regex') {
accuracy = 'complementary'; accuracy = 'complementary';
// Remove the trailing wildcard and "accuracy = complementary" will take care of // Remove the trailing wildcard and "accuracy = complementary" will take
// highlighting the relevant keywords. // care of highlighting the relevant keywords.
// Known bug: it will also highlight word that contain the term as a suffix for example for "ent*", it will highlight "present" // Known bug: it will also highlight word that contain the term as a
// which is incorrect (it should only highlight what starts with "ent") but for now will do. Mark.js doesn't have an option // suffix for example for "ent*", it will highlight "present" which is
// to tweak this behaviour. // incorrect (it should only highlight what starts with "ent") but for
// now will do. Mark.js doesn't have an option to tweak this behaviour.
value = keyword.value.substr(0, keyword.value.length - 1); value = keyword.value.substr(0, keyword.value.length - 1);
} }
@@ -30,6 +44,18 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
{}, {},
{ {
accuracy: accuracy, accuracy: accuracy,
filter: (node, _term, _totalCounter, _counter) => {
// We exclude SVG because it creates a "<mark>" tag inside
// the document, which is not a valid SVG tag. As a result
// the content within that tag disappears.
//
// mark.js has an "exclude" parameter, but it doesn't work
// so we use "filter" instead.
//
// https://github.com/joplin/plugin-abc-sheet-music
if (isInsideContainer(node, 'SVG')) return false;
return true;
},
}, },
extraOptions extraOptions
) )

View File

@@ -1050,6 +1050,17 @@ class Setting extends BaseModel {
isGlobal: true, isGlobal: true,
}, },
'editor.mobile.toolbarEnabled': {
value: true,
type: SettingItemType.Bool,
section: 'note',
public: true,
appTypes: [AppType.Mobile],
label: () => _('Enable the Markdown toolbar'),
storage: SettingStorage.File,
isGlobal: true,
},
// Works around a bug in which additional space is visible beneath the toolbar on some devices. // Works around a bug in which additional space is visible beneath the toolbar on some devices.
// See https://github.com/laurent22/joplin/pull/6823 // See https://github.com/laurent22/joplin/pull/6823
'editor.mobile.removeSpaceBelowToolbar': { 'editor.mobile.removeSpaceBelowToolbar': {
@@ -1634,10 +1645,17 @@ class Setting extends BaseModel {
storage: SettingStorage.Database, storage: SettingStorage.Database,
}, },
// The biometrics feature is disabled by default and marked as beta
// because it seems to cause a freeze or slow down startup on
// certain devices. May be the reason for:
//
// - https://discourse.joplinapp.org/t/on-android-when-joplin-gets-started-offline/29951/1
// - https://github.com/laurent22/joplin/issues/7956
'security.biometricsEnabled': { 'security.biometricsEnabled': {
value: false, value: false,
type: SettingItemType.Bool, type: SettingItemType.Bool,
label: () => _('Use biometrics to secure access to the app'), label: () => `${_('Use biometrics to secure access to the app')} (Beta)`,
description: () => 'Important: This is a beta feature and it is not compatible with certain devices. If the app no longer starts after enabling this or is very slow to start, please uninstall and reinstall the app.',
public: true, public: true,
appTypes: [AppType.Mobile], appTypes: [AppType.Mobile],
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/lib", "name": "@joplin/lib",
"version": "2.10.2", "version": "2.11.0",
"description": "Joplin Core library", "description": "Joplin Core library",
"author": "Laurent Cozic", "author": "Laurent Cozic",
"homepage": "", "homepage": "",
@@ -34,10 +34,11 @@
"@joplin/fork-htmlparser2": "^4.1.43", "@joplin/fork-htmlparser2": "^4.1.43",
"@joplin/fork-sax": "^1.2.47", "@joplin/fork-sax": "^1.2.47",
"@joplin/fork-uslug": "^1.0.8", "@joplin/fork-uslug": "^1.0.8",
"@joplin/htmlpack": "^2.10.2", "@joplin/htmlpack": "~2.11",
"@joplin/renderer": "^2.10.2", "@joplin/renderer": "~2.11",
"@joplin/turndown": "^4.0.65", "@joplin/turndown": "^4.0.65",
"@joplin/turndown-plugin-gfm": "^1.0.47", "@joplin/turndown-plugin-gfm": "^1.0.47",
"@joplin/utils": "~2.11",
"@types/nanoid": "3.0.0", "@types/nanoid": "3.0.0",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"base-64": "1.0.0", "base-64": "1.0.0",
@@ -53,7 +54,7 @@
"fast-xml-parser": "3.21.1", "fast-xml-parser": "3.21.1",
"follow-redirects": "1.15.2", "follow-redirects": "1.15.2",
"form-data": "4.0.0", "form-data": "4.0.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"hpagent": "1.2.0", "hpagent": "1.2.0",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"html-minifier": "4.0.0", "html-minifier": "4.0.0",
@@ -68,7 +69,7 @@
"moment": "2.29.4", "moment": "2.29.4",
"multiparty": "4.2.3", "multiparty": "4.2.3",
"mustache": "4.2.0", "mustache": "4.2.0",
"nanoid": "3.3.4", "nanoid": "3.3.6",
"node-fetch": "2.6.7", "node-fetch": "2.6.7",
"node-notifier": "10.0.1", "node-notifier": "10.0.1",
"node-persist": "3.1.3", "node-persist": "3.1.3",
@@ -82,7 +83,7 @@
"reselect": "4.1.7", "reselect": "4.1.7",
"server-destroy": "1.0.1", "server-destroy": "1.0.1",
"sprintf-js": "1.1.2", "sprintf-js": "1.1.2",
"sqlite3": "5.1.4", "sqlite3": "5.1.6",
"string-padding": "1.0.2", "string-padding": "1.0.2",
"string-to-stream": "3.0.1", "string-to-stream": "3.0.1",
"tar": "6.1.13", "tar": "6.1.13",

View File

@@ -1,6 +1,6 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
const { splitCommandString } = require('../../string-utils'); import { splitCommandString } from '@joplin/utils';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import Logger from '../../Logger'; import Logger from '../../Logger';
import Setting from '../../models/Setting'; import Setting from '../../models/Setting';

View File

@@ -110,6 +110,8 @@ export default class ReportService {
let syncedCount = 0; let syncedCount = 0;
for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) { for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) {
const d = BaseItem.syncItemDefinitions_[i]; const d = BaseItem.syncItemDefinitions_[i];
// ref: https://github.com/laurent22/joplin/issues/7940#issuecomment-1473709148
if (d.className === 'MasterKey') continue;
const ItemClass = BaseItem.getClass(d.className); const ItemClass = BaseItem.getClass(d.className);
const o = { const o = {
total: await ItemClass.count(), total: await ItemClass.count(),

View File

@@ -100,6 +100,11 @@ export default class PluginService extends BaseService {
return this.plugins_; return this.plugins_;
} }
public enabledPlugins(pluginSettings: PluginSettings): Plugins {
const enabledPlugins = Object.fromEntries(Object.entries(this.plugins_).filter((p) => this.pluginEnabled(pluginSettings, p[0])));
return enabledPlugins;
}
public get pluginIds(): string[] { public get pluginIds(): string[] {
return Object.keys(this.plugins_); return Object.keys(this.plugins_);
} }
@@ -108,6 +113,10 @@ export default class PluginService extends BaseService {
return this.isSafeMode_; return this.isSafeMode_;
} }
public get appVersion(): string {
return this.appVersion_;
}
public set isSafeMode(v: boolean) { public set isSafeMode(v: boolean) {
this.isSafeMode_ = v; this.isSafeMode_ = v;
} }

View File

@@ -215,21 +215,21 @@ export default class RepositoryApi {
return this.manifests_; return this.manifests_;
} }
public async canBeUpdatedPlugins(installedManifests: PluginManifest[]): Promise<string[]> { public async canBeUpdatedPlugins(installedManifests: PluginManifest[], appVersion: string): Promise<string[]> {
const output = []; const output = [];
for (const manifest of installedManifests) { for (const manifest of installedManifests) {
const canBe = await this.pluginCanBeUpdated(manifest.id, manifest.version); const canBe = await this.pluginCanBeUpdated(manifest.id, manifest.version, appVersion);
if (canBe) output.push(manifest.id); if (canBe) output.push(manifest.id);
} }
return output; return output;
} }
public async pluginCanBeUpdated(pluginId: string, installedVersion: string): Promise<boolean> { public async pluginCanBeUpdated(pluginId: string, installedVersion: string, appVersion: string): Promise<boolean> {
const manifest = (await this.manifests()).find(m => m.id === pluginId); const manifest = (await this.manifests()).find(m => m.id === pluginId);
if (!manifest) return false; if (!manifest) return false;
return compareVersions(installedVersion, manifest.version) < 0; return compareVersions(installedVersion, manifest.version) < 0 && compareVersions(appVersion, manifest.app_min_version) >= 0;
} }
} }

View File

@@ -138,80 +138,6 @@ function commandArgumentsToString(args) {
return output.join(' '); return output.join(' ');
} }
function splitCommandString(command, options = null) {
options = options || {};
if (!('handleEscape' in options)) {
options.handleEscape = true;
}
const args = [];
let state = 'start';
let current = '';
let quote = '"';
let escapeNext = false;
for (let i = 0; i < command.length; i++) {
const c = command[i];
if (state === 'quotes') {
if (c !== quote) {
current += c;
} else {
args.push(current);
current = '';
state = 'start';
}
continue;
}
if (escapeNext) {
current += c;
escapeNext = false;
continue;
}
if (c === '\\' && options.handleEscape) {
escapeNext = true;
continue;
}
if (c === '"' || c === '\'') {
state = 'quotes';
quote = c;
continue;
}
if (state === 'arg') {
if (c === ' ' || c === '\t') {
args.push(current);
current = '';
state = 'start';
} else {
current += c;
}
continue;
}
if (c !== ' ' && c !== '\t') {
state = 'arg';
current += c;
}
}
if (state === 'quotes') {
throw new Error(`Unclosed quote in command line: ${command}`);
}
if (current !== '') {
args.push(current);
}
if (args.length <= 0) {
throw new Error('Empty command line');
}
return args;
}
function splitCommandBatch(commandBatch) { function splitCommandBatch(commandBatch) {
const commandLines = []; const commandLines = [];
const eol = '\n'; const eol = '\n';
@@ -368,4 +294,4 @@ function scriptType(s) {
return 'en'; return 'en';
} }
module.exports = Object.assign({ formatCssSize, camelCaseToDash, removeDiacritics, substrWithEllipsis, nextWhitespaceIndex, escapeFilename, wrap, splitCommandString, splitCommandBatch, padLeft, toTitleCase, urlDecode, escapeHtml, surroundKeywords, scriptType, commandArgumentsToString }, stringUtilsCommon); module.exports = Object.assign({ formatCssSize, camelCaseToDash, removeDiacritics, substrWithEllipsis, nextWhitespaceIndex, escapeFilename, wrap, splitCommandBatch, padLeft, toTitleCase, urlDecode, escapeHtml, surroundKeywords, scriptType, commandArgumentsToString }, stringUtilsCommon);

View File

@@ -21,6 +21,17 @@ export function credentialDir() {
throw new Error(`Could not find credential directory in any of these paths: ${JSON.stringify(toTry)}`); throw new Error(`Could not find credential directory in any of these paths: ${JSON.stringify(toTry)}`);
} }
export const hasCredentialFile = (filename: string) => {
let d = '';
try {
d = credentialDir();
} catch (error) {
return false;
}
return pathExistsSync(`${d}/${filename}`);
};
export function credentialFile(filename: string) { export function credentialFile(filename: string) {
const rootDir = credentialDir(); const rootDir = credentialDir();
const output = `${rootDir}/${filename}`; const output = `${rootDir}/${filename}`;

View File

@@ -86,6 +86,7 @@ describe('getPluginLists', () => {
); );
plugins[plugin.manifest.id] = plugin; plugins[plugin.manifest.id] = plugin;
} }
const v = versionInfo(packageInfo, plugins); const v = versionInfo(packageInfo, plugins);
expect(v.body).toMatch(/\n\nPlugin1: 1\nPlugin2: 1\nPlugin3: 1/); expect(v.body).toMatch(/\n\nPlugin1: 1\nPlugin2: 1\nPlugin3: 1/);
@@ -110,6 +111,7 @@ describe('getPluginLists', () => {
plugins[plugin.manifest.id] = plugin; plugins[plugin.manifest.id] = plugin;
} }
const v = versionInfo(packageInfo, plugins); const v = versionInfo(packageInfo, plugins);
const body = '\n'; const body = '\n';

View File

@@ -16,6 +16,8 @@ function getPluginLists(plugins: Plugins): PluginList {
} }
} }
pluginList.sort(Intl.Collator().compare);
let completeList = ''; let completeList = '';
let summary = ''; let summary = '';
if (pluginList.length > 0) { if (pluginList.length > 0) {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/pdf-viewer", "name": "@joplin/pdf-viewer",
"version": "2.10.0", "version": "2.11.0",
"description": "Provides embedded PDF viewers for Joplin", "description": "Provides embedded PDF viewers for Joplin",
"main": "dist/main.js", "main": "dist/main.js",
"types": "src/main.ts", "types": "src/main.ts",
@@ -28,7 +28,7 @@
"css-loader": "6.7.3", "css-loader": "6.7.3",
"jest": "29.4.3", "jest": "29.4.3",
"jest-environment-jsdom": "29.4.3", "jest-environment-jsdom": "29.4.3",
"style-loader": "3.3.1", "style-loader": "3.3.2",
"ts-jest": "29.0.5", "ts-jest": "29.0.5",
"ts-loader": "9.4.2", "ts-loader": "9.4.2",
"typescript": "4.9.4", "typescript": "4.9.4",
@@ -39,11 +39,11 @@
"@fortawesome/fontawesome-svg-core": "6.1.2", "@fortawesome/fontawesome-svg-core": "6.1.2",
"@fortawesome/free-solid-svg-icons": "6.1.2", "@fortawesome/free-solid-svg-icons": "6.1.2",
"@fortawesome/react-fontawesome": "0.2.0", "@fortawesome/react-fontawesome": "0.2.0",
"@joplin/lib": "~2.10", "@joplin/lib": "~2.11",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"pdfjs-dist": "2.16.105", "pdfjs-dist": "2.16.105",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"styled-components": "5.3.8" "styled-components": "5.3.9"
} }
} }

View File

@@ -9,7 +9,7 @@ import * as path from 'path';
import * as process from 'process'; import * as process from 'process';
import validatePluginId from '@joplin/lib/services/plugins/utils/validatePluginId'; import validatePluginId from '@joplin/lib/services/plugins/utils/validatePluginId';
import validatePluginVersion from '@joplin/lib/services/plugins/utils/validatePluginVersion'; import validatePluginVersion from '@joplin/lib/services/plugins/utils/validatePluginVersion';
import { execCommand2, resolveRelativePathWithinDir, gitPullTry, gitRepoCleanTry, gitRepoClean } from '@joplin/tools/tool-utils.js'; import { resolveRelativePathWithinDir, gitPullTry, gitRepoCleanTry, gitRepoClean } from '@joplin/tools/tool-utils.js';
import checkIfPluginCanBeAdded from './lib/checkIfPluginCanBeAdded'; import checkIfPluginCanBeAdded from './lib/checkIfPluginCanBeAdded';
import updateReadme from './lib/updateReadme'; import updateReadme from './lib/updateReadme';
import { NpmPackage } from './lib/types'; import { NpmPackage } from './lib/types';
@@ -17,6 +17,7 @@ import gitCompareUrl from './lib/gitCompareUrl';
import commandUpdateRelease from './commands/updateRelease'; import commandUpdateRelease from './commands/updateRelease';
import { isJoplinPluginPackage, readJsonFile } from './lib/utils'; import { isJoplinPluginPackage, readJsonFile } from './lib/utils';
import { applyManifestOverrides, getObsoleteManifests, readManifestOverrides } from './lib/overrideUtils'; import { applyManifestOverrides, getObsoleteManifests, readManifestOverrides } from './lib/overrideUtils';
import { execCommand } from '@joplin/utils';
function pluginInfoFromSearchResults(results: any[]): NpmPackage[] { function pluginInfoFromSearchResults(results: any[]): NpmPackage[] {
const output: NpmPackage[] = []; const output: NpmPackage[] = [];
@@ -49,7 +50,7 @@ async function checkPluginRepository(dirPath: string, dryRun: boolean) {
async function extractPluginFilesFromPackage(existingManifests: any, workDir: string, packageName: string, destDir: string): Promise<any> { async function extractPluginFilesFromPackage(existingManifests: any, workDir: string, packageName: string, destDir: string): Promise<any> {
const previousDir = chdir(workDir); const previousDir = chdir(workDir);
await execCommand2(`npm install ${packageName} --save --ignore-scripts`, { showStderr: false, showStdout: false }); await execCommand(`npm install ${packageName} --save --ignore-scripts`, { showStderr: false, showStdout: false });
const pluginDir = resolveRelativePathWithinDir(workDir, 'node_modules', packageName, 'publish'); const pluginDir = resolveRelativePathWithinDir(workDir, 'node_modules', packageName, 'publish');
@@ -154,7 +155,7 @@ async function processNpmPackage(npmPackage: NpmPackage, repoDir: string, dryRun
await fs.mkdirp(packageTempDir); await fs.mkdirp(packageTempDir);
chdir(packageTempDir); chdir(packageTempDir);
await execCommand2('npm init --yes --loglevel silent', { quiet: true }); await execCommand('npm init --yes --loglevel silent', { quiet: true });
let actionType: ProcessingActionType = ProcessingActionType.Update; let actionType: ProcessingActionType = ProcessingActionType.Update;
let manifests: any = {}; let manifests: any = {};
@@ -200,8 +201,8 @@ async function processNpmPackage(npmPackage: NpmPackage, repoDir: string, dryRun
if (!dryRun) { if (!dryRun) {
if (!(await gitRepoClean())) { if (!(await gitRepoClean())) {
await execCommand2('git add -A', { showStdout: false }); await execCommand('git add -A', { showStdout: false });
await execCommand2(['git', 'commit', '-m', commitMessage(actionType, manifest, previousManifest, npmPackage, error)], { showStdout: false }); await execCommand(['git', 'commit', '-m', commitMessage(actionType, manifest, previousManifest, npmPackage, error)], { showStdout: false });
} else { } else {
console.info('Nothing to commit'); console.info('Nothing to commit');
} }
@@ -227,14 +228,14 @@ async function commandBuild(args: CommandBuildArgs) {
if (!dryRun) { if (!dryRun) {
if (!(await gitRepoClean())) { if (!(await gitRepoClean())) {
console.info('Updating README...'); console.info('Updating README...');
await execCommand2('git add -A'); await execCommand('git add -A');
await execCommand2('git commit -m "Update README"'); await execCommand('git commit -m "Update README"');
} }
} }
chdir(previousDir); chdir(previousDir);
const searchResults = (await execCommand2('npm search joplin-plugin --searchlimit 5000 --json', { showStdout: false, showStderr: false })).trim(); const searchResults = (await execCommand('npm search joplin-plugin --searchlimit 5000 --json', { showStdout: false, showStderr: false })).trim();
const npmPackages = pluginInfoFromSearchResults(JSON.parse(searchResults)); const npmPackages = pluginInfoFromSearchResults(JSON.parse(searchResults));
for (const npmPackage of npmPackages) { for (const npmPackage of npmPackages) {
@@ -245,11 +246,11 @@ async function commandBuild(args: CommandBuildArgs) {
await commandUpdateRelease(args); await commandUpdateRelease(args);
if (!(await gitRepoClean())) { if (!(await gitRepoClean())) {
await execCommand2('git add -A'); await execCommand('git add -A');
await execCommand2('git commit -m "Update stats"'); await execCommand('git commit -m "Update stats"');
} }
await execCommand2('git push'); await execCommand('git push');
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/plugin-repo-cli", "name": "@joplin/plugin-repo-cli",
"version": "2.10.2", "version": "2.11.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"bin": "./dist/index.js", "bin": "./dist/index.js",
@@ -18,9 +18,10 @@
"author": "", "author": "",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@joplin/lib": "^2.10.2", "@joplin/lib": "~2.11",
"@joplin/tools": "^2.10.2", "@joplin/tools": "~2.11",
"fs-extra": "11.1.0", "@joplin/utils": "~2.11",
"fs-extra": "11.1.1",
"gh-release-assets": "2.0.1", "gh-release-assets": "2.0.1",
"node-fetch": "2.6.7", "node-fetch": "2.6.7",
"source-map-support": "0.5.21", "source-map-support": "0.5.21",

View File

@@ -1,7 +1,7 @@
{ {
"name": "@joplin/react-native-alarm-notification", "name": "@joplin/react-native-alarm-notification",
"title": "React Native Alarm Notification for Joplin. Forked from https://github.com/emekalites/react-native-alarm-notification", "title": "React Native Alarm Notification for Joplin. Forked from https://github.com/emekalites/react-native-alarm-notification",
"version": "2.10.0", "version": "2.11.0",
"description": "schedule alarm with notification in react-native", "description": "schedule alarm with notification in react-native",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/react-native-saf-x", "name": "@joplin/react-native-saf-x",
"version": "2.10.2", "version": "2.11.0",
"description": "a module to help work with scoped storages on android easily", "description": "a module to help work with scoped storages on android easily",
"main": "src/index", "main": "src/index",
"react-native": "src/index", "react-native": "src/index",

View File

@@ -179,6 +179,8 @@ export interface RuleOptions {
noteId?: string; noteId?: string;
vendorDir?: string; vendorDir?: string;
itemIdToUrl?: ItemIdToUrlHandler; itemIdToUrl?: ItemIdToUrlHandler;
platformName?: string;
} }
export default class MdToHtml { export default class MdToHtml {

View File

@@ -1,6 +1,8 @@
import { RuleOptions } from '../../MdToHtml';
export default { export default {
assets: function() { assets: function(theme: any) {
return [ return [
{ name: 'mermaid.min.js' }, { name: 'mermaid.min.js' },
{ name: 'mermaid_render.js' }, { name: 'mermaid_render.js' },
@@ -12,14 +14,27 @@ export default {
text: '.mermaid { background-color: white; width: 640px; }', text: '.mermaid { background-color: white; width: 640px; }',
mime: 'text/css', mime: 'text/css',
}, },
{
inline: true,
// Export button in mermaid graph should be shown only on hovering the mermaid graph
// ref: https://github.com/laurent22/joplin/issues/6101
text: `
.mermaid-export-graph { visibility: hidden; }
.joplin-editable:hover .mermaid-export-graph { visibility: visible; }
.mermaid-export-graph:hover { background-color: ${theme.backgroundColorHover3} !important; }
`.trim(),
mime: 'text/css',
},
]; ];
}, },
plugin: function(markdownIt: any) { plugin: function(markdownIt: any, ruleOptions: RuleOptions) {
const defaultRender: Function = markdownIt.renderer.rules.fence || function(tokens: any[], idx: number, options: any, env: any, self: any) { const defaultRender: Function = markdownIt.renderer.rules.fence || function(tokens: any[], idx: number, options: any, env: any, self: any) {
return self.renderToken(tokens, idx, options, env, self); return self.renderToken(tokens, idx, options, env, self);
}; };
const exportButtonMarkup = isDesktop(ruleOptions.platformName) ? exportGraphButton(ruleOptions) : '';
markdownIt.renderer.rules.fence = function(tokens: any[], idx: number, options: {}, env: any, self: any) { markdownIt.renderer.rules.fence = function(tokens: any[], idx: number, options: {}, env: any, self: any) {
const token = tokens[idx]; const token = tokens[idx];
if (token.info !== 'mermaid') return defaultRender(tokens, idx, options, env, self); if (token.info !== 'mermaid') return defaultRender(tokens, idx, options, env, self);
@@ -31,9 +46,49 @@ export default {
return ` return `
<div class="joplin-editable"> <div class="joplin-editable">
<pre class="joplin-source" data-joplin-language="mermaid" data-joplin-source-open="\`\`\`mermaid&#10;" data-joplin-source-close="&#10;\`\`\`&#10;">${contentHtml}</pre> <pre class="joplin-source" data-joplin-language="mermaid" data-joplin-source-open="\`\`\`mermaid&#10;" data-joplin-source-close="&#10;\`\`\`&#10;">${contentHtml}</pre>
${exportButtonMarkup}
<pre class="mermaid">${contentHtml}</pre> <pre class="mermaid">${contentHtml}</pre>
</div> </div>
`; `;
}; };
}, },
}; };
const exportGraphButton = (ruleOptions: RuleOptions) => {
const theme = ruleOptions.theme;
// Clicking on export button manually triggers a right click context menu event
const onClickHandler = `
const target = arguments[0].target;
const button = target.closest("button.mermaid-export-graph");
if (!button) return false;
const $mermaid_elem = button.nextElementSibling;
const rightClickEvent = new PointerEvent("contextmenu", {bubbles: true});
rightClickEvent.target = $mermaid_elem;
$mermaid_elem.dispatchEvent(rightClickEvent);
return false;
`.trim();
const style = `
display: block;
margin-left: auto;
border-radius: ${theme.buttonStyle.borderRadius}px;
font-size: ${theme.fontSize}px;
color: ${theme.color};
background: ${theme.buttonStyle.backgroundColor};
border: ${theme.buttonStyle.border};
`.trim();
return `<button class="mermaid-export-graph" onclick='${onClickHandler}' style="${style}" alt="Export mermaid graph">${downloadIcon()}</button>`;
};
const downloadIcon = () => {
// https://www.svgrepo.com/svg/505363/download
return '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M20 15V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18L4 15M8 11L12 15M12 15L16 11M12 15V3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>';
};
const isDesktop = (platformName?: string) => {
if (!platformName) {
return false;
}
return ['darwin', 'linux', 'freebsd', 'win32'].includes(platformName);
};

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/renderer", "name": "@joplin/renderer",
"version": "2.10.2", "version": "2.11.0",
"description": "The Joplin note renderer, used the mobile and desktop application", "description": "The Joplin note renderer, used the mobile and desktop application",
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/renderer", "repository": "https://github.com/laurent22/joplin/tree/dev/packages/renderer",
"main": "index.js", "main": "index.js",
@@ -29,7 +29,7 @@
"@joplin/fork-htmlparser2": "^4.1.43", "@joplin/fork-htmlparser2": "^4.1.43",
"@joplin/fork-uslug": "^1.0.8", "@joplin/fork-uslug": "^1.0.8",
"font-awesome-filetypes": "2.1.0", "font-awesome-filetypes": "2.1.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"highlight.js": "11.7.0", "highlight.js": "11.7.0",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
@@ -43,7 +43,7 @@
"markdown-it-footnote": "3.0.3", "markdown-it-footnote": "3.0.3",
"markdown-it-ins": "3.0.1", "markdown-it-ins": "3.0.1",
"markdown-it-mark": "3.0.1", "markdown-it-mark": "3.0.1",
"markdown-it-multimd-table": "4.2.0", "markdown-it-multimd-table": "4.2.1",
"markdown-it-sub": "1.0.0", "markdown-it-sub": "1.0.0",
"markdown-it-sup": "1.0.0", "markdown-it-sup": "1.0.0",
"markdown-it-toc-done-right": "4.2.0", "markdown-it-toc-done-right": "4.2.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/server", "name": "@joplin/server",
"version": "2.10.10", "version": "2.11.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", "start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
@@ -23,8 +23,8 @@
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "3.241.0", "@aws-sdk/client-s3": "3.241.0",
"@fortawesome/fontawesome-free": "5.15.4", "@fortawesome/fontawesome-free": "5.15.4",
"@joplin/lib": "~2.10", "@joplin/lib": "~2.11",
"@joplin/renderer": "~2.10", "@joplin/renderer": "~2.11",
"@koa/cors": "3.1.0", "@koa/cors": "3.1.0",
"@types/uuid": "9.0.0", "@types/uuid": "9.0.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
@@ -33,9 +33,9 @@
"compare-versions": "3.6.0", "compare-versions": "3.6.0",
"dayjs": "1.11.7", "dayjs": "1.11.7",
"formidable": "2.1.1", "formidable": "2.1.1",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"jquery": "3.6.3", "jquery": "3.6.4",
"knex": "2.4.2", "knex": "2.4.2",
"koa": "2.14.1", "koa": "2.14.1",
"markdown-it": "13.0.1", "markdown-it": "13.0.1",
@@ -44,21 +44,21 @@
"node-cron": "3.0.2", "node-cron": "3.0.2",
"node-env-file": "0.1.8", "node-env-file": "0.1.8",
"nodemailer": "6.9.1", "nodemailer": "6.9.1",
"nodemon": "2.0.21", "nodemon": "2.0.22",
"pg": "8.9.0", "pg": "8.10.0",
"pretty-bytes": "5.6.0", "pretty-bytes": "5.6.0",
"prettycron": "0.10.0", "prettycron": "0.10.0",
"query-string": "7.1.3", "query-string": "7.1.3",
"rate-limiter-flexible": "2.4.1", "rate-limiter-flexible": "2.4.1",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"sqlite3": "5.1.4", "sqlite3": "5.1.6",
"stripe": "8.222.0", "stripe": "8.222.0",
"uuid": "9.0.0", "uuid": "9.0.0",
"yargs": "17.7.1", "yargs": "17.7.1",
"zxcvbn": "4.4.2" "zxcvbn": "4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@joplin/tools": "~2.10", "@joplin/tools": "~2.11",
"@rmp135/sql-ts": "1.16.0", "@rmp135/sql-ts": "1.16.0",
"@types/formidable": "2.0.5", "@types/formidable": "2.0.5",
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
@@ -74,8 +74,8 @@
"gulp": "4.0.2", "gulp": "4.0.2",
"jest": "29.4.3", "jest": "29.4.3",
"jest-expect-message": "1.1.3", "jest-expect-message": "1.1.3",
"jsdom": "21.0.0", "jsdom": "21.1.1",
"node-mocks-http": "1.12.1", "node-mocks-http": "1.12.2",
"source-map-support": "0.5.21", "source-map-support": "0.5.21",
"typescript": "4.9.4" "typescript": "4.9.4"
} }

View File

@@ -1,5 +1,6 @@
import { execCommand2, rootDir } from './tool-utils'; import { rootDir } from './tool-utils';
import * as moment from 'moment'; import * as moment from 'moment';
import { execCommand } from '@joplin/utils';
interface Argv { interface Argv {
dryRun?: boolean; dryRun?: boolean;
@@ -35,7 +36,7 @@ async function main() {
const buildDate = moment(new Date().getTime()).format('YYYY-MM-DDTHH:mm:ssZ'); const buildDate = moment(new Date().getTime()).format('YYYY-MM-DDTHH:mm:ssZ');
let revision = ''; let revision = '';
try { try {
revision = await execCommand2('git rev-parse --short HEAD', { showStdout: false }); revision = await execCommand('git rev-parse --short HEAD', { showStdout: false });
} catch (error) { } catch (error) {
console.info('Could not get git commit: metadata revision field will be empty'); console.info('Could not get git commit: metadata revision field will be empty');
} }
@@ -62,11 +63,11 @@ async function main() {
return; return;
} }
await execCommand2(dockerCommand); await execCommand(dockerCommand);
for (const tag of dockerTags) { for (const tag of dockerTags) {
await execCommand2(`docker tag "${repository}:${imageVersion}" "${repository}:${tag}"`); await execCommand(`docker tag "${repository}:${imageVersion}" "${repository}:${tag}"`);
if (pushImages) await execCommand2(`docker push ${repository}:${tag}`); if (pushImages) await execCommand(`docker push ${repository}:${tag}`);
} }
} }

View File

@@ -1,8 +1,8 @@
import { join } from 'path'; import { join, normalize } from 'path';
import { execCommand2 } from './tool-utils';
import { pathExists, mkdir, readFile, move, remove, writeFile } from 'fs-extra'; import { pathExists, mkdir, readFile, move, remove, writeFile } from 'fs-extra';
import { DefaultPluginsInfo } from '@joplin/lib/services/plugins/PluginService'; import { DefaultPluginsInfo } from '@joplin/lib/services/plugins/PluginService';
import getDefaultPluginsInfo from '@joplin/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo'; import getDefaultPluginsInfo from '@joplin/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo';
import { execCommand } from '@joplin/utils';
const fetch = require('node-fetch'); const fetch = require('node-fetch');
interface PluginAndVersion { interface PluginAndVersion {
@@ -41,7 +41,7 @@ async function downloadFile(url: string, outputPath: string) {
export async function extractPlugins(currentDir: string, defaultPluginDir: string, downloadedPluginsNames: PluginIdAndName): Promise<void> { export async function extractPlugins(currentDir: string, defaultPluginDir: string, downloadedPluginsNames: PluginIdAndName): Promise<void> {
for (const pluginId of Object.keys(downloadedPluginsNames)) { for (const pluginId of Object.keys(downloadedPluginsNames)) {
await execCommand2(`tar xzf ${currentDir}/${downloadedPluginsNames[pluginId]}`, { quiet: true }); await execCommand(`tar xzf ${currentDir}/${downloadedPluginsNames[pluginId]}`, { quiet: true, splitCommandOptions: { handleEscape: false } });
await move(`package/publish/${pluginId}.jpl`, `${defaultPluginDir}/${pluginId}/plugin.jpl`, { overwrite: true }); await move(`package/publish/${pluginId}.jpl`, `${defaultPluginDir}/${pluginId}/plugin.jpl`, { overwrite: true });
await move(`package/publish/${pluginId}.json`, `${defaultPluginDir}/${pluginId}/manifest.json`, { overwrite: true }); await move(`package/publish/${pluginId}.json`, `${defaultPluginDir}/${pluginId}/manifest.json`, { overwrite: true });
await remove(`${downloadedPluginsNames[pluginId]}`); await remove(`${downloadedPluginsNames[pluginId]}`);
@@ -74,7 +74,10 @@ export const downloadPlugins = async (localPluginsVersions: PluginAndVersion, de
}; };
async function start(): Promise<void> { async function start(): Promise<void> {
const defaultPluginDir = join(__dirname, '..', '..', 'packages', 'app-desktop', 'build', 'defaultPlugins'); // windows CI fix: normalizing __dirname for windows
const cwd = normalize(__dirname);
process.chdir(cwd);
const defaultPluginDir = join(cwd, '..', '..', 'packages', 'app-desktop', 'build', 'defaultPlugins');
const defaultPluginsInfo = getDefaultPluginsInfo(); const defaultPluginsInfo = getDefaultPluginsInfo();
const manifestData = await fetch('https://raw.githubusercontent.com/joplin/plugins/master/manifests.json'); const manifestData = await fetch('https://raw.githubusercontent.com/joplin/plugins/master/manifests.json');
@@ -83,7 +86,7 @@ async function start(): Promise<void> {
const localPluginsVersions = await localPluginsVersion(defaultPluginDir, defaultPluginsInfo); const localPluginsVersions = await localPluginsVersion(defaultPluginDir, defaultPluginsInfo);
const downloadedPluginNames: PluginIdAndName = await downloadPlugins(localPluginsVersions, defaultPluginsInfo, manifests); const downloadedPluginNames: PluginIdAndName = await downloadPlugins(localPluginsVersions, defaultPluginsInfo, manifests);
await extractPlugins(__dirname, defaultPluginDir, downloadedPluginNames); await extractPlugins(cwd, defaultPluginDir, downloadedPluginNames);
} }
if (require.main === module) { if (require.main === module) {
@@ -94,3 +97,7 @@ if (require.main === module) {
process.exit(1); process.exit(1);
}); });
} }
module.exports = async () => {
await start();
};

View File

@@ -1,4 +1,5 @@
import { execCommand2, rootDir } from './tool-utils'; import { execCommand } from '@joplin/utils';
import { rootDir } from './tool-utils';
const sqlts = require('@rmp135/sql-ts').default; const sqlts = require('@rmp135/sql-ts').default;
const fs = require('fs-extra'); const fs = require('fs-extra');
@@ -6,7 +7,7 @@ const fs = require('fs-extra');
async function main() { async function main() {
// Run the CLI app once so as to generate the database file // Run the CLI app once so as to generate the database file
process.chdir(`${rootDir}/packages/app-cli`); process.chdir(`${rootDir}/packages/app-cli`);
await execCommand2('yarn start version'); await execCommand('yarn start version');
const sqlTsConfig = { const sqlTsConfig = {
'client': 'sqlite3', 'client': 'sqlite3',

View File

@@ -0,0 +1,12 @@
// Allow running that task "buildCommandIndex" without gulp
const task = require('./buildCommandIndex.js');
const main = async () => {
await task.fn();
};
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -36,6 +36,7 @@ module.exports = {
'packages/fork-sax/**', 'packages/fork-sax/**',
'packages/lib/plugin_types/**', 'packages/lib/plugin_types/**',
'packages/server/**', 'packages/server/**',
'packages/utils/**',
], ],
}).filter(f => !f.endsWith('.d.ts')); }).filter(f => !f.endsWith('.d.ts'));

View File

@@ -0,0 +1,12 @@
// Allow running that task "updateIgnoredTypeScriptBuild" without gulp
const task = require('./updateIgnoredTypeScriptBuild.js');
const main = async () => {
await task.fn();
};
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -1,6 +1,7 @@
import { readdir, stat, writeFile } from 'fs-extra'; import { readdir, stat, writeFile } from 'fs-extra';
import { chdir, cwd } from 'process'; import { chdir, cwd } from 'process';
import { execCommand2, rootDir } from './tool-utils'; import { rootDir } from './tool-utils';
import { execCommand } from '@joplin/utils';
import yargs = require('yargs'); import yargs = require('yargs');
import { rtrimSlashes } from '@joplin/lib/path-utils'; import { rtrimSlashes } from '@joplin/lib/path-utils';
@@ -13,7 +14,7 @@ interface LicenseInfo {
const getLicenses = async (directory: string): Promise<Record<string, LicenseInfo>> => { const getLicenses = async (directory: string): Promise<Record<string, LicenseInfo>> => {
const previousDir = cwd(); const previousDir = cwd();
await chdir(directory); await chdir(directory);
const result = await execCommand2(['license-checker-rseidelsohn', '--production', '--json'], { quiet: true }); const result = await execCommand(['license-checker-rseidelsohn', '--production', '--json'], { quiet: true });
const info: Record<string, LicenseInfo> = JSON.parse(result); const info: Record<string, LicenseInfo> = JSON.parse(result);
if (!info) throw new Error(`Could not parse JSON: ${directory}`); if (!info) throw new Error(`Could not parse JSON: ${directory}`);
await chdir(previousDir); await chdir(previousDir);

File diff suppressed because it is too large Load Diff

View File

@@ -91,12 +91,12 @@ msgstr "%d päivää"
#: packages/lib/utils/joplinCloud.ts:136 packages/lib/utils/joplinCloud.ts:137 #: packages/lib/utils/joplinCloud.ts:136 packages/lib/utils/joplinCloud.ts:137
#: packages/lib/utils/joplinCloud.ts:138 #: packages/lib/utils/joplinCloud.ts:138
msgid "%d GB" msgid "%d GB"
msgstr "" msgstr "%d Gt"
#: packages/lib/utils/joplinCloud.ts:133 packages/lib/utils/joplinCloud.ts:134 #: packages/lib/utils/joplinCloud.ts:133 packages/lib/utils/joplinCloud.ts:134
#: packages/lib/utils/joplinCloud.ts:135 #: packages/lib/utils/joplinCloud.ts:135
msgid "%d GB storage space" msgid "%d GB storage space"
msgstr "" msgstr "%d Gt tallennustila"
#: packages/lib/models/Setting.ts:1345 #: packages/lib/models/Setting.ts:1345
msgid "%d hour" msgid "%d hour"
@@ -109,13 +109,12 @@ msgstr "%d tuntia"
#: packages/lib/utils/joplinCloud.ts:124 packages/lib/utils/joplinCloud.ts:125 #: packages/lib/utils/joplinCloud.ts:124 packages/lib/utils/joplinCloud.ts:125
#: packages/lib/utils/joplinCloud.ts:126 #: packages/lib/utils/joplinCloud.ts:126
msgid "%d MB" msgid "%d MB"
msgstr "" msgstr "%d Mt"
#: packages/lib/utils/joplinCloud.ts:121 packages/lib/utils/joplinCloud.ts:122 #: packages/lib/utils/joplinCloud.ts:121 packages/lib/utils/joplinCloud.ts:122
#: packages/lib/utils/joplinCloud.ts:123 #: packages/lib/utils/joplinCloud.ts:123
#, fuzzy
msgid "%d MB per note or attachment" msgid "%d MB per note or attachment"
msgstr "Muistiinpanon liitteet" msgstr "%d Mt muistiinpanoa tai liitettä kohti"
#: packages/lib/models/Setting.ts:1342 packages/lib/models/Setting.ts:1343 #: packages/lib/models/Setting.ts:1342 packages/lib/models/Setting.ts:1343
#: packages/lib/models/Setting.ts:1344 #: packages/lib/models/Setting.ts:1344
@@ -128,9 +127,8 @@ msgstr "%d muistiinpanot vastaavat tätä mallia. Poistetaanko ne?"
#: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:135 #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:135
#: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:144 #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:144
#, fuzzy
msgid "%s" msgid "%s"
msgstr "(%s)" msgstr "%s"
#: packages/app-desktop/gui/utils/NoteListUtils.ts:61 #: packages/app-desktop/gui/utils/NoteListUtils.ts:61
msgid "%s - Copy" msgid "%s - Copy"
@@ -323,6 +321,8 @@ msgstr "Lisätyökalut"
msgid "" msgid ""
"All data, including notes, notebooks and tags will be permanently deleted." "All data, including notes, notebooks and tags will be permanently deleted."
msgstr "" msgstr ""
"Kaikki tiedot, mukaan lukien muistiinpanot, muistikirjat ja tunnisteet, "
"poistetaan pysyvästi."
#: packages/app-desktop/gui/Sidebar/Sidebar.tsx:484 #: packages/app-desktop/gui/Sidebar/Sidebar.tsx:484
#: packages/app-mobile/components/screens/Notes.tsx:203 #: packages/app-mobile/components/screens/Notes.tsx:203
@@ -359,8 +359,8 @@ msgstr ""
#: packages/app-cli/app/command-mkbook.ts:33 #: packages/app-cli/app/command-mkbook.ts:33
#: packages/app-cli/app/command-mv.js:29 #: packages/app-cli/app/command-mv.js:29
msgid "" msgid ""
"Ambiguous notebook \"%s\". Please use short notebook id instead - press " "Ambiguous notebook \"%s\". Please use short notebook id instead - press \"ti"
"\"ti\" to see the short notebook id" "\" to see the short notebook id"
msgstr "" msgstr ""
"Epäselvä muistikirja \"%s\". Käytä sen sijaan lyhyttä muistikirjan tunnusta " "Epäselvä muistikirja \"%s\". Käytä sen sijaan lyhyttä muistikirjan tunnusta "
"- paina \"ti\" nähdäksesi lyhyen muistikirjan tunnuksen" "- paina \"ti\" nähdäksesi lyhyen muistikirjan tunnuksen"
@@ -390,6 +390,8 @@ msgid ""
"Are you sure you want to return to the default layout? The current layout " "Are you sure you want to return to the default layout? The current layout "
"configuration will be lost." "configuration will be lost."
msgstr "" msgstr ""
"Haluatko varmasti palata oletus ulkoasuun? Nykyinen ulkoasun määritys "
"menetetään."
#: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:517 #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:517
msgid "Arguments:" msgid "Arguments:"
@@ -494,7 +496,7 @@ msgstr "Takaisin"
#: packages/lib/utils/joplinCloud.ts:294 #: packages/lib/utils/joplinCloud.ts:294
msgid "Basic" msgid "Basic"
msgstr "" msgstr "Perus"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:33 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:33
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:132 #: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:132
@@ -598,9 +600,8 @@ msgid "Cannot find \"%s\"."
msgstr "Ei löydy \"%s\"." msgstr "Ei löydy \"%s\"."
#: packages/app-cli/app/command-mkbook.ts:28 #: packages/app-cli/app/command-mkbook.ts:28
#, fuzzy
msgid "Cannot find: \"%s\"" msgid "Cannot find: \"%s\""
msgstr "Ei löydy \"%s\"." msgstr "Ei löydy: \"%s\""
#: packages/app-cli/app/command-sync.ts:164 #: packages/app-cli/app/command-sync.ts:164
msgid "Cannot initialise synchroniser." msgid "Cannot initialise synchroniser."
@@ -743,9 +744,8 @@ msgid "Close"
msgstr "Sulkea" msgstr "Sulkea"
#: packages/app-mobile/components/Dropdown.tsx:166 #: packages/app-mobile/components/Dropdown.tsx:166
#, fuzzy
msgid "Close dropdown" msgid "Close dropdown"
msgstr "Sulje ikkuna" msgstr "Sulje pudotusvalikko"
#: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:24 #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:24
#: packages/app-desktop/gui/MenuBar.tsx:596 #: packages/app-desktop/gui/MenuBar.tsx:596
@@ -857,7 +857,7 @@ msgstr "Ristiriidat (liitteet)"
#: packages/lib/utils/joplinCloud.ts:171 #: packages/lib/utils/joplinCloud.ts:171
msgid "Consolidated billing" msgid "Consolidated billing"
msgstr "" msgstr "Yhdistetty laskutus"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:110 #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:110
msgid "Content provided by %s" msgid "Content provided by %s"
@@ -865,7 +865,7 @@ msgstr "Sisällön toimittaa %s"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:64 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:64
msgid "Continue" msgid "Continue"
msgstr "" msgstr "Jatkaa"
#: packages/app-mobile/components/screens/Note.tsx:930 #: packages/app-mobile/components/screens/Note.tsx:930
msgid "Convert to note" msgid "Convert to note"
@@ -970,9 +970,8 @@ msgstr ""
"Virhe oli: \"%s\"" "Virhe oli: \"%s\""
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:55 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:55
#, fuzzy
msgid "Could not switch profile: %s" msgid "Could not switch profile: %s"
msgstr "Laajennuksen asentaminen epäonnistui: %s" msgstr "Profiilia ei voitu vaihtaa: %s"
#: packages/lib/components/EncryptionConfigScreen/utils.ts:219 #: packages/lib/components/EncryptionConfigScreen/utils.ts:219
msgid "Could not upgrade master key: %s" msgid "Could not upgrade master key: %s"
@@ -988,16 +987,15 @@ msgstr ""
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:29 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:29
msgid "Could not verify your identify" msgid "Could not verify your identify"
msgstr "" msgstr "Henkilöllisyyttäsi ei voitu vahvistaa"
#: packages/app-desktop/gui/PromptDialog.tsx:260 #: packages/app-desktop/gui/PromptDialog.tsx:260
msgid "Create" msgid "Create"
msgstr "Luo" msgstr "Luo"
#: packages/app-cli/app/command-mkbook.ts:19 #: packages/app-cli/app/command-mkbook.ts:19
#, fuzzy
msgid "Create a new notebook under a parent notebook." msgid "Create a new notebook under a parent notebook."
msgstr "Luo uuden muistikirjan." msgstr "Luo uusi muistikirja päämuistikirjan alle."
#: packages/app-mobile/components/note-list.js:101 #: packages/app-mobile/components/note-list.js:101
msgid "Create a notebook" msgid "Create a notebook"
@@ -1220,9 +1218,8 @@ msgid "Delete plugin \"%s\"?"
msgstr "Poista laajennus \"%s\"?" msgstr "Poista laajennus \"%s\"?"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:101 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:101
#, fuzzy
msgid "Delete profile \"%s\"" msgid "Delete profile \"%s\""
msgstr "Poista muistiinpano \"%s\"?" msgstr "Poista profiili \"%s\""
#: packages/app-mobile/components/ScreenHeader.tsx:420 #: packages/app-mobile/components/ScreenHeader.tsx:420
msgid "Delete selected notes" msgid "Delete selected notes"
@@ -1241,9 +1238,8 @@ msgstr ""
"muistikirjaa." "muistikirjaa."
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:97 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:97
#, fuzzy
msgid "Delete this profile?" msgid "Delete this profile?"
msgstr "Poistetaanko nämä %d muistiinpanot?" msgstr "Poistetaanko tämä profiili?"
#: packages/lib/Synchronizer.ts:186 #: packages/lib/Synchronizer.ts:186
msgid "Deleted local items: %d." msgid "Deleted local items: %d."
@@ -1488,9 +1484,8 @@ msgid "Edit notebook"
msgstr "Muokkaa muistikirjaa" msgstr "Muokkaa muistikirjaa"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:87 #: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:87
#, fuzzy
msgid "Edit profile" msgid "Edit profile"
msgstr "Vie profiili" msgstr "Muokkaa profiilia"
#: packages/app-desktop/commands/editProfileConfig.ts:9 #: packages/app-desktop/commands/editProfileConfig.ts:9
msgid "Edit profile configuration..." msgid "Edit profile configuration..."
@@ -1582,7 +1577,7 @@ msgstr "Ota käyttöön audiosoitin"
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:61 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:61
msgid "Enable biometrics authentication?" msgid "Enable biometrics authentication?"
msgstr "" msgstr "Otetaanko biometrinen todennus käyttöön?"
#: packages/lib/models/Setting.ts:1146 #: packages/lib/models/Setting.ts:1146
msgid "Enable deflist syntax" msgid "Enable deflist syntax"
@@ -1635,7 +1630,7 @@ msgstr "Ota pehmeät tauot käyttöön"
#: packages/lib/models/Setting.ts:1048 #: packages/lib/models/Setting.ts:1048
msgid "Enable spellcheck in the text editor" msgid "Enable spellcheck in the text editor"
msgstr "" msgstr "Ota oikeinkirjoituksen tarkistus käyttöön tekstieditorissa"
#: packages/lib/models/Setting.ts:1143 #: packages/lib/models/Setting.ts:1143
msgid "Enable table of contents extension" msgid "Enable table of contents extension"
@@ -2298,7 +2293,7 @@ msgstr "Kohteet, joita ei voi synkronoida"
#: packages/app-desktop/gui/MenuBar.tsx:792 #: packages/app-desktop/gui/MenuBar.tsx:792
msgid "Join us on Twitter" msgid "Join us on Twitter"
msgstr "" msgstr "Liity meihin Twitterissä"
#: packages/app-desktop/gui/SyncWizard/Dialog.tsx:330 #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:330
msgid "" msgid ""
@@ -2547,14 +2542,12 @@ msgid "Manage master password..."
msgstr "Pääsalasanan hallinta..." msgstr "Pääsalasanan hallinta..."
#: packages/lib/utils/joplinCloud.ts:165 #: packages/lib/utils/joplinCloud.ts:165
#, fuzzy
msgid "Manage multiple users" msgid "Manage multiple users"
msgstr "Pääsalasanan hallinta" msgstr "Hallitse useita käyttäjiä"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:611 #: packages/app-mobile/components/screens/ConfigScreen.tsx:611
#, fuzzy
msgid "Manage profiles" msgid "Manage profiles"
msgstr "Päivitä profiili" msgstr "Hallitse profiileja"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:320 #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:320
msgid "Manage your plugins" msgid "Manage your plugins"
@@ -2621,9 +2614,8 @@ msgid "Max Item Size"
msgstr "Kohteen enimmäiskoko" msgstr "Kohteen enimmäiskoko"
#: packages/lib/utils/joplinCloud.ts:117 #: packages/lib/utils/joplinCloud.ts:117
#, fuzzy
msgid "Max note or attachment size" msgid "Max note or attachment size"
msgstr "Muistiinpanon liitteet" msgstr "Muistiinpanon tai liitteen enimmäiskoko"
#: packages/server/src/routes/admin/users.ts:150 #: packages/server/src/routes/admin/users.ts:150
msgid "Max Total Size" msgid "Max Total Size"
@@ -2642,9 +2634,8 @@ msgid "Missing required argument: %s"
msgstr "Vaadittu argumentti puuttuu: %s" msgstr "Vaadittu argumentti puuttuu: %s"
#: packages/app-cli/app/cli-utils.js:135 #: packages/app-cli/app/cli-utils.js:135
#, fuzzy
msgid "Missing required flag value: %s" msgid "Missing required flag value: %s"
msgstr "Vaadittu argumentti puuttuu: %s" msgstr "Pakollinen lipun arvo puuttuu: %s"
#: packages/app-mobile/components/side-menu-content.tsx:457 #: packages/app-mobile/components/side-menu-content.tsx:457
msgid "Mobile data - auto-sync disabled" msgid "Mobile data - auto-sync disabled"
@@ -2819,9 +2810,8 @@ msgid "Not generated"
msgstr "Ei luotu" msgstr "Ei luotu"
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:70 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:70
#, fuzzy
msgid "Not now" msgid "Not now"
msgstr "Hae se nyt" msgstr "Ei nyt"
#: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:110 #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:110
#: packages/server/src/models/UserModel.ts:215 #: packages/server/src/models/UserModel.ts:215
@@ -3084,7 +3074,7 @@ msgstr "Liitä"
#: packages/app-desktop/gui/NoteEditor/commands/pasteAsText.ts:6 #: packages/app-desktop/gui/NoteEditor/commands/pasteAsText.ts:6
#: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:181 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:181
msgid "Paste as text" msgid "Paste as text"
msgstr "" msgstr "Liitä tekstinä"
#: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:541 #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:541
msgid "Path:" msgid "Path:"
@@ -3097,7 +3087,7 @@ msgstr "PDF tiedosto"
#: packages/lib/utils/joplinCloud.ts:355 #: packages/lib/utils/joplinCloud.ts:355
msgid "Per user. Minimum of %d users." msgid "Per user. Minimum of %d users."
msgstr "" msgstr "Käyttäjää kohti. Vähintään %d käyttäjää."
#: packages/app-mobile/components/screens/Note.tsx:404 #: packages/app-mobile/components/screens/Note.tsx:404
msgid "Permission needed" msgid "Permission needed"
@@ -3258,16 +3248,15 @@ msgstr "Tulosta"
#: packages/lib/utils/joplinCloud.ts:183 #: packages/lib/utils/joplinCloud.ts:183
msgid "Priority support" msgid "Priority support"
msgstr "" msgstr "Ensisijainen tuki"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:703 #: packages/app-mobile/components/screens/ConfigScreen.tsx:703
msgid "Privacy Policy" msgid "Privacy Policy"
msgstr "Tietosuojakäytäntö" msgstr "Tietosuojakäytäntö"
#: packages/lib/utils/joplinCloud.ts:316 #: packages/lib/utils/joplinCloud.ts:316
#, fuzzy
msgid "Pro" msgid "Pro"
msgstr "Profiili" msgstr "Ammattilainen"
#: packages/server/src/services/TaskService.ts:24 #: packages/server/src/services/TaskService.ts:24
msgid "Process failed payment subscriptions" msgid "Process failed payment subscriptions"
@@ -3286,9 +3275,8 @@ msgid "Profile"
msgstr "Profiili" msgstr "Profiili"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:95 #: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:95
#, fuzzy
msgid "Profile name" msgid "Profile name"
msgstr "Profiilin nimi:" msgstr "Profiilin nimi"
#: packages/app-desktop/gui/MainScreen/commands/addProfile.ts:17 #: packages/app-desktop/gui/MainScreen/commands/addProfile.ts:17
msgid "Profile name:" msgid "Profile name:"
@@ -3299,9 +3287,8 @@ msgid "Profile Version: %s"
msgstr "Profiilin versio: %s" msgstr "Profiilin versio: %s"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:155 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:155
#, fuzzy
msgid "Profiles" msgid "Profiles"
msgstr "Profiili" msgstr "Profiilit"
#: packages/app-mobile/components/screens/Note.tsx:944 #: packages/app-mobile/components/screens/Note.tsx:944
msgid "Properties" msgid "Properties"
@@ -3450,9 +3437,8 @@ msgid "Replace: "
msgstr "Vaihda: " msgstr "Vaihda: "
#: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7 #: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7
#, fuzzy
msgid "Reset application layout" msgid "Reset application layout"
msgstr "Sovelluksen asettelun muuttaminen" msgstr "Palauta sovelluksen asettelu"
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:219 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:219
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220
@@ -3692,9 +3678,8 @@ msgid "Share"
msgstr "Jaa" msgstr "Jaa"
#: packages/lib/utils/joplinCloud.ts:159 #: packages/lib/utils/joplinCloud.ts:159
#, fuzzy
msgid "Share and collaborate on a notebook" msgid "Share and collaborate on a notebook"
msgstr "Muistiinpanoja voi luoda vain muistikirjaan." msgstr "Muistikirjan jakaminen ja yhteiskäyttö"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:339 #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:339
msgid "Share Notebook" msgid "Share Notebook"
@@ -3706,7 +3691,7 @@ msgstr "Muistikirjan jakaminen..."
#: packages/lib/utils/joplinCloud.ts:177 #: packages/lib/utils/joplinCloud.ts:177
msgid "Sharing access control" msgid "Sharing access control"
msgstr "" msgstr "Käyttöoikeuksien hallinnan jakaminen"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:305 #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:305
msgid "Sharing notebook..." msgid "Sharing notebook..."
@@ -3932,7 +3917,7 @@ msgstr "Lopeta ulkoisen tekstieditorin muokkaus"
#: packages/lib/utils/joplinCloud.ts:129 #: packages/lib/utils/joplinCloud.ts:129
msgid "Storage space" msgid "Storage space"
msgstr "" msgstr "Tallennustila"
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:19 #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:19
msgid "Strikethrough" msgid "Strikethrough"
@@ -4000,7 +3985,7 @@ msgstr ""
#: packages/lib/utils/joplinCloud.ts:147 #: packages/lib/utils/joplinCloud.ts:147
msgid "Sync as many devices as you want" msgid "Sync as many devices as you want"
msgstr "" msgstr "Synkronoi niin monta laitetta kuin haluat"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:612 #: packages/app-mobile/components/screens/ConfigScreen.tsx:612
msgid "Sync Status" msgid "Sync Status"
@@ -4115,7 +4100,7 @@ msgstr "Tehtävät"
#: packages/lib/utils/joplinCloud.ts:338 #: packages/lib/utils/joplinCloud.ts:338
msgid "Teams" msgid "Teams"
msgstr "" msgstr "Tiimit"
#: packages/lib/models/Setting.ts:1366 #: packages/lib/models/Setting.ts:1366
msgid "Text editor command" msgid "Text editor command"
@@ -4130,6 +4115,8 @@ msgid ""
"The active profile cannot be deleted. Switch to a different profile and try " "The active profile cannot be deleted. Switch to a different profile and try "
"again." "again."
msgstr "" msgstr ""
"Aktiivista profiilia ei voi poistaa. Vaihda toiseen profiiliin ja yritä "
"uudelleen."
#: packages/app-desktop/bridge.ts:280 #: packages/app-desktop/bridge.ts:280
msgid "" msgid ""
@@ -4195,7 +4182,7 @@ msgstr ""
#: packages/lib/services/profileConfig/index.ts:104 #: packages/lib/services/profileConfig/index.ts:104
msgid "The default profile cannot be deleted" msgid "The default profile cannot be deleted"
msgstr "" msgstr "Oletusprofiilia ei voi poistaa"
#: packages/lib/models/Setting.ts:1366 #: packages/lib/models/Setting.ts:1366
msgid "" msgid ""
@@ -4343,6 +4330,8 @@ msgid ""
"The WebDAV implementation of %s is incompatible with Joplin, and as such is " "The WebDAV implementation of %s is incompatible with Joplin, and as such is "
"no longer supported. Please use a different sync method." "no longer supported. Please use a different sync method."
msgstr "" msgstr ""
"%s WebDAV toteutus ei ole yhteensopiva Joplinin kanssa, joten sitä ei enää "
"tueta. Käytä toista synkronointitapaa."
#: packages/lib/models/Setting.ts:827 #: packages/lib/models/Setting.ts:827
msgid "Theme" msgid "Theme"
@@ -4356,7 +4345,7 @@ msgstr ""
#: packages/app-mobile/components/screens/ConfigScreen.tsx:341 #: packages/app-mobile/components/screens/ConfigScreen.tsx:341
msgid "There are unsaved changes." msgid "There are unsaved changes."
msgstr "" msgstr "On tallentamattomia muutoksia."
#: packages/app-desktop/gui/NoteList/NoteList.tsx:512 #: packages/app-desktop/gui/NoteList/NoteList.tsx:512
msgid "" msgid ""
@@ -4580,6 +4569,8 @@ msgid ""
"To switch the profile, the app is going to close and you will need to " "To switch the profile, the app is going to close and you will need to "
"restart it." "restart it."
msgstr "" msgstr ""
"Jos haluat vaihtaa profiilia, sovellus suljetaan ja sinun on käynnistettävä "
"se uudelleen."
#: packages/app-mobile/components/screens/ConfigScreen.tsx:651 #: packages/app-mobile/components/screens/ConfigScreen.tsx:651
msgid "" msgid ""
@@ -4661,9 +4652,8 @@ msgstr "Yritä uudestaan"
#: packages/lib/utils/joplinCloud.ts:309 packages/lib/utils/joplinCloud.ts:331 #: packages/lib/utils/joplinCloud.ts:309 packages/lib/utils/joplinCloud.ts:331
#: packages/lib/utils/joplinCloud.ts:353 #: packages/lib/utils/joplinCloud.ts:353
#, fuzzy
msgid "Try it now" msgid "Try it now"
msgstr "Hae se nyt" msgstr "Kokeile nyt"
#: packages/app-cli/app/command-help.js:71 #: packages/app-cli/app/command-help.js:71
msgid "" msgid ""
@@ -4822,7 +4812,7 @@ msgstr "Käyttö: %s"
#: packages/lib/models/Setting.ts:1640 #: packages/lib/models/Setting.ts:1640
msgid "Use biometrics to secure access to the app" msgid "Use biometrics to secure access to the app"
msgstr "" msgstr "Käytä biometrisiä tunnisteita suojataksesi pääsyn sovellukseen"
#: packages/app-cli/app/command-ls.js:32 packages/app-cli/app/command-tag.js:18 #: packages/app-cli/app/command-ls.js:32 packages/app-cli/app/command-tag.js:18
msgid "" msgid ""
@@ -4861,6 +4851,8 @@ msgid ""
"Use your biometrics to secure access to your application. You can always set " "Use your biometrics to secure access to your application. You can always set "
"it up later in Settings." "it up later in Settings."
msgstr "" msgstr ""
"Käytä biometrisiä tunnisteita suojataksesi pääsyn sovellukseen. Voit "
"määrittää sen myöhemmin asetuksissa."
#: packages/lib/models/Setting.ts:1244 #: packages/lib/models/Setting.ts:1244
msgid "" msgid ""
@@ -4896,7 +4888,7 @@ msgstr "Kelvollinen"
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:25 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:25
msgid "Verify your identity" msgid "Verify your identity"
msgstr "" msgstr "Vahvista henkilöllisyytesi"
#: packages/app-desktop/gui/NoteList/NoteList.tsx:167 #: packages/app-desktop/gui/NoteList/NoteList.tsx:167
msgid "View" msgid "View"

View File

@@ -653,7 +653,7 @@ msgstr ""
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:328 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:328
msgid "Case sensitive" msgid "Case sensitive"
msgstr "" msgstr "Razlikuje velika i mala slova"
#: packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.ts:7 #: packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.ts:7
msgid "Change application layout" msgid "Change application layout"
@@ -1072,7 +1072,7 @@ msgstr "Stvaranje izvještaja …"
#: packages/app-desktop/checkForUpdates.ts:180 #: packages/app-desktop/checkForUpdates.ts:180
msgid "Current version is up-to-date." msgid "Current version is up-to-date."
msgstr "Trenutačna verzija je najnovija verzija." msgstr "Trenutačna verzija je aktualna."
#: packages/lib/models/Note.ts:38 #: packages/lib/models/Note.ts:38
msgid "custom order" msgid "custom order"
@@ -1174,7 +1174,7 @@ msgstr "Izbriši istekle sesije"
#: packages/server/src/services/TaskService.ts:20 #: packages/server/src/services/TaskService.ts:20
msgid "Delete expired tokens" msgid "Delete expired tokens"
msgstr "Izbriši istekle tokene" msgstr "Izbriši istekle ključeve"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:88 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:88
msgid "Delete line" msgid "Delete line"
@@ -1392,7 +1392,7 @@ msgstr ""
#: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:149 #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:149
msgid "Done" msgid "Done"
msgstr "" msgstr "Gotovo"
#: packages/app-desktop/checkForUpdates.ts:199 #: packages/app-desktop/checkForUpdates.ts:199
msgid "Download" msgid "Download"
@@ -1582,7 +1582,7 @@ msgstr "Aktiviraj audio-player"
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:61 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:61
msgid "Enable biometrics authentication?" msgid "Enable biometrics authentication?"
msgstr "" msgstr "Aktivirati biometrijsku autentifikaciju?"
#: packages/lib/models/Setting.ts:1146 #: packages/lib/models/Setting.ts:1146
msgid "Enable deflist syntax" msgid "Enable deflist syntax"
@@ -2228,7 +2228,7 @@ msgstr "Umetnuti kȏd"
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:24 #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:24
msgid "Insert" msgid "Insert"
msgstr "Umetnuto" msgstr "Umetni"
#: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx:199 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx:199
msgid "Insert Hyperlink" msgid "Insert Hyperlink"
@@ -2394,7 +2394,7 @@ msgstr ""
#: packages/lib/models/Setting.ts:1530 #: packages/lib/models/Setting.ts:1530
msgid "Keep note history for" msgid "Keep note history for"
msgstr "Čuvaj povijest bilješke" msgstr "Čuvaj povijest bilježaka"
#: packages/lib/models/Setting.ts:1403 #: packages/lib/models/Setting.ts:1403
msgid "Keyboard Mode" msgid "Keyboard Mode"
@@ -2873,7 +2873,7 @@ msgstr "Bilješka ne postoji: „%s”. Želiš li je stvoriti?"
#: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:82 #: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:82
#, fuzzy #, fuzzy
msgid "Note editor" msgid "Note editor"
msgstr "Povijest bilježaka" msgstr "Uređivač za bilješke"
#: packages/app-cli/app/command-edit.js:97 #: packages/app-cli/app/command-edit.js:97
msgid "Note has been saved." msgid "Note has been saved."
@@ -3058,7 +3058,7 @@ msgstr "Ili stvori novi račun."
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:82 #: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:82
#, fuzzy #, fuzzy
msgid "Ordered list" msgid "Ordered list"
msgstr "Stvori korisnika" msgstr "Razvrstan popis"
#: packages/app-desktop/gui/MenuBar.tsx:409 #: packages/app-desktop/gui/MenuBar.tsx:409
msgid "Other applications..." msgid "Other applications..."
@@ -3150,8 +3150,8 @@ msgid ""
"Please note that if it is a large notebook, it may take a few minutes for " "Please note that if it is a large notebook, it may take a few minutes for "
"all the notes to show up on the recipient's device." "all the notes to show up on the recipient's device."
msgstr "" msgstr ""
"Imaj na umu, da ako je velika bilježnica, može potrajati nekoliko minuta dok " "Imaj na umu, da ako je bilježnica velika, pojavljivanje svih bilježaka na "
"se sve bilješke pojave na uređaju primatelja." "uređaju primatelja može potrajati nekoliko minuta."
#: packages/lib/onedrive-api-node-utils.js:118 #: packages/lib/onedrive-api-node-utils.js:118
msgid "" msgid ""
@@ -3162,9 +3162,9 @@ msgid ""
"will be shared with any third party." "will be shared with any third party."
msgstr "" msgstr ""
"Otvori sljedeći URL u pregledniku za autentificiranje programa. Program će " "Otvori sljedeći URL u pregledniku za autentificiranje programa. Program će "
"stvoriti mapu u „Aplikacije/Joplin” i koristit će je samo za čitanje i " "stvoriti mapu u „Aplikacije/Joplin” dozvolama za čitanje i pisanje. Program "
"pisanje. Program neće moći pristupiti datotekama izvan ove mape niti bilo " "neće moći pristupiti datotekama izvan ove mape niti bilo kojim drugim "
"kojim drugim osobnim podacima. Nikoji podaci se neće dijeliti s drugima." "osobnim podacima. Nikoji podaci se neće dijeliti s drugima."
#: packages/app-cli/app/command-ls.js:63 #: packages/app-cli/app/command-ls.js:63
msgid "Please select a notebook first." msgid "Please select a notebook first."
@@ -3262,7 +3262,7 @@ msgstr "Pritisni za postavljanje lozinke za dešifriranje."
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:278 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:278
msgid "Previous match" msgid "Previous match"
msgstr "" msgstr "Prethodno poklapanje"
#: packages/app-desktop/gui/NotePropertiesDialog.min.js:307 #: packages/app-desktop/gui/NotePropertiesDialog.min.js:307
#: packages/app-desktop/gui/NotePropertiesDialog.tsx:329 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:329
@@ -3464,7 +3464,7 @@ msgstr "Označi sve"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:236 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:236
msgid "Replace with..." msgid "Replace with..."
msgstr "" msgstr "Zamijeni sa …"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:257 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:257
msgid "Replace: " msgid "Replace: "
@@ -3473,7 +3473,7 @@ msgstr ""
#: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7 #: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7
#, fuzzy #, fuzzy
msgid "Reset application layout" msgid "Reset application layout"
msgstr "Promijeni raspored programa" msgstr "Obnovi raspored programa"
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:219 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:219
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220
@@ -3729,7 +3729,7 @@ msgstr "Dijeli bilježnicu …"
#: packages/lib/utils/joplinCloud.ts:177 #: packages/lib/utils/joplinCloud.ts:177
msgid "Sharing access control" msgid "Sharing access control"
msgstr "" msgstr "Dijeljenje kontrole pristupa"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:305 #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:305
msgid "Sharing notebook..." msgid "Sharing notebook..."
@@ -3737,7 +3737,7 @@ msgstr "Dijeljenje bilježnice …"
#: packages/app-cli/app/command-help.js:44 #: packages/app-cli/app/command-help.js:44
msgid "Shortcuts are not available in CLI mode." msgid "Shortcuts are not available in CLI mode."
msgstr "Prečaci nisu podržani u naredbenom retku." msgstr "Prečaci nisu dostupni u naredbenom retku."
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:208 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:208
#, fuzzy #, fuzzy
@@ -3776,7 +3776,7 @@ msgstr "Prikaži broj bilježaka"
#: packages/lib/models/Setting.ts:942 #: packages/lib/models/Setting.ts:942
msgid "Show sort order buttons" msgid "Show sort order buttons"
msgstr "Prikaži gumbe redoslijeda" msgstr "Prikaži gumbe za određivanje redoslijeda"
#: packages/lib/models/Setting.ts:1162 #: packages/lib/models/Setting.ts:1162
msgid "Show tray icon" msgid "Show tray icon"
@@ -4021,12 +4021,12 @@ msgid ""
"Switches to [notebook] - all further operations will happen within this " "Switches to [notebook] - all further operations will happen within this "
"notebook." "notebook."
msgstr "" msgstr ""
"Mijenja se u bilježnicu [notebook] – sve daljnje operacije izvode se u toj " "Prebacuje na bilježnicu [notebook] – sve daljnje operacije će se izvoditi u "
"bilježnici." "ovoj bilježnici."
#: packages/lib/utils/joplinCloud.ts:147 #: packages/lib/utils/joplinCloud.ts:147
msgid "Sync as many devices as you want" msgid "Sync as many devices as you want"
msgstr "" msgstr "Sinkroniziraj koliko god uređaja želiš"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:612 #: packages/app-mobile/components/screens/ConfigScreen.tsx:612
msgid "Sync Status" msgid "Sync Status"
@@ -4212,7 +4212,7 @@ msgid ""
"The default encryption method has been changed to a more secure one and it " "The default encryption method has been changed to a more secure one and it "
"is recommended that you apply it to your data." "is recommended that you apply it to your data."
msgstr "" msgstr ""
"Standardna metoda šifriranja promijenjena je u sigurniju metodu. " "Standardna metoda šifriranja je promijenjena sa sigurnijom metodom. "
"Preporučujemo da je primijeniš na tvoje podatke." "Preporučujemo da je primijeniš na tvoje podatke."
#: packages/app-desktop/gui/MainScreen/MainScreen.tsx:619 #: packages/app-desktop/gui/MainScreen/MainScreen.tsx:619
@@ -4404,7 +4404,7 @@ msgid ""
"\n" "\n"
"%s" "%s"
msgstr "" msgstr ""
"Došlo je do [konflikta](%s) s dolje navedenim privitkom.\n" "Došlo je do konflikta [conflict](%s) s dolje navedenim privitkom.\n"
"\n" "\n"
"%s" "%s"
@@ -4467,7 +4467,7 @@ msgid ""
"access Joplin." "access Joplin."
msgstr "" msgstr ""
"Ovaj ključ za autorizaciju potreban je samo za dozvoljavanje drugim " "Ovaj ključ za autorizaciju potreban je samo za dozvoljavanje drugim "
"programima pristupiti Joplinu." "programima da pristupe Joplinu."
#: packages/app-desktop/gui/ResourceScreen.tsx:231 #: packages/app-desktop/gui/ResourceScreen.tsx:231
msgid "" msgid ""
@@ -4747,7 +4747,7 @@ msgstr ""
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:69 #: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:69
#, fuzzy #, fuzzy
msgid "Unordered list" msgid "Unordered list"
msgstr "Stvori korisnika" msgstr "Nerazvstan popis"
#: packages/app-desktop/gui/ShareNoteDialog.tsx:162 #: packages/app-desktop/gui/ShareNoteDialog.tsx:162
msgid "Unpublish note" msgid "Unpublish note"
@@ -4853,7 +4853,7 @@ msgstr "Korištenje: %s"
#: packages/lib/models/Setting.ts:1640 #: packages/lib/models/Setting.ts:1640
msgid "Use biometrics to secure access to the app" msgid "Use biometrics to secure access to the app"
msgstr "" msgstr "Koristi biometrijske podatke za osiguravanje pristupa programu"
#: packages/app-cli/app/command-ls.js:32 packages/app-cli/app/command-tag.js:18 #: packages/app-cli/app/command-ls.js:32 packages/app-cli/app/command-tag.js:18
msgid "" msgid ""
@@ -5437,6 +5437,9 @@ msgstr "Umanji prikaz"
#~ msgid "Give focus to next pane" #~ msgid "Give focus to next pane"
#~ msgstr "Fokusiraj sljedeće okno" #~ msgstr "Fokusiraj sljedeće okno"
#~ msgid "Give focus to previous pane"
#~ msgstr "Fokusiraj prethodno okno"
#~ msgid "Exit command line mode" #~ msgid "Exit command line mode"
#~ msgstr "Napusti naredbeni redak" #~ msgstr "Napusti naredbeni redak"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@joplin/tools", "name": "@joplin/tools",
"version": "2.10.2", "version": "2.11.0",
"description": "Various tools for Joplin", "description": "Various tools for Joplin",
"main": "index.js", "main": "index.js",
"author": "Laurent Cozic", "author": "Laurent Cozic",
@@ -20,13 +20,12 @@
}, },
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@joplin/lib": "^2.10.2", "@joplin/lib": "~2.11",
"@joplin/renderer": "^2.10.2", "@joplin/renderer": "~2.11",
"@types/node-fetch": "2.6.2", "@joplin/utils": "~2.11",
"@types/yargs": "17.0.20",
"dayjs": "1.11.7", "dayjs": "1.11.7",
"execa": "4.1.0", "execa": "4.1.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"gettext-parser": "6.0.0", "gettext-parser": "6.0.0",
"glob": "8.1.0", "glob": "8.1.0",
"markdown-it": "13.0.1", "markdown-it": "13.0.1",
@@ -48,13 +47,15 @@
"@types/jest": "29.2.6", "@types/jest": "29.2.6",
"@types/mustache": "4.2.2", "@types/mustache": "4.2.2",
"@types/node": "18.11.18", "@types/node": "18.11.18",
"gettext-extractor": "3.6.2", "@types/node-fetch": "2.6.2",
"@types/yargs": "17.0.20",
"gettext-extractor": "3.7.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"jest": "29.4.3", "jest": "29.4.3",
"rss": "1.2.2", "rss": "1.2.2",
"sass": "1.58.3", "sass": "1.59.3",
"sqlite3": "5.1.4", "sqlite3": "5.1.6",
"typescript": "4.9.4" "typescript": "4.9.4"
}, },
"gitHead": "eb4b0e64eab40a51b0895d3a40a9d8c3cb7b1b14" "gitHead": "eb4b0e64eab40a51b0895d3a40a9d8c3cb7b1b14"

View File

@@ -1,5 +1,6 @@
import { execCommand } from '@joplin/utils';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import { execCommandVerbose, execCommandWithPipes, githubRelease, githubOauthToken, fileExists, gitPullTry, completeReleaseWithChangelog, execCommand2 } from './tool-utils'; import { execCommandVerbose, execCommandWithPipes, githubRelease, githubOauthToken, fileExists, gitPullTry, completeReleaseWithChangelog } from './tool-utils';
const path = require('path'); const path = require('path');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const uriTemplate = require('uri-template'); const uriTemplate = require('uri-template');
@@ -150,7 +151,7 @@ async function main() {
const isPreRelease = !('type' in argv) || argv.type === 'prerelease'; const isPreRelease = !('type' in argv) || argv.type === 'prerelease';
process.chdir(rnDir); process.chdir(rnDir);
await execCommand2('yarn run build', { showStdout: false }); await execCommand('yarn run build', { showStdout: false });
if (isPreRelease) console.info('Creating pre-release'); if (isPreRelease) console.info('Creating pre-release');
console.info('Updating version numbers in build.gradle...'); console.info('Updating version numbers in build.gradle...');

View File

@@ -1,4 +1,5 @@
import { execCommand2, rootDir, completeReleaseWithChangelog } from './tool-utils'; import { execCommand } from '@joplin/utils';
import { rootDir, completeReleaseWithChangelog } from './tool-utils';
const appDir = `${rootDir}/packages/app-cli`; const appDir = `${rootDir}/packages/app-cli`;
const changelogPath = `${rootDir}/readme/changelog_cli.md`; const changelogPath = `${rootDir}/readme/changelog_cli.md`;
@@ -8,19 +9,19 @@ const changelogPath = `${rootDir}/readme/changelog_cli.md`;
async function main() { async function main() {
process.chdir(appDir); process.chdir(appDir);
await execCommand2('git pull'); await execCommand('git pull');
const newVersion = (await execCommand2('npm version patch')).trim(); const newVersion = (await execCommand('npm version patch')).trim();
console.info(`Building ${newVersion}...`); console.info(`Building ${newVersion}...`);
const newTag = `cli-${newVersion}`; const newTag = `cli-${newVersion}`;
await execCommand2('touch app/main.js'); await execCommand('touch app/main.js');
await execCommand2('yarn run build'); await execCommand('yarn run build');
await execCommand2('cp ../../README.md build/'); await execCommand('cp ../../README.md build/');
process.chdir(`${appDir}/build`); process.chdir(`${appDir}/build`);
await execCommand2('npm publish'); await execCommand('npm publish');
await completeReleaseWithChangelog(changelogPath, newVersion, newTag, 'CLI', false); await completeReleaseWithChangelog(changelogPath, newVersion, newTag, 'CLI', false);
} }

View File

@@ -1,4 +1,5 @@
import { execCommand2, gitCurrentBranch, githubRelease, gitPullTry, rootDir } from './tool-utils'; import { execCommand } from '@joplin/utils';
import { gitCurrentBranch, githubRelease, gitPullTry, rootDir } from './tool-utils';
const appDir = `${rootDir}/packages/app-desktop`; const appDir = `${rootDir}/packages/app-desktop`;
@@ -11,16 +12,16 @@ async function main() {
console.info(`Running from: ${process.cwd()}`); console.info(`Running from: ${process.cwd()}`);
const version = (await execCommand2('npm version patch')).trim(); const version = (await execCommand('npm version patch')).trim();
const tagName = version; const tagName = version;
console.info(`New version number: ${version}`); console.info(`New version number: ${version}`);
await execCommand2('git add -A'); await execCommand('git add -A');
await execCommand2(`git commit -m "Desktop release ${version}"`); await execCommand(`git commit -m "Desktop release ${version}"`);
await execCommand2(`git tag ${tagName}`); await execCommand(`git tag ${tagName}`);
await execCommand2('git push'); await execCommand('git push');
await execCommand2('git push --tags'); await execCommand('git push --tags');
const releaseOptions = { isDraft: true, isPreRelease: !!argv.beta }; const releaseOptions = { isDraft: true, isPreRelease: !!argv.beta };

View File

@@ -1,5 +1,6 @@
import { execCommand } from '@joplin/utils';
import { chdir } from 'process'; import { chdir } from 'process';
import { rootDir, gitPullTry, execCommand2, releaseFinalGitCommands } from './tool-utils'; import { rootDir, gitPullTry, releaseFinalGitCommands } from './tool-utils';
const workDir = `${rootDir}/packages/plugin-repo-cli`; const workDir = `${rootDir}/packages/plugin-repo-cli`;
@@ -7,18 +8,18 @@ async function main() {
await gitPullTry(); await gitPullTry();
chdir(rootDir); chdir(rootDir);
await execCommand2('yarn run tsc'); await execCommand('yarn run tsc');
chdir(workDir); chdir(workDir);
await execCommand2('yarn run dist'); await execCommand('yarn run dist');
const newVersion = (await execCommand2('npm version patch')).trim(); const newVersion = (await execCommand('npm version patch')).trim();
console.info(`New version: ${newVersion}`); console.info(`New version: ${newVersion}`);
const tagName = `plugin-repo-cli-${newVersion}`; const tagName = `plugin-repo-cli-${newVersion}`;
console.info(`Tag name: ${tagName}`); console.info(`Tag name: ${tagName}`);
await execCommand2('npm publish'); await execCommand('npm publish');
console.info(releaseFinalGitCommands('Plugin Repo CLI', newVersion, tagName)); console.info(releaseFinalGitCommands('Plugin Repo CLI', newVersion, tagName));
} }

View File

@@ -1,4 +1,5 @@
import { execCommand2, rootDir, gitPullTry, completeReleaseWithChangelog } from './tool-utils'; import { execCommand } from '@joplin/utils';
import { rootDir, gitPullTry, completeReleaseWithChangelog } from './tool-utils';
const serverDir = `${rootDir}/packages/server`; const serverDir = `${rootDir}/packages/server`;
@@ -12,7 +13,7 @@ async function main() {
await gitPullTry(); await gitPullTry();
process.chdir(serverDir); process.chdir(serverDir);
const version = (await execCommand2('npm version patch')).trim(); const version = (await execCommand('npm version patch')).trim();
const versionSuffix = ''; // isPreRelease ? '-beta' : ''; const versionSuffix = ''; // isPreRelease ? '-beta' : '';
const tagName = `server-${version}${versionSuffix}`; const tagName = `server-${version}${versionSuffix}`;

View File

@@ -40,7 +40,7 @@ yarn install
# to change after installation. # to change after installation.
git reset --hard git reset --hard
yarn run updateMarkdownDoc JOPLIN_GITHUB_OAUTH_TOKEN=$JOPLIN_GITHUB_OAUTH_TOKEN yarn run updateMarkdownDoc
yarn run updateNews $DISCOURSE_API_KEY $DISCOURSE_USERNAME yarn run updateNews $DISCOURSE_API_KEY $DISCOURSE_USERNAME
# We commit and push the change. It will be a noop if nothing was actually # We commit and push the change. It will be a noop if nothing was actually

View File

@@ -139,6 +139,7 @@ async function main() {
await updatePackageVersion(`${rootDir}/packages/renderer/package.json`, majorMinorVersion, options); await updatePackageVersion(`${rootDir}/packages/renderer/package.json`, majorMinorVersion, options);
await updatePackageVersion(`${rootDir}/packages/server/package.json`, majorMinorVersion, options); await updatePackageVersion(`${rootDir}/packages/server/package.json`, majorMinorVersion, options);
await updatePackageVersion(`${rootDir}/packages/tools/package.json`, majorMinorVersion, options); await updatePackageVersion(`${rootDir}/packages/tools/package.json`, majorMinorVersion, options);
await updatePackageVersion(`${rootDir}/packages/utils/package.json`, majorMinorVersion, options);
if (options.updateVersion) { if (options.updateVersion) {
await updateGradleVersion(`${rootDir}/packages/app-mobile/android/app/build.gradle`, majorMinorVersion); await updateGradleVersion(`${rootDir}/packages/app-mobile/android/app/build.gradle`, majorMinorVersion);

View File

@@ -1,6 +1,7 @@
import yargs = require('yargs'); import yargs = require('yargs');
import { chdir } from 'process'; import { chdir } from 'process';
import { execCommand2, rootDir } from './tool-utils'; import { rootDir } from './tool-utils';
import { execCommand } from '@joplin/utils';
const main = async () => { const main = async () => {
const argv = await yargs.argv; const argv = await yargs.argv;
@@ -10,7 +11,7 @@ const main = async () => {
chdir(rootDir); chdir(rootDir);
try { try {
await execCommand2(['yarn', 'run', 'cspell'].concat(filePaths), { showStderr: false, showStdout: false }); await execCommand(['yarn', 'run', 'cspell'].concat(filePaths), { showStderr: false, showStdout: false });
} catch (error) { } catch (error) {
if (!error.stdout.trim()) return; if (!error.stdout.trim()) return;

View File

@@ -64,11 +64,6 @@
"title": "Serei Network", "title": "Serei Network",
"imageName": "SeireiNetwork.png" "imageName": "SeireiNetwork.png"
}, },
{
"url": "https://usrigging.com/",
"title": "U.S. Ringing Supply",
"imageName": "RingingSupply.svg"
},
{ {
"url": "https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-github&mtm_medium=banner", "url": "https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-github&mtm_medium=banner",
"urlWebsite": "https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner", "urlWebsite": "https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner",
@@ -86,5 +81,11 @@
"imageName": "Grundstueckspreise.png" "imageName": "Grundstueckspreise.png"
} }
], ],
"orgsOld": [] "orgsOld": [
{
"url": "https://usrigging.com/",
"title": "U.S. Ringing Supply",
"imageName": "RingingSupply.svg"
}
]
} }

View File

@@ -1,4 +1,4 @@
import { execCommand2 } from './tool-utils'; import { execCommand } from '@joplin/utils';
async function main() { async function main() {
const argv = require('yargs').argv; const argv = require('yargs').argv;
@@ -6,9 +6,9 @@ async function main() {
const version = argv._[0]; const version = argv._[0];
await execCommand2(`docker pull "joplin/server:${version}"`); await execCommand(`docker pull "joplin/server:${version}"`);
await execCommand2(`docker tag "joplin/server:${version}" "joplin/server:latest"`); await execCommand(`docker tag "joplin/server:${version}" "joplin/server:latest"`);
await execCommand2('docker push joplin/server:latest'); await execCommand('docker push joplin/server:latest');
} }
if (require.main === module) { if (require.main === module) {

View File

@@ -1,9 +1,9 @@
import * as fs from 'fs-extra'; import { pathExists, readFile, writeFile, unlink, stat, createWriteStream } from 'fs-extra';
import { readCredentialFile } from '@joplin/lib/utils/credentialFiles'; import { hasCredentialFile, readCredentialFile } from '@joplin/lib/utils/credentialFiles';
import { execCommand as execCommand2, commandToString } from '@joplin/utils';
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const execa = require('execa'); const execa = require('execa');
const { splitCommandString } = require('@joplin/lib/string-utils');
const moment = require('moment'); const moment = require('moment');
export interface GitHubReleaseAsset { export interface GitHubReleaseAsset {
@@ -20,27 +20,10 @@ export interface GitHubRelease {
draft: boolean; draft: boolean;
} }
function quotePath(path: string) {
if (!path) return '';
if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path;
path = path.replace(/"/, '\\"');
return `"${path}"`;
}
function commandToString(commandName: string, args: string[] = []) {
const output = [quotePath(commandName)];
for (const arg of args) {
output.push(quotePath(arg));
}
return output.join(' ');
}
async function insertChangelog(tag: string, changelogPath: string, changelog: string, isPrerelease: boolean, repoTagUrl: string = '') { async function insertChangelog(tag: string, changelogPath: string, changelog: string, isPrerelease: boolean, repoTagUrl: string = '') {
repoTagUrl = repoTagUrl || 'https://github.com/laurent22/joplin/releases/tag'; repoTagUrl = repoTagUrl || 'https://github.com/laurent22/joplin/releases/tag';
const currentText = await fs.readFile(changelogPath, 'UTF-8'); const currentText = await readFile(changelogPath, 'UTF-8');
const lines = currentText.split('\n'); const lines = currentText.split('\n');
const beforeLines = []; const beforeLines = [];
@@ -97,7 +80,7 @@ export async function completeReleaseWithChangelog(changelogPath: string, newVer
const newChangelog = await insertChangelog(newTag, changelogPath, changelog, isPreRelease, repoTagUrl); const newChangelog = await insertChangelog(newTag, changelogPath, changelog, isPreRelease, repoTagUrl);
await fs.writeFile(changelogPath, newChangelog); await writeFile(changelogPath, newChangelog);
console.info(''); console.info('');
console.info('Verify that the changelog is correct:'); console.info('Verify that the changelog is correct:');
@@ -112,8 +95,8 @@ export async function completeReleaseWithChangelog(changelogPath: string, newVer
async function loadGitHubUsernameCache() { async function loadGitHubUsernameCache() {
const path = `${__dirname}/github_username_cache.json`; const path = `${__dirname}/github_username_cache.json`;
if (await fs.pathExists(path)) { if (await pathExists(path)) {
const jsonString = await fs.readFile(path, 'utf8'); const jsonString = await readFile(path, 'utf8');
return JSON.parse(jsonString); return JSON.parse(jsonString);
} }
@@ -122,7 +105,7 @@ async function loadGitHubUsernameCache() {
async function saveGitHubUsernameCache(cache: any) { async function saveGitHubUsernameCache(cache: any) {
const path = `${__dirname}/github_username_cache.json`; const path = `${__dirname}/github_username_cache.json`;
await fs.writeFile(path, JSON.stringify(cache)); await writeFile(path, JSON.stringify(cache));
} }
// Returns the project root dir // Returns the project root dir
@@ -163,52 +146,6 @@ export function execCommandVerbose(commandName: string, args: string[] = []) {
return promise; return promise;
} }
interface ExecCommandOptions {
showInput?: boolean;
showStdout?: boolean;
showStderr?: boolean;
quiet?: boolean;
}
// There's lot of execCommandXXX functions, but eventually all scripts should
// use the one below, which supports:
//
// - Printing the command being executed
// - Printing the output in real time (piping to stdout)
// - Returning the command result as string
export async function execCommand2(command: string | string[], options: ExecCommandOptions = null): Promise<string> {
options = {
showInput: true,
showStdout: true,
showStderr: true,
quiet: false,
...options,
};
if (options.quiet) {
options.showInput = false;
options.showStdout = false;
options.showStderr = false;
}
if (options.showInput) {
if (typeof command === 'string') {
console.info(`> ${command}`);
} else {
console.info(`> ${commandToString(command[0], command.slice(1))}`);
}
}
const args: string[] = typeof command === 'string' ? splitCommandString(command) : command as string[];
const executableName = args[0];
args.splice(0, 1);
const promise = execa(executableName, args);
if (options.showStdout) promise.stdout.pipe(process.stdout);
if (options.showStderr) promise.stdout.pipe(process.stderr);
const result = await promise;
return result.stdout.trim();
}
export function execCommandWithPipes(executable: string, args: string[]) { export function execCommandWithPipes(executable: string, args: string[]) {
const spawn = require('child_process').spawn; const spawn = require('child_process').spawn;
@@ -236,22 +173,21 @@ export function toSystemSlashes(path: string) {
} }
export async function setPackagePrivateField(filePath: string, value: any) { export async function setPackagePrivateField(filePath: string, value: any) {
const text = await fs.readFile(filePath, 'utf8'); const text = await readFile(filePath, 'utf8');
const obj = JSON.parse(text); const obj = JSON.parse(text);
if (!value) { if (!value) {
delete obj.private; delete obj.private;
} else { } else {
obj.private = true; obj.private = true;
} }
await fs.writeFile(filePath, JSON.stringify(obj, null, 2), 'utf8'); await writeFile(filePath, JSON.stringify(obj, null, 2), 'utf8');
} }
export async function downloadFile(url: string, targetPath: string) { export async function downloadFile(url: string, targetPath: string) {
const https = require('https'); const https = require('https');
const fs = require('fs');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const file = fs.createWriteStream(targetPath); const file = createWriteStream(targetPath);
https.get(url, (response: any) => { https.get(url, (response: any) => {
if (response.statusCode !== 200) reject(new Error(`HTTP error ${response.statusCode}`)); if (response.statusCode !== 200) reject(new Error(`HTTP error ${response.statusCode}`));
response.pipe(file); response.pipe(file);
@@ -285,10 +221,8 @@ export function fileSha256(filePath: string) {
} }
export async function unlinkForce(filePath: string) { export async function unlinkForce(filePath: string) {
const fs = require('fs-extra');
try { try {
await fs.unlink(filePath); await unlink(filePath);
} catch (error) { } catch (error) {
if (error.code === 'ENOENT') return; if (error.code === 'ENOENT') return;
throw error; throw error;
@@ -296,10 +230,8 @@ export async function unlinkForce(filePath: string) {
} }
export function fileExists(filePath: string) { export function fileExists(filePath: string) {
const fs = require('fs-extra');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.stat(filePath, (error: any) => { stat(filePath, (error: any) => {
if (!error) { if (!error) {
resolve(true); resolve(true);
} else if (error.code === 'ENOENT') { } else if (error.code === 'ENOENT') {
@@ -389,7 +321,10 @@ export function patreonOauthToken() {
} }
export function githubOauthToken() { export function githubOauthToken() {
return readCredentialFile('github_oauth_token.txt'); const filename = 'github_oauth_token.txt';
if (hasCredentialFile(filename)) return readCredentialFile(filename);
if (process.env.JOPLIN_GITHUB_OAUTH_TOKEN) return process.env.JOPLIN_GITHUB_OAUTH_TOKEN;
throw new Error(`Cannot get Oauth token. Neither ${filename} nor the env variable JOPLIN_GITHUB_OAUTH_TOKEN are present`);
} }
// Note that the GitHub API releases/latest is broken on the joplin-android repo // Note that the GitHub API releases/latest is broken on the joplin-android repo
@@ -485,12 +420,11 @@ export function isMac() {
} }
export async function insertContentIntoFile(filePath: string, markerOpen: string, markerClose: string, contentToInsert: string) { export async function insertContentIntoFile(filePath: string, markerOpen: string, markerClose: string, contentToInsert: string) {
const fs = require('fs-extra'); let content = await readFile(filePath, 'utf-8');
let content = await fs.readFile(filePath, 'utf-8');
// [^]* matches any character including new lines // [^]* matches any character including new lines
const regex = new RegExp(`${markerOpen}[^]*?${markerClose}`); const regex = new RegExp(`${markerOpen}[^]*?${markerClose}`);
content = content.replace(regex, markerOpen + contentToInsert + markerClose); content = content.replace(regex, markerOpen + contentToInsert + markerClose);
await fs.writeFile(filePath, content); await writeFile(filePath, content);
} }
export function dirname(path: string) { export function dirname(path: string) {

View File

@@ -1,43 +1,9 @@
import { readFile } from 'fs-extra';
import { insertContentIntoFile, rootDir } from './tool-utils'; import { insertContentIntoFile, rootDir } from './tool-utils';
import markdownUtils, { MarkdownTableHeader, MarkdownTableJustify, MarkdownTableRow } from '@joplin/lib/markdownUtils'; import markdownUtils, { MarkdownTableHeader, MarkdownTableJustify, MarkdownTableRow } from '@joplin/lib/markdownUtils';
import { GithubSponsor, GithubUser, OrgSponsor, Sponsors } from './website/utils/types'; import { GithubSponsor, loadSponsors, OrgSponsor } from './utils/loadSponsors';
import fetch from 'node-fetch';
const { escapeHtml } = require('@joplin/lib/string-utils'); const { escapeHtml } = require('@joplin/lib/string-utils');
const readmePath = `${rootDir}/README.md`; const readmePath = `${rootDir}/README.md`;
const sponsorsPath = `${rootDir}/packages/tools/sponsors.json`;
const sleep = (ms: number) => {
return new Promise(resolve => setTimeout(resolve, ms));
};
const fetchWithRetry = async (url: string, opts: any = null) => {
if (!opts) opts = {};
let retry = opts && opts.retry || 3;
while (retry > 0) {
try {
return fetch(url, opts);
} catch (e) {
if (opts && opts.callback) {
opts.callback(retry);
}
retry = retry - 1;
if (retry === 0) {
throw e;
}
if (opts && opts.pause) {
if (opts && !opts.silent) console.log('pausing..');
await sleep(opts.pause);
if (opts && !opts.silent) console.log('done pausing...');
}
}
}
return null;
};
async function createGitHubSponsorTable(sponsors: GithubSponsor[]): Promise<string> { async function createGitHubSponsorTable(sponsors: GithubSponsor[]): Promise<string> {
sponsors = sponsors.slice(); sponsors = sponsors.slice();
@@ -70,9 +36,7 @@ async function createGitHubSponsorTable(sponsors: GithubSponsor[]): Promise<stri
sponsorIndex++; sponsorIndex++;
if (!sponsor) break; if (!sponsor) break;
const userResponse = await fetchWithRetry(`https://api.github.com/users/${sponsor.name}`); row[`col${colIndex}`] = `<img width="50" src="https://avatars2.githubusercontent.com/u/${sponsor.id}?s=96&v=4"/></br>[${sponsor.name}](https://github.com/${sponsor.name})`;
const user = await userResponse.json() as GithubUser;
row[`col${colIndex}`] = `<img width="50" src="https://avatars2.githubusercontent.com/u/${user.id}?s=96&v=4"/></br>[${sponsor.name}](https://github.com/${sponsor.name})`;
} }
if (Object.keys(row)) rows.push(row); if (Object.keys(row)) rows.push(row);
@@ -94,7 +58,7 @@ async function createOrgSponsorTable(sponsors: OrgSponsor[]): Promise<string> {
} }
async function main() { async function main() {
const sponsors: Sponsors = JSON.parse(await readFile(sponsorsPath, 'utf8')); const sponsors = await loadSponsors();
await insertContentIntoFile( await insertContentIntoFile(
readmePath, readmePath,

View File

@@ -1,5 +1,6 @@
import { execCommand } from '@joplin/utils';
import { chdir } from 'process'; import { chdir } from 'process';
import { execCommand2, rootDir, gitRepoCleanTry } from './tool-utils'; import { rootDir, gitRepoCleanTry } from './tool-utils';
import updateDownloadPage from './website/updateDownloadPage'; import updateDownloadPage from './website/updateDownloadPage';
async function main() { async function main() {
@@ -7,23 +8,23 @@ async function main() {
if (doGitOperations) { if (doGitOperations) {
await gitRepoCleanTry(); await gitRepoCleanTry();
await execCommand2(['git', 'pull', '--rebase']); await execCommand(['git', 'pull', '--rebase']);
} }
await execCommand2(['node', `${rootDir}/packages/tools/update-readme-download.js`]); await execCommand(['node', `${rootDir}/packages/tools/update-readme-download.js`]);
await execCommand2(['node', `${rootDir}/packages/tools/build-release-stats.js`, '--types=changelog']); await execCommand(['node', `${rootDir}/packages/tools/build-release-stats.js`, '--types=changelog']);
await execCommand2(['node', `${rootDir}/packages/tools/build-release-stats.js`, '--types=stats', '--update-interval=30']); await execCommand(['node', `${rootDir}/packages/tools/build-release-stats.js`, '--types=stats', '--update-interval=30']);
await execCommand2(['node', `${rootDir}/packages/tools/update-readme-sponsors.js`]); await execCommand(['node', `${rootDir}/packages/tools/update-readme-sponsors.js`]);
await execCommand2(['node', `${rootDir}/packages/tools/build-welcome.js`]); await execCommand(['node', `${rootDir}/packages/tools/build-welcome.js`]);
chdir(rootDir); chdir(rootDir);
await execCommand2(['yarn', 'run', 'buildApiDoc']); await execCommand(['yarn', 'run', 'buildApiDoc']);
await updateDownloadPage(); await updateDownloadPage();
if (doGitOperations) { if (doGitOperations) {
await execCommand2(['git', 'add', '-A']); await execCommand(['git', 'add', '-A']);
await execCommand2(['git', 'commit', '-m', 'Update Markdown doc']); await execCommand(['git', 'commit', '-m', 'Update Markdown doc']);
await execCommand2(['git', 'pull', '--rebase']); await execCommand(['git', 'pull', '--rebase']);
await execCommand2(['git', 'push']); await execCommand(['git', 'push']);
} }
} }

View File

@@ -0,0 +1,48 @@
import { readFile } from 'fs-extra';
import { getRootDir } from '@joplin/utils';
import { fetchWithRetry } from '@joplin/utils/net';
import { githubOauthToken } from '../tool-utils';
export interface GithubSponsor {
name: string;
id: string;
}
export interface Sponsors {
github: GithubSponsor[];
orgs: OrgSponsor[];
}
export interface OrgSponsor {
url: string;
urlWebsite?: string;
title: string;
imageName: string;
}
export const loadSponsors = async (): Promise<Sponsors> => {
const sponsorsPath = `${await getRootDir()}/packages/tools/sponsors.json`;
const output: Sponsors = JSON.parse(await readFile(sponsorsPath, 'utf8'));
output.orgs = output.orgs.map(o => {
if (o.urlWebsite) o.url = o.urlWebsite;
return o;
});
const oauthToken = await githubOauthToken();
for (const ghSponsor of output.github) {
const userResponse = await fetchWithRetry(`https://api.github.com/users/${ghSponsor.name}`, {
headers: {
'Content-Type': 'application/json',
'Authorization': `token ${oauthToken}`,
},
});
if (!userResponse.ok) throw new Error(await userResponse.text());
const user = await userResponse.json();
ghSponsor.id = user.id;
}
return output;
};

View File

@@ -2,7 +2,7 @@ import { readFileSync, readFile, mkdirpSync, writeFileSync, remove, copy, pathEx
import { rootDir } from '../tool-utils'; import { rootDir } from '../tool-utils';
import { pressCarouselItems } from './utils/pressCarousel'; import { pressCarouselItems } from './utils/pressCarousel';
import { getMarkdownIt, loadMustachePartials, markdownToPageHtml, renderMustache } from './utils/render'; import { getMarkdownIt, loadMustachePartials, markdownToPageHtml, renderMustache } from './utils/render';
import { AssetUrls, Env, Partials, PlanPageParams, Sponsors, TemplateParams } from './utils/types'; import { AssetUrls, Env, Partials, PlanPageParams, TemplateParams } from './utils/types';
import { createFeatureTableMd, getPlans, loadStripeConfig } from '@joplin/lib/utils/joplinCloud'; import { createFeatureTableMd, getPlans, loadStripeConfig } from '@joplin/lib/utils/joplinCloud';
import { stripOffFrontMatter } from './utils/frontMatter'; import { stripOffFrontMatter } from './utils/frontMatter';
import { dirname, basename } from 'path'; import { dirname, basename } from 'path';
@@ -13,6 +13,7 @@ import { getNewsDateString } from './utils/news';
import { parsePoFile, parseTranslations, Translations } from '../utils/translation'; import { parsePoFile, parseTranslations, Translations } from '../utils/translation';
import { countryCodeOnly, setLocale } from '@joplin/lib/locale'; import { countryCodeOnly, setLocale } from '@joplin/lib/locale';
import applyTranslations from './utils/applyTranslations'; import applyTranslations from './utils/applyTranslations';
import { loadSponsors } from '../utils/loadSponsors';
interface BuildConfig { interface BuildConfig {
env: Env; env: Env;
@@ -175,16 +176,6 @@ function makeHomePageMd() {
return md; return md;
} }
async function loadSponsors(): Promise<Sponsors> {
const sponsorsPath = `${rootDir}/packages/tools/sponsors.json`;
const output: Sponsors = JSON.parse(await readFile(sponsorsPath, 'utf8'));
output.orgs = output.orgs.map(o => {
if (o.urlWebsite) o.url = o.urlWebsite;
return o;
});
return output;
}
const processNewsMarkdown = (md: string, mdFilePath: string): string => { const processNewsMarkdown = (md: string, mdFilePath: string): string => {
const info = stripOffFrontMatter(md); const info = stripOffFrontMatter(md);
md = info.doc.trim(); md = info.doc.trim();

View File

@@ -1,4 +1,5 @@
import { Plan, StripePublicConfig } from '@joplin/lib/utils/joplinCloud'; import { Plan, StripePublicConfig } from '@joplin/lib/utils/joplinCloud';
import { Sponsors } from '../../utils/loadSponsors';
import { OpenGraphTags } from './openGraph'; import { OpenGraphTags } from './openGraph';
export enum Env { export enum Env {
@@ -6,26 +7,10 @@ export enum Env {
Prod = 'prod', Prod = 'prod',
} }
export interface GithubSponsor {
name: string;
}
export interface GithubUser { export interface GithubUser {
id: string; id: string;
} }
export interface OrgSponsor {
url: string;
urlWebsite?: string;
title: string;
imageName: string;
}
export interface Sponsors {
github: GithubSponsor[];
orgs: OrgSponsor[];
}
interface PressCarouselItem { interface PressCarouselItem {
active: string; active: string;
body: string; body: string;

View File

@@ -11,7 +11,7 @@
"browserify": "14.5.0", "browserify": "14.5.0",
"rollup": "0.50.1", "rollup": "0.50.1",
"standard": "17.0.0", "standard": "17.0.0",
"turndown": "7.1.1", "turndown": "7.1.2",
"turndown-attendant": "0.0.3" "turndown-attendant": "0.0.3"
}, },
"files": [ "files": [

View File

@@ -13,7 +13,7 @@
"dependencies": { "dependencies": {
"css": "3.0.0", "css": "3.0.0",
"html-entities": "1.4.0", "html-entities": "1.4.0",
"jsdom": "21.0.0" "jsdom": "21.1.1"
}, },
"devDependencies": { "devDependencies": {
"browserify": "14.5.0", "browserify": "14.5.0",

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