Compare commits
579 Commits
android-v2
...
server-v2.
Author | SHA1 | Date | |
---|---|---|---|
|
47a49fd5de | ||
|
be949390f8 | ||
|
b26a9f1b22 | ||
|
b7b0f770ee | ||
|
1ae5d4ea9b | ||
|
aa267f0dc6 | ||
|
691618b50c | ||
|
33ed7545a9 | ||
|
d8d0e705f2 | ||
|
bdc970d718 | ||
|
4636d1539c | ||
|
bc1165be46 | ||
|
f5e1e45f6f | ||
|
352ee6496e | ||
|
fdbfa78e53 | ||
|
dfe5383d4b | ||
|
eb1e9e0436 | ||
|
3d7f864982 | ||
|
1ffe30b359 | ||
|
5d5bd3abd6 | ||
|
747264bd89 | ||
|
7bd1bdb0e3 | ||
|
d5ec92e540 | ||
|
2b50e99bb1 | ||
|
a4c5164bea | ||
|
88d6c94e6b | ||
|
4f45c977e2 | ||
|
cbf7e24c47 | ||
|
7ebc98633a | ||
|
1d4e3fe3ea | ||
|
94e0ea403a | ||
|
d217478852 | ||
|
4c9cbd61a4 | ||
|
d07a540618 | ||
|
720b6f0190 | ||
|
33fff4c8f0 | ||
|
6f83ccd044 | ||
|
7d68dafaed | ||
|
4f066b06d2 | ||
|
a11bed1bb2 | ||
|
96c9e29025 | ||
|
2519b73117 | ||
|
639bfc4533 | ||
|
97a04ea9e3 | ||
|
150ee7631e | ||
|
9a68157b86 | ||
|
12878672e4 | ||
|
15f019789b | ||
|
311905f6d2 | ||
|
a74035c22f | ||
|
361e56e9b4 | ||
|
04fa761258 | ||
|
b2109dab99 | ||
|
61a3962eda | ||
|
97af8cb7f5 | ||
|
17bdec22ca | ||
|
1d176b31ff | ||
|
32e76d7988 | ||
|
94e3582bb8 | ||
|
b9b2d37fdd | ||
|
a465d0ee8d | ||
|
a29666d442 | ||
|
d3ccb9786b | ||
|
2625f0d89e | ||
|
1cd0c3742e | ||
|
2e94b01700 | ||
|
20b1c2e7cb | ||
|
4e8863d81f | ||
|
a34a911b1e | ||
|
2bf2395f1b | ||
|
a6b150e63a | ||
|
50a7b21f8d | ||
|
76e8186858 | ||
|
763716397b | ||
|
68e04f944f | ||
|
91b51adc48 | ||
|
4c12c25bd8 | ||
|
c0dcf1d3e3 | ||
|
efa35d9317 | ||
|
3c210a012a | ||
|
92667bafc1 | ||
|
fc7d053521 | ||
|
47072b3813 | ||
|
7a13003af5 | ||
|
723b708d89 | ||
|
36a24a5ed8 | ||
|
091bf4a3d7 | ||
|
ce8e5e61be | ||
|
b8462c4754 | ||
|
73ad7e0572 | ||
|
2bf4f39ca1 | ||
|
29b8fcd5bb | ||
|
2a96012577 | ||
|
474e8c95a0 | ||
|
906b7c3a33 | ||
|
0a2afdb010 | ||
|
a281163353 | ||
|
9aa7240d5e | ||
|
9cf63168da | ||
|
430f73c47a | ||
|
7e8c87e908 | ||
|
4e09b6f2a4 | ||
|
d02058d337 | ||
|
f95ee689fd | ||
|
164e53ee7d | ||
|
cb1322f01e | ||
|
cc22d71408 | ||
|
ff7c13ac85 | ||
|
302bc4dcc7 | ||
|
ebfc5da0fe | ||
|
00eee19077 | ||
|
4048d83dd7 | ||
|
48b8fae625 | ||
|
60fbc6e022 | ||
|
ae73b5b87c | ||
|
6bc2ef9869 | ||
|
206d4ab56d | ||
|
96456aa851 | ||
|
adf0ccee2f | ||
|
01394e43d9 | ||
|
39c19db69c | ||
|
105e408dca | ||
|
37dbea1613 | ||
|
2512adebd2 | ||
|
28538de028 | ||
|
a0b4f5acac | ||
|
30a5bda5b9 | ||
|
c5865b3bf5 | ||
|
a9f6b38120 | ||
|
75447f7267 | ||
|
ca703adf6a | ||
|
f38abc5718 | ||
|
d733a7f5ae | ||
|
0f388b13c7 | ||
|
754ca39926 | ||
|
8a05baa97f | ||
|
1df00a1e5a | ||
|
5e63b623ca | ||
|
f8a25cb275 | ||
|
1e866ead3e | ||
|
3970b0876d | ||
|
6b711f655d | ||
|
65d3ed0c67 | ||
|
512e37b46a | ||
|
ed15b5e5da | ||
|
f9d1157266 | ||
|
cda0538681 | ||
|
3342b138b4 | ||
|
9285bb7a88 | ||
|
590769b1ae | ||
|
0873b1900b | ||
|
5df499e6c7 | ||
|
d89c686555 | ||
|
d81497f7b8 | ||
|
8cd377013e | ||
|
c623d98bda | ||
|
02232c0ca3 | ||
|
8ae3210378 | ||
|
bf907f21c4 | ||
|
cec5f1f3ba | ||
|
b4928eb7e5 | ||
|
3dcbb2ed51 | ||
|
e744cf0171 | ||
|
1ffafdcefc | ||
|
e48303aeb7 | ||
|
fb13e0ca80 | ||
|
7345cd4678 | ||
|
5341501d53 | ||
|
1fcfa9c591 | ||
|
1cd2d9254f | ||
|
ee18271f9b | ||
|
bf59b23efe | ||
|
973193623a | ||
|
495f088320 | ||
|
d264bdd14d | ||
|
144ec1eea2 | ||
|
7d60bfc192 | ||
|
b5428ddc2a | ||
|
2075626d42 | ||
|
4b9307015e | ||
|
9c88cb2151 | ||
|
45dcca865d | ||
|
c421a5a732 | ||
|
f7158f5e27 | ||
|
780c269e14 | ||
|
5eb0cda8b9 | ||
|
3b4eb16110 | ||
|
674bbf9667 | ||
|
f7e64e9681 | ||
|
4ec2fb216e | ||
|
ddebeb68b2 | ||
|
8b09d71d5b | ||
|
3df499714b | ||
|
6e9ff89dda | ||
|
880215acc4 | ||
|
d4157e14fe | ||
|
b237a92e02 | ||
|
0bd164642e | ||
|
872fadf454 | ||
|
404e86cef4 | ||
|
5f6b2f1a63 | ||
|
858205a72b | ||
|
dc8ea620a6 | ||
|
28527541f5 | ||
|
b1051a3144 | ||
|
06639eb399 | ||
|
5e3c12aeb8 | ||
|
7e50b117ed | ||
|
bb47c59414 | ||
|
26459ea9dc | ||
|
67a68709e3 | ||
|
d13a3fc5c8 | ||
|
27b5f59d7c | ||
|
6b7c11d694 | ||
|
1bf38eff32 | ||
|
c93f22d84b | ||
|
17c25b72f0 | ||
|
a2ded180cb | ||
|
d6c7902390 | ||
|
167892e383 | ||
|
62dd4b9926 | ||
|
b19a0761fd | ||
|
e47ac1de6a | ||
|
d2fe33183b | ||
|
02658370a6 | ||
|
46ed6411c1 | ||
|
c333e9c802 | ||
|
73617bf019 | ||
|
f3038c9cf9 | ||
|
0f81b08f89 | ||
|
0c34497c78 | ||
|
f244f44c7b | ||
|
b11006c3a7 | ||
|
d63b84ee1f | ||
|
e761b97944 | ||
|
49cf4d9965 | ||
|
3732d3e360 | ||
|
62a64ed575 | ||
|
20cb03ab69 | ||
|
995423cadf | ||
|
a730d349e4 | ||
|
6d6f9b3c3b | ||
|
09b5ef6713 | ||
|
e0cc8da884 | ||
|
d17e36d038 | ||
|
815a0a5db4 | ||
|
19b68102b2 | ||
|
04e0274055 | ||
|
bce94f1775 | ||
|
0e847685ff | ||
|
c008b58712 | ||
|
de67ec4684 | ||
|
06bf6b85fe | ||
|
0d1529f1ad | ||
|
4fc786cf0b | ||
|
6306a0f371 | ||
|
45c483263e | ||
|
d50e347f35 | ||
|
913e650bb3 | ||
|
5e537db538 | ||
|
706e7e07d1 | ||
|
dc9f732ded | ||
|
cedf84698e | ||
|
9915a59bce | ||
|
1bbec445d5 | ||
|
27a0959f30 | ||
|
b70589ef56 | ||
|
b6039e739a | ||
|
7558c2e9fe | ||
|
d63fc524bf | ||
|
48ea014ee0 | ||
|
fd5a4dcbbf | ||
|
92a0964a8d | ||
|
c0c32a7ac1 | ||
|
5cfe945c4e | ||
|
51f96eb9dd | ||
|
f6121bae2b | ||
|
3c40854a8c | ||
|
b271e54828 | ||
|
2c0f8d5c6b | ||
|
474365188d | ||
|
80c2a87da2 | ||
|
a8f0f01826 | ||
|
4bb06cb4a0 | ||
|
9d0a862798 | ||
|
583c6da970 | ||
|
9a7c737f15 | ||
|
08805f01e7 | ||
|
01cc550adf | ||
|
1a250639ca | ||
|
d610036692 | ||
|
f05307d69f | ||
|
cc99ec3edf | ||
|
604dcbc35b | ||
|
b459ba7224 | ||
|
aaa1dc853d | ||
|
cadc974999 | ||
|
d812cf273f | ||
|
0d0398312f | ||
|
39c8fc812d | ||
|
9e89357e64 | ||
|
0638d711d7 | ||
|
dad91594c8 | ||
|
fb77c75520 | ||
|
00adf2aced | ||
|
aaddc58416 | ||
|
5092e21067 | ||
|
388000ded3 | ||
|
567c513d83 | ||
|
1e14dffab0 | ||
|
ed02a0a900 | ||
|
f989698998 | ||
|
0a75480a32 | ||
|
86b470359d | ||
|
9bad668cc5 | ||
|
c18c31ab7f | ||
|
7c24a2f4be | ||
|
56438ea644 | ||
|
7f9bc1e15c | ||
|
6ddae5b654 | ||
|
3ee8da0cae | ||
|
2fd985b9ac | ||
|
3cc87e6acd | ||
|
ac6c6e9996 | ||
|
7c6db44cc7 | ||
|
fb7f524415 | ||
|
fd4f70f62b | ||
|
afd653ba4d | ||
|
9827788176 | ||
|
b1c8cb5632 | ||
|
2924bb5437 | ||
|
7ce954da30 | ||
|
84e8f8b0dc | ||
|
0a2bcf7342 | ||
|
ddd8b99637 | ||
|
705565e4bf | ||
|
92d446e0a3 | ||
|
345c602e07 | ||
|
852991f429 | ||
|
e2f9e87cdf | ||
|
7f0d86a1e5 | ||
|
a97cb65bbc | ||
|
61d32926e7 | ||
|
f0a1b41794 | ||
|
6f902201a9 | ||
|
e5ffe3af0f | ||
|
54cc4898a4 | ||
|
414e60aa48 | ||
|
8869c7b6c2 | ||
|
74f7801f25 | ||
|
3c8a8619f9 | ||
|
35849b1d34 | ||
|
306b043b30 | ||
|
0117f23ee4 | ||
|
8c5eaaf65c | ||
|
529140cf87 | ||
|
d11bdf586a | ||
|
02982464a6 | ||
|
c103bbce14 | ||
|
62e317db05 | ||
|
e0795748a9 | ||
|
7936e789c0 | ||
|
67070ed3d5 | ||
|
fec8c6131c | ||
|
f267d8853b | ||
|
46ce792ef2 | ||
|
074261862d | ||
|
069c7a6b34 | ||
|
7272ad771b | ||
|
74d66a9f1a | ||
|
6244999899 | ||
|
9930359210 | ||
|
84cc1576a8 | ||
|
29b42b3b37 | ||
|
3b15834e8d | ||
|
24ed5bda63 | ||
|
2b9bf6deba | ||
|
0abaeef05e | ||
|
b2e86d2f8a | ||
|
52a3a59623 | ||
|
c78afc46c9 | ||
|
9b89f4ecfb | ||
|
99be29707f | ||
|
2a62bbdbd3 | ||
|
c5e15e93f4 | ||
|
719e0e6104 | ||
|
1eea2400cb | ||
|
83efd67ff8 | ||
|
8ef682dcf9 | ||
|
401d551daa | ||
|
8a533b2003 | ||
|
27f888d0c4 | ||
|
4aeb2fafb2 | ||
|
dbb354ad10 | ||
|
dc20402f5b | ||
|
9b078de9d8 | ||
|
214f9916d9 | ||
|
87aeffa160 | ||
|
14a2d2d795 | ||
|
3560bc62a2 | ||
|
0729d1db27 | ||
|
5f27d425bf | ||
|
e2956c391d | ||
|
bdc8f30705 | ||
|
2c9bf9f03a | ||
|
60c2964acd | ||
|
97248035b1 | ||
|
35c79a2cfb | ||
|
9b9762f940 | ||
|
e186fe8936 | ||
|
213cd419f0 | ||
|
b89b5fef65 | ||
|
92dccbe98d | ||
|
9b775d77f6 | ||
|
4fd6937d05 | ||
|
7230f0e698 | ||
|
ada82538ee | ||
|
e7dd981db6 | ||
|
767bf9f002 | ||
|
f698068587 | ||
|
d0955b4ca2 | ||
|
18e86a7ba3 | ||
|
f9a1ab4d40 | ||
|
062d0898a0 | ||
|
3b51b4fd72 | ||
|
1a78ff4398 | ||
|
544af8d118 | ||
|
2616c377a9 | ||
|
4a63331306 | ||
|
48621443ec | ||
|
79fd66b94c | ||
|
6a6c8c1d83 | ||
|
cf19dacbaf | ||
|
50925abc40 | ||
|
c80cbaa32f | ||
|
f7cb1aef4b | ||
|
96d5d1dfab | ||
|
98d608fec5 | ||
|
1af46b0246 | ||
|
1e530b74d4 | ||
|
e61c4acce5 | ||
|
184499711d | ||
|
2c0181d097 | ||
|
06ea12adb3 | ||
|
9923e5c821 | ||
|
9a06e59cfe | ||
|
80a2cd91f4 | ||
|
df9ed3e487 | ||
|
368d0130f6 | ||
|
824e1b44dd | ||
|
ccf1c8ee31 | ||
|
d5f6d83f6d | ||
|
5d422f85c8 | ||
|
78aeb46d56 | ||
|
091bf45149 | ||
|
8d9d24740b | ||
|
21e5f88cb2 | ||
|
5d4259d064 | ||
|
9ac03ec33a | ||
|
e760276341 | ||
|
206f35ffe5 | ||
|
ddf716479d | ||
|
ec7f94df25 | ||
|
bcbba0973f | ||
|
bd1ddb8522 | ||
|
fb47398554 | ||
|
10356f4009 | ||
|
ba83fca47a | ||
|
b01295f0fd | ||
|
b928e614cc | ||
|
973b9c354c | ||
|
c12444d6e8 | ||
|
1401d28f82 | ||
|
335269f92d | ||
|
6211606a22 | ||
|
5f7d438ac1 | ||
|
ee2df96cfb | ||
|
692e925997 | ||
|
39803f53a0 | ||
|
b3591808b7 | ||
|
2427677fd5 | ||
|
9a051effcd | ||
|
e6e9f92e01 | ||
|
ca6762c891 | ||
|
76d07beb27 | ||
|
f3daa7f0e4 | ||
|
041ad22443 | ||
|
6cd0938ee4 | ||
|
c3dc30ee5d | ||
|
37c925dcf2 | ||
|
05bd51f85c | ||
|
cfbc37df8d | ||
|
36635c452c | ||
|
d08a16c381 | ||
|
1cee10ce12 | ||
|
b06974e104 | ||
|
bfafe7a70c | ||
|
05a29b4509 | ||
|
54f7a83789 | ||
|
1d04ec6b64 | ||
|
99d93f0a85 | ||
|
b78101ef90 | ||
|
6261d30574 | ||
|
672d028d29 | ||
|
0340c7f65c | ||
|
632802e58b | ||
|
c3510bf26b | ||
|
e22aa4f6e9 | ||
|
76a8ae3a83 | ||
|
1c104d2e83 | ||
|
7c38c2c8f2 | ||
|
188d9ac159 | ||
|
91751d5fa3 | ||
|
5124cbfd9b | ||
|
cb21a61d7c | ||
|
f50019d098 | ||
|
ab9a1776c8 | ||
|
a357665c77 | ||
|
be097afd83 | ||
|
b417299616 | ||
|
582b963570 | ||
|
1405def25d | ||
|
e9c598cf46 | ||
|
02361e37f0 | ||
|
041414b11e | ||
|
b4ca00ebf5 | ||
|
9d96866531 | ||
|
6593025051 | ||
|
a38fe11bbe | ||
|
b030ca914d | ||
|
88b44a0f74 | ||
|
7b2cf0e483 | ||
|
5d3e920370 | ||
|
7cec62fc71 | ||
|
698d16e970 | ||
|
d88af474d2 | ||
|
7488129517 | ||
|
9772389fd9 | ||
|
c2a1ea8cba | ||
|
9afc94fb3b | ||
|
390b28c3f5 | ||
|
8be22ed910 | ||
|
b097ab29ee | ||
|
d9bf0b7d82 | ||
|
0f5533af55 | ||
|
1c47db70a0 | ||
|
9723ab0ba6 | ||
|
2b9d519f4b | ||
|
4478ce118a | ||
|
7b56311729 | ||
|
09b52237f2 | ||
|
c7c86c2b52 | ||
|
dce8bced15 | ||
|
a9719307af | ||
|
0c8b475736 | ||
|
dbd3db873f | ||
|
073781da92 | ||
|
7d87d0b394 | ||
|
0cb2a3a385 | ||
|
c1e970a703 | ||
|
17831bf87a | ||
|
a93c558479 | ||
|
13b09aa9a4 | ||
|
e7e5a316f1 | ||
|
703fe35121 | ||
|
a7dddaf2c4 | ||
|
a95a66104d | ||
|
dd47571dff | ||
|
0a2c3b3a91 | ||
|
694ca6480e | ||
|
86b00d0a2b | ||
|
b8c26b2ef3 | ||
|
3343c2b0aa | ||
|
f9c60bd47b | ||
|
71d2256fb7 | ||
|
66fe2f9390 | ||
|
3fe473cdd3 | ||
|
3255f4d63b | ||
|
66036c2027 |
128
.eslintignore
@@ -59,6 +59,8 @@ packages/app-mobile/locales
|
||||
packages/app-mobile/node_modules
|
||||
packages/app-mobile/pluginAssets/
|
||||
packages/fork-*
|
||||
packages/default-plugins/plugin-base-repo/
|
||||
packages/default-plugins/plugin-sources/
|
||||
packages/htmlpack/dist/
|
||||
packages/lib/assets/
|
||||
packages/lib/lib/lib.js
|
||||
@@ -85,13 +87,35 @@ packages/lib/countable/Countable.js
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.js
|
||||
packages/app-cli/app/base-command.js
|
||||
packages/app-cli/app/command-apidoc.js
|
||||
packages/app-cli/app/command-attach.js
|
||||
packages/app-cli/app/command-cat.js
|
||||
packages/app-cli/app/command-config.js
|
||||
packages/app-cli/app/command-cp.js
|
||||
packages/app-cli/app/command-done.test.js
|
||||
packages/app-cli/app/command-done.js
|
||||
packages/app-cli/app/command-dump.js
|
||||
packages/app-cli/app/command-e2ee.js
|
||||
packages/app-cli/app/command-edit.js
|
||||
packages/app-cli/app/command-exit.js
|
||||
packages/app-cli/app/command-export-sync-status.js
|
||||
packages/app-cli/app/command-export.js
|
||||
packages/app-cli/app/command-geoloc.js
|
||||
packages/app-cli/app/command-help.js
|
||||
packages/app-cli/app/command-import.js
|
||||
packages/app-cli/app/command-ls.js
|
||||
packages/app-cli/app/command-mkbook.test.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-mv.js
|
||||
packages/app-cli/app/command-ren.js
|
||||
packages/app-cli/app/command-rmbook.js
|
||||
packages/app-cli/app/command-rmnote.js
|
||||
packages/app-cli/app/command-set.js
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-testing.js
|
||||
packages/app-cli/app/command-use.js
|
||||
packages/app-cli/app/command-version.js
|
||||
packages/app-cli/app/gui/StatusBarWidget.js
|
||||
packages/app-cli/app/services/plugins/PluginRunner.js
|
||||
packages/app-cli/app/setupCommand.js
|
||||
@@ -222,7 +246,6 @@ packages/app-desktop/gui/Navigator.js
|
||||
packages/app-desktop/gui/NoteContentPropertiesDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/setupVim.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.test.js
|
||||
@@ -249,6 +272,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.test.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
|
||||
@@ -260,6 +285,7 @@ packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.test.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
|
||||
@@ -377,11 +403,16 @@ packages/app-desktop/gui/style/StyledTextInput.js
|
||||
packages/app-desktop/gui/utils/NoteListUtils.js
|
||||
packages/app-desktop/gui/utils/convertToScreenCoordinates.js
|
||||
packages/app-desktop/gui/utils/loadScript.js
|
||||
packages/app-desktop/gulpfile.js
|
||||
packages/app-desktop/integration-tests/main.spec.js
|
||||
packages/app-desktop/integration-tests/models/MainScreen.js
|
||||
packages/app-desktop/integration-tests/models/NoteEditorScreen.js
|
||||
packages/app-desktop/integration-tests/models/SettingsScreen.js
|
||||
packages/app-desktop/integration-tests/simpleBackup.spec.js
|
||||
packages/app-desktop/integration-tests/util/activateMainMenuItem.js
|
||||
packages/app-desktop/integration-tests/util/createStartupArgs.js
|
||||
packages/app-desktop/integration-tests/util/firstNonDevToolsWindow.js
|
||||
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
|
||||
packages/app-desktop/integration-tests/util/test.js
|
||||
packages/app-desktop/playwright.config.js
|
||||
packages/app-desktop/plugins/GotoAnything.js
|
||||
@@ -409,12 +440,15 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/copy7Zip.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/tools/renameReleaseAssets.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.test.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtilsTestData.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-desktop/utils/restartInSafeModeFromMain.test.js
|
||||
packages/app-desktop/utils/restartInSafeModeFromMain.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
packages/app-mobile/components/BackButtonDialogBox.js
|
||||
@@ -424,6 +458,7 @@ packages/app-mobile/components/Dropdown.test.js
|
||||
packages/app-mobile/components/Dropdown.js
|
||||
packages/app-mobile/components/ExtendedWebView.js
|
||||
packages/app-mobile/components/FolderPicker.js
|
||||
packages/app-mobile/components/Icon.js
|
||||
packages/app-mobile/components/Modal.js
|
||||
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.test.js
|
||||
@@ -450,10 +485,15 @@ packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToggleSpaceButton.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/Toolbar.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarButton.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarOverflowRows.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useActionButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useHeaderButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useInlineFormattingButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useListButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/types.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js
|
||||
packages/app-mobile/components/NoteEditor/SearchPanel.js
|
||||
packages/app-mobile/components/NoteEditor/hooks/useKeyboardVisible.js
|
||||
packages/app-mobile/components/NoteEditor/types.js
|
||||
packages/app-mobile/components/NoteList.js
|
||||
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
|
||||
@@ -464,17 +504,29 @@ packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/TextInput.js
|
||||
packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/base-screen.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/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreenButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/FileSystemPathSelector.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportDebugReport.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportProfile.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SectionHeader.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SectionSelector.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/types.js
|
||||
packages/app-mobile/components/screens/LogScreen.js
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Notes.js
|
||||
@@ -492,7 +544,10 @@ packages/app-mobile/services/profiles/index.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
packages/app-mobile/setupQuickActions.js
|
||||
packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/tools/buildInjectedJs/BundledFile.js
|
||||
packages/app-mobile/tools/buildInjectedJs/constants.js
|
||||
packages/app-mobile/tools/buildInjectedJs/copyJs.js
|
||||
packages/app-mobile/tools/buildInjectedJs/gulpTasks.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
packages/app-mobile/utils/ShareUtils.test.js
|
||||
packages/app-mobile/utils/ShareUtils.js
|
||||
@@ -506,21 +561,30 @@ packages/app-mobile/utils/fs-driver/runOnDeviceTests.js
|
||||
packages/app-mobile/utils/setupNotifications.js
|
||||
packages/app-mobile/utils/shareHandler.js
|
||||
packages/app-mobile/utils/types.js
|
||||
packages/default-plugins/build.js
|
||||
packages/default-plugins/buildDefaultPlugins.js
|
||||
packages/default-plugins/commands/buildAll.js
|
||||
packages/default-plugins/commands/editPatch.js
|
||||
packages/default-plugins/utils/getPathToPatchFileFor.js
|
||||
packages/default-plugins/utils/readRepositoryJson.js
|
||||
packages/default-plugins/utils/waitForCliInput.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/Decorator.js
|
||||
packages/editor/CodeMirror/CodeMirrorControl.test.js
|
||||
packages/editor/CodeMirror/CodeMirrorControl.js
|
||||
packages/editor/CodeMirror/PluginLoader.js
|
||||
packages/editor/CodeMirror/configFromSettings.js
|
||||
packages/editor/CodeMirror/createEditor.test.js
|
||||
packages/editor/CodeMirror/createEditor.js
|
||||
packages/editor/CodeMirror/editorCommands/editorCommands.js
|
||||
packages/editor/CodeMirror/editorCommands/insertLineAfter.test.js
|
||||
packages/editor/CodeMirror/editorCommands/insertLineAfter.js
|
||||
packages/editor/CodeMirror/editorCommands/supportsCommand.js
|
||||
packages/editor/CodeMirror/editorCommands/swapLine.js
|
||||
packages/editor/CodeMirror/getScrollFraction.js
|
||||
packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js
|
||||
packages/editor/CodeMirror/markdown/computeSelectionFormatting.js
|
||||
packages/editor/CodeMirror/markdown/decoratorExtension.test.js
|
||||
packages/editor/CodeMirror/markdown/decoratorExtension.js
|
||||
packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js
|
||||
packages/editor/CodeMirror/markdown/markdownCommands.test.js
|
||||
@@ -531,12 +595,15 @@ packages/editor/CodeMirror/markdown/markdownMathParser.js
|
||||
packages/editor/CodeMirror/markdown/markdownReformatter.test.js
|
||||
packages/editor/CodeMirror/markdown/markdownReformatter.js
|
||||
packages/editor/CodeMirror/markdown/syntaxHighlightingLanguages.js
|
||||
packages/editor/CodeMirror/pluginApi/PluginLoader.js
|
||||
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
|
||||
packages/editor/CodeMirror/testUtil/createEditorSettings.js
|
||||
packages/editor/CodeMirror/testUtil/createTestEditor.js
|
||||
packages/editor/CodeMirror/testUtil/forceFullParse.js
|
||||
packages/editor/CodeMirror/testUtil/loadLanguages.js
|
||||
packages/editor/CodeMirror/theme.js
|
||||
packages/editor/CodeMirror/util/isInSyntaxNode.js
|
||||
packages/editor/CodeMirror/util/setupVim.js
|
||||
packages/editor/SelectionFormatting.js
|
||||
packages/editor/events.js
|
||||
packages/editor/types.js
|
||||
@@ -597,10 +664,12 @@ packages/lib/commands/index.js
|
||||
packages/lib/commands/openMasterPasswordDialog.js
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||
packages/lib/components/shared/config/config-shared.js
|
||||
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.test.js
|
||||
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.js
|
||||
packages/lib/components/shared/note-screen-shared.js
|
||||
packages/lib/components/shared/reduxSharedMiddleware.js
|
||||
packages/lib/components/shared/side-menu-shared.js
|
||||
packages/lib/database-driver-better-sqlite.js
|
||||
packages/lib/database.js
|
||||
packages/lib/debug/DebugService.js
|
||||
@@ -611,7 +680,9 @@ packages/lib/eventManager.js
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-memory.js
|
||||
packages/lib/file-api-driver.test.js
|
||||
packages/lib/file-api.test.js
|
||||
packages/lib/file-api.js
|
||||
packages/lib/folders-screen-utils.js
|
||||
packages/lib/fs-driver-base.js
|
||||
packages/lib/fs-driver-node.js
|
||||
packages/lib/fsDriver.test.js
|
||||
@@ -628,6 +699,7 @@ packages/lib/import-enex.js
|
||||
packages/lib/initLib.js
|
||||
packages/lib/locale.test.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/makeDiscourseDebugUrl.test.js
|
||||
packages/lib/makeDiscourseDebugUrl.js
|
||||
packages/lib/markdownUtils.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
@@ -658,6 +730,7 @@ packages/lib/models/Search.js
|
||||
packages/lib/models/Setting.test.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/SmartFilter.js
|
||||
packages/lib/models/Tag.test.js
|
||||
packages/lib/models/Tag.js
|
||||
packages/lib/models/dateTimeFormats.test.js
|
||||
packages/lib/models/settings/FileHandler.js
|
||||
@@ -666,11 +739,13 @@ packages/lib/models/utils/itemCanBeEncrypted.js
|
||||
packages/lib/models/utils/paginatedFeed.js
|
||||
packages/lib/models/utils/paginationToSql.js
|
||||
packages/lib/models/utils/readOnly.js
|
||||
packages/lib/models/utils/resourceUtils.js
|
||||
packages/lib/models/utils/types.js
|
||||
packages/lib/models/utils/userData.test.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/net-utils.js
|
||||
packages/lib/ntp.js
|
||||
packages/lib/onedrive-api.test.js
|
||||
packages/lib/onedrive-api.js
|
||||
packages/lib/path-utils.js
|
||||
packages/lib/reducer.js
|
||||
@@ -713,9 +788,13 @@ packages/lib/services/commands/propsHaveChanged.js
|
||||
packages/lib/services/commands/stateToWhenClauseContext.js
|
||||
packages/lib/services/contextkey/contextkey.js
|
||||
packages/lib/services/database/addMigrationFile.js
|
||||
packages/lib/services/database/isSqliteSyntaxError.js
|
||||
packages/lib/services/database/migrations/42.js
|
||||
packages/lib/services/database/migrations/43.js
|
||||
packages/lib/services/database/migrations/44.js
|
||||
packages/lib/services/database/migrations/45.js
|
||||
packages/lib/services/database/migrations/index.js
|
||||
packages/lib/services/database/sqlStringToLines.js
|
||||
packages/lib/services/database/types.js
|
||||
packages/lib/services/debug/populateDatabase.js
|
||||
packages/lib/services/e2ee/EncryptionService.test.js
|
||||
@@ -762,6 +841,13 @@ packages/lib/services/keychain/KeychainServiceDriverBase.js
|
||||
packages/lib/services/noteList/defaultLeftToRightListRenderer.js
|
||||
packages/lib/services/noteList/defaultListRenderer.js
|
||||
packages/lib/services/noteList/renderers.js
|
||||
packages/lib/services/ocr/OcrDriverBase.js
|
||||
packages/lib/services/ocr/OcrService.test.js
|
||||
packages/lib/services/ocr/OcrService.js
|
||||
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
|
||||
packages/lib/services/ocr/utils/filterOcrText.test.js
|
||||
packages/lib/services/ocr/utils/filterOcrText.js
|
||||
packages/lib/services/ocr/utils/types.js
|
||||
packages/lib/services/plugins/BasePlatformImplementation.js
|
||||
packages/lib/services/plugins/BasePluginRunner.js
|
||||
packages/lib/services/plugins/MenuController.js
|
||||
@@ -823,6 +909,7 @@ packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/master_keys.js
|
||||
packages/lib/services/rest/routes/notes.test.js
|
||||
packages/lib/services/rest/routes/notes.js
|
||||
packages/lib/services/rest/routes/ping.js
|
||||
packages/lib/services/rest/routes/resources.js
|
||||
@@ -838,15 +925,17 @@ packages/lib/services/rest/utils/paginatedResults.js
|
||||
packages/lib/services/rest/utils/readonlyProperties.js
|
||||
packages/lib/services/rest/utils/requestFields.js
|
||||
packages/lib/services/rest/utils/requestPaginationOptions.js
|
||||
packages/lib/services/searchengine/SearchEngine.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.test.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchFilter.test.js
|
||||
packages/lib/services/searchengine/filterParser.test.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/queryBuilder.js
|
||||
packages/lib/services/search/SearchEngine.resources.test.js
|
||||
packages/lib/services/search/SearchEngine.test.js
|
||||
packages/lib/services/search/SearchEngine.js
|
||||
packages/lib/services/search/SearchEngineUtils.test.js
|
||||
packages/lib/services/search/SearchEngineUtils.js
|
||||
packages/lib/services/search/SearchFilter.test.js
|
||||
packages/lib/services/search/filterParser.test.js
|
||||
packages/lib/services/search/filterParser.js
|
||||
packages/lib/services/search/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/search/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/search/queryBuilder.js
|
||||
packages/lib/services/share/ShareService.test.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/reducer.js
|
||||
@@ -885,6 +974,7 @@ packages/lib/services/synchronizer/utils/handleSyncStartupOperation.js
|
||||
packages/lib/services/synchronizer/utils/resourceRemotePath.js
|
||||
packages/lib/services/synchronizer/utils/syncDeleteStep.js
|
||||
packages/lib/services/synchronizer/utils/types.js
|
||||
packages/lib/shim-init-node.js
|
||||
packages/lib/shim.js
|
||||
packages/lib/testing/syncTargetUtils.js
|
||||
packages/lib/testing/test-utils-synchronizer.js
|
||||
@@ -900,8 +990,10 @@ packages/lib/themes/solarizedDark.js
|
||||
packages/lib/themes/solarizedLight.js
|
||||
packages/lib/themes/type.js
|
||||
packages/lib/time.js
|
||||
packages/lib/types.js
|
||||
packages/lib/utils/credentialFiles.js
|
||||
packages/lib/utils/joplinCloud.js
|
||||
packages/lib/utils/processStartFlags.js
|
||||
packages/lib/utils/userFetcher.js
|
||||
packages/lib/utils/webDAVUtils.test.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
@@ -940,6 +1032,8 @@ packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugin-repo-cli/lib/validateUntrustedManifest.test.js
|
||||
packages/plugin-repo-cli/lib/validateUntrustedManifest.js
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
@@ -969,13 +1063,15 @@ packages/renderer/MdToHtml/rules/sanitize_html.js
|
||||
packages/renderer/MdToHtml/rules/source_map.js
|
||||
packages/renderer/MdToHtml/setupLinkify.js
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/assetsToHeaders.js
|
||||
packages/renderer/defaultResourceModel.js
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/highlight.js
|
||||
packages/renderer/htmlUtils.test.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/index.js
|
||||
packages/renderer/noteStyle.js
|
||||
packages/renderer/pathUtils.js
|
||||
packages/renderer/types.js
|
||||
packages/renderer/utils.js
|
||||
packages/tools/build-release-stats.test.js
|
||||
packages/tools/build-release-stats.js
|
||||
@@ -983,8 +1079,6 @@ packages/tools/build-translation.js
|
||||
packages/tools/build-welcome.js
|
||||
packages/tools/buildServerDocker.test.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/bundleDefaultPlugins.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/checkIgnoredFiles.js
|
||||
packages/tools/checkLibPaths.test.js
|
||||
packages/tools/checkLibPaths.js
|
||||
|
@@ -157,6 +157,8 @@ module.exports = {
|
||||
// In user-facing text, it should be "notebook".
|
||||
'id-denylist': ['error', 'err', 'notebook', 'notebooks'],
|
||||
'prefer-arrow-callback': ['error'],
|
||||
|
||||
'no-constant-binary-expression': ['error'],
|
||||
},
|
||||
'plugins': [
|
||||
'react',
|
||||
|
62
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Bug Report
|
||||
description: Report a reproducible bug or regression in Joplin.
|
||||
labels: ['bug']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: "Operating system"
|
||||
multiple: false
|
||||
options:
|
||||
- "Windows"
|
||||
- "macOS"
|
||||
- "Linux"
|
||||
- "Android"
|
||||
- "iOS"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: "Joplin version"
|
||||
placeholder: "For example 1.0.5"
|
||||
description: Please note that we will close the issue if the exact version is not provided, as we cannot help without this.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: desktop-about-content
|
||||
attributes:
|
||||
label: "Desktop version info"
|
||||
description: "If this issue is about the **desktop app**, please open the \"About\" dialog under the \"Help\" or \"Joplin\" menu and copy its content here."
|
||||
placeholder: "Joplin 2.13.5 (dev, darwin)\n\nClient ID: ..."
|
||||
|
||||
- type: textarea
|
||||
id: current
|
||||
attributes:
|
||||
label: Current behaviour
|
||||
description: What did Joplin do? Include screenshots and video recordings for UI problems if needed. If you are reporting a clipper bug, please include an example URL that shows the issue.
|
||||
placeholder: |
|
||||
1. This
|
||||
2. Then that
|
||||
3. Then this
|
||||
4. Etc.
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: What did you expect Joplin to do?
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: "If relevant, please provide a log file as described here: https://joplinapp.org/help/apps/debugging"
|
52
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,52 +0,0 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: Report a reproducible bug or regression in Joplin.
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please provide a clear and concise description of what the bug is. (In the section Steps To Reproduce.)
|
||||
Include screenshots for UI problems if needed.
|
||||
DO NOT create screenshots of text !!! Copy and paste the text into a code block.
|
||||
Please test using the latest Joplin release to make sure your issue has not already been fixed.
|
||||
-->
|
||||
|
||||
<!--
|
||||
IMPORTANT: If you are reporting a clipper bug, please include an example URL that shows the issue.
|
||||
Without the URL the issue is likely to be closed.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
|
||||
Joplin version:
|
||||
Platform:
|
||||
OS specifics:
|
||||
|
||||
<!--
|
||||
Platform can be one of: macOS, Linux, Windows, Android, iOS, terminal (or a combination)
|
||||
OS specifics: e.g. OS version, Linux distribution, Android/iOS version...
|
||||
-->
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
<!--
|
||||
Issues without reproduction steps are likely to stall.
|
||||
-->
|
||||
|
||||
## Describe what you expected to happen
|
||||
|
||||
|
||||
|
||||
## Logfile
|
||||
|
||||
<!--
|
||||
Please attach a debug log. Issues without a debug log are likely to stall.
|
||||
For information on how to collect a log file: https://joplinapp.org/help/apps/debugging/
|
||||
-->
|
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: "\U0001F914 Feature requests and support"
|
||||
url: https://discourse.joplinapp.org/
|
||||
about: I have a question or feature request …
|
||||
- name: Feature Requests
|
||||
url: https://discourse.joplinapp.org/c/features/
|
||||
about: Discuss ideas for new features or changes
|
||||
- name: Support
|
||||
url: https://discourse.joplinapp.org/c/support/
|
||||
about: Please ask for help here
|
56
.github/scripts/run_ci.sh
vendored
@@ -8,16 +8,23 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
ROOT_DIR="$SCRIPT_DIR/../.."
|
||||
|
||||
IS_PULL_REQUEST=0
|
||||
IS_DEV_BRANCH=0
|
||||
IS_DESKTOP_RELEASE=0
|
||||
IS_SERVER_RELEASE=0
|
||||
IS_LINUX=0
|
||||
IS_MACOS=0
|
||||
|
||||
# If pull requests are coming from a branch of the main repository,
|
||||
# IS_PULL_REQUEST will be zero.
|
||||
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
|
||||
IS_PULL_REQUEST=1
|
||||
fi
|
||||
|
||||
if [ "$GITHUB_REF" == "refs/heads/dev" ]; then
|
||||
IS_DEV_BRANCH=1
|
||||
if [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
|
||||
IS_SERVER_RELEASE=1
|
||||
fi
|
||||
|
||||
if [[ $GIT_TAG_NAME = v* ]]; then
|
||||
IS_DESKTOP_RELEASE=1
|
||||
fi
|
||||
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
@@ -28,6 +35,14 @@ else
|
||||
IS_MACOS=1
|
||||
fi
|
||||
|
||||
# Tests can randomly fail in some cases, so only run them when not publishing
|
||||
# a release
|
||||
RUN_TESTS=0
|
||||
|
||||
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ]; then
|
||||
RUN_TESTS=1
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Print environment
|
||||
# =============================================================================
|
||||
@@ -43,7 +58,9 @@ echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX"
|
||||
|
||||
echo "IS_CONTINUOUS_INTEGRATION=$IS_CONTINUOUS_INTEGRATION"
|
||||
echo "IS_PULL_REQUEST=$IS_PULL_REQUEST"
|
||||
echo "IS_DEV_BRANCH=$IS_DEV_BRANCH"
|
||||
echo "IS_DESKTOP_RELEASE=$IS_DESKTOP_RELEASE"
|
||||
echo "IS_SERVER_RELEASE=$IS_SERVER_RELEASE"
|
||||
echo "RUN_TESTS=$RUN_TESTS"
|
||||
echo "IS_LINUX=$IS_LINUX"
|
||||
echo "IS_MACOS=$IS_MACOS"
|
||||
|
||||
@@ -64,17 +81,20 @@ if [ $testResult -ne 0 ]; then
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Run test units. Only do it for pull requests and dev branch because we don't
|
||||
# want it to randomly fail when trying to create a desktop release.
|
||||
# Run test units
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ "$RUN_TESTS" == "1" ]; then
|
||||
echo "Step: Running tests..."
|
||||
|
||||
# On Linux, we run the Joplin Server tests using PostgreSQL
|
||||
if [ "$IS_LINUX" == "1" ]; then
|
||||
echo "Running Joplin Server tests using PostgreSQL..."
|
||||
sudo docker-compose --file docker-compose.db-dev.yml up -d
|
||||
cmdResult=$?
|
||||
if [ $cmdResult -ne 0 ]; then
|
||||
exit $cmdResult
|
||||
fi
|
||||
export JOPLIN_TESTS_SERVER_DB=pg
|
||||
else
|
||||
echo "Running Joplin Server tests using SQLite..."
|
||||
@@ -94,23 +114,12 @@ if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Check that the website builder can run without errors
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ "$IS_LINUX" == "1" ]; then
|
||||
echo "Step: Running website builder..."
|
||||
node packages/tools/website/processDocs.js --env dev
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Run linter for pull requests only. We also don't want this to make the desktop
|
||||
# release randomly fail.
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ "$RUN_TESTS" == "1" ]; then
|
||||
echo "Step: Running linter..."
|
||||
|
||||
yarn run linter-ci ./
|
||||
@@ -150,7 +159,7 @@ fi
|
||||
# what commit may have broken translation building.
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ "$RUN_TESTS" == "1" ]; then
|
||||
if [ "$IS_LINUX" == "1" ]; then
|
||||
echo "Step: Checking for lost translation strings..."
|
||||
|
||||
@@ -186,10 +195,11 @@ fi
|
||||
# Check that the website still builds
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ "$RUN_TESTS" == "1" ]; then
|
||||
echo "Step: Check that the website still builds..."
|
||||
|
||||
mkdir -p ../joplin-website/docs
|
||||
ll ../joplin-website/docs/api/references/plugin_api
|
||||
SKIP_SPONSOR_PROCESSING=1 yarn run buildWebsite
|
||||
testResult=$?
|
||||
if [ $testResult -ne 0 ]; then
|
||||
@@ -222,7 +232,7 @@ fi
|
||||
|
||||
cd "$ROOT_DIR/packages/app-desktop"
|
||||
|
||||
if [[ $GIT_TAG_NAME = v* ]]; then
|
||||
if [ "$IS_DESKTOP_RELEASE" == "1" ]; then
|
||||
echo "Step: Building and publishing desktop application..."
|
||||
# cd "$ROOT_DIR/packages/tools"
|
||||
# node bundleDefaultPlugins.js
|
||||
@@ -247,7 +257,7 @@ if [[ $GIT_TAG_NAME = v* ]]; then
|
||||
else
|
||||
USE_HARD_LINKS=false yarn run dist
|
||||
fi
|
||||
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
|
||||
elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then
|
||||
echo "Step: Building Docker Image..."
|
||||
cd "$ROOT_DIR"
|
||||
yarn run buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
|
||||
|
2
.github/workflows/build-android.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
sudo apt-get update || true
|
||||
sudo apt-get install -y libsecret-1-dev
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
|
13
.github/workflows/build-macos-m1.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: olegtarasov/get-tag@v2.1
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -33,6 +33,17 @@ jobs:
|
||||
# https://yarnpkg.com/getting-started/install
|
||||
corepack enable
|
||||
|
||||
- name: Install macOs dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
# Required for building the canvas package
|
||||
brew install pango
|
||||
|
||||
# See github-action-main.yml for explanation
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Build macOS M1 app
|
||||
env:
|
||||
APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }}
|
||||
|
9
.github/workflows/check-pr-title.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
name: Check pull request title
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Slashgear/action-check-pr-title@v4.3.0
|
||||
with:
|
||||
regexp: "(Desktop|Mobile|All|Cli|Tools|Chore|Clipper|Server|Android|iOS|Plugins|CI|Plugin Repo|Doc): (Fixes|Resolves) #[0-9]+: .+"
|
14
.github/workflows/comment-on-failure.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: comment-on-failure
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Joplin Continuous Integration
|
||||
- react-native-android-build-apk
|
||||
- Build macOS M1
|
||||
types: [ completed ]
|
||||
|
||||
jobs:
|
||||
comment-failure:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: quipper/comment-failure-action@v0.1.1
|
21
.github/workflows/github-actions-main.yml
vendored
@@ -59,6 +59,12 @@ jobs:
|
||||
# testing.
|
||||
sudo apt-get install -y xvfb
|
||||
|
||||
- name: Install macOs dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
# Required for building the canvas package
|
||||
brew install pango
|
||||
|
||||
- name: Install Docker Engine
|
||||
# if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
|
||||
if: runner.os == 'Linux'
|
||||
@@ -75,7 +81,7 @@ jobs:
|
||||
sudo apt-get update || true
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: olegtarasov/get-tag@v2.1
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -92,12 +98,21 @@ jobs:
|
||||
# Login to Docker only if we're on a server release tag. If we run this on
|
||||
# a pull request it will fail because the PR doesn't have access to
|
||||
# secrets
|
||||
- uses: docker/login-action@v2
|
||||
- uses: docker/login-action@v3
|
||||
if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# macos-latest ships with Python 3.12 by default, but this removes a
|
||||
# utility that's used by electron-builder (distutils) so we need to pin
|
||||
# Python to an earlier version.
|
||||
# Fixes error `ModuleNotFoundError: No module named 'distutils'`
|
||||
# Ref: https://github.com/nodejs/node-gyp/issues/2869
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Run tests, build and publish Linux and macOS apps
|
||||
if: runner.os == 'Linux' || runner.os == 'macOs'
|
||||
env:
|
||||
@@ -165,7 +180,7 @@ jobs:
|
||||
sudo apt-get update || true
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
|
127
.gitignore
vendored
@@ -51,6 +51,7 @@ lerna-debug.log
|
||||
.env
|
||||
docs/**/*.mustache
|
||||
.idea
|
||||
/readme/i18n
|
||||
|
||||
# Yarn stuff
|
||||
# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
|
||||
@@ -66,13 +67,35 @@ docs/**/*.mustache
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.js
|
||||
packages/app-cli/app/base-command.js
|
||||
packages/app-cli/app/command-apidoc.js
|
||||
packages/app-cli/app/command-attach.js
|
||||
packages/app-cli/app/command-cat.js
|
||||
packages/app-cli/app/command-config.js
|
||||
packages/app-cli/app/command-cp.js
|
||||
packages/app-cli/app/command-done.test.js
|
||||
packages/app-cli/app/command-done.js
|
||||
packages/app-cli/app/command-dump.js
|
||||
packages/app-cli/app/command-e2ee.js
|
||||
packages/app-cli/app/command-edit.js
|
||||
packages/app-cli/app/command-exit.js
|
||||
packages/app-cli/app/command-export-sync-status.js
|
||||
packages/app-cli/app/command-export.js
|
||||
packages/app-cli/app/command-geoloc.js
|
||||
packages/app-cli/app/command-help.js
|
||||
packages/app-cli/app/command-import.js
|
||||
packages/app-cli/app/command-ls.js
|
||||
packages/app-cli/app/command-mkbook.test.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-mv.js
|
||||
packages/app-cli/app/command-ren.js
|
||||
packages/app-cli/app/command-rmbook.js
|
||||
packages/app-cli/app/command-rmnote.js
|
||||
packages/app-cli/app/command-set.js
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-testing.js
|
||||
packages/app-cli/app/command-use.js
|
||||
packages/app-cli/app/command-version.js
|
||||
packages/app-cli/app/gui/StatusBarWidget.js
|
||||
packages/app-cli/app/services/plugins/PluginRunner.js
|
||||
packages/app-cli/app/setupCommand.js
|
||||
@@ -203,7 +226,6 @@ packages/app-desktop/gui/Navigator.js
|
||||
packages/app-desktop/gui/NoteContentPropertiesDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/setupVim.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.test.js
|
||||
@@ -230,6 +252,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.test.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
|
||||
@@ -241,6 +265,7 @@ packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.test.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
|
||||
@@ -358,11 +383,16 @@ packages/app-desktop/gui/style/StyledTextInput.js
|
||||
packages/app-desktop/gui/utils/NoteListUtils.js
|
||||
packages/app-desktop/gui/utils/convertToScreenCoordinates.js
|
||||
packages/app-desktop/gui/utils/loadScript.js
|
||||
packages/app-desktop/gulpfile.js
|
||||
packages/app-desktop/integration-tests/main.spec.js
|
||||
packages/app-desktop/integration-tests/models/MainScreen.js
|
||||
packages/app-desktop/integration-tests/models/NoteEditorScreen.js
|
||||
packages/app-desktop/integration-tests/models/SettingsScreen.js
|
||||
packages/app-desktop/integration-tests/simpleBackup.spec.js
|
||||
packages/app-desktop/integration-tests/util/activateMainMenuItem.js
|
||||
packages/app-desktop/integration-tests/util/createStartupArgs.js
|
||||
packages/app-desktop/integration-tests/util/firstNonDevToolsWindow.js
|
||||
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
|
||||
packages/app-desktop/integration-tests/util/test.js
|
||||
packages/app-desktop/playwright.config.js
|
||||
packages/app-desktop/plugins/GotoAnything.js
|
||||
@@ -390,12 +420,15 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/copy7Zip.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/tools/renameReleaseAssets.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.test.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtilsTestData.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-desktop/utils/restartInSafeModeFromMain.test.js
|
||||
packages/app-desktop/utils/restartInSafeModeFromMain.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
packages/app-mobile/components/BackButtonDialogBox.js
|
||||
@@ -405,6 +438,7 @@ packages/app-mobile/components/Dropdown.test.js
|
||||
packages/app-mobile/components/Dropdown.js
|
||||
packages/app-mobile/components/ExtendedWebView.js
|
||||
packages/app-mobile/components/FolderPicker.js
|
||||
packages/app-mobile/components/Icon.js
|
||||
packages/app-mobile/components/Modal.js
|
||||
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.test.js
|
||||
@@ -431,10 +465,15 @@ packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToggleSpaceButton.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/Toolbar.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarButton.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarOverflowRows.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useActionButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useHeaderButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useInlineFormattingButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/buttons/useListButtons.js
|
||||
packages/app-mobile/components/NoteEditor/MarkdownToolbar/types.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js
|
||||
packages/app-mobile/components/NoteEditor/SearchPanel.js
|
||||
packages/app-mobile/components/NoteEditor/hooks/useKeyboardVisible.js
|
||||
packages/app-mobile/components/NoteEditor/types.js
|
||||
packages/app-mobile/components/NoteList.js
|
||||
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
|
||||
@@ -445,17 +484,29 @@ packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/TextInput.js
|
||||
packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/base-screen.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/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreenButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/FileSystemPathSelector.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportDebugReport.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/exportProfile.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SectionHeader.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SectionSelector.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/types.js
|
||||
packages/app-mobile/components/screens/LogScreen.js
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Notes.js
|
||||
@@ -473,7 +524,10 @@ packages/app-mobile/services/profiles/index.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
packages/app-mobile/setupQuickActions.js
|
||||
packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/tools/buildInjectedJs/BundledFile.js
|
||||
packages/app-mobile/tools/buildInjectedJs/constants.js
|
||||
packages/app-mobile/tools/buildInjectedJs/copyJs.js
|
||||
packages/app-mobile/tools/buildInjectedJs/gulpTasks.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
packages/app-mobile/utils/ShareUtils.test.js
|
||||
packages/app-mobile/utils/ShareUtils.js
|
||||
@@ -487,21 +541,30 @@ packages/app-mobile/utils/fs-driver/runOnDeviceTests.js
|
||||
packages/app-mobile/utils/setupNotifications.js
|
||||
packages/app-mobile/utils/shareHandler.js
|
||||
packages/app-mobile/utils/types.js
|
||||
packages/default-plugins/build.js
|
||||
packages/default-plugins/buildDefaultPlugins.js
|
||||
packages/default-plugins/commands/buildAll.js
|
||||
packages/default-plugins/commands/editPatch.js
|
||||
packages/default-plugins/utils/getPathToPatchFileFor.js
|
||||
packages/default-plugins/utils/readRepositoryJson.js
|
||||
packages/default-plugins/utils/waitForCliInput.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.js
|
||||
packages/editor/CodeMirror/CodeMirror5Emulation/Decorator.js
|
||||
packages/editor/CodeMirror/CodeMirrorControl.test.js
|
||||
packages/editor/CodeMirror/CodeMirrorControl.js
|
||||
packages/editor/CodeMirror/PluginLoader.js
|
||||
packages/editor/CodeMirror/configFromSettings.js
|
||||
packages/editor/CodeMirror/createEditor.test.js
|
||||
packages/editor/CodeMirror/createEditor.js
|
||||
packages/editor/CodeMirror/editorCommands/editorCommands.js
|
||||
packages/editor/CodeMirror/editorCommands/insertLineAfter.test.js
|
||||
packages/editor/CodeMirror/editorCommands/insertLineAfter.js
|
||||
packages/editor/CodeMirror/editorCommands/supportsCommand.js
|
||||
packages/editor/CodeMirror/editorCommands/swapLine.js
|
||||
packages/editor/CodeMirror/getScrollFraction.js
|
||||
packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js
|
||||
packages/editor/CodeMirror/markdown/computeSelectionFormatting.js
|
||||
packages/editor/CodeMirror/markdown/decoratorExtension.test.js
|
||||
packages/editor/CodeMirror/markdown/decoratorExtension.js
|
||||
packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js
|
||||
packages/editor/CodeMirror/markdown/markdownCommands.test.js
|
||||
@@ -512,12 +575,15 @@ packages/editor/CodeMirror/markdown/markdownMathParser.js
|
||||
packages/editor/CodeMirror/markdown/markdownReformatter.test.js
|
||||
packages/editor/CodeMirror/markdown/markdownReformatter.js
|
||||
packages/editor/CodeMirror/markdown/syntaxHighlightingLanguages.js
|
||||
packages/editor/CodeMirror/pluginApi/PluginLoader.js
|
||||
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
|
||||
packages/editor/CodeMirror/testUtil/createEditorSettings.js
|
||||
packages/editor/CodeMirror/testUtil/createTestEditor.js
|
||||
packages/editor/CodeMirror/testUtil/forceFullParse.js
|
||||
packages/editor/CodeMirror/testUtil/loadLanguages.js
|
||||
packages/editor/CodeMirror/theme.js
|
||||
packages/editor/CodeMirror/util/isInSyntaxNode.js
|
||||
packages/editor/CodeMirror/util/setupVim.js
|
||||
packages/editor/SelectionFormatting.js
|
||||
packages/editor/events.js
|
||||
packages/editor/types.js
|
||||
@@ -578,10 +644,12 @@ packages/lib/commands/index.js
|
||||
packages/lib/commands/openMasterPasswordDialog.js
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||
packages/lib/components/shared/config/config-shared.js
|
||||
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.test.js
|
||||
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.js
|
||||
packages/lib/components/shared/note-screen-shared.js
|
||||
packages/lib/components/shared/reduxSharedMiddleware.js
|
||||
packages/lib/components/shared/side-menu-shared.js
|
||||
packages/lib/database-driver-better-sqlite.js
|
||||
packages/lib/database.js
|
||||
packages/lib/debug/DebugService.js
|
||||
@@ -592,7 +660,9 @@ packages/lib/eventManager.js
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-memory.js
|
||||
packages/lib/file-api-driver.test.js
|
||||
packages/lib/file-api.test.js
|
||||
packages/lib/file-api.js
|
||||
packages/lib/folders-screen-utils.js
|
||||
packages/lib/fs-driver-base.js
|
||||
packages/lib/fs-driver-node.js
|
||||
packages/lib/fsDriver.test.js
|
||||
@@ -609,6 +679,7 @@ packages/lib/import-enex.js
|
||||
packages/lib/initLib.js
|
||||
packages/lib/locale.test.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/makeDiscourseDebugUrl.test.js
|
||||
packages/lib/makeDiscourseDebugUrl.js
|
||||
packages/lib/markdownUtils.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
@@ -639,6 +710,7 @@ packages/lib/models/Search.js
|
||||
packages/lib/models/Setting.test.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/SmartFilter.js
|
||||
packages/lib/models/Tag.test.js
|
||||
packages/lib/models/Tag.js
|
||||
packages/lib/models/dateTimeFormats.test.js
|
||||
packages/lib/models/settings/FileHandler.js
|
||||
@@ -647,11 +719,13 @@ packages/lib/models/utils/itemCanBeEncrypted.js
|
||||
packages/lib/models/utils/paginatedFeed.js
|
||||
packages/lib/models/utils/paginationToSql.js
|
||||
packages/lib/models/utils/readOnly.js
|
||||
packages/lib/models/utils/resourceUtils.js
|
||||
packages/lib/models/utils/types.js
|
||||
packages/lib/models/utils/userData.test.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/net-utils.js
|
||||
packages/lib/ntp.js
|
||||
packages/lib/onedrive-api.test.js
|
||||
packages/lib/onedrive-api.js
|
||||
packages/lib/path-utils.js
|
||||
packages/lib/reducer.js
|
||||
@@ -694,9 +768,13 @@ packages/lib/services/commands/propsHaveChanged.js
|
||||
packages/lib/services/commands/stateToWhenClauseContext.js
|
||||
packages/lib/services/contextkey/contextkey.js
|
||||
packages/lib/services/database/addMigrationFile.js
|
||||
packages/lib/services/database/isSqliteSyntaxError.js
|
||||
packages/lib/services/database/migrations/42.js
|
||||
packages/lib/services/database/migrations/43.js
|
||||
packages/lib/services/database/migrations/44.js
|
||||
packages/lib/services/database/migrations/45.js
|
||||
packages/lib/services/database/migrations/index.js
|
||||
packages/lib/services/database/sqlStringToLines.js
|
||||
packages/lib/services/database/types.js
|
||||
packages/lib/services/debug/populateDatabase.js
|
||||
packages/lib/services/e2ee/EncryptionService.test.js
|
||||
@@ -743,6 +821,13 @@ packages/lib/services/keychain/KeychainServiceDriverBase.js
|
||||
packages/lib/services/noteList/defaultLeftToRightListRenderer.js
|
||||
packages/lib/services/noteList/defaultListRenderer.js
|
||||
packages/lib/services/noteList/renderers.js
|
||||
packages/lib/services/ocr/OcrDriverBase.js
|
||||
packages/lib/services/ocr/OcrService.test.js
|
||||
packages/lib/services/ocr/OcrService.js
|
||||
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
|
||||
packages/lib/services/ocr/utils/filterOcrText.test.js
|
||||
packages/lib/services/ocr/utils/filterOcrText.js
|
||||
packages/lib/services/ocr/utils/types.js
|
||||
packages/lib/services/plugins/BasePlatformImplementation.js
|
||||
packages/lib/services/plugins/BasePluginRunner.js
|
||||
packages/lib/services/plugins/MenuController.js
|
||||
@@ -804,6 +889,7 @@ packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/master_keys.js
|
||||
packages/lib/services/rest/routes/notes.test.js
|
||||
packages/lib/services/rest/routes/notes.js
|
||||
packages/lib/services/rest/routes/ping.js
|
||||
packages/lib/services/rest/routes/resources.js
|
||||
@@ -819,15 +905,17 @@ packages/lib/services/rest/utils/paginatedResults.js
|
||||
packages/lib/services/rest/utils/readonlyProperties.js
|
||||
packages/lib/services/rest/utils/requestFields.js
|
||||
packages/lib/services/rest/utils/requestPaginationOptions.js
|
||||
packages/lib/services/searchengine/SearchEngine.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.test.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchFilter.test.js
|
||||
packages/lib/services/searchengine/filterParser.test.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/queryBuilder.js
|
||||
packages/lib/services/search/SearchEngine.resources.test.js
|
||||
packages/lib/services/search/SearchEngine.test.js
|
||||
packages/lib/services/search/SearchEngine.js
|
||||
packages/lib/services/search/SearchEngineUtils.test.js
|
||||
packages/lib/services/search/SearchEngineUtils.js
|
||||
packages/lib/services/search/SearchFilter.test.js
|
||||
packages/lib/services/search/filterParser.test.js
|
||||
packages/lib/services/search/filterParser.js
|
||||
packages/lib/services/search/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/search/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/search/queryBuilder.js
|
||||
packages/lib/services/share/ShareService.test.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/reducer.js
|
||||
@@ -866,6 +954,7 @@ packages/lib/services/synchronizer/utils/handleSyncStartupOperation.js
|
||||
packages/lib/services/synchronizer/utils/resourceRemotePath.js
|
||||
packages/lib/services/synchronizer/utils/syncDeleteStep.js
|
||||
packages/lib/services/synchronizer/utils/types.js
|
||||
packages/lib/shim-init-node.js
|
||||
packages/lib/shim.js
|
||||
packages/lib/testing/syncTargetUtils.js
|
||||
packages/lib/testing/test-utils-synchronizer.js
|
||||
@@ -881,8 +970,10 @@ packages/lib/themes/solarizedDark.js
|
||||
packages/lib/themes/solarizedLight.js
|
||||
packages/lib/themes/type.js
|
||||
packages/lib/time.js
|
||||
packages/lib/types.js
|
||||
packages/lib/utils/credentialFiles.js
|
||||
packages/lib/utils/joplinCloud.js
|
||||
packages/lib/utils/processStartFlags.js
|
||||
packages/lib/utils/userFetcher.js
|
||||
packages/lib/utils/webDAVUtils.test.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
@@ -921,6 +1012,8 @@ packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugin-repo-cli/lib/validateUntrustedManifest.test.js
|
||||
packages/plugin-repo-cli/lib/validateUntrustedManifest.js
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
@@ -950,13 +1043,15 @@ packages/renderer/MdToHtml/rules/sanitize_html.js
|
||||
packages/renderer/MdToHtml/rules/source_map.js
|
||||
packages/renderer/MdToHtml/setupLinkify.js
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/assetsToHeaders.js
|
||||
packages/renderer/defaultResourceModel.js
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/highlight.js
|
||||
packages/renderer/htmlUtils.test.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/index.js
|
||||
packages/renderer/noteStyle.js
|
||||
packages/renderer/pathUtils.js
|
||||
packages/renderer/types.js
|
||||
packages/renderer/utils.js
|
||||
packages/tools/build-release-stats.test.js
|
||||
packages/tools/build-release-stats.js
|
||||
@@ -964,8 +1059,6 @@ packages/tools/build-translation.js
|
||||
packages/tools/build-welcome.js
|
||||
packages/tools/buildServerDocker.test.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/bundleDefaultPlugins.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/checkIgnoredFiles.js
|
||||
packages/tools/checkLibPaths.test.js
|
||||
packages/tools/checkLibPaths.js
|
||||
|
@@ -1,3 +1,5 @@
|
||||
packages/app-clipper/popup/
|
||||
packages/app-cli/tests/support/plugins/
|
||||
packages/doc-builder/
|
||||
packages/doc-builder/
|
||||
packages/default-plugins/plugin-base-repo/
|
||||
packages/default-plugins/plugin-sources/
|
12
.yarn/patches/nanoid-npm-3.3.7-98824ba130.patch
Normal file
@@ -0,0 +1,12 @@
|
||||
diff --git a/package.json b/package.json
|
||||
index 4f24d9658ca167733dbe9c3fb3bcfc3f4e6d20c8..15062cc4eb3bc8e14b54b07a9c873e5a5c4b6ab8 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -35,7 +35,6 @@
|
||||
"module": "index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
- "browser": "./index.browser.js",
|
||||
"require": {
|
||||
"types": "./index.d.cts",
|
||||
"default": "./index.cjs"
|
15
.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
# We remove the `canvas` optional dependency because electron-rebuild fails to build it, and
|
||||
# the `canvas` API is already part of Electron
|
||||
diff --git a/package.json b/package.json
|
||||
index 105811f53d508486e08a60dc1b6e437cd24d7427..dea6a4e6612c4a4006cc482e46ff5270dcfda1e5 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -13,7 +13,6 @@
|
||||
"bugs": "https://github.com/mozilla/pdf.js/issues",
|
||||
"license": "Apache-2.0",
|
||||
"optionalDependencies": {
|
||||
- "canvas": "^2.11.2",
|
||||
"path2d-polyfill": "^2.0.1"
|
||||
},
|
||||
"browser": {
|
@@ -6,7 +6,7 @@ plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||
spec: "@yarnpkg/plugin-workspace-tools"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.6.3.cjs
|
||||
yarnPath: .yarn/releases/yarn-3.6.4.cjs
|
||||
|
||||
logFilters:
|
||||
|
||||
|
BIN
Assets/BadgeMacOSM1.psd
Normal file
@@ -23,6 +23,7 @@ module.exports = {
|
||||
return `joplin.${camelCaseToDots(p)
|
||||
.replace(/menu\.items/, 'menuItems')
|
||||
.replace(/toolbar\.buttons/, 'toolbarButtons')
|
||||
.replace(/note\.list/, 'noteList')
|
||||
.replace(/content\.scripts/, 'contentScripts')}`;
|
||||
},
|
||||
|
||||
|
BIN
Assets/WebsiteAssets/images/BadgeMacOSM1.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
Assets/WebsiteAssets/images/news/20231203-drawing.png
Normal file
After Width: | Height: | Size: 973 KiB |
BIN
Assets/WebsiteAssets/images/news/20231203-rte-table.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
Assets/WebsiteAssets/images/news/20231203-settings.png
Normal file
After Width: | Height: | Size: 143 KiB |
BIN
Assets/WebsiteAssets/images/ocr/search_results.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
Assets/WebsiteAssets/images/publish_note/Banner.png
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
Assets/WebsiteAssets/images/sponsors/SortedTravel.png
Normal file
After Width: | Height: | Size: 21 KiB |
@@ -1,6 +1,31 @@
|
||||
function getOs() {
|
||||
async function getOs() {
|
||||
|
||||
// The macOS release is available for Intel and Apple silicon processors,
|
||||
// and the only way to get that info is through this new
|
||||
// `getHighEntropyValues` function (which is not available on all browsers).
|
||||
// So here we either return "macOs" for Intel or "macOsM1" for Apple
|
||||
// Silicon. If we don't know which it is, we return "macOsUndefined".
|
||||
// https://stackoverflow.com/a/75177111/561309
|
||||
|
||||
if (navigator.appVersion.indexOf("Mac")!=-1) {
|
||||
let platformInfo = null;
|
||||
try {
|
||||
platformInfo = await navigator.userAgentData.getHighEntropyValues(['architecture'])
|
||||
} catch (error) {
|
||||
console.warn('Failed getting Mac architecture:', error);
|
||||
return 'macOsUndefined';
|
||||
}
|
||||
|
||||
console.info('Got platform info:', platformInfo);
|
||||
|
||||
if (platformInfo.architecture === 'arm') {
|
||||
return "macOsM1";
|
||||
} else {
|
||||
return "macOs";
|
||||
}
|
||||
}
|
||||
|
||||
if (navigator.appVersion.indexOf("Win")!=-1) return "windows";
|
||||
if (navigator.appVersion.indexOf("Mac")!=-1) return "macOs";
|
||||
if (navigator.appVersion.indexOf("X11")!=-1) return "linux";
|
||||
if (navigator.appVersion.indexOf("Linux")!=-1) return "linux";
|
||||
return null;
|
||||
@@ -45,7 +70,7 @@ function setupMobileMenu() {
|
||||
});
|
||||
}
|
||||
|
||||
function setupDownloadPage() {
|
||||
async function setupDownloadPage() {
|
||||
if (!$('.page-download').length) return;
|
||||
|
||||
const downloadLinks = {};
|
||||
@@ -55,6 +80,7 @@ function setupDownloadPage() {
|
||||
|
||||
if (href.indexOf('-Setup') > 0) downloadLinks['windows'] = href;
|
||||
if (href.indexOf('.dmg') > 0) downloadLinks['macOs'] = href;
|
||||
if (href.endsWith('arm64.DMG')) downloadLinks['macOsM1'] = href;
|
||||
if (href.indexOf('.AppImage') > 0) downloadLinks['linux'] = href;
|
||||
});
|
||||
|
||||
@@ -70,8 +96,17 @@ function setupDownloadPage() {
|
||||
if (mobileOs) {
|
||||
$('.page-download .intro').hide();
|
||||
} else {
|
||||
const os = getOs();
|
||||
if (!os || !downloadLinks[os]) {
|
||||
const os = await getOs();
|
||||
|
||||
if (os === 'macOsUndefined') {
|
||||
// If we don't know which macOS version it is, we let the user choose.
|
||||
$('.main-content .intro').html('<p class="macos-m1-info">The macOS release is available for Intel processors or for Apple Silicon (M1) processors. Please select your version:</p>');
|
||||
const macOsLink = $('.download-link-macOs');
|
||||
const macOsM1Link = $('.download-link-macOsM1');
|
||||
$('.macos-m1-info').after('<p style="font-style: italic; font-size: .8em;">To find out what processor you have, click on the <b>Apple logo</b> in the macOS menu bar, choose <b>About This Mac</b> from the dropdown menu. If you have an Apple silicon it should say"Apple M1" under "Chip". Otherwise you have an Intel processor.</p>');
|
||||
$('.macos-m1-info').after(macOsM1Link);
|
||||
$('.macos-m1-info').after(macOsLink);
|
||||
} else if (!os || !downloadLinks[os]) {
|
||||
// If we don't know, display the section to manually download the app
|
||||
$('.page-download .get-it-desktop').show();
|
||||
} else if (os === 'linux') {
|
||||
@@ -89,5 +124,5 @@ function setupDownloadPage() {
|
||||
|
||||
$(function () {
|
||||
setupMobileMenu();
|
||||
setupDownloadPage();
|
||||
void setupDownloadPage();
|
||||
});
|
||||
|
@@ -1,4 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Mon, 23 Oct 2023 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Mon, 23 Oct 2023 00:00:00 GMT</pubDate><item><title><![CDATA[Working in the shadows with white-hat hackers]]></title><description><![CDATA[<p>The majority of Joplin's development is carried out in the public domain. This includes the discussion of issues on GitHub, as well as the submission of pull requests and related discussions. The transparency of these processes allows for collaborative problem-solving and shared insights.</p>
|
||||
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Sat, 23 Dec 2023 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Sat, 23 Dec 2023 00:00:00 GMT</pubDate><item><title><![CDATA[Faster synchronisation in upcoming Joplin version!]]></title><description><![CDATA[<p>The next version of Joplin Cloud (and Joplin Server) will include a change that will make synchronisation, in particular when synchronising a new device for the first time, significantly faster. This is achieved by bundling more data with the calls that retrieve notes and other data, thus reducing the number of unnecessary requests.</p>
|
||||
<p>This change will be applied soon to Joplin Cloud (and Server), and the Joplin mobile, desktop and CLI applications will be able to use it from version 2.14.</p>
|
||||
<p>In my tests with about 26,000 items, synchronisation was more than twice as fast on Joplin Cloud (22.5 minutes vs 9.5 minutes):</p>
|
||||
<h2>Before<a name="before" href="#before" class="heading-anchor">🔗</a></h2>
|
||||
<p>Created local items: 21814. Fetched items: 26591/26591. Completed: 23/12/2023 10:38 (<strong>1346s</strong>)</p>
|
||||
<p><strong>real 22m35.810s</strong><br/><br>
|
||||
user 3m19.182s<br/><br>
|
||||
sys 1m24.207s</p>
|
||||
<h2>Optimised<a name="optimised" href="#optimised" class="heading-anchor">🔗</a></h2>
|
||||
<p>Created local items: 21822. Fetched items: 26600/26600. Completed: 23/12/2023 11:48 (<strong>571s</strong>)</p>
|
||||
<p><strong>real 9m38.932s</strong><br/><br>
|
||||
user 1m10.119s<br/><br>
|
||||
sys 0m38.013s</p>
|
||||
]]></description><link>https://joplinapp.org/news/20231223-faster-sync</link><guid isPermaLink="false">20231223-faster-sync</guid><pubDate>Sat, 23 Dec 2023 00:00:00 GMT</pubDate><twitter-text>Faster synchronisation in upcoming Joplin version!</twitter-text></item><item><title><![CDATA[What's new in Joplin 2.13]]></title><description><![CDATA[<h2>Desktop<a name="desktop" href="#desktop" class="heading-anchor">🔗</a></h2>
|
||||
<h3>Rich Text Editor improvements<a name="rich-text-editor-improvements" href="#rich-text-editor-improvements" class="heading-anchor">🔗</a></h3>
|
||||
<p>In this update, significant enhancements have been implemented in the Rich Text Editor to enhance user experience. One notable improvement is the ability to seamlessly embed various content within tables, including lists and other tables, which was a frequently requested feature:</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20231203-rte-table.png" alt=""></p>
|
||||
<p>The interoperability with other text editors such as Word and Excel has also been improved, in particular when copying and pasting content between these tools and Joplin.</p>
|
||||
<h3>Improved ENEX import<a name="improved-enex-import" href="#improved-enex-import" class="heading-anchor">🔗</a></h3>
|
||||
<p>The Evernote Export format, known as ENEX, has always been challenging to support. This is because Evernote frequently changes it, breaking importers, and may also occasionally introduce bugs. At times, their own application struggles to import back files that it has exported, highlighting the volatility of the ENEX format.</p>
|
||||
<p>After undergoing continuous improvements for seven years, the importer has achieved a relatively stable state. The majority of issues encountered now stem from invalid files generated by Evernote, a result of bugs introduced in recent versions. Despite these challenges, we strive to enhance the import process by employing various heuristics to process the invalid data as effectively as possible.</p>
|
||||
<p>The list of bug fixes is below:</p>
|
||||
<ul>
|
||||
<li>Apply correct size to images imported from ENEX files</li>
|
||||
<li>ENEX files that contain resources with invalid mime types are imported correctly</li>
|
||||
<li>Ensure that ENEX resources with invalid filenames are imported correctly</li>
|
||||
<li>Prevent application from being stuck when importing an invalid ENEX file</li>
|
||||
</ul>
|
||||
<h3>New plugins APIs<a name="new-plugins-apis" href="#new-plugins-apis" class="heading-anchor">🔗</a></h3>
|
||||
<h4>Note list<a name="note-list" href="#note-list" class="heading-anchor">🔗</a></h4>
|
||||
<p>We are continuously improving the plugin API to make it as easy as possible to customize the application.</p>
|
||||
<p>One of the main addition is support note list plugins - it allows any plugins to customise what the list should display each note.</p>
|
||||
<p>See the <a href="https://joplinapp.org/api/references/plugin_api/classes/joplinviewsnotelist.html">Joplin Plugin Note List API</a> and the <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/note_list_renderer/src/index.ts">Note List Demo</a> for more information.</p>
|
||||
<p>The demo includes three examples of note lists: a fundamental "top to bottom" version, a sophisticated "left to right" variant that additionally displays a note thumbnail, and a demonstration of an interactive note list, allowing direct modification of the note title from the list.</p>
|
||||
<p>This API was developed based on the feedback we got and we hope it will be useful. We remain open to further input from users and plugin developers regarding any potential missing features and areas for improvement!</p>
|
||||
<h4>Imaging API<a name="imaging-api" href="#imaging-api" class="heading-anchor">🔗</a></h4>
|
||||
<p>The imaging API was created to allow plugin developers to easily load and manipulate images. For now it is possible to load PNG and JPG files, and to resize and crop them.</p>
|
||||
<p><a href="https://joplinapp.org/api/references/plugin_api/classes/joplinimaging.html">https://joplinapp.org/api/references/plugin_api/classes/joplinimaging.html</a></p>
|
||||
<h4>And more<a name="and-more" href="#and-more" class="heading-anchor">🔗</a></h4>
|
||||
<p>A few more APIs have been added such as one to <a href="https://joplinapp.org/api/references/plugin_api/classes/joplinviewsdialogs.html#showopendialog">open dialog to select a file or folder</a> and a way to <a href="https://joplinapp.org/api/references/plugin_api/enums/contentscripttype.html#getting-the-settings-from-the-renderer">access the plugin settings from a renderer script</a>.</p>
|
||||
<h3>New beta Markdown editor<a name="new-beta-markdown-editor" href="#new-beta-markdown-editor" class="heading-anchor">🔗</a></h3>
|
||||
<p>This version also features a new Markdown editor based on <a href="https://codemirror.net/">CodeMirror 6</a>. This change means that we'll be able to use the same editor on both the desktop and mobile application (which already uses CodeMirror 6), which will allow a more consistent user experience across devices.</p>
|
||||
<p>Another benefit is that, in a future version, it will allow us to support plugins on the mobile application. There are several other advantages that Henry <a href="https://discourse.joplinapp.org/t/pre-release-v2-13-is-now-available-updated-18-11-2023/32697/12?u=laurent">listed in this forum post</a>.</p>
|
||||
<h2>Mobile<a name="mobile" href="#mobile" class="heading-anchor">🔗</a></h2>
|
||||
<h3>Drawing option<a name="drawing-option" href="#drawing-option" class="heading-anchor">🔗</a></h3>
|
||||
<p>In this new version, Henry integrated the js-draw editor to the mobile app. Js-draw is a powerful freehand drawing library which allows you to draw using a pen, touch screen or mouse.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20231203-drawing.png" alt=""></p>
|
||||
<p>The editor is integrated to the mobile application. On desktop application, you can use the same library and edit your drawings using the <a href="https://github.com/personalizedrefrigerator/joplin-plugin-freehand-drawing">Freehand Drawing plugin</a>. We will make this plugin available by default in a future desktop release.</p>
|
||||
<h3>Setting screen<a name="setting-screen" href="#setting-screen" class="heading-anchor">🔗</a></h3>
|
||||
<p>The mobile version also features a redesigned configuration screen. It is now divided into multiple sections with clear titles, and you can also search for settings using the built-in search option.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20231203-settings.png" alt=""></p>
|
||||
<h1>Full changelog<a name="full-changelog" href="#full-changelog" class="heading-anchor">🔗</a></h1>
|
||||
<p>This is just an overview of the main features. The full changelog is available there:</p>
|
||||
<ul>
|
||||
<li>Desktop: <a href="https://joplinapp.org/help/about/changelog/desktop">https://joplinapp.org/help/about/changelog/desktop</a></li>
|
||||
<li>Android: <a href="https://joplinapp.org/help/about/changelog/android/">https://joplinapp.org/help/about/changelog/android/</a></li>
|
||||
<li>iOS: <a href="https://joplinapp.org/help/about/changelog/ios/">https://joplinapp.org/help/about/changelog/ios/</a></li>
|
||||
</ul>
|
||||
]]></description><link>https://joplinapp.org/news/20231204-release-2-13</link><guid isPermaLink="false">20231204-release-2-13</guid><pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate><twitter-text>What's new in Joplin 2.13</twitter-text></item><item><title><![CDATA[Working in the shadows with white-hat hackers]]></title><description><![CDATA[<p>The majority of Joplin's development is carried out in the public domain. This includes the discussion of issues on GitHub, as well as the submission of pull requests and related discussions. The transparency of these processes allows for collaborative problem-solving and shared insights.</p>
|
||||
<p>However, there is one aspect that operates behind closed doors, and for good reason: addressing cybersecurity vulnerabilities. It is imperative that these issues remain undisclosed until they have been resolved. Once a solution is implemented, it is usually accompanied by discreet commits and a message in the changelog to signify the progress made.</p>
|
||||
<p>Typically, the process begins with an email from a security researcher. They provide valuable insights, such as a specially crafted note that triggers a bug, or an API call, along with an explanation of how the application's security can be circumvented. We examine the vulnerability, create a fix, and create automated test units to prevent any accidental reintroduction of the vulnerability in future code updates. An example of such a commit is: <a href="https://github.com/laurent22/joplin/commit/9e90d9016daf79b5414646a93fd369aedb035071">9e90d9016daf79b5414646a93fd369aedb035071</a></p>
|
||||
<p>We then share our fix with the researcher for validation. Additionally, we often apply the fix to previous versions of Joplin, depending on the severity of the vulnerability.</p>
|
||||
@@ -26,7 +84,7 @@
|
||||
<p>In this release, we've undertaken numerous enhancements and addressed various bugs in the Rich Text editor. Notably, we've introduced support for plugin toolbar icons. Additionally, we've refined the editor's ability to manage text that's copied from applications like Word, Office, and LibreOffice, thereby enhancing cross-application compatibility. Among the minor yet impactful improvements, we've fine-tuned the handling of newlines and paragraphs—a highly requested feature. Another notable update is the improved automatic switching between light and dark modes.</p>
|
||||
<p>Altogether, this release encompasses around 12 significant changes for the Rich Text editor, and rest assured, there's more to come in the future!</p>
|
||||
<h3>Share permissions<a name="share-permissions" href="#share-permissions" class="heading-anchor">🔗</a></h3>
|
||||
<p>Using Joplin Cloud Pro and Teams, you now have the ability to customize the read and write permissions for the notebooks you share. You have the option to grant other users permission to edit the notes or share them as read-only. This ensures that you can confidently share a notebook without worrying about unintentional modifications by your friends or colleagues.</p>
|
||||
<p>Using Joplin Cloud Teams, you now have the ability to customize the read and write permissions for the notebooks you share. You have the option to grant other users permission to edit the notes or share them as read-only. This ensures that you can confidently share a notebook without worrying about unintentional modifications by your friends or colleagues.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230825-share-permissions.png" alt=""></p>
|
||||
<h3>Email to Note<a name="email-to-note" href="#email-to-note" class="heading-anchor">🔗</a></h3>
|
||||
<p>Joplin Cloud Pro and Teams also now include the Email to Note feature, allowing you to conveniently store your emails within Joplin Cloud. By simply forwarding your emails to your Joplin Cloud address, you can transform them into notes. The email's subject will serve as the note title, while the body of the email will be the note's content. These notes will be organized within a notebook named "Inbox."</p>
|
||||
@@ -306,38 +364,4 @@
|
||||
<h2>Plugin API improvements<a name="plugin-api-improvements" href="#plugin-api-improvements" class="heading-anchor">🔗</a></h2>
|
||||
<p>This version also includes a number of improvements to the plugin API, in particular it is now easier to customise the editor context menu from a plugin and dynamically add items to it depending on the context. For example, with the Rich Markdown plugin it will be possible to right-click on an image and open it, or copy it to the clipboard.</p>
|
||||
<p>A few additional functions have also been added to make plugin development simpler - in particular a command to open any item, whether it's a notebook, note, tag or attachement; and functions to work with attachements, in particular to reveal an attachement in the system file explorer, and to track changes to an attachement.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20220224-release-2-7</link><guid isPermaLink="false">20220224-release-2-7</guid><pubDate>Thu, 24 Feb 2022 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Automatic deletion of disabled accounts on Joplin Cloud]]></title><description><![CDATA[<p>As of 15 Feb 2022, disabled accounts on Joplin Cloud will be automatically deleted after 90 days. A disabled account is one where the Stripe subscription has been cancelled either by the user or automatically (eg for unpaid invoices).</p>
|
||||
<p>Although it is an automated system, I will manually verify each account that's queued for deletion over the next few days for additional safety (for now everything's working as expected).</p>
|
||||
<p>When an account is queued for deletion, all notes, notebooks, tags, etc are removed from the system within 2 days, and permanently deleted within 7 days. User information, in particular email and full name will be removed from the system within 2 days, but archived for an additional 90 days for legal reasons, after which they will be deleted too.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20220215-142000</link><guid isPermaLink="false">20220215-142000</guid><pubDate>Tue, 15 Feb 2022 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Joplin 2.6 is available!]]></title><description><![CDATA[<p>Many changes in this new release, available on mobile, desktop and CLI:</p>
|
||||
<p><strong>Per-notebook sort order and sort buttons</strong></p>
|
||||
<p>This new feature adds a number of changes to the way notes are sorted. The most visible one is the addition of a sort button above the note list - it allows sorting by modification date, creation date, title or by custom order, in either ascending or descending order:</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20211217-120324_0.png" alt=""></p>
|
||||
<p>By default, this sort order is going to apply to all notebooks, however you can now also assign a per-notebook sort order. In this case, any sort order will be apply to that notebook only. To enable this behaviour, simply right-click on a notebook and select "Toggle own sort order":</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20211217-120324_1.png" alt=""></p>
|
||||
<p>Thanks to Kenichi Kobayashi for developing this feature!</p>
|
||||
<p><strong>Support for notebook icons</strong></p>
|
||||
<p>It is now possible to associate icons with notebooks no both the desktop and mobile applications. To do so, right-click on a notebook and selected "Edit".</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20211217-120324_2.png" alt=""></p>
|
||||
<p>This will open the new notebook dialog from which can change the title and assign an icon. For now the icons are emojis but perhaps custom icons could be supported later on.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20211217-120324_3.png" alt=""></p>
|
||||
<p><strong>Allow collaborating on encrypted notebooks using Joplin Cloud</strong></p>
|
||||
<p>Thanks to the encryption improvements in the previous Joplin versions it is now possible to share and collaborated on encrypted notebooks, when synchronising with Joplin Cloud (or Joplin Server).</p>
|
||||
<p>To get this working, you and the recipient will need to have Joplin 2.6 and the person who shares will need to have encryption enabled. After that most of the process is handled automatically by the apps - in particular it will automatically generate and share the required encryption keys for each users.</p>
|
||||
<p><strong>Improved synchronisation startup speed</strong></p>
|
||||
<p>Synchronisation is also a bit faster in this release due to an optimisation on the startup process. When syncing, the app needs to acquire a lock, which may be time consuming since it requires making multiple requests. This has now been optimised so that less requests are necessary and also each request consumes less resources. This will have a postive impact on Joplin Cloud in particular, but you should also see improvements with Joplin Server and smaller improvements with the other sync targets.</p>
|
||||
<p><strong>Improved Markdown editor split view scrolling</strong></p>
|
||||
<p>Kenichi Kobayashi made some great improvements to the Markdown editor scrolling in this release. The issue before was that the editor on the left and the viewer on the right would often not be in sync, in particular if the note contains several images and other media.</p>
|
||||
<p>With Kenichi's change the editor and viewer stay nicely in sync, regardless of the note content. In fact it looks a bit like magic when you scroll through large notes - notice in particular how each side appear to wait for the other or speed up in order to make sure both sides are aligned as well possible. Kenichi provides a nice technical documentation about the feature <a href="https://github.com/laurent22/joplin/pull/5512#issuecomment-931277022">here</a>.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=Wbs5XZR0oeU">https://www.youtube.com/watch?v=Wbs5XZR0oeU</a></p>
|
||||
<p><strong>Improved and optimised S3 synchronisation</strong></p>
|
||||
<p>Thanks to the efforts of Lee Matos, synchronisation with S3 is now more reliable and errors are also better handled. The underlying S3 SDK has also been upgraded from v2 to v3 which results in a smaller executable size (about 3-5 MB depending on the operating system)</p>
|
||||
<p><strong>Export notes as self-contained HTML files</strong></p>
|
||||
<p>Exporting a single note as HTML is now more user friendly as all images, scripts, styles and other attachments are all packed into a single HTML file (Previously it would create multiples files and directories). This makes it easier to share the complete note with someone who doesn't have Joplin.</p>
|
||||
<p><strong>Other changes and bug fixes</strong></p>
|
||||
<p>This release includes a total of 19 new features and improvements and 16 bug fixes. See the 2.6.x changelogs for more details:</p>
|
||||
<p><a href="https://joplinapp.org/help/about/changelog/desktop">https://joplinapp.org/help/about/changelog/desktop</a></p>
|
||||
<p><a href="https://joplinapp.org/help/about/changelog/android/">https://joplinapp.org/help/about/changelog/android/</a></p>
|
||||
<p><a href="https://joplinapp.org/help/about/changelog/ios/">https://joplinapp.org/help/about/changelog/ios/</a></p>
|
||||
<p><a href="https://joplinapp.org/help/about/changelog/cli/">https://joplinapp.org/help/about/changelog/cli/</a></p>
|
||||
]]></description><link>https://joplinapp.org/news/20211217-120324</link><guid isPermaLink="false">20211217-120324</guid><pubDate>Fri, 17 Dec 2021 12:03:24 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>
|
||||
]]></description><link>https://joplinapp.org/news/20220224-release-2-7</link><guid isPermaLink="false">20220224-release-2-7</guid><pubDate>Thu, 24 Feb 2022 00:00:00 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>
|
@@ -71,7 +71,7 @@ EXPOSE ${APP_PORT}
|
||||
# https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#handling-kernel-signals
|
||||
WORKDIR /home/$user/packages/server
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
CMD ["node", "dist/app.js"]
|
||||
CMD ["yarn", "start-prod"]
|
||||
|
||||
# Build-time metadata
|
||||
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
|
||||
|
@@ -124,7 +124,7 @@ else
|
||||
fi
|
||||
if [[ $LIBFUSE == "" ]] ; then
|
||||
print "${COLOR_RED}Error: Can't get libfuse2 on system, please install libfuse2${COLOR_RESET}"
|
||||
print "See https://joplinapp.org/faq/#desktop-application-will-not-launch-on-linux and https://github.com/AppImage/AppImageKit/wiki/FUSE for more information"
|
||||
print "See https://joplinapp.org/help/faq/#desktop-application-will-not-launch-on-linux and https://github.com/AppImage/AppImageKit/wiki/FUSE for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -205,9 +205,16 @@ if command -v lsb_release &> /dev/null; then
|
||||
# Check for "The SUID sandbox helper binary was found, but is not configured correctly" problem.
|
||||
# It is present in Debian 1X. A (temporary) patch will be applied at .desktop file
|
||||
# Linux Mint 4 Debbie is based on Debian 10 and requires the same param handling.
|
||||
if [[ $DISTVER =~ Debian1. ]] || [ "$DISTVER" = "Linuxmint4" ] && [ "$DISTCODENAME" = "debbie" ] || [ "$DISTVER" = "CentOS" ] && [[ "$DISTMAJOR" =~ 6|7 ]]
|
||||
#
|
||||
# This also works around Ubuntu 23.10+'s restrictions on unprivileged user namespaces. Electron
|
||||
# uses these to sandbox processes. Unfortunately, it doesn't look like we can get around this
|
||||
# without writing the AppImage to a non-user-writable location (without invalidating other security
|
||||
# controls). See https://discourse.joplinapp.org/t/possible-future-requirement-for-no-sandbox-flag-for-ubuntu-23-10/.
|
||||
if [[ $DISTVER = "Ubuntu23.10" || $DISTVER =~ Debian1. || ( "$DISTVER" = "Linuxmint4" && "$DISTCODENAME" = "debbie" ) || ( "$DISTVER" = "CentOS" && "$DISTMAJOR" =~ 6|7 ) ]]
|
||||
then
|
||||
SANDBOXPARAM="--no-sandbox"
|
||||
print "${COLOR_YELLOW}WARNING${COLOR_RESET} Electron sandboxing disabled."
|
||||
print " See https://discourse.joplinapp.org/t/32160/5 for details."
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@@ -26,12 +26,12 @@ For more information about the applications, see the [full Joplin documentation]
|
||||
|
||||
Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.
|
||||
|
||||
Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/readme/about/donate.md) for information on how to support the development of Joplin.
|
||||
Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/readme/donate.md) for information on how to support the development of Joplin.
|
||||
|
||||
# Sponsors
|
||||
|
||||
<!-- SPONSORS-ORG -->
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&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://tranio.com/spain/"><img title="Property for sale in Spain" width="256" src="https://joplinapp.org/images/sponsors/TranioOverseasProperty.jpg"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.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&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></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://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp "><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com "><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
@@ -42,8 +42,8 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) | <img width="50" src="https://avatars2.githubusercontent.com/u/2793530?s=96&v=4"/></br>[CyberXZT](https://github.com/CyberXZT) | <img width="50" src="https://avatars2.githubusercontent.com/u/1307332?s=96&v=4"/></br>[dbrandonjohnson](https://github.com/dbrandonjohnson) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/14873877?s=96&v=4"/></br>[dchecks](https://github.com/dchecks) | <img width="50" src="https://avatars2.githubusercontent.com/u/56287?s=96&v=4"/></br>[fats](https://github.com/fats) | <img width="50" src="https://avatars2.githubusercontent.com/u/8030470?s=96&v=4"/></br>[Galliver7](https://github.com/Galliver7) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/1310474?s=96&v=4"/></br>[jknowles](https://github.com/jknowles) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/24908652?s=96&v=4"/></br>[konishi-t](https://github.com/konishi-t) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/126279083?s=96&v=4"/></br>[matmoly](https://github.com/matmoly) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/31054972?s=96&v=4"/></br>[saarantras](https://github.com/saarantras) | <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) | <img width="50" src="https://avatars2.githubusercontent.com/u/333944?s=96&v=4"/></br>[tateisu](https://github.com/tateisu) | | |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/126279083?s=96&v=4"/></br>[matmoly](https://github.com/matmoly) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/4560672?s=96&v=4"/></br>[mu88](https://github.com/mu88) | <img width="50" src="https://avatars2.githubusercontent.com/u/31054972?s=96&v=4"/></br>[saarantras](https://github.com/saarantras) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) | <img width="50" src="https://avatars2.githubusercontent.com/u/333944?s=96&v=4"/></br>[tateisu](https://github.com/tateisu) | |
|
||||
<!-- SPONSORS-GITHUB -->
|
||||
|
||||
# Community
|
||||
|
23
crowdin.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
project_id: '624298'
|
||||
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||
preserve_hierarchy: true
|
||||
files:
|
||||
|
||||
- source: /readme/**/*
|
||||
translation: /readme/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
|
||||
ignore:
|
||||
- /readme/_i18n
|
||||
- /readme/i18n
|
||||
- /readme/about/changelog
|
||||
- /readme/about/stats.md
|
||||
- /readme/api
|
||||
- /readme/dev
|
||||
- /readme/news
|
||||
- /readme/cla.md
|
||||
- /readme/connection_check.md
|
||||
- /readme/privacy.md
|
||||
- /**/*.yml
|
||||
- /**/*.json
|
||||
- /**/*.png
|
||||
- /**/*.jpg
|
||||
|
@@ -6,7 +6,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:15
|
||||
image: postgres:16
|
||||
command: postgres -c work_mem=100000
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
@@ -18,7 +18,7 @@ services:
|
||||
- POSTGRES_PORT=5432
|
||||
- POSTGRES_HOST=localhost
|
||||
db:
|
||||
image: postgres:15
|
||||
image: postgres:16
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
|
@@ -19,7 +19,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:15
|
||||
image: postgres:16
|
||||
volumes:
|
||||
- ./data/postgres:/var/lib/postgresql/data
|
||||
ports:
|
||||
|
16
jest.base-setup.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
|
||||
module.exports = () => {
|
||||
// Disable the additional information that Jest adds to each console
|
||||
// statement. It's rarely needed and if it is it can be commented out here.
|
||||
|
||||
const jestConsole = console;
|
||||
|
||||
beforeEach(() => {
|
||||
global.console = require('console');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.console = jestConsole;
|
||||
});
|
||||
};
|
@@ -182,6 +182,11 @@
|
||||
"docs/images/flags": true,
|
||||
"lerna-debug.log": true,
|
||||
"node_modules/": true,
|
||||
"packages/doc-builder/build": true,
|
||||
"packages/doc-builder/help": true,
|
||||
"packages/doc-builder/news": true,
|
||||
"packages/doc-builder/i18n": true,
|
||||
"readme/i18n": true,
|
||||
"packages/app-cli/**/*.*~": true,
|
||||
"packages/app-cli/**/*.mo": true,
|
||||
"packages/app-cli/**/build/": true,
|
||||
@@ -362,6 +367,12 @@
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceFolder}/packages/server && yarn tsc",
|
||||
"group": "build",
|
||||
},
|
||||
{
|
||||
"label": "transpile-lib",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceFolder}/packages/lib && yarn tsc",
|
||||
"group": "build",
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -390,6 +401,19 @@
|
||||
"APP_BASE_URL": "http://joplincloud.local:22300",
|
||||
"API_BASE_URL": "http://api.joplincloud.local:22300",
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "lib: debug test file",
|
||||
"preLaunchTask": "transpile-lib",
|
||||
"program": "${workspaceFolder}/packages/lib/node_modules/.bin/jest",
|
||||
"args": [
|
||||
"${fileBasenameNoExtension}",
|
||||
"--config",
|
||||
"packages/lib/jest.config.js",
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
64
package.json
@@ -12,31 +12,34 @@
|
||||
"node": ">=16"
|
||||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"buildApiDoc": "yarn workspace joplin start apidoc ../../readme/api/references/rest_api.md",
|
||||
"buildCommandIndex": "node packages/tools/gulp/tasks/buildCommandIndexRun.js",
|
||||
"buildScriptIndexes": "node packages/tools/gulp/tasks/buildScriptIndexesRun.js",
|
||||
"buildParallel": "yarn workspaces foreach --verbose --interlaced --parallel --jobs 2 --topological run build && yarn run tsc",
|
||||
"buildPluginDoc": "cd packages/generate-plugin-doc && yarn run buildPluginDoc_",
|
||||
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
|
||||
"updateNews": "node ./packages/tools/website/updateNews",
|
||||
"postPreReleasesToForum": "node ./packages/tools/postPreReleasesToForum",
|
||||
"buildSequential": "yarn workspaces foreach --verbose --interlaced --topological run build && yarn run tsc",
|
||||
"buildServerDocker": "node packages/tools/buildServerDocker.js",
|
||||
"buildSettingJsonSchema": "yarn workspace joplin start settingschema ../../../joplin-website/docs/schema/settings.json",
|
||||
"buildTranslations": "node packages/tools/build-translation.js",
|
||||
"buildWebsiteTranslations": "node packages/tools/website/buildTranslations.js",
|
||||
"buildWebsite": "node ./packages/tools/website/processDocs.js --env prod && node ./packages/tools/website/build.js && yarn run buildPluginDoc && yarn run buildSettingJsonSchema",
|
||||
"checkLibPaths": "node ./packages/tools/checkLibPaths.js",
|
||||
"buildWebsiteTranslations": "node packages/tools/website/buildTranslations.js",
|
||||
"checkIgnoredFiles": "node ./packages/tools/checkIgnoredFiles.js",
|
||||
"checkLibPaths": "node ./packages/tools/checkLibPaths.js",
|
||||
"circularDependencyCheck": "madge --warning --circular --extensions js ./",
|
||||
"clean": "npm run clean --workspaces --if-present && node packages/tools/clean && yarn cache clean",
|
||||
"crowdin": "crowdin",
|
||||
"crowdinDownload": "crowdin download",
|
||||
"crowdinUpload": "crowdin upload",
|
||||
"cspell": "cspell",
|
||||
"dependencyTree": "madge",
|
||||
"generateDatabaseTypes": "node packages/tools/generate-database-types",
|
||||
"linkChecker": "linkchecker https://joplinapp.org",
|
||||
"generateTypes": "node packages/tools/generate-database-types",
|
||||
"linkChecker": "linkchecker https://joplinapp.org/ && linkchecker --check-extern https://joplinapp.org/api/references/plugin_api/classes/joplin.html",
|
||||
"linter-ci": "eslint --resolve-plugins-relative-to . --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter-interactive": "eslint-interactive --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter-precommit": "eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter": "eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter-interactive": "eslint-interactive --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"packageJsonLint": "node ./packages/tools/packageJsonLint.js",
|
||||
"postinstall": "gulp build",
|
||||
"postPreReleasesToForum": "node ./packages/tools/postPreReleasesToForum",
|
||||
"publishAll": "git pull && yarn run buildParallel && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
|
||||
"releaseAndroid": "PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" node packages/tools/release-android.js",
|
||||
"releaseAndroidClean": "node packages/tools/release-android.js",
|
||||
@@ -47,15 +50,15 @@
|
||||
"releasePluginGenerator": "node packages/tools/release-plugin-generator.js",
|
||||
"releasePluginRepoCli": "node packages/tools/release-plugin-repo-cli.js",
|
||||
"releaseServer": "node packages/tools/release-server.js",
|
||||
"cspell": "cspell",
|
||||
"setupNewRelease": "node ./packages/tools/setupNewRelease",
|
||||
"spellcheck": "node packages/tools/spellcheck.js",
|
||||
"tagServerLatest": "node packages/tools/tagServerLatest.js",
|
||||
"buildServerDocker": "node packages/tools/buildServerDocker.js",
|
||||
"setupNewRelease": "node ./packages/tools/setupNewRelease",
|
||||
"test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci",
|
||||
"test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test",
|
||||
"tsc": "yarn workspaces foreach --parallel --verbose --interlaced run tsc",
|
||||
"updateIgnored": "node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js",
|
||||
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
|
||||
"updateNews": "node ./packages/tools/website/updateNews",
|
||||
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
|
||||
"watch": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 999 run watch",
|
||||
"watchWebsite": "nodemon --delay 1 --watch Assets/WebsiteAssets --watch packages/tools/website --watch packages/tools/website/utils --watch packages/doc-builder/build --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\""
|
||||
@@ -66,41 +69,44 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@crowdin/cli": "3",
|
||||
"@joplin/utils": "~2.12",
|
||||
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
|
||||
"@typescript-eslint/eslint-plugin": "6.0.0",
|
||||
"@typescript-eslint/parser": "6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "6.8.0",
|
||||
"@typescript-eslint/parser": "6.8.0",
|
||||
"cspell": "5.21.2",
|
||||
"eslint": "8.47.0",
|
||||
"eslint": "8.52.0",
|
||||
"eslint-interactive": "10.8.0",
|
||||
"eslint-plugin-import": "2.28.1",
|
||||
"eslint-plugin-jest": "27.2.3",
|
||||
"eslint-plugin-jest": "27.4.3",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"execa": "5.1.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"glob": "10.3.10",
|
||||
"gulp": "4.0.2",
|
||||
"husky": "3.1.0",
|
||||
"lerna": "3.22.1",
|
||||
"lint-staged": "13.3.0",
|
||||
"lint-staged": "15.2.0",
|
||||
"madge": "6.1.0",
|
||||
"npm-package-json-lint": "7.0.0",
|
||||
"typescript": "5.1.6"
|
||||
"npm-package-json-lint": "7.1.0",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "11.0.2",
|
||||
"eslint-plugin-github": "4.9.2",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"eslint-plugin-github": "4.10.1",
|
||||
"http-server": "14.1.1",
|
||||
"node-gyp": "9.4.0",
|
||||
"nodemon": "3.0.1"
|
||||
"node-gyp": "9.4.1",
|
||||
"nodemon": "3.0.2"
|
||||
},
|
||||
"packageManager": "yarn@3.6.3",
|
||||
"packageManager": "yarn@3.6.4",
|
||||
"resolutions": {
|
||||
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch",
|
||||
"react-native-vosk@0.1.12": "patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch",
|
||||
"eslint": "patch:eslint@8.47.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"eslint": "patch:eslint@8.52.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch",
|
||||
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch"
|
||||
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch",
|
||||
"nanoid": "patch:nanoid@npm%3A3.3.7#./.yarn/patches/nanoid-npm-3.3.7-98824ba130.patch",
|
||||
"pdfjs-dist": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch"
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const BaseApplication = require('@joplin/lib/BaseApplication').default;
|
||||
const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js');
|
||||
const { refreshFolders } = require('@joplin/lib/folders-screen-utils.js');
|
||||
const ResourceService = require('@joplin/lib/services/ResourceService').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
@@ -435,7 +435,7 @@ class Application extends BaseApplication {
|
||||
// initialised. So we manually call dispatchUpdateAll() to force an update.
|
||||
Setting.dispatchUpdateAll();
|
||||
|
||||
await FoldersScreenUtils.refreshFolders();
|
||||
await refreshFolders((action) => { this.store().dispatch(action); });
|
||||
|
||||
const tags = await Tag.allWithNotes();
|
||||
|
||||
|
@@ -1,33 +1,34 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import BaseCommand from './base-command';
|
||||
import BaseItem from '@joplin/lib/models/BaseItem';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
const { toTitleCase } = require('@joplin/lib/string-utils.js');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const markdownUtils = require('@joplin/lib/markdownUtils').default;
|
||||
const Database = require('@joplin/lib/database').default;
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
import { reg } from '@joplin/lib/registry.js';
|
||||
import markdownUtils, { MarkdownTableRow } from '@joplin/lib/markdownUtils';
|
||||
import Database from '@joplin/lib/database';
|
||||
import shim from '@joplin/lib/shim';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'apidoc <file>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return 'Build the API doc';
|
||||
}
|
||||
|
||||
enabled() {
|
||||
public override enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
createPropertiesTable(tableFields) {
|
||||
private createPropertiesTable(tableFields: MarkdownTableRow[]) {
|
||||
const headers = [
|
||||
{ name: 'name', label: 'Name' },
|
||||
{
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
filter: value => {
|
||||
return Database.enumName('fieldType', value);
|
||||
filter: (value: string|number) => {
|
||||
const valueAsNumber = typeof value === 'number' ? value : parseInt(value, 10);
|
||||
return Database.enumName('fieldType', valueAsNumber);
|
||||
},
|
||||
},
|
||||
{ name: 'description', label: 'Description' },
|
||||
@@ -36,7 +37,7 @@ class Command extends BaseCommand {
|
||||
return markdownUtils.createMarkdownTable(headers, tableFields);
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const models = [
|
||||
{
|
||||
type: BaseModel.TYPE_NOTE,
|
||||
@@ -57,6 +58,10 @@ class Command extends BaseCommand {
|
||||
|
||||
const lines = [];
|
||||
|
||||
lines.push('---');
|
||||
lines.push('sidebar_position: 2');
|
||||
lines.push('---');
|
||||
lines.push('');
|
||||
lines.push('# Joplin Data API');
|
||||
lines.push('');
|
||||
lines.push('This API is available when the clipper server is running. It provides access to the notes, notebooks, tags and other Joplin object via a REST API. Plugins can also access this API even when the clipper server is not running.');
|
@@ -1,19 +1,19 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import shim from '@joplin/lib/shim';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'attach <note> <file>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Attaches the given file to the note.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const title = args['note'];
|
||||
|
||||
const note = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
|
@@ -1,24 +1,24 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import BaseItem from '@joplin/lib/models/BaseItem';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'cat <note>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Displays the given note.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
return [['-v, --verbose', _('Displays the complete information about note.')]];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const title = args['note'];
|
||||
|
||||
const item = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
|
@@ -1,19 +1,20 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { _, setLocale } = require('@joplin/lib/locale');
|
||||
import BaseCommand from './base-command';
|
||||
import { _, setLocale } from '@joplin/lib/locale';
|
||||
const { app } = require('./app.js');
|
||||
const fs = require('fs-extra');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
import * as fs from 'fs-extra';
|
||||
import Setting, { AppType } from '@joplin/lib/models/Setting';
|
||||
import { ReadStream } from 'tty';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'config [name] [value]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
return [
|
||||
['-v, --verbose', _('Also displays unset and hidden config variables.')],
|
||||
['--export', 'Writes all settings to STDOUT as JSON including secure variables.'],
|
||||
@@ -21,11 +22,12 @@ class Command extends BaseCommand {
|
||||
['--import-file <file>', 'Reads in settings from <file>. <file> must contain valid JSON.'],
|
||||
];
|
||||
}
|
||||
async __importSettings(inputStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
private async __importSettings(inputStream: ReadStream|fs.ReadStream) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// being defensive and not attempting to settle twice
|
||||
let isSettled = false;
|
||||
const chunks = [];
|
||||
const chunks: any = [];
|
||||
|
||||
inputStream.on('readable', () => {
|
||||
let chunk;
|
||||
@@ -64,13 +66,14 @@ class Command extends BaseCommand {
|
||||
});
|
||||
});
|
||||
}
|
||||
async action(args) {
|
||||
|
||||
public override async action(args: any) {
|
||||
const verbose = args.options.verbose;
|
||||
const isExport = args.options.export;
|
||||
const isImport = args.options.import || args.options.importFile;
|
||||
const importFile = args.options.importFile;
|
||||
|
||||
const renderKeyValue = name => {
|
||||
const renderKeyValue = (name: string) => {
|
||||
const md = Setting.settingMetadata(name);
|
||||
let value = Setting.value(name);
|
||||
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
|
||||
@@ -84,11 +87,11 @@ class Command extends BaseCommand {
|
||||
};
|
||||
|
||||
if (isExport || (!isImport && !args.value)) {
|
||||
const keys = Setting.keys(!verbose, 'cli');
|
||||
const keys = Setting.keys(!verbose, AppType.Cli);
|
||||
keys.sort();
|
||||
|
||||
if (isExport) {
|
||||
const resultObj = keys.reduce((acc, key) => {
|
||||
const resultObj = keys.reduce<Record<string, any>>((acc, key) => {
|
||||
const value = Setting.value(key);
|
||||
if (!verbose && !value) return acc;
|
||||
acc[key] = value;
|
||||
@@ -113,7 +116,7 @@ class Command extends BaseCommand {
|
||||
}
|
||||
|
||||
if (isImport) {
|
||||
let fileStream = process.stdin;
|
||||
let fileStream: ReadStream|fs.ReadStream = process.stdin;
|
||||
if (importFile) {
|
||||
fileStream = fs.createReadStream(importFile, { autoClose: true });
|
||||
}
|
@@ -1,19 +1,19 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'cp <note> [notebook]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Duplicates the notes matching <note> to [notebook]. If no notebook is specified the note is duplicated in the current notebook.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
let folder = null;
|
||||
if (args['notebook']) {
|
||||
folder = await app().loadItem(BaseModel.TYPE_FOLDER, args['notebook']);
|
||||
@@ -28,7 +28,7 @@ class Command extends BaseCommand {
|
||||
|
||||
for (let i = 0; i < notes.length; i++) {
|
||||
const newNote = await Note.copyToFolder(notes[i].id, folder.id);
|
||||
Note.updateGeolocation(newNote.id);
|
||||
void Note.updateGeolocation(newNote.id);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,20 +1,20 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const time = require('@joplin/lib/time').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import time from '@joplin/lib/time';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'done <note>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Marks a to-do as done.');
|
||||
}
|
||||
|
||||
static async handleAction(commandInstance, args, isCompleted) {
|
||||
public static async handleAction(commandInstance: BaseCommand, args: any, isCompleted: boolean) {
|
||||
const note = await app().loadItem(BaseModel.TYPE_NOTE, args.note);
|
||||
commandInstance.encryptionCheck(note);
|
||||
if (!note) throw new Error(_('Cannot find "%s".', args.note));
|
||||
@@ -30,7 +30,7 @@ class Command extends BaseCommand {
|
||||
});
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
await Command.handleAction(this, args, true);
|
||||
}
|
||||
}
|
@@ -1,22 +1,22 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const Tag = require('@joplin/lib/models/Tag').default;
|
||||
import BaseCommand from './base-command';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Tag from '@joplin/lib/models/Tag';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'dump';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return 'Dumps the complete database as JSON.';
|
||||
}
|
||||
|
||||
hidden() {
|
||||
public override hidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async action() {
|
||||
public override async action() {
|
||||
let items = [];
|
||||
const folders = await Folder.all();
|
||||
for (let i = 0; i < folders.length; i++) {
|
@@ -1,24 +1,24 @@
|
||||
const fs = require('fs-extra');
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { splitCommandString } = require('@joplin/utils');
|
||||
const uuid = require('@joplin/lib/uuid').default;
|
||||
import * as fs from 'fs-extra';
|
||||
import BaseCommand from './base-command';
|
||||
import { splitCommandString } from '@joplin/utils';
|
||||
import uuid from '@joplin/lib/uuid';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'edit <note>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Edit note.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
let tempFilePath = null;
|
||||
public override async action(args: any) {
|
||||
let tempFilePath: string|null = null;
|
||||
|
||||
const onFinishedEditing = async () => {
|
||||
if (tempFilePath) fs.removeSync(tempFilePath);
|
@@ -1,21 +1,21 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'exit';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Exits the application.');
|
||||
}
|
||||
|
||||
compatibleUis() {
|
||||
public override compatibleUis() {
|
||||
return ['gui'];
|
||||
}
|
||||
|
||||
async action() {
|
||||
public override async action() {
|
||||
await app().exit();
|
||||
}
|
||||
}
|
@@ -1,25 +1,25 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const ReportService = require('@joplin/lib/services/ReportService').default;
|
||||
const fs = require('fs-extra');
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import ReportService from '@joplin/lib/services/ReportService';
|
||||
import * as fs from 'fs-extra';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'export-sync-status';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return 'Export sync status';
|
||||
}
|
||||
|
||||
hidden() {
|
||||
public override hidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async action() {
|
||||
public override async action() {
|
||||
const service = new ReportService();
|
||||
const csv = await service.basicItemList({ format: 'csv' });
|
||||
const csv = await service.basicItemList({ format: 'csv' }) as string;
|
||||
const filePath = `${Setting.value('profileDir')}/syncReport-${new Date().getTime()}.csv`;
|
||||
await fs.writeFileSync(filePath, csv);
|
||||
this.stdout(`Sync status exported to ${filePath}`);
|
@@ -1,19 +1,20 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const InteropService = require('@joplin/lib/services/interop/InteropService').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import BaseCommand from './base-command';
|
||||
import InteropService from '@joplin/lib/services/interop/InteropService';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { ExportOptions } from '@joplin/lib/services/interop/types';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'export <path>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
const service = InteropService.instance();
|
||||
const formats = service
|
||||
.modules()
|
||||
@@ -23,8 +24,8 @@ class Command extends BaseCommand {
|
||||
return [['--format <format>', _('Destination format: %s', formats.join(', '))], ['--note <note>', _('Exports only the given note.')], ['--notebook <notebook>', _('Exports only the given notebook.')]];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
const exportOptions = {};
|
||||
public override async action(args: any) {
|
||||
const exportOptions: ExportOptions = {};
|
||||
exportOptions.path = args.path;
|
||||
|
||||
exportOptions.format = args.options.format ? args.options.format : 'jex';
|
||||
@@ -34,11 +35,11 @@ class Command extends BaseCommand {
|
||||
if (args.options.note) {
|
||||
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args.options.note, { parent: app().currentFolder() });
|
||||
if (!notes.length) throw new Error(_('Cannot find "%s".', args.options.note));
|
||||
exportOptions.sourceNoteIds = notes.map(n => n.id);
|
||||
exportOptions.sourceNoteIds = notes.map((n: any) => n.id);
|
||||
} else if (args.options.notebook) {
|
||||
const folders = await app().loadItems(BaseModel.TYPE_FOLDER, args.options.notebook);
|
||||
if (!folders.length) throw new Error(_('Cannot find "%s".', args.options.notebook));
|
||||
exportOptions.sourceFolderIds = folders.map(n => n.id);
|
||||
exportOptions.sourceFolderIds = folders.map((n: any) => n.id);
|
||||
}
|
||||
|
||||
const service = InteropService.instance();
|
@@ -1,19 +1,19 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'geoloc <note>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Displays a geolocation URL for the note.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const title = args['note'];
|
||||
|
||||
const item = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
|
@@ -1,19 +1,19 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { renderCommandHelp } = require('./help-utils.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'help [command]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Displays usage information.');
|
||||
}
|
||||
|
||||
allCommands() {
|
||||
private allCommands() {
|
||||
const commands = app().commands(app().uiType());
|
||||
const output = [];
|
||||
for (const n in commands) {
|
||||
@@ -29,7 +29,7 @@ class Command extends BaseCommand {
|
||||
return output;
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const stdoutWidth = app().commandStdoutMaxWidth();
|
||||
|
||||
if (args.command === 'shortcuts' || args.command === 'keymap') {
|
||||
@@ -52,7 +52,7 @@ class Command extends BaseCommand {
|
||||
|
||||
for (let i = 0; i < keymap.length; i++) {
|
||||
const item = keymap[i];
|
||||
const keys = item.keys.map(k => (k === ' ' ? '(SPACE)' : k));
|
||||
const keys = item.keys.map((k: string) => (k === ' ' ? '(SPACE)' : k));
|
||||
rows.push([keys.join(', '), item.command]);
|
||||
}
|
||||
|
@@ -1,20 +1,22 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const InteropService = require('@joplin/lib/services/interop/InteropService').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import BaseCommand from './base-command';
|
||||
import InteropService from '@joplin/lib/services/interop/InteropService';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { ImportOptions } from '@joplin/lib/services/interop/types';
|
||||
import { unique } from '@joplin/lib/array';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'import <path> [notebook]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Imports data into Joplin.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
const service = InteropService.instance();
|
||||
const formats = service
|
||||
.modules()
|
||||
@@ -22,18 +24,18 @@ class Command extends BaseCommand {
|
||||
.map(m => m.format);
|
||||
|
||||
return [
|
||||
['--format <format>', _('Source format: %s', ['auto'].concat(formats).join(', '))],
|
||||
['--format <format>', _('Source format: %s', ['auto'].concat(unique(formats)).join(', '))],
|
||||
['-f, --force', _('Do not ask for confirmation.')],
|
||||
['--output-format <output-format>', _('Output format: %s', 'md, html')],
|
||||
];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
|
||||
|
||||
if (args.notebook && !folder) throw new Error(_('Cannot find "%s".', args.notebook));
|
||||
|
||||
const importOptions = {};
|
||||
const importOptions: ImportOptions = {};
|
||||
importOptions.path = args.path;
|
||||
importOptions.format = args.options.format ? args.options.format : 'auto';
|
||||
importOptions.destinationFolderId = folder ? folder.id : null;
|
@@ -1,28 +1,28 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const time = require('@joplin/lib/time').default;
|
||||
import time from '@joplin/lib/time';
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'ls [note-pattern]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Displays the notes in the current notebook. Use `ls /` to display the list of notebooks.');
|
||||
}
|
||||
|
||||
enabled() {
|
||||
public override enabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
return [
|
||||
['-n, --limit <num>', _('Displays only the first top <num> notes.')],
|
||||
['-s, --sort <field>', _('Sorts the item by <field> (eg. title, updated_time, created_time).')],
|
||||
@@ -33,12 +33,12 @@ class Command extends BaseCommand {
|
||||
];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const pattern = args['note-pattern'];
|
||||
let items = [];
|
||||
const options = args.options;
|
||||
|
||||
const queryOptions = {};
|
||||
const queryOptions: any = {};
|
||||
if (options.limit) queryOptions.limit = options.limit;
|
||||
if (options.sort) {
|
||||
queryOptions.orderBy = options.sort;
|
@@ -1,20 +1,20 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'mv <item> [notebook]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Moves the given <item> to [notebook]');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const pattern = args['item'];
|
||||
const destination = args['notebook'];
|
||||
let folder = null;
|
@@ -1,20 +1,20 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'ren <item> <name>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Renames the given <item> (note or notebook) to <name>.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const pattern = args['item'];
|
||||
const name = args['name'];
|
||||
|
@@ -1,23 +1,23 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'rmbook <notebook>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Deletes the given notebook.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
return [['-f, --force', _('Deletes the notebook without asking for confirmation.')]];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const pattern = args['notebook'];
|
||||
const force = args.options && args.options.force === true;
|
||||
|
@@ -1,23 +1,23 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'rmnote <note-pattern>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Deletes the notes matching <note-pattern>.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public override options() {
|
||||
return [['-f, --force', _('Deletes the notes without asking for confirmation.')]];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const pattern = args['note-pattern'];
|
||||
const force = args.options && args.options.force === true;
|
||||
|
||||
@@ -26,7 +26,7 @@ class Command extends BaseCommand {
|
||||
|
||||
const ok = force ? true : await this.prompt(notes.length > 1 ? _('%d notes match this pattern. Delete them?', notes.length) : _('Delete note?'), { booleanAnswerDefault: 'n' });
|
||||
if (!ok) return;
|
||||
const ids = notes.map(n => n.id);
|
||||
const ids = notes.map((n: any) => n.id);
|
||||
await Note.batchDelete(ids);
|
||||
}
|
||||
}
|
@@ -1,16 +1,16 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Database = require('@joplin/lib/database').default;
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Database from '@joplin/lib/database';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'set <note> <name> [value]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
const fields = Note.fields();
|
||||
const s = [];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
@@ -22,7 +22,7 @@ class Command extends BaseCommand {
|
||||
return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const title = args['note'];
|
||||
const propName = args['name'];
|
||||
let propValue = args['value'];
|
||||
@@ -36,7 +36,7 @@ class Command extends BaseCommand {
|
||||
|
||||
const timestamp = Date.now();
|
||||
|
||||
const newNote = {
|
||||
const newNote: any = {
|
||||
id: notes[i].id,
|
||||
type_: notes[i].type_,
|
||||
updated_time: timestamp,
|
@@ -1,22 +1,22 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'use <notebook>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Switches to [notebook] - all further operations will happen within this notebook.');
|
||||
}
|
||||
|
||||
compatibleUis() {
|
||||
public override compatibleUis() {
|
||||
return ['cli'];
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
public override async action(args: any) {
|
||||
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, args['notebook']);
|
||||
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
|
||||
app().switchCurrentFolder(folder);
|
@@ -1,17 +1,17 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
import BaseCommand from './base-command';
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const versionInfo = require('@joplin/lib/versionInfo').default;
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public override usage() {
|
||||
return 'version';
|
||||
}
|
||||
|
||||
description() {
|
||||
public override description() {
|
||||
return _('Displays version information');
|
||||
}
|
||||
|
||||
async action() {
|
||||
public override async action() {
|
||||
this.stdout(versionInfo(require('./package.json'), {}).message);
|
||||
}
|
||||
}
|
@@ -52,7 +52,7 @@ export default class PluginRunner extends BasePluginRunner {
|
||||
this.activeSandboxCalls_[callId] = true;
|
||||
const promise = executeSandboxCall(pluginId, sandbox, `joplin.${path}`, mapEventHandlersToIds(args, this.eventHandlers_), this.eventHandler);
|
||||
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
|
||||
promise.finally(() => {
|
||||
void promise.finally(() => {
|
||||
delete this.activeSandboxCalls_[callId];
|
||||
});
|
||||
return promise;
|
||||
|
@@ -3,6 +3,7 @@ const { shimInit } = require('@joplin/lib/shim-init-node.js');
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
const sharp = require('sharp');
|
||||
const nodeSqlite = require('sqlite3');
|
||||
require('../../jest.base-setup.js')();
|
||||
|
||||
let keytar;
|
||||
try {
|
||||
|
@@ -35,19 +35,19 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "2.13.0",
|
||||
"version": "2.14.0",
|
||||
"bin": "./main.js",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.13",
|
||||
"@joplin/renderer": "~2.13",
|
||||
"@joplin/utils": "~2.13",
|
||||
"@joplin/lib": "~2.14",
|
||||
"@joplin/renderer": "~2.14",
|
||||
"@joplin/utils": "~2.14",
|
||||
"aws-sdk": "2.1340.0",
|
||||
"chalk": "4.1.2",
|
||||
"compare-version": "0.1.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"html-entities": "1.4.0",
|
||||
"image-type": "3.1.0",
|
||||
"keytar": "7.9.0",
|
||||
@@ -57,7 +57,7 @@
|
||||
"proper-lockfile": "4.1.2",
|
||||
"read-chunk": "2.1.0",
|
||||
"server-destroy": "1.0.1",
|
||||
"sharp": "0.32.6",
|
||||
"sharp": "0.33.1",
|
||||
"sprintf-js": "1.1.3",
|
||||
"sqlite3": "5.1.6",
|
||||
"string-padding": "1.0.2",
|
||||
@@ -70,14 +70,14 @@
|
||||
"yargs-parser": "21.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.13",
|
||||
"@types/fs-extra": "11.0.2",
|
||||
"@types/jest": "29.5.4",
|
||||
"@types/node": "18.17.19",
|
||||
"@joplin/tools": "~2.14",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/jest": "29.5.8",
|
||||
"@types/node": "18.19.3",
|
||||
"@types/proper-lockfile": "^4.1.2",
|
||||
"gulp": "4.0.2",
|
||||
"jest": "29.6.4",
|
||||
"jest": "29.7.0",
|
||||
"temp": "0.9.4",
|
||||
"typescript": "5.1.6"
|
||||
"typescript": "5.2.2"
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,14 @@ describe('HtmlToMd', () => {
|
||||
htmlToMdOptions.preserveImageTagsWithSize = true;
|
||||
}
|
||||
|
||||
if (htmlFilename.indexOf('preserve_nested_tables') === 0) {
|
||||
htmlToMdOptions.preserveNestedTables = true;
|
||||
}
|
||||
|
||||
if (htmlFilename.indexOf('text_color') === 0) {
|
||||
htmlToMdOptions.preserveColorStyles = true;
|
||||
}
|
||||
|
||||
const html = await readFile(htmlPath, 'utf8');
|
||||
let expectedMd = await readFile(mdPath, 'utf8');
|
||||
|
||||
@@ -83,8 +91,8 @@ describe('HtmlToMd', () => {
|
||||
|
||||
it('should allow disabling escape', async () => {
|
||||
const htmlToMd = new HtmlToMd();
|
||||
expect(htmlToMd.parse('https://test.com/1_2_3.pdf', { disableEscapeContent: true })).toBe('https://test.com/1_2_3.pdf');
|
||||
expect(htmlToMd.parse('https://test.com/1_2_3.pdf', { disableEscapeContent: false })).toBe('https://test.com/1\\_2\\_3.pdf');
|
||||
expect(htmlToMd.parse('> 1 _2_ 3.pdf', { disableEscapeContent: true })).toBe('> 1 _2_ 3.pdf');
|
||||
expect(htmlToMd.parse('> 1 _2_ 3.pdf', { disableEscapeContent: false })).toBe('\\> 1 \\_2_ 3.pdf');
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
import MarkupToHtml, { MarkupLanguage, RenderResult } from '@joplin/renderer/MarkupToHtml';
|
||||
import MarkupToHtml, { MarkupLanguage } from '@joplin/renderer/MarkupToHtml';
|
||||
import { RenderResult } from '@joplin/renderer/types';
|
||||
|
||||
describe('MarkupToHtml', () => {
|
||||
|
||||
|
@@ -66,8 +66,10 @@ describe('MdToHtml', () => {
|
||||
actualHtml,
|
||||
'--------------------------------- Raw:',
|
||||
actualHtml.split('\n'),
|
||||
'--------------------------------- Expected:',
|
||||
'--------------------------------- Expected (Lines)',
|
||||
expectedHtml.split('\n'),
|
||||
'--------------------------------- Expected (Text)',
|
||||
expectedHtml,
|
||||
'--------------------------------------------',
|
||||
'',
|
||||
];
|
||||
@@ -289,4 +291,29 @@ describe('MdToHtml', () => {
|
||||
expect(html.html).toContain(opening + trimmedTex + closing);
|
||||
}
|
||||
});
|
||||
|
||||
it('should render inline KaTeX after a numbered equation', async () => {
|
||||
const mdToHtml = newTestMdToHtml();
|
||||
|
||||
// This test is intended to verify that inline KaTeX renders correctly
|
||||
// after creating a numbered equation with \begin{align}...\end{align}.
|
||||
//
|
||||
// See https://github.com/laurent22/joplin/issues/9455 for details.
|
||||
|
||||
const markdown = [
|
||||
'$$',
|
||||
'\\begin{align}\\text{Block}\\end{align}',
|
||||
'$$',
|
||||
'',
|
||||
'$\\text{Inline}$',
|
||||
].join('\n');
|
||||
const { html } = await mdToHtml.render(markdown, null, { bodyOnly: true });
|
||||
|
||||
// Because we don't control the output of KaTeX, this test should be as general as
|
||||
// possible while still verifying that rendering (without an error) occurs.
|
||||
|
||||
// Should have rendered the inline and block content without errors
|
||||
expect(html).toContain('Inline</span>');
|
||||
expect(html).toContain('Block</span>');
|
||||
});
|
||||
});
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<en-note><div>Plain note</div></en-note>]]></content><created>20201223T163948Z</created><updated>20201223T163953Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>Note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
|
||||
|
||||
<en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr<td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><br/></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bl</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20201223T164010Z</created><updated>20201223T164023Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>plain note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr<td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><br/></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bl</div></t><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20201223T164010Z</created><updated>20201223T164023Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>plain note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
|
||||
|
||||
<en-note><div><br/></div></en-note>]]></content><created>20201223T164236Z</created><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export>
|
||||
|
49
packages/app-cli/tests/enex_to_md/linked_notes.enex
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export4.dtd">
|
||||
<en-export export-date="20231224T151504Z" application="Evernote" version="10.68.2">
|
||||
<note>
|
||||
<title>Note 1</title>
|
||||
<created>20160730T164129Z</created>
|
||||
<updated>20231224T151443Z</updated>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div><a href="evernote:///view/5223870/s49/9cd5e810-fa03-429a-8194-ab847f2f1ab2/c99d9e01-ca35-4c75-ba63-f0c0ef97787d/" rel="noopener noreferrer" rev="en_rl_none">Note 2</a><a href="evernote:///view/5223870/s49/9cd5e810-fa03-429a-8194-ab847f2f1ab2/c99d9e01-ca35-4c75-ba63-f0c0ef97787d/" rel="noopener noreferrer" rev="en_rl_none">Note 3</a></div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
<note>
|
||||
<title>Note 2</title>
|
||||
<created>20160730T111759Z</created>
|
||||
<updated>20160730T111807Z</updated>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>Testing</div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
<note>
|
||||
<title>Note 3</title>
|
||||
<created>20160730T111759Z</created>
|
||||
<updated>20160730T111807Z</updated>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div><a href="evernote:///view/5223870/s49/9cd5e810-fa03-429a-8194-ab847f2f1ab2/c99d9e01-ca35-4c75-ba63-f0c0ef97787d/" rel="noopener noreferrer" rev="en_rl_none">Ambiguous note</a></div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
<note>
|
||||
<title>Ambiguous note</title>
|
||||
<created>20160730T111759Z</created>
|
||||
<updated>20160730T111807Z</updated>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>Testing</div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
<note>
|
||||
<title>Ambiguous note</title>
|
||||
<created>20160730T111759Z</created>
|
||||
<updated>20160730T111807Z</updated>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>Testing</div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
</en-export>
|
@@ -0,0 +1,12 @@
|
||||
<table>
|
||||
<div></div> <!-- INVALID! -->
|
||||
<tr>
|
||||
<td>one</td>
|
||||
<td>two</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<div></div> <!-- INVALID! -->
|
||||
<td>three</td>
|
||||
<td>four</td>
|
||||
</tr>
|
||||
</table>
|
@@ -0,0 +1,4 @@
|
||||
| | |
|
||||
| --- | --- |
|
||||
| one | two |
|
||||
| three | four |
|
@@ -15,7 +15,4 @@ however.
|
||||
Because it isn't
|
||||
|
||||
necessary.
|
||||
|
||||
|
||||
|
||||
...
|
||||
<br/><br/><br/>...
|
@@ -0,0 +1,19 @@
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Left side of the main table</td>
|
||||
<td>
|
||||
<table>
|
||||
<b>Nested Table</b>
|
||||
<tr>
|
||||
<td>nested table C1</td>
|
||||
<td>nested table C2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>nested table</td>
|
||||
<td>nested table</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
@@ -0,0 +1 @@
|
||||
<table><tbody><tr><td>Left side of the main table</td><td><b>Nested Table</b><table><tbody><tr><td>nested table C1</td><td>nested table C2</td></tr><tr><td>nested table</td><td>nested table</td></tr></tbody></table></td></tr></tbody></table>
|
4
packages/app-cli/tests/html_to_md/repeated_brs.html
Normal file
@@ -0,0 +1,4 @@
|
||||
A<br/><br/><br/>test.<br/>
|
||||
|
||||
A single <br/><br/>can use two spaces at the end of the line,
|
||||
but<br/><br/>the markdown renderer discards these if the line is otherwise empty.
|
5
packages/app-cli/tests/html_to_md/repeated_brs.md
Normal file
@@ -0,0 +1,5 @@
|
||||
A
|
||||
<br/><br/>test.
|
||||
A single <br/>
|
||||
can use two spaces at the end of the line, but
|
||||
<br/>the markdown renderer discards these if the line is otherwise empty.
|
31
packages/app-cli/tests/html_to_md/table_with_code_3.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<div id="rendered-md">
|
||||
<table class="jop-noMdConv">
|
||||
<thead class="jop-noMdConv">
|
||||
<tr class="jop-noMdConv">
|
||||
<th class="jop-noMdConv">Code</th>
|
||||
<th class="jop-noMdConv">Description</th>
|
||||
</tr>
|
||||
<tr class="jop-noMdConv">
|
||||
<td class="jop-noMdConv">
|
||||
<pre class="jop-noMdConv"><code class="jop-noMdConv">const test = "hello";
|
||||
|
||||
// Another line
|
||||
console.log('Test...');
|
||||
|
||||
// Blank lines
|
||||
|
||||
|
||||
|
||||
// Should not break things.</code></pre>
|
||||
</td>
|
||||
<td class="jop-noMdConv">abcda</td>
|
||||
</tr>
|
||||
<tr class="jop-noMdConv">
|
||||
<td class="jop-noMdConv">
|
||||
<pre class="jop-noMdConv"><code class="jop-noMdConv">const test = "hello";</code></pre>
|
||||
</td>
|
||||
<td class="jop-noMdConv">abcd</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
10
packages/app-cli/tests/html_to_md/table_with_code_3.md
Normal file
@@ -0,0 +1,10 @@
|
||||
<table class="jop-noMdConv"><thead class="jop-noMdConv"><tr class="jop-noMdConv"><th class="jop-noMdConv">Code</th><th class="jop-noMdConv">Description</th></tr><tr class="jop-noMdConv"><td class="jop-noMdConv"><pre class="jop-noMdConv"><code class="">const test = "hello";
|
||||
<!-- -->
|
||||
// Another line
|
||||
console.log('Test...');
|
||||
<!-- -->
|
||||
// Blank lines
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
// Should not break things.</code></pre></td><td class="jop-noMdConv">abcda</td></tr><tr class="jop-noMdConv"><td class="jop-noMdConv"><pre class="jop-noMdConv"><code class="">const test = "hello";</code></pre></td><td class="jop-noMdConv">abcd</td></tr></thead></table>
|
1
packages/app-cli/tests/html_to_md/text_color.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>Text <span style="color: #fff000;">Text</span></p>
|
1
packages/app-cli/tests/html_to_md/text_color.md
Normal file
@@ -0,0 +1 @@
|
||||
Text <span style="color: #fff000;">Text</span>
|
14
packages/app-cli/tests/html_to_md/underscores_in_words.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<p>
|
||||
Some URLs in the Rich_Text_Editor contain <code>_</code> characters, but haven't been converted
|
||||
to links yet. For example, https://www.example.com/a_test_of_links.
|
||||
</p>
|
||||
<p>We should preserve the underscores _without escaping them_ to prevent the links from breaking.</p>
|
||||
<p>
|
||||
This should also correctly handle unicode characters. For example, punctuation❯_requires escapes_,
|
||||
but 𝔏𝔈𝔗𝔗𝔈𝕽_𝔠𝔥𝔞𝔯𝔞𝔠𝔱𝔢𝔯𝔰_and_897_numbers_𝒟on_'t.
|
||||
</p>
|
||||
<p>
|
||||
_Note_ that what [_causes_] a `_` to create italics_ seems to depend only on the character before
|
||||
and an escape at the _beginning_ seems to be sufficient.
|
||||
</p>
|
||||
<p>_s also don't need escapes if _ followed _ by a _space.</p>
|
@@ -0,0 +1,9 @@
|
||||
Some URLs in the Rich_Text_Editor contain `_` characters, but haven't been converted to links yet. For example, https://www.example.com/a_test_of_links.
|
||||
|
||||
We should preserve the underscores \_without escaping them_ to prevent the links from breaking.
|
||||
|
||||
This should also correctly handle unicode characters. For example, punctuation❯\_requires escapes_, but 𝔏𝔈𝔗𝔗𝔈𝕽_𝔠𝔥𝔞𝔯𝔞𝔠𝔱𝔢𝔯𝔰_and_897_numbers_𝒟on_'t.
|
||||
|
||||
\_Note_ that what \[\_causes_\] a \`\_\` to create italics_ seems to depend only on the character before and an escape at the \_beginning_ seems to be sufficient.
|
||||
|
||||
\_s also don't need escapes if _ followed _ by a \_space.
|
7
packages/app-cli/tests/md_to_html/sanitize_links.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<p><a href=":/62d16d1c1e28418da6624fa8742a7ed0" class="jop-noMdConv">Resource link</a></p>
|
||||
<p><a href="https://example.com/ok" class="jop-noMdConv">ok</a></p>
|
||||
<p><a href="http://example.com/ok" class="jop-noMdConv">ok</a></p>
|
||||
<p><a href="mailto:name@email.com" class="jop-noMdConv">ok</a></p>
|
||||
<p><a href="joplin://62d16d1c1e28418da6624fa8742a7ed0" class="jop-noMdConv">ok</a></p>
|
||||
<p><a href="#" class="jop-noMdConv">not ok</a></p>
|
||||
<p><a href="#" class="jop-noMdConv">not ok</a></p>
|
13
packages/app-cli/tests/md_to_html/sanitize_links.md
Normal file
@@ -0,0 +1,13 @@
|
||||
<a href=":/62d16d1c1e28418da6624fa8742a7ed0">Resource link</a>
|
||||
|
||||
<a href="https://example.com/ok">ok</a>
|
||||
|
||||
<a href="http://example.com/ok">ok</a>
|
||||
|
||||
<a href="mailto:name@email.com">ok</a>
|
||||
|
||||
<a href="joplin://62d16d1c1e28418da6624fa8742a7ed0">ok</a>
|
||||
|
||||
<a href="file:///etc/passwd">not ok</a>
|
||||
|
||||
<a href="data://blabla">not ok</a>
|
@@ -0,0 +1,3 @@
|
||||
<nav class="table-of-contents"><ul><li><a href="#test">test</a></li><li><a href="#test-2">test</a></li><li><a href="#test2">test2</a></li></ul></nav><h1 id="test">test</h1>
|
||||
<h1 id="test-2">test</h1>
|
||||
<h1 id="test2">test2</h1>
|
5
packages/app-cli/tests/md_to_html/toc_duplicate_items.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[toc]
|
||||
|
||||
# test
|
||||
# test
|
||||
# test2
|
BIN
packages/app-cli/tests/ocr_samples/dummy.pdf
Normal file
BIN
packages/app-cli/tests/ocr_samples/testocr.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
packages/app-cli/tests/ocr_samples/with_bullets.png
Normal file
After Width: | Height: | Size: 117 KiB |
@@ -1,5 +1,5 @@
|
||||
import PluginRunner from '../../../app/services/plugins/PluginRunner';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import { ContentScriptType } from '@joplin/lib/services/plugins/api/types';
|
||||
import MdToHtml from '@joplin/renderer/MdToHtml';
|
||||
import shim from '@joplin/lib/shim';
|
||||
@@ -206,7 +206,7 @@ describe('services_PluginService', () => {
|
||||
|
||||
const mdToHtml = new MdToHtml();
|
||||
const module = require(contentScript.path).default;
|
||||
mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({}));
|
||||
mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({}), '');
|
||||
|
||||
const result = await mdToHtml.render([
|
||||
'```justtesting',
|
||||
@@ -304,4 +304,33 @@ describe('services_PluginService', () => {
|
||||
expect(JSON.parse(folders[0].title)).toBe(expectedPath);
|
||||
}));
|
||||
|
||||
it('should uninstall multiple plugins', async () => {
|
||||
const service = newPluginService();
|
||||
const pluginId1 = 'org.joplinapp.FirstJplPlugin';
|
||||
const pluginId2 = 'org.joplinapp.plugins.TocDemo';
|
||||
const pluginPath1 = `${testPluginDir}/jpl_test/${pluginId1}.jpl`;
|
||||
const pluginPath2 = `${testPluginDir}/toc/${pluginId2}.jpl`;
|
||||
|
||||
await service.installPlugin(pluginPath1);
|
||||
await service.installPlugin(pluginPath2);
|
||||
|
||||
// Both should be installed
|
||||
expect(await fs.pathExists(`${Setting.value('pluginDir')}/${pluginId1}.jpl`)).toBe(true);
|
||||
expect(await fs.pathExists(`${Setting.value('pluginDir')}/${pluginId2}.jpl`)).toBe(true);
|
||||
|
||||
const pluginSettings: PluginSettings = {
|
||||
[pluginId1]: { enabled: true, deleted: true, hasBeenUpdated: false },
|
||||
[pluginId2]: { enabled: true, deleted: true, hasBeenUpdated: false },
|
||||
};
|
||||
|
||||
const newPluginSettings = await service.uninstallPlugins(pluginSettings);
|
||||
|
||||
// Should have deleted plugins
|
||||
expect(await fs.pathExists(`${Setting.value('pluginDir')}/${pluginId1}.jpl`)).toBe(false);
|
||||
expect(await fs.pathExists(`${Setting.value('pluginDir')}${pluginId2}.jpl`)).toBe(false);
|
||||
|
||||
// Should clear deleted plugins from settings
|
||||
expect(newPluginSettings[pluginId1]).toBe(undefined);
|
||||
expect(newPluginSettings[pluginId2]).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
@@ -1,11 +1,9 @@
|
||||
import { installDefaultPlugins, getDefaultPluginsInstallState, setSettingsForDefaultPlugins, checkPreInstalledDefaultPlugins } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
||||
import { afterDefaultPluginsLoaded, getDefaultPluginPathsAndSettings } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
||||
import PluginRunner from '../../../app/services/plugins/PluginRunner';
|
||||
import { pathExists } from 'fs-extra';
|
||||
import { checkThrow, setupDatabaseAndSynchronizer, supportDir, switchClient } from '@joplin/lib/testing/test-utils';
|
||||
import PluginService, { defaultPluginSetting, DefaultPluginsInfo, PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import PluginService, { defaultPluginSetting, DefaultPluginsInfo } from '@joplin/lib/services/plugins/PluginService';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
|
||||
const testPluginDir = `${supportDir}/plugins`;
|
||||
|
||||
function newPluginService(appVersion = '1.4') {
|
||||
const runner = new PluginRunner();
|
||||
@@ -27,13 +25,17 @@ function newPluginService(appVersion = '1.4') {
|
||||
describe('defaultPluginsUtils', () => {
|
||||
|
||||
const pluginsId = ['joplin.plugin.ambrt.backlinksToNote', 'org.joplinapp.plugins.ToggleSidebars'];
|
||||
const defaultPluginsInfo = {
|
||||
'joplin.plugin.ambrt.backlinksToNote': {},
|
||||
'org.joplinapp.plugins.ToggleSidebars': {},
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
});
|
||||
|
||||
it('should install default plugins with no previous default plugins installed', (async () => {
|
||||
it('should load default plugins when nor previously installed', (async () => {
|
||||
const testPluginDir = `${supportDir}/pluginRepo/plugins`;
|
||||
Setting.setValue('installedDefaultPlugins', []);
|
||||
|
||||
@@ -41,218 +43,150 @@ describe('defaultPluginsUtils', () => {
|
||||
|
||||
const pluginSettings = service.unserializePluginSettings(Setting.value('plugins.states'));
|
||||
|
||||
const newPluginsSettings = await installDefaultPlugins(service, testPluginDir, pluginsId, pluginSettings);
|
||||
for (const pluginId of pluginsId) {
|
||||
expect(pluginSettings[pluginId]).toBeFalsy();
|
||||
}
|
||||
|
||||
const installedPluginPath1 = `${Setting.value('pluginDir')}/${pluginsId[0]}.jpl`;
|
||||
const installedPluginPath2 = `${Setting.value('pluginDir')}/${pluginsId[1]}.jpl`;
|
||||
|
||||
expect(await pathExists(installedPluginPath1)).toBe(true);
|
||||
expect(await pathExists(installedPluginPath2)).toBe(true);
|
||||
|
||||
expect(newPluginsSettings[pluginsId[0]]).toMatchObject(defaultPluginSetting());
|
||||
expect(newPluginsSettings[pluginsId[1]]).toMatchObject(defaultPluginSetting());
|
||||
const pluginPathsAndNewSettings = await getDefaultPluginPathsAndSettings(testPluginDir, defaultPluginsInfo, pluginSettings);
|
||||
|
||||
for (const pluginId of pluginsId) {
|
||||
expect(
|
||||
pluginPathsAndNewSettings.pluginSettings[pluginId],
|
||||
).toMatchObject(defaultPluginSetting());
|
||||
}
|
||||
}));
|
||||
|
||||
it('should install default plugins with previous default plugins installed', (async () => {
|
||||
|
||||
it('should keep already created default plugins disabled with previous default plugins installed', (async () => {
|
||||
const testPluginDir = `${supportDir}/pluginRepo/plugins`;
|
||||
Setting.setValue('installedDefaultPlugins', ['org.joplinapp.plugins.ToggleSidebars']);
|
||||
Setting.setValue('plugins.states', {
|
||||
'org.joplinapp.plugins.ToggleSidebars': { ...defaultPluginSetting(), enabled: false },
|
||||
});
|
||||
|
||||
const service = newPluginService('2.1');
|
||||
|
||||
const pluginSettings = service.unserializePluginSettings(Setting.value('plugins.states'));
|
||||
const pluginPathsAndNewSettings = await getDefaultPluginPathsAndSettings(testPluginDir, defaultPluginsInfo, pluginSettings);
|
||||
|
||||
const newPluginsSettings = await installDefaultPlugins(service, testPluginDir, pluginsId, pluginSettings);
|
||||
|
||||
const installedPluginPath1 = `${Setting.value('pluginDir')}/${pluginsId[0]}.jpl`;
|
||||
const installedPluginPath2 = `${Setting.value('pluginDir')}/${pluginsId[1]}.jpl`;
|
||||
|
||||
expect(await pathExists(installedPluginPath1)).toBe(true);
|
||||
expect(await pathExists(installedPluginPath2)).toBe(false);
|
||||
|
||||
expect(newPluginsSettings[pluginsId[0]]).toMatchObject(defaultPluginSetting());
|
||||
expect(newPluginsSettings[pluginsId[1]]).toBeUndefined();
|
||||
// Should still be disabled
|
||||
expect(
|
||||
pluginPathsAndNewSettings.pluginSettings['org.joplinapp.plugins.ToggleSidebars'].enabled,
|
||||
).toBe(false);
|
||||
}));
|
||||
|
||||
it('should get default plugins install state', (async () => {
|
||||
const testCases = [
|
||||
{
|
||||
'installedDefaultPlugins': [''],
|
||||
'loadingPlugins': [`${testPluginDir}/simple`, `${testPluginDir}/jpl_test/org.joplinapp.FirstJplPlugin.jpl`],
|
||||
'plugin1DefaultState': defaultPluginSetting(),
|
||||
'plugin2DefaultState': defaultPluginSetting(),
|
||||
'installedDefaultPlugins1': true,
|
||||
'installedDefaultPlugins2': true,
|
||||
},
|
||||
{
|
||||
'installedDefaultPlugins': [''],
|
||||
'loadingPlugins': [`${testPluginDir}/simple`],
|
||||
'plugin1DefaultState': defaultPluginSetting(),
|
||||
'plugin2DefaultState': undefined,
|
||||
'installedDefaultPlugins1': true,
|
||||
'installedDefaultPlugins2': false,
|
||||
},
|
||||
{
|
||||
'installedDefaultPlugins': ['org.joplinapp.plugins.Simple'],
|
||||
'loadingPlugins': [`${testPluginDir}/simple`, `${testPluginDir}/jpl_test/org.joplinapp.FirstJplPlugin.jpl`],
|
||||
'plugin1DefaultState': undefined,
|
||||
'plugin2DefaultState': defaultPluginSetting(),
|
||||
'installedDefaultPlugins1': true,
|
||||
'installedDefaultPlugins2': true,
|
||||
},
|
||||
{
|
||||
'installedDefaultPlugins': ['org.joplinapp.plugins.Simple'],
|
||||
'loadingPlugins': [`${testPluginDir}/simple`],
|
||||
'plugin1DefaultState': undefined,
|
||||
'plugin2DefaultState': undefined,
|
||||
'installedDefaultPlugins1': true,
|
||||
'installedDefaultPlugins2': false,
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
const service = newPluginService();
|
||||
const pluginsId = ['org.joplinapp.plugins.Simple', 'org.joplinapp.FirstJplPlugin'];
|
||||
|
||||
Setting.setValue('installedDefaultPlugins', testCase.installedDefaultPlugins);
|
||||
await service.loadAndRunPlugins(testCase.loadingPlugins, {});
|
||||
|
||||
// setting installedDefaultPlugins state
|
||||
const defaultInstallStates: PluginSettings = getDefaultPluginsInstallState(service, pluginsId);
|
||||
|
||||
expect(defaultInstallStates[pluginsId[0]]).toStrictEqual(testCase.plugin1DefaultState);
|
||||
expect(defaultInstallStates[pluginsId[1]]).toStrictEqual(testCase.plugin2DefaultState);
|
||||
|
||||
|
||||
const installedDefaultPlugins = Setting.value('installedDefaultPlugins');
|
||||
expect(installedDefaultPlugins.includes(pluginsId[0])).toBe(testCase.installedDefaultPlugins1);
|
||||
expect(installedDefaultPlugins.includes(pluginsId[1])).toBe(testCase.installedDefaultPlugins2);
|
||||
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
it('should check pre-installed default plugins', (async () => {
|
||||
// with previous pre-installed default plugins
|
||||
Setting.setValue('installedDefaultPlugins', ['']);
|
||||
let pluginSettings, installedDefaultPlugins;
|
||||
|
||||
pluginSettings = { [pluginsId[0]]: defaultPluginSetting() };
|
||||
checkPreInstalledDefaultPlugins(pluginsId, pluginSettings);
|
||||
|
||||
installedDefaultPlugins = Setting.value('installedDefaultPlugins');
|
||||
expect(installedDefaultPlugins.includes(pluginsId[0])).toBe(true);
|
||||
expect(installedDefaultPlugins.includes(pluginsId[1])).toBe(false);
|
||||
|
||||
|
||||
// with no previous pre-installed default plugins
|
||||
Setting.setValue('installedDefaultPlugins', ['not-a-default-plugin']);
|
||||
pluginSettings = {};
|
||||
checkPreInstalledDefaultPlugins(pluginsId, pluginSettings);
|
||||
|
||||
installedDefaultPlugins = Setting.value('installedDefaultPlugins');
|
||||
expect(installedDefaultPlugins.includes(pluginsId[0])).toBe(false);
|
||||
expect(installedDefaultPlugins.includes(pluginsId[1])).toBe(false);
|
||||
|
||||
}));
|
||||
const sampleJsBundlePlugin = `
|
||||
/* joplin-manifest:
|
||||
{
|
||||
"id": "io.github.jackgruber.backup",
|
||||
"manifest_version": 1,
|
||||
"app_min_version": "1.4",
|
||||
"name": "JS Bundle test",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
*/
|
||||
joplin.plugins.register({
|
||||
onStart: async function() {
|
||||
await joplin.settings.registerSettings({
|
||||
path: {
|
||||
value: "initial-path",
|
||||
type: 2,
|
||||
section: "backupSection",
|
||||
public: true,
|
||||
label: "Backup path",
|
||||
},
|
||||
})
|
||||
},
|
||||
});`;
|
||||
|
||||
it('should set initial settings for default plugins', async () => {
|
||||
const service = newPluginService();
|
||||
|
||||
const pluginScript = `
|
||||
/* joplin-manifest:
|
||||
{
|
||||
"id": "io.github.jackgruber.backup",
|
||||
"manifest_version": 1,
|
||||
"app_min_version": "1.4",
|
||||
"name": "JS Bundle test",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
*/
|
||||
joplin.plugins.register({
|
||||
onStart: async function() {
|
||||
await joplin.settings.registerSettings({
|
||||
path: {
|
||||
value: "initial-path",
|
||||
type: 2,
|
||||
section: "backupSection",
|
||||
public: true,
|
||||
label: "Backup path",
|
||||
},
|
||||
})
|
||||
},
|
||||
});`;
|
||||
|
||||
const plugin = await service.loadPluginFromJsBundle('', pluginScript);
|
||||
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
||||
plugin.builtIn = true;
|
||||
await service.runPlugin(plugin);
|
||||
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
||||
|
||||
const defaultPluginsInfo: DefaultPluginsInfo = {
|
||||
'io.github.jackgruber.backup': {
|
||||
version: '1.0.2',
|
||||
settings: {
|
||||
'path': `${Setting.value('profileDir')}`,
|
||||
},
|
||||
},
|
||||
'plugin.calebjohn.rich-markdown': {
|
||||
version: '0.8.3',
|
||||
},
|
||||
};
|
||||
|
||||
// with pre-installed default plugin
|
||||
Setting.setValue('installedDefaultPlugins', ['io.github.jackgruber.backup']);
|
||||
setSettingsForDefaultPlugins(defaultPluginsInfo);
|
||||
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
||||
|
||||
await afterDefaultPluginsLoaded(
|
||||
runningPlugins,
|
||||
defaultPluginsInfo,
|
||||
pluginSettings,
|
||||
);
|
||||
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe('initial-path');
|
||||
await service.destroy();
|
||||
|
||||
// with no pre-installed default plugin
|
||||
Setting.setValue('installedDefaultPlugins', ['']);
|
||||
setSettingsForDefaultPlugins(defaultPluginsInfo);
|
||||
await afterDefaultPluginsLoaded(
|
||||
runningPlugins,
|
||||
defaultPluginsInfo,
|
||||
pluginSettings,
|
||||
);
|
||||
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe(`${Setting.value('profileDir')}`);
|
||||
await service.destroy();
|
||||
});
|
||||
|
||||
it('should not overwrite existing settings for a user-installed version of a built-in plugin', async () => {
|
||||
const service = newPluginService();
|
||||
|
||||
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
||||
plugin.builtIn = false;
|
||||
await service.runPlugin(plugin);
|
||||
|
||||
const defaultPluginsInfo: DefaultPluginsInfo = {
|
||||
'io.github.jackgruber.backup': {
|
||||
settings: {
|
||||
'path': 'overwrite?',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// No pre-installed default plugins
|
||||
Setting.setValue('installedDefaultPlugins', []);
|
||||
|
||||
// The plugin is running and enabled
|
||||
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
||||
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
||||
|
||||
await afterDefaultPluginsLoaded(
|
||||
runningPlugins,
|
||||
defaultPluginsInfo,
|
||||
pluginSettings,
|
||||
);
|
||||
|
||||
// Should not overwrite
|
||||
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe('initial-path');
|
||||
});
|
||||
|
||||
it('should not throw error on missing setting key', async () => {
|
||||
|
||||
const service = newPluginService();
|
||||
|
||||
const pluginScript = `
|
||||
/* joplin-manifest:
|
||||
{
|
||||
"id": "io.github.jackgruber.backup",
|
||||
"manifest_version": 1,
|
||||
"app_min_version": "1.4",
|
||||
"name": "JS Bundle test",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
*/
|
||||
joplin.plugins.register({
|
||||
onStart: async function() {
|
||||
await joplin.settings.registerSettings({
|
||||
path: {
|
||||
value: "initial-path",
|
||||
type: 2,
|
||||
section: "backupSection",
|
||||
public: true,
|
||||
label: "Backup path",
|
||||
},
|
||||
})
|
||||
},
|
||||
});`;
|
||||
|
||||
const plugin = await service.loadPluginFromJsBundle('', pluginScript);
|
||||
const plugin = await service.loadPluginFromJsBundle('', sampleJsBundlePlugin);
|
||||
plugin.builtIn = true;
|
||||
await service.runPlugin(plugin);
|
||||
|
||||
const defaultPluginsInfo: DefaultPluginsInfo = {
|
||||
'io.github.jackgruber.backup': {
|
||||
version: '1.0.2',
|
||||
settings: {
|
||||
'path': `${Setting.value('profileDir')}`,
|
||||
'missing-key1': 'someValue',
|
||||
},
|
||||
},
|
||||
'plugin.calebjohn.rich-markdown': {
|
||||
version: '0.8.3',
|
||||
settings: {
|
||||
'missing-key2': 'someValue',
|
||||
},
|
||||
@@ -260,7 +194,10 @@ describe('defaultPluginsUtils', () => {
|
||||
};
|
||||
|
||||
Setting.setValue('installedDefaultPlugins', ['']);
|
||||
expect(checkThrow(() => setSettingsForDefaultPlugins(defaultPluginsInfo))).toBe(false);
|
||||
const pluginSettings = { 'io.github.jackgruber.backup': defaultPluginSetting() };
|
||||
const runningPlugins = { 'io.github.jackgruber.backup': plugin };
|
||||
|
||||
expect(checkThrow(() => afterDefaultPluginsLoaded(runningPlugins, defaultPluginsInfo, pluginSettings))).toBe(false);
|
||||
expect(Setting.value('plugin-io.github.jackgruber.backup.path')).toBe(`${Setting.value('profileDir')}`);
|
||||
await service.destroy();
|
||||
});
|
||||
|
3
packages/app-cli/tests/support/plugins/codemirror6/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
node_modules/
|
||||
publish/
|
@@ -0,0 +1,8 @@
|
||||
*.md
|
||||
!README.md
|
||||
/*.jpl
|
||||
/api
|
||||
/src
|
||||
/dist
|
||||
tsconfig.json
|
||||
webpack.config.js
|
@@ -0,0 +1,78 @@
|
||||
# Plugin development
|
||||
|
||||
This documentation describes how to create a plugin, and how to work with the plugin builder framework and API.
|
||||
|
||||
## Installation
|
||||
|
||||
First, install [Yeoman](http://yeoman.io) and generator-joplin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)).
|
||||
|
||||
```bash
|
||||
npm install -g yo
|
||||
npm install -g generator-joplin
|
||||
```
|
||||
|
||||
Then generate your new project:
|
||||
|
||||
```bash
|
||||
yo --node-package-manager npm joplin
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
The main two files you will want to look at are:
|
||||
|
||||
- `/src/index.ts`, which contains the entry point for the plugin source code.
|
||||
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
|
||||
|
||||
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
|
||||
|
||||
## Building the plugin
|
||||
|
||||
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
|
||||
|
||||
To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Updating the manifest version number
|
||||
|
||||
You can run `npm run updateVersion` to bump the patch part of the version number, so for example 1.0.3 will become 1.0.4. This script will update both the package.json and manifest.json version numbers so as to keep them in sync.
|
||||
|
||||
## Publishing the plugin
|
||||
|
||||
To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
|
||||
|
||||
- In `package.json`, the name starts with "joplin-plugin-". For example, "joplin-plugin-toc".
|
||||
- In `package.json`, the keywords include "joplin-plugin".
|
||||
- In the `publish/` directory, there should be a .jpl and .json file (which are built by `npm run dist`)
|
||||
|
||||
In general all this is done automatically by the plugin generator, which will set the name and keywords of package.json, and will put the right files in the "publish" directory. But if something doesn't work and your plugin doesn't appear in the repository, double-check the above conditions.
|
||||
|
||||
## Updating the plugin framework
|
||||
|
||||
To update the plugin framework, run `npm run update`.
|
||||
|
||||
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
|
||||
|
||||
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
|
||||
|
||||
## External script files
|
||||
|
||||
By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
|
||||
|
||||
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
|
||||
|
||||
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
|
||||
|
||||
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
|
||||
|
||||
## More information
|
||||
|
||||
- [Joplin Plugin API](https://joplinapp.org/api/references/plugin_api/classes/joplin.html)
|
||||
- [Joplin Data API](https://joplinapp.org/help/api/references/rest_api)
|
||||
- [Joplin Plugin Manifest](https://joplinapp.org/api/references/plugin_manifest/)
|
||||
- Ask for help on the [forum](https://discourse.joplinapp.org/) or our [Discord channel](https://discord.gg/VSj7AFHvpq)
|
||||
|
||||
## License
|
||||
|
||||
MIT © Laurent Cozic
|
@@ -0,0 +1,9 @@
|
||||
# CodeMirror 6 sample plugin
|
||||
|
||||
This plugin demonstrates how to use the CodeMirror 6 plugin API. See `src/contentScript.ts`.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> At the time of this writing, the CodeMirror 6 editor is in beta and must be enabled
|
||||
> in settings.
|
||||
>
|
14
packages/app-cli/tests/support/plugins/codemirror6/api/Global.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import Plugin from '../Plugin';
|
||||
import Joplin from './Joplin';
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export default class Global {
|
||||
private joplin_;
|
||||
constructor(implementation: any, plugin: Plugin, store: any);
|
||||
get joplin(): Joplin;
|
||||
get process(): any;
|
||||
}
|
74
packages/app-cli/tests/support/plugins/codemirror6/api/Joplin.d.ts
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import Plugin from '../Plugin';
|
||||
import JoplinData from './JoplinData';
|
||||
import JoplinPlugins from './JoplinPlugins';
|
||||
import JoplinWorkspace from './JoplinWorkspace';
|
||||
import JoplinFilters from './JoplinFilters';
|
||||
import JoplinCommands from './JoplinCommands';
|
||||
import JoplinViews from './JoplinViews';
|
||||
import JoplinInterop from './JoplinInterop';
|
||||
import JoplinSettings from './JoplinSettings';
|
||||
import JoplinContentScripts from './JoplinContentScripts';
|
||||
import JoplinClipboard from './JoplinClipboard';
|
||||
import JoplinWindow from './JoplinWindow';
|
||||
import BasePlatformImplementation from '../BasePlatformImplementation';
|
||||
import JoplinImaging from './JoplinImaging';
|
||||
/**
|
||||
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
|
||||
*
|
||||
* The API is now relatively stable and in general maintaining backward compatibility is a top priority, so you shouldn't except much breakages.
|
||||
*
|
||||
* If a breaking change ever becomes needed, best effort will be done to:
|
||||
*
|
||||
* - Deprecate features instead of removing them, so as to give you time to fix the issue;
|
||||
* - Document breaking changes in the changelog;
|
||||
*
|
||||
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code.
|
||||
*/
|
||||
export default class Joplin {
|
||||
private data_;
|
||||
private plugins_;
|
||||
private imaging_;
|
||||
private workspace_;
|
||||
private filters_;
|
||||
private commands_;
|
||||
private views_;
|
||||
private interop_;
|
||||
private settings_;
|
||||
private contentScripts_;
|
||||
private clipboard_;
|
||||
private window_;
|
||||
private implementation_;
|
||||
constructor(implementation: BasePlatformImplementation, plugin: Plugin, store: any);
|
||||
get data(): JoplinData;
|
||||
get clipboard(): JoplinClipboard;
|
||||
get imaging(): JoplinImaging;
|
||||
get window(): JoplinWindow;
|
||||
get plugins(): JoplinPlugins;
|
||||
get workspace(): JoplinWorkspace;
|
||||
get contentScripts(): JoplinContentScripts;
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* Not sure if it's the best way to hook into the app
|
||||
* so for now disable filters.
|
||||
*/
|
||||
get filters(): JoplinFilters;
|
||||
get commands(): JoplinCommands;
|
||||
get views(): JoplinViews;
|
||||
get interop(): JoplinInterop;
|
||||
get settings(): JoplinSettings;
|
||||
/**
|
||||
* It is not possible to bundle native packages with a plugin, because they
|
||||
* need to work cross-platforms. Instead access to certain useful native
|
||||
* packages is provided using this function.
|
||||
*
|
||||
* Currently these packages are available:
|
||||
*
|
||||
* - [sqlite3](https://www.npmjs.com/package/sqlite3)
|
||||
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
|
||||
*/
|
||||
require(_path: string): any;
|
||||
versionInfo(): Promise<import("./types").VersionInfo>;
|
||||
}
|
23
packages/app-cli/tests/support/plugins/codemirror6/api/JoplinClipboard.d.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
export default class JoplinClipboard {
|
||||
private electronClipboard_;
|
||||
private electronNativeImage_;
|
||||
constructor(electronClipboard: any, electronNativeImage: any);
|
||||
readText(): Promise<string>;
|
||||
writeText(text: string): Promise<void>;
|
||||
readHtml(): Promise<string>;
|
||||
writeHtml(html: string): Promise<void>;
|
||||
/**
|
||||
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
|
||||
*/
|
||||
readImage(): Promise<string>;
|
||||
/**
|
||||
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
|
||||
*/
|
||||
writeImage(dataUrl: string): Promise<void>;
|
||||
/**
|
||||
* Returns the list available formats (mime types).
|
||||
*
|
||||
* For example [ 'text/plain', 'text/html' ]
|
||||
*/
|
||||
availableFormats(): Promise<string[]>;
|
||||
}
|
89
packages/app-cli/tests/support/plugins/codemirror6/api/JoplinCommands.d.ts
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Command } from './types';
|
||||
/**
|
||||
* This class allows executing or registering new Joplin commands. Commands
|
||||
* can be executed or associated with
|
||||
* {@link JoplinViewsToolbarButtons | toolbar buttons} or
|
||||
* {@link JoplinViewsMenuItems | menu items}.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
|
||||
*
|
||||
* ## Executing Joplin's internal commands
|
||||
*
|
||||
* It is also possible to execute internal Joplin's commands which, as of
|
||||
* now, are not well documented. You can find the list directly on GitHub
|
||||
* though at the following locations:
|
||||
*
|
||||
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/MainScreen/commands)
|
||||
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/commands)
|
||||
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts)
|
||||
*
|
||||
* To view what arguments are supported, you can open any of these files
|
||||
* and look at the `execute()` command.
|
||||
*
|
||||
* ## Executing editor commands
|
||||
*
|
||||
* There might be a situation where you want to invoke editor commands
|
||||
* without using a {@link JoplinContentScripts | contentScript}. For this
|
||||
* reason Joplin provides the built in `editor.execCommand` command.
|
||||
*
|
||||
* `editor.execCommand` should work with any core command in both the
|
||||
* [CodeMirror](https://codemirror.net/doc/manual.html#execCommand) and
|
||||
* [TinyMCE](https://www.tiny.cloud/docs/api/tinymce/tinymce.editorcommands/#execcommand) editors,
|
||||
* as well as most functions calls directly on a CodeMirror editor object (extensions).
|
||||
*
|
||||
* * [CodeMirror commands](https://codemirror.net/doc/manual.html#commands)
|
||||
* * [TinyMCE core editor commands](https://www.tiny.cloud/docs/advanced/editor-command-identifiers/#coreeditorcommands)
|
||||
*
|
||||
* `editor.execCommand` supports adding arguments for the commands.
|
||||
*
|
||||
* ```typescript
|
||||
* await joplin.commands.execute('editor.execCommand', {
|
||||
* name: 'madeUpCommand', // CodeMirror and TinyMCE
|
||||
* args: [], // CodeMirror and TinyMCE
|
||||
* ui: false, // TinyMCE only
|
||||
* value: '', // TinyMCE only
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* [View the example using the CodeMirror editor](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts)
|
||||
*
|
||||
*/
|
||||
export default class JoplinCommands {
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Executes the given
|
||||
* command.
|
||||
*
|
||||
* The command can take any number of arguments, and the supported
|
||||
* arguments will vary based on the command. For custom commands, this
|
||||
* is the `args` passed to the `execute()` function. For built-in
|
||||
* commands, you can find the supported arguments by checking the links
|
||||
* above.
|
||||
*
|
||||
* ```typescript
|
||||
* // Create a new note in the current notebook:
|
||||
* await joplin.commands.execute('newNote');
|
||||
*
|
||||
* // Create a new sub-notebook under the provided notebook
|
||||
* // Note: internally, notebooks are called "folders".
|
||||
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
|
||||
* ```
|
||||
*/
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Registers a new command.
|
||||
*
|
||||
* ```typescript
|
||||
* // Register a new commmand called "testCommand1"
|
||||
*
|
||||
* await joplin.commands.register({
|
||||
* name: 'testCommand1',
|
||||
* label: 'My Test Command 1',
|
||||
* iconName: 'fas fa-music',
|
||||
* execute: () => {
|
||||
* alert('Testing plugin command 1');
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register(command: Command): Promise<void>;
|
||||
}
|