Compare commits

..

73 Commits

Author SHA1 Message Date
Ammar Ahmed
6457733697 mobile: fix download file overwrite error 2024-09-20 12:01:33 +05:00
Abdullah Atta
0e3a661dd0 desktop: delete app data on uninstall (fixes #5209) 2024-09-16 14:25:50 +05:00
Abdullah Atta
fba350ed1e editor: refactor toggleCodeBlock 2024-09-16 12:34:25 +05:00
Sean-Wyn Ng
76bfbc7316 desktop: fix issues with codeblock toggling (#6435)
Signed-off-by: Sean-Wyn Ng <seanwynng@gmail.com>
Co-authored-by: seanwynwins <shidderwinsgit.hcma2@slmail.me>
2024-09-16 12:26:20 +05:00
Abdullah Atta
7683d8fa5b core: fix crash when searching 2024-09-16 11:49:49 +05:00
Abdullah Atta
3fe5352b56 core: resort date formats and add DD.MM.YYYY format (fixes #4744) 2024-09-13 15:39:09 +05:00
Abdullah Atta
a86d9a9c0c web: default notebook always assigned to note (fixes #5861) 2024-09-13 14:35:38 +05:00
Ammar Ahmed
a68f74bc1b core: fix locking notes with empty content (#6545)
* core: fix locking notes with empty content

* core: lock note and return if rawContent already locked

* core: update comment

* core: allow locking an empty note

* core: updates

* core: updates

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-13 12:18:55 +05:00
Muhammad Ali
18310698f6 editor: add ctrl+k to create link shortcut (#3501)
* editor: added link pop-up keyboard short-cut

* editor: Ctrl+K to create link

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-13 11:10:50 +05:00
Abdullah Atta
020244231f desktop: update electron to v30 (#6498) 2024-09-13 08:39:18 +05:00
Abdullah Atta
59085d7b19 editor: update packages 2024-09-13 08:37:03 +05:00
Muhammad Ali
c15410e168 editor: press enter in link popup to insert link (#4423)
* editor: added shortcut key for link-popup completion.

* editor: remove commented out code

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-12 15:46:26 +05:00
Muhammad Ali
2962f13457 editor: exit a link by pressing space (#3122)
* editor: added keyboard shortcut for handling space

* editor: simplify

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-12 15:06:13 +05:00
Muhammad Ali
bfc77fc9a4 web: add delete key shortcut for deleting items (#1655)
* web: added delete key short cut for trashing notes

* web: added del key shortcut for tags, topics,trash, reminders, attachments

* web: handle delete key in sub notebooks

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-12 14:55:04 +05:00
Abdullah Atta
7e88ec88ee core: search query should be AND by default instead of OR 2024-09-12 12:54:16 +05:00
Abdullah Atta
9ef07f22af core: ignore diacritics when searching (requires rebuilding search index) 2024-09-12 12:54:16 +05:00
Ammar Ahmed
268343be3e mobile: fix android crash when app removed from recents 2024-09-12 11:40:16 +05:00
Abdullah Atta
956e5373d1 web: ignore Error in input stream global error 2024-09-11 20:45:57 +05:00
Abdullah Atta
919fa9bdf1 web: fix invalid filename when saving recovery key (fixes #6436) 2024-09-11 15:04:31 +05:00
Abdullah Atta
e06192c5b4 core: update @streetwriters/showdown (fixes #4470) 2024-09-11 14:59:07 +05:00
Ammar Ahmed
b5be5e0b59 mobile: fix itemExists error 2024-09-11 14:12:56 +05:00
Abdullah Atta
05695cfcc8 web: add menu items to open, view & unpublish a monograph (fixes #4812) 2024-09-11 13:56:18 +05:00
Abdullah Atta
423e1c6816 web: update features list (fixes #6514) 2024-09-11 13:33:35 +05:00
Ammar Ahmed
6db1cf5cc1 clipper: add images only for pro users (#6528) 2024-09-11 13:26:57 +05:00
Ammar Ahmed
2e4a87abd9 core: fix export title has appended Notesnook to end (#6529) 2024-09-11 13:26:20 +05:00
Ammar Ahmed
c26988134f editor: fix heading and p gap (#6530)
* editor: fix heading and p gap

* Update packages/editor/styles/styles.css

Signed-off-by: Abdullah Atta <thecodrr@protonmail.com>

---------

Signed-off-by: Abdullah Atta <thecodrr@protonmail.com>
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2024-09-11 13:24:58 +05:00
Abdullah Atta
bcffdd0f91 editor: improve toolbar popup controls 2024-09-11 13:22:53 +05:00
Abdullah Atta
de1051d52d editor: remove unnecessary useMemo dependency 2024-09-11 13:22:53 +05:00
Abdullah Atta
b1a360e445 editor: add more neutral default colors for highlight 2024-09-11 13:22:53 +05:00
Abdullah Atta
49e85dfa87 editor: position color picker according to mouse position 2024-09-11 13:22:53 +05:00
Abdullah Atta
452ff12071 editor: use ref instead of document.getElementById 2024-09-11 13:22:53 +05:00
Muhammad Ali
1b6fc40633 editor: fix input is not editable in color picker 2024-09-11 13:22:53 +05:00
Ammar Ahmed
82b28f8263 mobile: fix pricingPhases undefined error 2024-09-10 14:02:41 +05:00
Abdullah Atta
6e47eae30a web: fix error when registering task with invalid time (fixes #4890) 2024-09-10 09:41:16 +05:00
Abdullah Atta
4040f2ecc4 common: fix notes with empty title exporting with empty filename (fixes #6088) 2024-09-10 09:36:55 +05:00
Abdullah Atta
2293866c61 core: fix note title can be set to empty 2024-09-10 09:27:38 +05:00
Ammar Ahmed
2cb4a10076 clipper: add safe querySelector method 2024-09-09 14:57:49 +05:00
Abdullah Atta
2f7b8d3377 web: add clear instructions on how to import from other apps 2024-09-09 13:14:17 +05:00
Abdullah Atta
983220b2f2 web: add support for importing nested notebooks 2024-09-09 13:13:46 +05:00
Ammar Ahmed
ca2848e491 mobile: release v3.0.17 2024-09-06 12:58:36 +05:00
Ammar Ahmed
48e5c4d908 mobile: fix crash in background on boot 2024-09-06 12:33:34 +05:00
Ammar Ahmed
5774dd8c60 mobile: fix crash on opening app from tile 2024-09-06 12:33:00 +05:00
Steve Divskinsy
9d65184f42 docs(help): Fix typo in is-there-an-eta.md
docs(help): Fix typo in is-there-an-eta.md - unnecessary was incorrectly spelled

Signed-off-by: Stephen Argent <stevesbrain@users.noreply.github.com>

Signed-off-by: Steve Divskinsy <stevesbrain@users.noreply.github.com>
2024-09-05 20:10:54 +05:00
Abdullah Atta
395b2750e8 web: increase table viewport by 300px 2024-09-05 09:45:58 +05:00
Abdullah Atta
3bfb1d57a5 web: fix attachment downloading stuck on error 2024-09-05 09:45:44 +05:00
Abdullah Atta
e59b432007 web: ensure file exists & is of the right size after encryption 2024-09-05 09:41:06 +05:00
Abdullah Atta
efbc566386 web: compare uploaded file size with actual file size after upload 2024-09-05 09:40:45 +05:00
Abdullah Atta
2576f1dd00 web: handle errors in attachment manager 2024-09-05 09:39:29 +05:00
Abdullah Atta
7d9388bd27 web: check select all checkbox when all attachments are selected 2024-09-05 09:38:57 +05:00
Abdullah Atta
1979cd2ea4 web: show progress when rechecking attachments in bulk 2024-09-05 09:38:29 +05:00
Abdullah Atta
7bd5dfb772 web: add support for configuring server urls from login screen 2024-09-04 11:07:23 +05:00
Abdullah Atta
ac7c88218b core: fix custom server urls not working in production 2024-09-04 11:06:38 +05:00
Abdullah Atta
fb642233c8 docs(help): add xkcd comic just for kicks and laughs 2024-09-04 09:36:22 +05:00
Abdullah Atta
6e2a19d7e0 docs(help): add "is there an eta for X feature" FAQ 2024-09-04 09:20:02 +05:00
Abdullah Atta
4d4993c570 docs(help): improve merge conflicts documentation 2024-09-04 09:10:35 +05:00
Abdullah Atta
916e097cb3 clipper(web): bump version to v0.3.4 2024-09-03 11:52:53 +05:00
Abdullah Atta
6def76e1bb web: bump version to 3.0.17 2024-09-03 10:39:09 +05:00
Ammar Ahmed
d93ec27c9e mobile: release v3.0.16 2024-09-02 16:29:13 +05:00
Abdullah Atta
15329597a5 core: fix notes search for queries less than 3 letters (#6489) 2024-09-02 15:29:18 +05:00
Abdullah Atta
49caf23436 web: show loader when loading next page in themes 2024-09-02 14:58:13 +05:00
Abdullah Atta
e6d8401c56 desktop: fix multiple updates running simultaneously 2024-09-02 14:21:13 +05:00
Abdullah Atta
11a5e8c180 core: delete all relations with fromId/toId set to null 2024-09-02 14:20:58 +05:00
Abdullah Atta
5bd7a081c1 core: do not allow invalid reference to be added in relations 2024-09-02 14:20:58 +05:00
Abdullah Atta
a740a5db81 clipper(web): fix tags not assigned to clip 2024-09-02 14:20:58 +05:00
Abdullah Atta
a61f2efacf web: fix type errors 2024-09-02 13:43:05 +05:00
Brogio
51a253f3e2 mobile: fix typo in settings (#6485)
Fix typo

Signed-off-by: Brogio <contact@brog.io>
2024-09-02 12:18:49 +05:00
Abdullah Atta
19ed753079 clipper(web): only clip images if user is premium 2024-08-29 12:56:10 +05:00
Abdullah Atta
4a85c49f5d desktop: remove sodium-native package for now 2024-08-28 15:08:52 +05:00
Abdullah Atta
16dd4b3359 web: bump version to 3.0.16 2024-08-28 14:45:31 +05:00
Abdullah Atta
9279c671ac desktop: fix ft.dirname is not a function for "good" 2024-08-28 14:44:40 +05:00
Abdullah Atta
225b21977e crypto: remove libsodium-sumo patch 2024-08-28 13:46:29 +05:00
Abdullah Atta
026b9212c4 web: bump version to v3.0.15 2024-08-28 13:33:56 +05:00
Abdullah Atta
5ce59c6125 desktop: fix ft.dirname is not a function error 2024-08-28 13:32:38 +05:00
189 changed files with 4742 additions and 29748 deletions

View File

@@ -1,35 +1,34 @@
{
"name": "@notesnook/desktop",
"version": "3.0.14",
"version": "3.0.17",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/desktop",
"version": "3.0.14",
"version": "3.0.17",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"better-sqlite3-multiple-ciphers": "^9.5.0",
"electron-trpc": "0.5.2",
"@trpc/client": "10.45.2",
"@trpc/server": "10.45.2",
"better-sqlite3-multiple-ciphers": "^11.2.1",
"electron-trpc": "0.6.1",
"electron-updater": "^6.2.1",
"icojs": "^0.17.1",
"sodium-native": "^4.1.1",
"icojs": "^0.19.4",
"typed-emitter": "^2.1.0",
"yargs": "^17.6.2",
"yargs": "^17.7.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"@streetwriters/kysely": "^0.27.4",
"@types/node": "20.14.8",
"@types/yargs": "^17.0.33",
"chokidar": "^3.5.3",
"electron": "^29.3.1",
"electron": "^30.4.0",
"electron-builder": "^24.13.3",
"esbuild": "^0.23.0",
"kysely": "^0.27.3",
"node-abi": "^3.67.0",
"node-gyp-build": "^4.8.0",
"prebuildify": "^6.0.1",
"tree-kill": "^1.2.2",
@@ -42,6 +41,7 @@
"../../packages/crypto": {
"name": "@notesnook/crypto",
"version": "2.0.7",
"extraneous": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/sodium": "file:../sodium"
@@ -768,6 +768,26 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/@jimp/bmp": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz",
"integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==",
"dependencies": {
"@jimp/utils": "^0.22.12",
"bmp-js": "^0.1.0"
},
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
}
},
"node_modules/@jimp/utils": {
"version": "0.22.12",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz",
"integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==",
"dependencies": {
"regenerator-runtime": "^0.13.3"
}
},
"node_modules/@malept/cross-spawn-promise": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
@@ -820,10 +840,6 @@
"node": ">=10"
}
},
"node_modules/@notesnook/crypto": {
"resolved": "../../packages/crypto",
"link": true
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -834,6 +850,11 @@
"node": ">=14"
}
},
"node_modules/@sec-ant/readable-stream": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
@@ -846,6 +867,15 @@
"url": "https://github.com/sindresorhus/is?sponsor=1"
}
},
"node_modules/@streetwriters/kysely": {
"version": "0.27.4",
"resolved": "https://registry.npmjs.org/@streetwriters/kysely/-/kysely-0.27.4.tgz",
"integrity": "sha512-c2p+wtX8WESSVjJAc16j4lT44w/g1DvJFEIeKj/CFy36vmi0uq9FOAzxc50VtRc7rp0UlECCfl3Sxd+BTZOHFg==",
"dev": true,
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@@ -873,20 +903,20 @@
}
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.45.2.tgz",
"integrity": "sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.38.3"
"@trpc/server": "10.45.2"
}
},
"node_modules/@trpc/server": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg==",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.45.2.tgz",
"integrity": "sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg==",
"funding": [
"https://trpc.io/sponsor"
]
@@ -943,10 +973,13 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.16.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz",
"integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==",
"devOptional": true
"version": "20.14.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz",
"integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==",
"devOptional": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/plist": {
"version": "3.0.2",
@@ -974,9 +1007,9 @@
"optional": true
},
"node_modules/@types/yargs": {
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
"integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
"dev": true,
"dependencies": {
"@types/yargs-parser": "*"
@@ -1212,9 +1245,9 @@
]
},
"node_modules/better-sqlite3-multiple-ciphers": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/better-sqlite3-multiple-ciphers/-/better-sqlite3-multiple-ciphers-9.5.0.tgz",
"integrity": "sha512-6A9xBRvssONJW07Lur6pmkaUwlCGz1bnjFmXrrAR3qXETUBk92OI4C/+LhMOatn5wQ8AQzLScFZC/CKUpxkTaw==",
"version": "11.2.1",
"resolved": "https://registry.npmjs.org/better-sqlite3-multiple-ciphers/-/better-sqlite3-multiple-ciphers-11.2.1.tgz",
"integrity": "sha512-qYZ9GnZMnSOek/d00KnaXsECRFoMrNXSu9ubgeHaQi/5310+OQisaNo7FqBCCQlucPk15+etHgLwNHCeS6QzWQ==",
"hasInstallScript": true,
"dependencies": {
"bindings": "^1.5.0",
@@ -1896,9 +1929,9 @@
}
},
"node_modules/electron": {
"version": "29.3.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-29.3.1.tgz",
"integrity": "sha512-auge1/6RVqgUd6TgIq88wKdUCJi2cjESi3jy7d+6X4JzvBGprKBqMJ8JSSFpu/Px1YJrFUKAxfy6SC+TQf1uLw==",
"version": "30.4.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-30.4.0.tgz",
"integrity": "sha512-ric3KLPQ9anXYjtTDkj5NbEcXZqRUwqxrxTviIjLdMdHqd5O+hkSHEzXgbSJUOt+7uw+zZuybn9+IM9y7iEpqg==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -1955,9 +1988,9 @@
}
},
"node_modules/electron-trpc": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.5.2.tgz",
"integrity": "sha512-lJTeTwrd/E1C3VGFvdSBQggdmdDeHGrrpnuiB1e3bQR/1f91HmprySMygs9e4i12+CLqR+RIyKTQWLKCNjy5/Q==",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.6.1.tgz",
"integrity": "sha512-Yj13UrjjjOW4+TD06YunAML2tgmtSYJMiFw6E6r1D4in/0EZ2MRwMoQc7AtMPAA6In23e+Kmq71e8h0ir+c3Jg==",
"dependencies": {
"debug": "^4.3.4"
},
@@ -1982,15 +2015,6 @@
"tiny-typed-emitter": "^2.1.0"
}
},
"node_modules/electron/node_modules/@types/node": {
"version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2145,21 +2169,37 @@
}
},
"node_modules/file-type": {
"version": "16.5.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
"version": "19.4.1",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-19.4.1.tgz",
"integrity": "sha512-RuWzwF2L9tCHS76KR/Mdh+DwJZcFCzrhrPXpOw6MlEfl/o31fjpTikzcKlYuyeV7e7ftdCGVJTNOCzkYD/aLbw==",
"dependencies": {
"readable-web-to-node-stream": "^3.0.0",
"strtok3": "^6.2.4",
"token-types": "^4.1.1"
"get-stream": "^9.0.1",
"strtok3": "^8.1.0",
"token-types": "^6.0.0",
"uint8array-extras": "^1.3.0"
},
"engines": {
"node": ">=10"
"node": ">=18"
},
"funding": {
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
}
},
"node_modules/file-type/node_modules/get-stream": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
"dependencies": {
"@sec-ant/readable-stream": "^0.4.1",
"is-stream": "^4.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -2580,19 +2620,27 @@
}
},
"node_modules/icojs": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/icojs/-/icojs-0.17.1.tgz",
"integrity": "sha512-yGqa/9Uq82EAAq5V0Earig1SUubOi5ogRj/XEDiwAv/jewP9p3p/qIu/2zHWG5f8VKxRuNZB5xNgIzDxAxtPQg==",
"version": "0.19.4",
"resolved": "https://registry.npmjs.org/icojs/-/icojs-0.19.4.tgz",
"integrity": "sha512-86oNepPk2jAmbb96BPeucZI7HoSBobFlXDhhjIbwRb3wkQpvdBO5HO9KtMUNzMFT3qqQZsjLsfW+L0/9Rl9VqA==",
"dependencies": {
"bmp-js": "0.1.0",
"@jimp/bmp": "^0.22.12",
"decode-ico": "^0.4.1",
"file-type": "^16.5.4",
"file-type": "^19.0.0",
"jpeg-js": "^0.4.4",
"pngjs": "^6.0.0",
"to-data-view": "^1.1.0"
"pngjs": "^7.0.0",
"to-data-view": "^2.0.0"
},
"engines": {
"node": ">=14.19.1"
"node": ">=18.17.1"
}
},
"node_modules/icojs/node_modules/to-data-view": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-2.0.0.tgz",
"integrity": "sha512-RGEM5KqlPHr+WVTPmGNAXNeFEmsBnlkxXaIfEpUYV0AST2Z5W1EGq9L/MENFrMMmL2WQr1wjkmZy/M92eKhjYA==",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/iconv-corefoundation": {
@@ -2725,6 +2773,17 @@
"node": ">=0.12.0"
}
},
"node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isbinaryfile": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz",
@@ -2868,15 +2927,6 @@
"json-buffer": "3.0.1"
}
},
"node_modules/kysely": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.3.tgz",
"integrity": "sha512-lG03Ru+XyOJFsjH3OMY6R/9U38IjDPfnOfDgO3ynhbDr+Dz8fak+X6L62vqu3iybQnj+lG84OttBuU9KY3L9kA==",
"dev": true,
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/lazy-val": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
@@ -3055,9 +3105,9 @@
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
},
"node_modules/node-abi": {
"version": "3.54.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz",
"integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==",
"version": "3.67.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz",
"integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==",
"dependencies": {
"semver": "^7.3.5"
},
@@ -3075,6 +3125,7 @@
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
"integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
"dev": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
@@ -3200,11 +3251,11 @@
}
},
"node_modules/peek-readable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.2.0.tgz",
"integrity": "sha512-U94a+eXHzct7vAd19GH3UQ2dH4Satbng0MyYTMaQatL0pvYYL5CTPR25HBhKtecl+4bfu1/i3vC6k0hydO5Vcw==",
"engines": {
"node": ">=8"
"node": ">=14.16"
},
"funding": {
"type": "github",
@@ -3244,11 +3295,11 @@
}
},
"node_modules/pngjs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"engines": {
"node": ">=12.13.0"
"node": ">=14.19.0"
}
},
"node_modules/prebuild-install": {
@@ -3389,21 +3440,6 @@
"node": ">= 6"
}
},
"node_modules/readable-web-to-node-stream": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
"dependencies": {
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -3416,6 +3452,11 @@
"node": ">=8.10.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -3667,15 +3708,6 @@
"npm": ">= 3.0.0"
}
},
"node_modules/sodium-native": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.1.1.tgz",
"integrity": "sha512-LXkAfRd4FHtkQS4X6g+nRcVaN7mWVNepV06phIsC6+IZFvGh1voW5TNQiQp2twVaMf05gZqQjuS+uWLM6gHhNQ==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.8.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -3780,15 +3812,15 @@
}
},
"node_modules/strtok3": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-8.1.0.tgz",
"integrity": "sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^4.1.0"
"peek-readable": "^5.1.4"
},
"engines": {
"node": ">=10"
"node": ">=16"
},
"funding": {
"type": "github",
@@ -3918,15 +3950,15 @@
}
},
"node_modules/token-types": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.0.0.tgz",
"integrity": "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
"engines": {
"node": ">=10"
"node": ">=14.16"
},
"funding": {
"type": "github",
@@ -3989,6 +4021,17 @@
"node": ">=14.17"
}
},
"node_modules/uint8array-extras": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz",
"integrity": "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/undici": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.14.1.tgz",
@@ -4002,7 +4045,7 @@
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
"devOptional": true
},
"node_modules/universalify": {
"version": "2.0.0",

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "3.0.14",
"version": "3.0.17",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/index.js",
@@ -11,26 +11,25 @@
"repository": "https://github.com/streetwriters/notesnook",
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"better-sqlite3-multiple-ciphers": "^9.5.0",
"electron-trpc": "0.5.2",
"@trpc/client": "10.45.2",
"@trpc/server": "10.45.2",
"better-sqlite3-multiple-ciphers": "^11.2.1",
"electron-trpc": "0.6.1",
"electron-updater": "^6.2.1",
"icojs": "^0.17.1",
"sodium-native": "^4.1.1",
"icojs": "^0.19.4",
"typed-emitter": "^2.1.0",
"yargs": "^17.6.2",
"yargs": "^17.7.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"@streetwriters/kysely": "^0.27.4",
"@types/node": "20.14.8",
"@types/yargs": "^17.0.33",
"chokidar": "^3.5.3",
"electron": "^29.3.1",
"electron": "^30.4.0",
"electron-builder": "^24.13.3",
"esbuild": "^0.23.0",
"kysely": "^0.27.3",
"node-abi": "^3.67.0",
"node-gyp-build": "^4.8.0",
"prebuildify": "^6.0.1",
"tree-kill": "^1.2.2",
@@ -159,7 +158,8 @@
},
"nsis": {
"oneClick": true,
"createDesktopShortcut": "always"
"createDesktopShortcut": "always",
"deleteAppDataOnUninstall": true
},
"linux": {
"target": [

View File

@@ -94,7 +94,7 @@ async function patchBetterSQLite3() {
);
const json = JSON.parse(await readFile(jsonPath, "utf-8"));
json.version = "9.5.1";
json.version = "11.2.2";
json.homepage = "https://github.com/thecodrr/better-sqlite3-multiple-ciphers";
json.repository.url =
"git://github.com/thecodrr/better-sqlite3-multiple-ciphers.git";

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type { Database, Statement } from "better-sqlite3-multiple-ciphers";
import type { QueryResult } from "kysely";
import type { QueryResult } from "@streetwriters/kysely";
type SQLiteCompatibleType =
| number

View File

@@ -29,19 +29,37 @@ type Progress = { percent: number };
const t = initTRPC.create();
let cancellationToken: CancellationToken | undefined = undefined;
let downloadTimeout: NodeJS.Timeout | undefined = undefined;
export const updaterRouter = t.router({
autoUpdates: t.procedure.query(() => config.automaticUpdates),
install: t.procedure.query(() => autoUpdater.quitAndInstall()),
download: t.procedure.query(async () => {
if (cancellationToken) return;
cancellationToken = new CancellationToken();
await autoUpdater
.downloadUpdate(cancellationToken)
.finally(() => (cancellationToken = undefined));
clearTimeout(downloadTimeout);
await new Promise<string[]>((resolve, reject) => {
downloadTimeout = setTimeout(async () => {
cancellationToken = new CancellationToken();
autoUpdater.isUpdaterActive();
await autoUpdater
.downloadUpdate(cancellationToken)
.then(resolve)
.catch(reject)
.finally(() => (cancellationToken = undefined));
}, 1000);
});
}),
check: t.procedure.query(async () => {
await autoUpdater.checkForUpdates().catch(console.error);
if (cancellationToken) return;
clearTimeout(downloadTimeout);
await new Promise<void>((resolve) => {
downloadTimeout = setTimeout(async () => {
await autoUpdater
.checkForUpdates()
.catch(console.error)
.finally(resolve);
}, 1000);
});
}),
toggleAutoUpdates: t.procedure

View File

@@ -20,14 +20,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { ELECTRON_TRPC_CHANNEL } from "electron-trpc/main";
import { type RendererGlobalElectronTRPC } from "electron-trpc/src/types";
import type { NNCrypto } from "@notesnook/crypto";
// import type { NNCrypto } from "@notesnook/crypto";
import { ipcRenderer } from "electron";
import { platform } from "os";
declare global {
var os: () => "mas" | ReturnType<typeof platform>;
var electronTRPC: RendererGlobalElectronTRPC;
var NativeNNCrypto: (new () => NNCrypto) | undefined;
// var NativeNNCrypto: (new () => NNCrypto) | undefined;
}
process.once("loaded", async () => {
@@ -40,5 +40,5 @@ process.once("loaded", async () => {
globalThis.electronTRPC = electronTRPC;
});
globalThis.NativeNNCrypto = require("@notesnook/crypto").NNCrypto;
// globalThis.NativeNNCrypto = require("@notesnook/crypto").NNCrypto;
globalThis.os = () => (MAC_APP_STORE ? "mas" : platform());

View File

@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { NativeImage, nativeImage } from "electron";
import path from "path";
import { isDevelopment } from "./index";
import { parse, ParsedImage } from "icojs";
import { ParsedImage, parseICO } from "icojs";
import { getSystemTheme } from "./theme";
import { readFile } from "fs/promises";
@@ -71,7 +71,7 @@ export class AssetManager {
`${icon}${prefix}.ico`
);
const icoBuffer = await readFile(icoPath);
const images = await parse(icoBuffer, "image/png");
const images = await parseICO(icoBuffer, "image/png");
ALL_ICONS.push({ id: icon, images, prefix });
}
}

View File

@@ -23,7 +23,11 @@ import { Platform } from "react-native";
import * as Gzip from "react-native-gzip";
import EventSource from "../../utils/sse/even-source-ios";
import AndroidEventSource from "../../utils/sse/event-source";
import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely";
import {
SqliteAdapter,
SqliteIntrospector,
SqliteQueryCompiler
} from "@streetwriters/kysely";
import filesystem from "../filesystem";
import Storage from "./storage";
import { RNSqliteDriver } from "./sqlite.kysely";

View File

@@ -18,7 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { initialize } from "@notesnook/core/dist/logger";
import { SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler } from "kysely";
import {
SqliteAdapter,
SqliteIntrospector,
SqliteQueryCompiler
} from "@streetwriters/kysely";
import { Platform } from "react-native";
import { setLogger } from ".";
import { RNSqliteDriver } from "./sqlite.kysely";

View File

@@ -17,8 +17,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type { DatabaseConnection, Driver, QueryResult } from "kysely";
import { CompiledQuery } from "kysely";
import type {
DatabaseConnection,
Driver,
QueryResult
} from "@streetwriters/kysely";
import { CompiledQuery } from "@streetwriters/kysely";
import { QuickSQLiteConnection, open } from "react-native-quick-sqlite";
type Config = { dbName: string; async: boolean; location: string };

View File

@@ -43,6 +43,7 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
DatabaseLogger.log(`File Exists already: ${filename}`);
return true;
}
const attachment = await db.attachments.attachment(filename);
const size = await getUploadedFileSize(filename);
@@ -90,7 +91,8 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
DatabaseLogger.log(`Download starting: ${filename}`);
let request = RNFetchBlob.config({
path: tempFilePath,
IOSBackgroundTask: true
IOSBackgroundTask: true,
overwrite: true
})
.fetch("GET", downloadUrl, null)
.progress(async (recieved, total) => {
@@ -122,6 +124,11 @@ export async function downloadFile(filename, requestOptions, cancelToken) {
let status = response.info().status;
useAttachmentStore.getState().remove(filename);
if (exists(originalFilePath)) {
await RNFetchBlob.fs.unlink(originalFilePath).catch(console.log);
}
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath);
if (!(await exists(filename))) {

View File

@@ -167,7 +167,7 @@ export const Component = ({ close, promo }) => {
>
(
{Platform.OS === "android"
? pricing.product?.subscriptionOfferDetails[0].pricingPhases
? pricing.product?.subscriptionOfferDetails[0]?.pricingPhases
.pricingPhaseList?.[0].formattedPrice
: pricing.product?.localizedPrice}{" "}
/ mo)

View File

@@ -85,7 +85,7 @@ export const PricingItem = ({
>
{Platform.OS === "android"
? (product.data as RNIap.SubscriptionAndroid | undefined)
?.subscriptionOfferDetails[0].pricingPhases
?.subscriptionOfferDetails?.[0]?.pricingPhases
.pricingPhaseList?.[0]?.formattedPrice
: (product.data as RNIap.SubscriptionIOS | undefined)
?.localizedPrice}

View File

@@ -393,7 +393,7 @@ export const PricingPlans = ({
>
{Platform.OS === "android"
? (product.data as RNIap.SubscriptionAndroid)
?.subscriptionOfferDetails[0].pricingPhases
?.subscriptionOfferDetails[0]?.pricingPhases
.pricingPhaseList?.[0]?.formattedPrice
: (product.data as RNIap.SubscriptionIOS)
?.introductoryPrice ||

View File

@@ -19,17 +19,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { FeatureType } from "./components/sheets/new-feature";
export const features: FeatureType[] = [
{
title: "Full offline mode",
body: "Enable full offline mode from Settings -> Account -> Sync Settings. This will allow you to keep all your attachments and data offline on the client"
},
{
title: "Backup with attachments",
body: "You can now backup your notes alongwith all your attachments - kind of like a full account snapshot."
},
{
title: "Self hosting",
body: "This release also adds initial support for changing server URLs i.e. to connect your own instance of Notesnook. Please note that this is still experimental and may not work as expected."
}
];
export const features: FeatureType[] = [];

View File

@@ -95,6 +95,7 @@ import {
import { getGithubVersion } from "../utils/github-version";
import { tabBarRef } from "../utils/global-refs";
import { sleep } from "../utils/time";
import { NotesnookModule } from "../utils/notesnook-module";
const onCheckSyncStatus = async (type: SyncStatusEvent) => {
const { disableSync, disableAutoSync } = SettingsService.get();
@@ -254,9 +255,9 @@ async function saveEditorState() {
movedAway: editorState().movedAway,
timestamp: Date.now()
});
MMKV.setString("appState", state);
NotesnookModule.setAppState(state);
} else {
MMKV.removeItem("appState");
NotesnookModule.setAppState("");
}
}
@@ -632,7 +633,7 @@ export const useAppEvents = () => {
Sync.run("global", false, "full");
reconnectSSE();
await checkForShareExtensionLaunchedInBackground();
MMKV.removeItem("appState");
NotesnookModule.setAppState("");
let user = await db.user.getUser();
if (user && !user?.isEmailConfirmed) {
try {

View File

@@ -36,11 +36,11 @@
"react-native-wheel-color-picker": "^1.3.1",
"tinycolor2": "1.6.0",
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@tanstack/react-query": "^4.29.19",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/server": "10.38.3",
"kysely": "^0.26.3",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "10.45.2",
"@trpc/react-query": "10.45.2",
"@trpc/server": "10.45.2",
"@streetwriters/kysely": "^0.27.4",
"pathe": "1.1.2"
},
"sideEffects": false

View File

@@ -660,9 +660,9 @@ export const useEditor = (
lock.current = true;
// Handle this case where note was locked on another device and synced.
const locked = await db.vaults.itemExists(
currentNotes.current[noteId] as ItemReference
);
const locked = note
? await db.vaults.itemExists(note as ItemReference)
: false;
if (note) {
if (!locked && tab?.noteLocked) {

View File

@@ -31,6 +31,7 @@ import { useTabStore } from "./use-tab-store";
import { parseInternalLink } from "@notesnook/core";
import { eOnLoadNote } from "../../../utils/events";
import { db } from "../../../common/database";
import { NotesnookModule } from "../../../utils/notesnook-module";
export const textInput = createRef<TextInput>();
export const editorController =
createRef<useEditorType>() as MutableRefObject<useEditorType>;
@@ -165,7 +166,7 @@ const canRestoreAppState = (appState: AppState) => {
let appState: AppState | undefined;
export function getAppState() {
if (appState && canRestoreAppState(appState)) return appState as AppState;
const json = MMKV.getString("appState");
const json = NotesnookModule.getAppState();
if (json) {
appState = JSON.parse(json) as AppState;
if (canRestoreAppState(appState)) {
@@ -180,7 +181,7 @@ export function getAppState() {
export function clearAppState() {
appState = undefined;
MMKV.removeItem("appState");
NotesnookModule.setAppState("");
}
export async function openInternalLink(url: string) {

View File

@@ -1490,9 +1490,9 @@ NOTE: Creating a backup with attachments can take a while, and also fail complet
}
},
{
id: "join-mastodom",
id: "join-mastodon",
name: "Follow us on Mastodon",
description: "We are on mastodom",
description: "We are on mastodon",
icon: "mastodon",
modifer: () => {
Linking.openURL("https://fosstodon.org/@notesnook").catch(

View File

@@ -90,7 +90,7 @@ export const Subscription = () => {
function getPrice() {
return Platform.OS === "android"
? monthlyPlan?.product?.subscriptionOfferDetails[0].pricingPhases
? monthlyPlan?.product?.subscriptionOfferDetails[0]?.pricingPhases
.pricingPhaseList?.[0]?.formattedPrice
: monthlyPlan?.product?.localizedPrice;
}

View File

@@ -137,6 +137,7 @@ const onBoot = async () => {
try {
if (!SettingsService.getProperty("backgroundSync")) {
DatabaseLogger.info("BACKGROUND SYNC ON BOOT DISABLED");
return;
}

View File

@@ -35,22 +35,21 @@ import dayjs, { Dayjs } from "dayjs";
import { encodeNonAsciiHTML } from "entities";
import { Platform } from "react-native";
import { db, setupDatabase } from "../common/database";
import { MMKV } from "../common/database/mmkv";
import { presentDialog } from "../components/dialog/functions";
import { useTabStore } from "../screens/editor/tiptap/use-tab-store";
import { editorState } from "../screens/editor/tiptap/utils";
import { useRelationStore } from "../stores/use-relation-store";
import { useReminderStore } from "../stores/use-reminder-store";
import { useSettingStore } from "../stores/use-setting-store";
import { eOnLoadNote } from "../utils/events";
import { useUserStore } from "../stores/use-user-store";
import { tabBarRef } from "../utils/global-refs";
import { convertNoteToText } from "../utils/note-to-text";
import { NotesnookModule } from "../utils/notesnook-module";
import { sleep } from "../utils/time";
import { DDS } from "./device-detection";
import { eSendEvent } from "./event-manager";
import Navigation from "./navigation";
import SettingsService from "./settings";
import { useUserStore } from "../stores/use-user-store";
import { useTabStore } from "../screens/editor/tiptap/use-tab-store";
let pinned: DisplayedNotification[] = [];
@@ -126,7 +125,7 @@ const onEvent = async ({ type, detail }: Event) => {
if (type === EventType.PRESS) {
notifee.decrementBadgeCount();
if (notification?.data?.type === "quickNote") return;
MMKV.removeItem("appState");
NotesnookModule.setAppState("");
if (notification?.data?.type === "reminder" && notification?.id) {
const reminder = await db.reminders?.reminder(
notification.id?.split("_")[0]
@@ -410,9 +409,7 @@ async function loadNote(id: string, jump: boolean) {
if (!DDS.isTab && jump) {
tabBarRef.current?.goToPage(1);
}
MMKV.setString(
"appState",
NotesnookModule.setAppState(
JSON.stringify({
editing: true,
movedAway: false,

View File

@@ -23,13 +23,17 @@ interface NotesnookModuleInterface {
getActivityName: () => Promise<string>;
setBackgroundColor: (color: string) => void;
setSecureMode: (enabled: boolean) => void;
setAppState: (appState: string) => void;
getAppState: () => string;
}
export const NotesnookModule: NotesnookModuleInterface = Platform.select({
ios: {
getActivityName: () => {},
setBackgroundColor: () => {},
setSecureMode: () => {}
setSecureMode: () => {},
setAppState: () => {},
getAppState: () => {}
},
android: NativeModules.NNativeModule
});

View File

@@ -116,7 +116,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 3025
versionCode 3027
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -3,6 +3,7 @@ package com.streetwriters.notesnook;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.app.ActivityManager;
import com.facebook.react.HeadlessJsTaskService;
@@ -19,8 +20,12 @@ public class BootRecieverService extends BroadcastReceiver {
network connections
**/
Intent serviceIntent = new Intent(context, BootTaskService.class);
context.startService(serviceIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent);
} else {
context.startService(serviceIntent);
}
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}

View File

@@ -1,15 +1,24 @@
package com.streetwriters.notesnook;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import javax.annotation.Nullable;
public class BootTaskService extends HeadlessJsTaskService {
Notification notification;
@Override
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Log.d("BootTask", "Task Started");
return new HeadlessJsTaskConfig(
"com.streetwriters.notesnook.BOOT_TASK",
Arguments.createMap(),
@@ -17,4 +26,31 @@ public class BootTaskService extends HeadlessJsTaskService {
false // optional: defines whether or not the task is allowed in foreground. Default is false
);
}
@Override
public void onHeadlessJsTaskFinish(int taskId) {
super.onHeadlessJsTaskFinish(taskId);
Log.d("BootTask", "Task completed");
stopSelf();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
"Default",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
notification = new NotificationCompat.Builder(this, channel.getId())
.setContentTitle("Sync on boot")
.setContentText("")
.setSmallIcon(R.drawable.ic_stat_name)
.build();
startForeground(1, notification);
}
return super.onStartCommand(intent, flags, startId);
}
}

View File

@@ -1,5 +1,7 @@
package com.streetwriters.notesnook;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.service.quicksettings.Tile;
@@ -9,11 +11,24 @@ import androidx.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.N)
public class NotesnookTileService extends TileService {
@SuppressLint("StartActivityAndCollapseDeprecated")
@Override
public void onClick() {
super.onClick();
Intent intent = new Intent(this.getApplicationContext(), ShareActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityAndCollapse(intent);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(
PendingIntent.getActivity(
this.getApplicationContext(),
0,
intent,
PendingIntent.FLAG_IMMUTABLE
)
);
} else {
startActivityAndCollapse(intent);
}
}
}

View File

@@ -1,17 +1,12 @@
package com.streetwriters.notesnook;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
import com.ammarahmed.mmkv.MMKV;
public class OnClearFromRecentService extends Service {
static {
System.loadLibrary("rnmmkv");
}
@Override
public IBinder onBind(Intent intent) {
return null;
@@ -30,15 +25,12 @@ public class OnClearFromRecentService extends Service {
@Override
public void onTaskRemoved(Intent rootIntent) {
try {
MMKV.initialize(getApplicationContext());
MMKV mmkv = MMKV.mmkvWithID("default",MMKV.SINGLE_PROCESS_MODE);
mmkv.removeValueForKey("appState");
SharedPreferences appStateDetails = getApplicationContext().getSharedPreferences("appStateDetails", MODE_PRIVATE);
SharedPreferences.Editor edit = appStateDetails.edit();
edit.remove("appState");
edit.apply();
stopSelf();
} catch (UnsatisfiedLinkError e) {
} catch (Exception e) {
} catch (UnsatisfiedLinkError | Exception e) {
}
//System.exit(0);
}
}

View File

@@ -1,7 +1,10 @@
package com.streetwriters.notesnook;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.util.Log;
import android.view.WindowManager;
import com.facebook.react.bridge.Promise;
@@ -67,6 +70,21 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
}
}
@ReactMethod
public void setAppState(final String appState) {
SharedPreferences appStateDetails = getReactApplicationContext().getSharedPreferences("appStateDetails", Context.MODE_PRIVATE);
SharedPreferences.Editor edit = appStateDetails.edit();
edit.putString("appState", appState);
edit.apply();
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String getAppState() {
SharedPreferences appStateDetails = getReactApplicationContext().getSharedPreferences("appStateDetails", Context.MODE_PRIVATE);
String appStateValue = appStateDetails.getString("appState", "");
return appStateValue.isEmpty() ? null : appStateValue;
}
}

View File

@@ -1,7 +1,6 @@
- Added full offline mode with enable downloading attachments on sync
- Now you can change sync server urls in the app settings to use your own self hosted servers
- Now you can take backups with attachments included
- Removed all kinds of telemetry and analytics
- Fix crash when launching Notesnook from Notification tiles
- Fix app crashing on background on boot
- Fix self-hosted server urls not working
- Bug fixes and small improvements
Thank you for using Notesnook!

View File

@@ -11,6 +11,10 @@ import NetInfo from "@react-native-community/netinfo";
import { enableFreeze } from "react-native-screens";
import {BackgroundSync} from '../app/services/background-sync';
BackgroundSync.registerHeadlessTask();
BackgroundSync.start();
Notifications.init();
enableFreeze(true);
NetInfo.configure({
reachabilityUrl: "https://notesnook.com",
@@ -19,8 +23,7 @@ NetInfo.configure({
return response?.status >= 200 && response?.status < 300;
}
});
BackgroundSync.start();
Notifications.init();
const appName = appJson.name;
if (Config.isTesting) {

View File

@@ -1061,7 +1061,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1135,7 +1135,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1166,7 +1166,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1240,7 +1240,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1399,7 +1399,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1411,7 +1411,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1442,7 +1442,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1455,7 +1455,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1485,7 +1485,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1559,7 +1559,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1590,7 +1590,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2112;
CURRENT_PROJECT_VERSION = 2114;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1665,7 +1665,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.0.15;
MARKETING_VERSION = 3.0.17;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "3.0.14",
"version": "3.0.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.0.14",
"version": "3.0.15",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"workspaces": [
@@ -23811,17 +23811,19 @@
"name": "@notesnook/sodium",
"version": "2.0.7",
"dev": true,
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"libsodium-wrappers-sumo": "^0.7.15"
},
"devDependencies": {
"@types/libsodium-wrappers-sumo": "0.7.5",
"@types/libsodium-wrappers-sumo": "0.7.8",
"benny": "^3.7.1",
"libsodium-wrappers-sumo": "^0.7.11",
"sodium-native": "^4.1.1",
"ts-node": "^10.9.1",
"vitest": "^0.32.2"
},
"peerDependencies": {
"libsodium-wrappers-sumo": ">=0.7",
"sodium-native": ">=4"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "3.0.15",
"version": "3.0.17",
"private": true,
"license": "GPL-3.0-or-later",
"workspaces": [

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@
"@notesnook/web": "file:../web",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.38.3",
"@trpc/client": "10.45.2",
"@types/react-dom": "^18.3.0",
"clipboard-polyfill": "^4.0.0",
"file-saver": "^2.0.5",
@@ -979,7 +979,7 @@
},
"../web": {
"name": "@notesnook/web",
"version": "3.0.13",
"version": "3.0.17",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -993,7 +993,7 @@
"@henrygd/queue": "^1.0.6",
"@mdi/js": "^7.2.96",
"@mdi/react": "^1.6.1",
"@notesnook-importer/core": "^2.0.0",
"@notesnook-importer/core": "^2.1.1",
"@notesnook/common": "file:../../packages/common",
"@notesnook/core": "file:../../packages/core",
"@notesnook/crypto": "file:../../packages/crypto",
@@ -1007,13 +1007,14 @@
"@notesnook/web-clipper": "file:../../extensions/web-clipper",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.29.19",
"@streetwriters/kysely": "^0.27.4",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-virtual": "^3.0.1",
"@theme-ui/color": "^0.16.1",
"@theme-ui/components": "^0.16.1",
"@theme-ui/core": "^0.16.1",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/client": "10.45.2",
"@trpc/react-query": "10.45.2",
"@zip.js/zip.js": "^2.7.32",
"async-mutex": "^0.4.0",
"axios": "^1.3.4",
@@ -1031,8 +1032,6 @@
"hash-wasm": "^4.9.0",
"hotkeys-js": "^3.8.3",
"katex": "0.16.2",
"kysely": "^0.26.3",
"libsodium-wrappers": "^0.7.13",
"mac-scrollbar": "^0.13.5",
"marked": "^4.1.0",
"mutative": "^1.0.6",
@@ -1068,7 +1067,7 @@
"@playwright/test": "^1.43.1",
"@swc/core": "^1.5.24",
"@swc/plugin-react-remove-properties": "^2.0.4",
"@trpc/server": "10.38.3",
"@trpc/server": "10.45.2",
"@types/babel__core": "^7.20.1",
"@types/event-source-polyfill": "^1.0.1",
"@types/file-saver": "^2.0.5",
@@ -2019,14 +2018,14 @@
}
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.45.2.tgz",
"integrity": "sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.38.3"
"@trpc/server": "10.45.2"
}
},
"node_modules/@types/babel__core": {

View File

@@ -16,7 +16,7 @@
"@notesnook/web": "file:../web",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.38.3",
"@trpc/client": "10.45.2",
"@types/react-dom": "^18.3.0",
"clipboard-polyfill": "^4.0.0",
"file-saver": "^2.0.5",

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/web",
"version": "3.0.14",
"version": "3.0.17",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/web",
"version": "3.0.14",
"version": "3.0.17",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -20,7 +20,7 @@
"@henrygd/queue": "^1.0.6",
"@mdi/js": "^7.2.96",
"@mdi/react": "^1.6.1",
"@notesnook-importer/core": "^2.0.0",
"@notesnook-importer/core": "^2.1.1",
"@notesnook/common": "file:../../packages/common",
"@notesnook/core": "file:../../packages/core",
"@notesnook/crypto": "file:../../packages/crypto",
@@ -34,13 +34,14 @@
"@notesnook/web-clipper": "file:../../extensions/web-clipper",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.29.19",
"@streetwriters/kysely": "^0.27.4",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-virtual": "^3.0.1",
"@theme-ui/color": "^0.16.1",
"@theme-ui/components": "^0.16.1",
"@theme-ui/core": "^0.16.1",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/client": "10.45.2",
"@trpc/react-query": "10.45.2",
"@zip.js/zip.js": "^2.7.32",
"async-mutex": "^0.4.0",
"axios": "^1.3.4",
@@ -58,8 +59,6 @@
"hash-wasm": "^4.9.0",
"hotkeys-js": "^3.8.3",
"katex": "0.16.2",
"kysely": "^0.26.3",
"libsodium-wrappers": "^0.7.13",
"mac-scrollbar": "^0.13.5",
"marked": "^4.1.0",
"mutative": "^1.0.6",
@@ -95,7 +94,7 @@
"@playwright/test": "^1.43.1",
"@swc/core": "^1.5.24",
"@swc/plugin-react-remove-properties": "^2.0.4",
"@trpc/server": "10.38.3",
"@trpc/server": "10.45.2",
"@types/babel__core": "^7.20.1",
"@types/event-source-polyfill": "^1.0.1",
"@types/file-saver": "^2.0.5",
@@ -137,7 +136,7 @@
},
"../../extensions/web-clipper": {
"name": "@notesnook/web-clipper",
"version": "0.3.2",
"version": "0.3.4",
"license": "GPL-3.0-or-later",
"dependencies": {
"@emotion/react": "11.11.1",
@@ -26854,7 +26853,8 @@
"@microsoft/signalr": "^8.0.0",
"@notesnook/logger": "file:../logger",
"@readme/data-urls": "^3.0.0",
"@streetwriters/showdown": "^3.0.7-alpha",
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.8-alpha",
"async-mutex": "^0.3.2",
"dayjs": "1.11.9",
"dom-serializer": "^2.0.0",
@@ -26865,7 +26865,6 @@
"html-to-text": "^9.0.5",
"htmlparser2": "^8.0.1",
"katex": "0.16.2",
"kysely": "^0.26.3",
"linkedom": "^0.14.17",
"liqe": "^1.13.0",
"mime-db": "1.52.0",
@@ -28477,13 +28476,6 @@
"node": ">= 12"
}
},
"../../packages/core/node_modules/kysely": {
"version": "0.26.3",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"../../packages/core/node_modules/leac": {
"version": "0.6.0",
"license": "MIT",
@@ -29903,70 +29895,76 @@
"@notesnook/core": "file:../core",
"@notesnook/theme": "file:../theme",
"@notesnook/ui": "file:../ui",
"@social-embed/lib": "^0.0.2-next.1",
"@tiptap/core": "2.2.4",
"@tiptap/extension-character-count": "2.2.4",
"@tiptap/extension-color": "2.2.4",
"@tiptap/extension-font-family": "2.2.4",
"@tiptap/extension-history": "2.2.4",
"@tiptap/extension-horizontal-rule": "2.2.4",
"@tiptap/extension-list-keymap": "2.2.4",
"@tiptap/extension-placeholder": "2.2.4",
"@tiptap/extension-subscript": "2.2.4",
"@tiptap/extension-superscript": "2.2.4",
"@tiptap/extension-table": "2.2.4",
"@tiptap/extension-table-cell": "2.2.4",
"@tiptap/extension-table-header": "2.2.4",
"@tiptap/extension-table-row": "2.2.4",
"@tiptap/extension-task-item": "2.2.4",
"@tiptap/extension-task-list": "2.2.4",
"@tiptap/extension-text-align": "2.2.4",
"@tiptap/extension-text-style": "2.2.4",
"@tiptap/extension-underline": "2.2.4",
"@tiptap/pm": "2.2.4",
"@tiptap/starter-kit": "2.2.4",
"@social-embed/lib": "^0.1.0-next.7",
"@tiptap/core": "2.6.6",
"@tiptap/extension-blockquote": "^2.6.6",
"@tiptap/extension-bullet-list": "^2.6.6",
"@tiptap/extension-character-count": "2.6.6",
"@tiptap/extension-code": "^2.6.6",
"@tiptap/extension-color": "2.6.6",
"@tiptap/extension-font-family": "2.6.6",
"@tiptap/extension-heading": "^2.6.6",
"@tiptap/extension-history": "2.6.6",
"@tiptap/extension-horizontal-rule": "2.6.6",
"@tiptap/extension-list-item": "^2.6.6",
"@tiptap/extension-list-keymap": "2.6.6",
"@tiptap/extension-ordered-list": "^2.6.6",
"@tiptap/extension-placeholder": "2.6.6",
"@tiptap/extension-subscript": "2.6.6",
"@tiptap/extension-superscript": "2.6.6",
"@tiptap/extension-table": "2.6.6",
"@tiptap/extension-table-cell": "2.6.6",
"@tiptap/extension-table-header": "2.6.6",
"@tiptap/extension-table-row": "2.6.6",
"@tiptap/extension-task-item": "2.6.6",
"@tiptap/extension-task-list": "2.6.6",
"@tiptap/extension-text-align": "2.6.6",
"@tiptap/extension-text-style": "2.6.6",
"@tiptap/extension-underline": "2.6.6",
"@tiptap/pm": "2.6.6",
"@tiptap/starter-kit": "2.6.6",
"alfaaz": "^1.1.0",
"async-mutex": "^0.4.0",
"clipboard-polyfill": "4.0.0",
"detect-indent": "^7.0.0",
"entities": "^4.5.0",
"katex": "0.16.9",
"async-mutex": "^0.5.0",
"clipboard-polyfill": "4.1.0",
"detect-indent": "^7.0.1",
"entities": "^5.0.0",
"katex": "0.16.11",
"linkifyjs": "^4.1.3",
"nanoid": "^4.0.1",
"nanoid": "^5.0.7",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "1.33.1",
"re-resizable": "^6.9.11",
"prosemirror-view": "1.34.2",
"re-resizable": "^6.9.18",
"react-colorful": "^5.6.1",
"redent": "^4.0.0",
"refractor": "^4.8.1",
"strip-indent": "^4.0.0",
"unfurl.js": "^6.3.2"
"unfurl.js": "^6.4.0"
},
"devDependencies": {
"@emotion/react": "11.11.1",
"@mdi/js": "^7.2.96",
"@emotion/react": "11.13.3",
"@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1",
"@theme-ui/components": "^0.16.1",
"@theme-ui/core": "^0.16.1",
"@types/katex": "^0.14.0",
"@types/prismjs": "^1.26.0",
"@types/react": "^18.2.39",
"@types/react-color": "^3.0.6",
"@types/react-dom": "^18.2.17",
"@theme-ui/components": "^0.16.2",
"@theme-ui/core": "^0.16.2",
"@types/katex": "^0.16.7",
"@types/prismjs": "^1.26.4",
"@types/react": "^18.3.5",
"@types/react-color": "^3.0.12",
"@types/react-dom": "^18.3.0",
"@types/react-modal": "^3.16.3 ",
"@types/tinycolor2": "^1.4.3",
"framer-motion": "^10.16.8",
"happy-dom": "^8.9.0",
"@types/tinycolor2": "^1.4.6",
"framer-motion": "^11.5.4",
"happy-dom": "^15.7.4",
"isomorphic-fetch": "^3.0.0",
"prosemirror-test-builder": "^1.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"prosemirror-test-builder": "^1.1.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-modal": "3.16.1",
"tinycolor2": "^1.6.0",
"vitest": "^0.29.2",
"web-vitals": "^2.1.4",
"zustand": "4.4.7"
"vitest": "^2.0.5",
"web-vitals": "^4.2.3",
"zustand": "4.5.5"
},
"peerDependencies": {
"@emotion/react": ">=11",
@@ -33094,17 +33092,19 @@
"../../packages/sodium": {
"name": "@notesnook/sodium",
"version": "2.0.7",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"libsodium-wrappers-sumo": "^0.7.15"
},
"devDependencies": {
"@types/libsodium-wrappers-sumo": "0.7.5",
"@types/libsodium-wrappers-sumo": "0.7.8",
"benny": "^3.7.1",
"libsodium-wrappers-sumo": "^0.7.11",
"sodium-native": "^4.1.1",
"ts-node": "^10.9.1",
"vitest": "^0.32.2"
},
"peerDependencies": {
"libsodium-wrappers-sumo": ">=0.7",
"sodium-native": ">=4"
}
},
@@ -33713,12 +33713,10 @@
},
"../../packages/sodium/node_modules/libsodium-sumo": {
"version": "0.7.11",
"dev": true,
"license": "ISC"
},
"../../packages/sodium/node_modules/libsodium-wrappers-sumo": {
"version": "0.7.11",
"dev": true,
"license": "ISC",
"dependencies": {
"libsodium-sumo": "^0.7.11"
@@ -37729,30 +37727,29 @@
},
"../desktop": {
"name": "@notesnook/desktop",
"version": "3.0.13",
"version": "3.0.17",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"better-sqlite3-multiple-ciphers": "^9.5.0",
"electron-trpc": "0.5.2",
"@trpc/client": "10.45.2",
"@trpc/server": "10.45.2",
"better-sqlite3-multiple-ciphers": "^11.2.1",
"electron-trpc": "0.6.1",
"electron-updater": "^6.2.1",
"icojs": "^0.17.1",
"sodium-native": "^4.1.1",
"icojs": "^0.19.4",
"typed-emitter": "^2.1.0",
"yargs": "^17.6.2",
"yargs": "^17.7.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"@streetwriters/kysely": "^0.27.4",
"@types/node": "20.14.8",
"@types/yargs": "^17.0.33",
"chokidar": "^3.5.3",
"electron": "^29.3.1",
"electron": "^30.4.0",
"electron-builder": "^24.13.3",
"esbuild": "^0.23.0",
"kysely": "^0.27.3",
"node-abi": "^3.67.0",
"node-gyp-build": "^4.8.0",
"prebuildify": "^6.0.1",
"tree-kill": "^1.2.2",
@@ -38137,10 +38134,6 @@
"node": ">=10"
}
},
"../desktop/node_modules/@notesnook/crypto": {
"resolved": "../../packages/crypto",
"link": true
},
"../desktop/node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"dev": true,
@@ -39884,14 +39877,6 @@
"json-buffer": "3.0.1"
}
},
"../desktop/node_modules/kysely": {
"version": "0.27.3",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"../desktop/node_modules/lazy-val": {
"version": "1.0.5",
"license": "MIT"
@@ -40061,6 +40046,7 @@
},
"../desktop/node_modules/node-gyp-build": {
"version": "4.8.0",
"dev": true,
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
@@ -40582,14 +40568,6 @@
"node": ">=10"
}
},
"../desktop/node_modules/sodium-native": {
"version": "4.1.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-gyp-build": "^4.8.0"
}
},
"../desktop/node_modules/source-map": {
"version": "0.6.1",
"dev": true,
@@ -41038,54 +41016,69 @@
}
},
"node_modules/@azure/msal-browser": {
"version": "3.6.0",
"license": "MIT",
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.23.0.tgz",
"integrity": "sha512-+QgdMvaeEpdtgRTD7AHHq9aw8uga7mXVHV1KshO1RQ2uI5B55xJ4aEpGlg/ga3H+0arEVcRfT4ZVmX7QLXiCVw==",
"optional": true,
"dependencies": {
"@azure/msal-common": "14.5.0"
"@azure/msal-common": "14.14.2"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-common": {
"version": "14.5.0",
"license": "MIT",
"version": "14.14.2",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.2.tgz",
"integrity": "sha512-XV0P5kSNwDwCA/SjIxTe9mEAsKB0NqGNSuaVrkCCE2lAyBr/D6YtD80Vkdp4tjWnPFwjzkwldjr1xU/facOJog==",
"optional": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-node": {
"version": "2.6.0",
"license": "MIT",
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.1.tgz",
"integrity": "sha512-sijfzPNorKt6+9g1/miHwhj6Iapff4mPQx1azmmZExgzUROqWTM1o3ACyxDja0g47VpowFy/sxTM/WsuCyXTiw==",
"optional": true,
"dependencies": {
"@azure/msal-common": "14.5.0",
"@azure/msal-common": "14.14.2",
"jsonwebtoken": "^9.0.0",
"uuid": "^8.3.0"
},
"engines": {
"node": "16|| 18 || 20"
"node": ">=16"
}
},
"node_modules/@azure/msal-node-extensions": {
"version": "1.0.8",
"license": "MIT",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node-extensions/-/msal-node-extensions-1.1.0.tgz",
"integrity": "sha512-tn4ULOjUb7FRI1KMTBnS3kflcV0oI3xdG0b0IEhOufmxhQAGs5hIaugE+HxvNw4y7ceFpOm7r6zzzrTj0NFtvg==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"@azure/msal-common": "14.5.0",
"@azure/msal-common": "14.14.0",
"@azure/msal-node-runtime": "^0.13.6-alpha.0",
"keytar": "^7.8.0"
},
"engines": {
"node": "16 || 18 || 20"
"node": ">=16"
}
},
"node_modules/@azure/msal-node-extensions/node_modules/@azure/msal-common": {
"version": "14.14.0",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.0.tgz",
"integrity": "sha512-OxcOk9H1/1fktHh6//VCORgSNJc2dCQObTm6JNmL824Z6iZSO6eFo/Bttxe0hETn9B+cr7gDouTQtsRq3YPuSQ==",
"optional": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-node-runtime": {
"version": "0.13.6-alpha.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.13.6-alpha.0.tgz",
"integrity": "sha512-Tu5e4wBFiaiBLrOu7bsJF7FYknFH9XIOvUyCqCnmLJFMMOUnYULZ7fOFYuintFFcNPMOT2u8BVfSCPxETri5ng==",
"hasInstallScript": true,
"license": "MIT",
"optional": true
},
"node_modules/@babel/code-frame": {
@@ -43047,7 +43040,8 @@
},
"node_modules/@microsoft/microsoft-graph-client": {
"version": "3.0.7",
"license": "MIT",
"resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-client/-/microsoft-graph-client-3.0.7.tgz",
"integrity": "sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"tslib": "^2.2.0"
@@ -43103,14 +43097,17 @@
}
},
"node_modules/@notesnook-importer/core": {
"version": "2.0.0",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@notesnook-importer/core/-/core-2.1.1.tgz",
"integrity": "sha512-aVCvRPLQCwCzhqJ9/MZ4HtT8xtRGPS+JY5/pJD27ggEhzyF9OOd+AT9ugf7w2lpbTIP8f/3Nsn/CXiCJgDO98w==",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook-importer/enex": "^1.7.0",
"@notesnook-importer/onenote": "^1.7.0",
"@notesnook-importer/storage": "^1.7.0",
"@notesnook-importer/znel": "^1.7.0",
"@notesnook-importer/enex": "^1.8.1",
"@notesnook-importer/onenote": "^1.8.1",
"@notesnook-importer/storage": "^1.8.1",
"@notesnook-importer/znel": "^1.8.1",
"@skiff-org/skiff-crypto": "^1.0.3",
"@stablelib/chacha20poly1305": "^1.0.1",
"@standardnotes/features": "1.58.0",
"@standardnotes/models": "1.42.0",
"@streamparser/json": "^0.0.10",
@@ -43124,6 +43121,7 @@
"gray-matter": "^4.0.3",
"hast-util-is-element": "^2.1.3",
"htmlparser2": "^8.0.1",
"magic-bytes.js": "^1.8.0",
"rehype-stringify": "^9.0.3",
"remark": "^14.0.3",
"remark-comments": "^1.2.9",
@@ -43133,7 +43131,8 @@
"remark-supersub": "^1.0.0",
"spark-md5": "^3.0.2",
"unified": "^10.1.2",
"unist-util-visit": "^5.0.0"
"unist-util-visit": "^5.0.0",
"zod": "^3.22.4"
}
},
"node_modules/@notesnook-importer/core/node_modules/fflate": {
@@ -43141,8 +43140,9 @@
"license": "MIT"
},
"node_modules/@notesnook-importer/enex": {
"version": "1.7.0",
"license": "GPL-3.0-or-later",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@notesnook-importer/enex/-/enex-1.8.1.tgz",
"integrity": "sha512-k+DzJQPr/79rKg0hnml/ZHS9PX/4vm/ndOfF6PLdTBJsoAVgYhEOkroSwm8oA6V1j9Bn1Ew/7jpssKoUGqebsg==",
"dependencies": {
"base64-js": "^1.5.1",
"css-select": "^5.1.0",
@@ -43154,8 +43154,9 @@
}
},
"node_modules/@notesnook-importer/onenote": {
"version": "1.7.0",
"license": "GPL-3.0-or-later",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@notesnook-importer/onenote/-/onenote-1.8.1.tgz",
"integrity": "sha512-4xTPNHn9E/Fb5BnpqLghNLporgyHNOJTitzdJwBvNWAfomfS/limFPYNyfwYRFbX/Uq1drSKzdv0uAvq8/dhiQ==",
"dependencies": {
"@microsoft/microsoft-graph-client": "^3.0.7",
"css-select": "^5.1.0",
@@ -43173,22 +43174,25 @@
}
},
"node_modules/@notesnook-importer/onenote/node_modules/dotenv": {
"version": "16.3.1",
"license": "BSD-2-Clause",
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/motdotla/dotenv?sponsor=1"
"url": "https://dotenvx.com"
}
},
"node_modules/@notesnook-importer/storage": {
"version": "1.7.0",
"license": "GPL-3.0-or-later"
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@notesnook-importer/storage/-/storage-1.8.1.tgz",
"integrity": "sha512-/IFBI+yZHQOvD+vPLcKvixhbS9TJ4pfQcCkl3WvWZWDwHDYhkSL2Yf2bIgayPxjXWL/U8089tJt8hzWGmsecfw=="
},
"node_modules/@notesnook-importer/znel": {
"version": "1.7.0",
"license": "GPL-3.0-or-later",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@notesnook-importer/znel/-/znel-1.8.1.tgz",
"integrity": "sha512-YkbDfzWREN/HW/Cg6cnZk4eajVEyMdMpxbF3qn2R5YaLWl8Rffa5bm1d/QlGf8u2XL6dyT9Q1tQ5MJ4umKfJvQ==",
"dependencies": {
"base64-js": "^1.5.1",
"css-select": "^5.1.0",
@@ -43570,6 +43574,100 @@
"dev": true,
"license": "MIT"
},
"node_modules/@skiff-org/skiff-crypto": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@skiff-org/skiff-crypto/-/skiff-crypto-1.0.3.tgz",
"integrity": "sha512-SGHUUo+hLqkyjirX1/ucJIZBVPloV3BYIntIIIKpIe8gfyAVi7rfQ3X6NDer/rf3yUA8YPHPxvedhh8/SWUHzg==",
"dependencies": {
"@stablelib/chacha20poly1305": "^1.0.1",
"argon2-browser": "^1.18.0",
"base64-js": "^1.5.1",
"buffer": "^6.0.3",
"fflate": "^0.7.3",
"futoin-hkdf": "^1.5.0",
"lodash": "^4.17.21",
"randombytes": "^2.1.0",
"semver": "^7.3.4",
"tslib": "^2.4.0",
"tweetnacl": "^1.0.3",
"varint": "^6.0.0"
}
},
"node_modules/@skiff-org/skiff-crypto/node_modules/fflate": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
"integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw=="
},
"node_modules/@skiff-org/skiff-crypto/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@stablelib/aead": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz",
"integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg=="
},
"node_modules/@stablelib/binary": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz",
"integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==",
"dependencies": {
"@stablelib/int": "^1.0.1"
}
},
"node_modules/@stablelib/chacha": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz",
"integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==",
"dependencies": {
"@stablelib/binary": "^1.0.1",
"@stablelib/wipe": "^1.0.1"
}
},
"node_modules/@stablelib/chacha20poly1305": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz",
"integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==",
"dependencies": {
"@stablelib/aead": "^1.0.1",
"@stablelib/binary": "^1.0.1",
"@stablelib/chacha": "^1.0.1",
"@stablelib/constant-time": "^1.0.1",
"@stablelib/poly1305": "^1.0.1",
"@stablelib/wipe": "^1.0.1"
}
},
"node_modules/@stablelib/constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz",
"integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg=="
},
"node_modules/@stablelib/int": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz",
"integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w=="
},
"node_modules/@stablelib/poly1305": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz",
"integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==",
"dependencies": {
"@stablelib/constant-time": "^1.0.1",
"@stablelib/wipe": "^1.0.1"
}
},
"node_modules/@stablelib/wipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz",
"integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg=="
},
"node_modules/@standardnotes/auth": {
"version": "3.19.4",
"license": "AGPL-3.0-or-later",
@@ -43653,6 +43751,14 @@
"version": "0.0.10",
"license": "MIT"
},
"node_modules/@streetwriters/kysely": {
"version": "0.27.4",
"resolved": "https://registry.npmjs.org/@streetwriters/kysely/-/kysely-0.27.4.tgz",
"integrity": "sha512-c2p+wtX8WESSVjJAc16j4lT44w/g1DvJFEIeKj/CFy36vmi0uq9FOAzxc50VtRc7rp0UlECCfl3Sxd+BTZOHFg==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@styled-system/background": {
"version": "5.1.2",
"license": "MIT",
@@ -44223,36 +44329,39 @@
}
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.45.2.tgz",
"integrity": "sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==",
"funding": [
"https://trpc.io/sponsor"
],
"license": "MIT",
"peerDependencies": {
"@trpc/server": "10.38.3"
"@trpc/server": "10.45.2"
}
},
"node_modules/@trpc/react-query": {
"version": "10.38.3",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.45.2.tgz",
"integrity": "sha512-BAqb9bGZIscroradlNx+Cc9522R+idY3BOSf5z0jHUtkxdMbjeGKxSSMxxu7JzoLqSIEC+LVzL3VvF8sdDWaZQ==",
"funding": [
"https://trpc.io/sponsor"
],
"license": "MIT",
"peerDependencies": {
"@tanstack/react-query": "^4.18.0",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.45.2",
"@trpc/server": "10.45.2",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@trpc/server": {
"version": "10.38.3",
"version": "10.45.2",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.45.2.tgz",
"integrity": "sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg==",
"dev": true,
"funding": [
"https://trpc.io/sponsor"
],
"license": "MIT"
]
},
"node_modules/@types/babel__core": {
"version": "7.20.4",
@@ -44647,6 +44756,11 @@
"node": ">=10"
}
},
"node_modules/argon2-browser": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.18.0.tgz",
"integrity": "sha512-ImVAGIItnFnvET1exhsQB7apRztcoC5TnlSqernMJDUjbc/DLq3UEYeXFrLPrlaIl8cVfwnXb6wX2KpFf2zxHw=="
},
"node_modules/argparse": {
"version": "1.0.10",
"license": "MIT",
@@ -44926,7 +45040,8 @@
},
"node_modules/boolbase": {
"version": "1.0.0",
"license": "ISC"
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@@ -44980,7 +45095,6 @@
},
"node_modules/buffer": {
"version": "6.0.3",
"dev": true,
"funding": [
{
"type": "github",
@@ -45334,7 +45448,8 @@
},
"node_modules/css-select": {
"version": "5.1.0",
"license": "BSD-2-Clause",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
@@ -45348,7 +45463,8 @@
},
"node_modules/css-what": {
"version": "6.1.0",
"license": "BSD-2-Clause",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"engines": {
"node": ">= 6"
},
@@ -46310,6 +46426,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/futoin-hkdf": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz",
"integrity": "sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/gauge": {
"version": "3.0.2",
"license": "ISC",
@@ -46745,6 +46869,8 @@
},
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
@@ -46752,7 +46878,6 @@
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
@@ -46798,7 +46923,6 @@
},
"node_modules/ieee754": {
"version": "1.2.1",
"devOptional": true,
"funding": [
{
"type": "github",
@@ -47223,7 +47347,8 @@
},
"node_modules/isomorphic-fetch": {
"version": "3.0.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz",
"integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==",
"dependencies": {
"node-fetch": "^2.6.1",
"whatwg-fetch": "^3.4.1"
@@ -47392,8 +47517,9 @@
},
"node_modules/keytar": {
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
"integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-addon-api": "^4.3.0",
@@ -47414,13 +47540,6 @@
"node": ">=6"
}
},
"node_modules/kysely": {
"version": "0.26.3",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/leven": {
"version": "3.1.0",
"dev": true,
@@ -47429,17 +47548,6 @@
"node": ">=6"
}
},
"node_modules/libsodium": {
"version": "0.7.13",
"license": "ISC"
},
"node_modules/libsodium-wrappers": {
"version": "0.7.13",
"license": "ISC",
"dependencies": {
"libsodium": "^0.7.13"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"license": "MIT"
@@ -47474,7 +47582,6 @@
},
"node_modules/lodash": {
"version": "4.17.21",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.debounce": {
@@ -47586,6 +47693,11 @@
"version": "0.13.6",
"license": "MIT"
},
"node_modules/magic-bytes.js": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz",
"integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ=="
},
"node_modules/magic-string": {
"version": "0.30.10",
"dev": true,
@@ -48634,7 +48746,8 @@
},
"node_modules/node-addon-api": {
"version": "4.3.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
"optional": true
},
"node_modules/node-fetch": {
@@ -48719,7 +48832,8 @@
},
"node_modules/nth-check": {
"version": "2.1.1",
"license": "BSD-2-Clause",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dependencies": {
"boolbase": "^1.0.0"
},
@@ -49190,7 +49304,6 @@
},
"node_modules/randombytes": {
"version": "2.1.0",
"dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.0"
@@ -50060,7 +50173,8 @@
},
"node_modules/spark-md5": {
"version": "3.0.2",
"license": "(WTFPL OR MIT)"
"resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz",
"integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="
},
"node_modules/sprintf-js": {
"version": "1.0.3",
@@ -50502,6 +50616,11 @@
"node": "*"
}
},
"node_modules/tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"node_modules/type-detect": {
"version": "4.0.8",
"dev": true,
@@ -50819,7 +50938,8 @@
},
"node_modules/uuid": {
"version": "8.3.2",
"license": "MIT",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"optional": true,
"bin": {
"uuid": "dist/bin/uuid"
@@ -50841,6 +50961,11 @@
"node": ">=8"
}
},
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="
},
"node_modules/vfile": {
"version": "5.3.7",
"license": "MIT",
@@ -51124,7 +51249,8 @@
},
"node_modules/whatwg-fetch": {
"version": "3.6.20",
"license": "MIT"
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="
},
"node_modules/whatwg-mimetype": {
"version": "3.0.0",
@@ -51673,6 +51799,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zustand": {
"version": "4.4.7",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
{
"name": "@notesnook/web",
"description": "Your private note taking space",
"version": "3.0.14",
"version": "3.0.17",
"private": true,
"main": "./src/app.js",
"homepage": "https://notesnook.com/",
@@ -18,7 +18,7 @@
"@henrygd/queue": "^1.0.6",
"@mdi/js": "^7.2.96",
"@mdi/react": "^1.6.1",
"@notesnook-importer/core": "^2.0.0",
"@notesnook-importer/core": "^2.1.1",
"@notesnook/common": "file:../../packages/common",
"@notesnook/core": "file:../../packages/core",
"@notesnook/crypto": "file:../../packages/crypto",
@@ -32,13 +32,13 @@
"@notesnook/web-clipper": "file:../../extensions/web-clipper",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.29.19",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-virtual": "^3.0.1",
"@theme-ui/color": "^0.16.1",
"@theme-ui/components": "^0.16.1",
"@theme-ui/core": "^0.16.1",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/client": "10.45.2",
"@trpc/react-query": "10.45.2",
"@zip.js/zip.js": "^2.7.32",
"async-mutex": "^0.4.0",
"axios": "^1.3.4",
@@ -56,8 +56,7 @@
"hash-wasm": "^4.9.0",
"hotkeys-js": "^3.8.3",
"katex": "0.16.2",
"kysely": "^0.26.3",
"libsodium-wrappers": "^0.7.13",
"@streetwriters/kysely": "^0.27.4",
"mac-scrollbar": "^0.13.5",
"marked": "^4.1.0",
"mutative": "^1.0.6",
@@ -93,7 +92,7 @@
"@playwright/test": "^1.43.1",
"@swc/core": "^1.5.24",
"@swc/plugin-react-remove-properties": "^2.0.4",
"@trpc/server": "10.38.3",
"@trpc/server": "10.45.2",
"@types/babel__core": "^7.20.1",
"@types/event-source-polyfill": "^1.0.1",
"@types/file-saver": "^2.0.5",

File diff suppressed because it is too large Load Diff

View File

@@ -116,12 +116,10 @@ export async function checkAttachment(hash: string) {
if (!attachment) return { failed: "Attachment not found." };
try {
const size = await lazify(
import("../interfaces/fs"),
({ getUploadedFileSize }) => getUploadedFileSize(hash)
await lazify(import("../interfaces/fs"), ({ checkUpload }) =>
checkUpload(hash, attachment.chunkSize, attachment.size)
);
if (size === 0) throw new Error("File length is 0.");
else if (size === -1) throw new Error("File verification check failed.");
await db.attachments.markAsFailed(attachment.id);
} catch (e) {
const reason = e instanceof Error ? e.message : "Unknown error.";
await db.attachments.markAsFailed(attachment.id, reason);

View File

@@ -21,6 +21,8 @@ import { store as noteStore } from "../stores/note-store";
import { store as notebookStore } from "../stores/notebook-store";
import { store as attachmentStore } from "../stores/attachment-store";
import { store as reminderStore } from "../stores/reminder-store";
import { store as tagStore } from "../stores/tag-store";
import { store as appStore } from "../stores/app-store";
import { db } from "./db";
import { showToast } from "../utils/toast";
import Vault from "./vault";
@@ -59,6 +61,8 @@ async function moveNotesToTrash(ids: string[], confirm = true) {
}
async function moveNotebooksToTrash(ids: string[]) {
if (!ids.length) return;
const isMultiselect = ids.length > 1;
if (isMultiselect) {
if (!(await showMultiDeleteConfirmation(ids.length))) return;
@@ -134,9 +138,42 @@ async function moveRemindersToTrash(ids: string[]) {
showToast("success", `${pluralize(ids.length, "reminder")} deleted.`);
}
async function deleteTags(ids: string[]) {
if (
!(await ConfirmDialog.show({
title: "Are you sure?",
message:
"Are you sure you want to permanently delete these tags? This action is IRREVERSIBLE.",
negativeButtonText: "No",
positiveButtonText: "Yes"
}))
)
return;
await TaskManager.startTask({
type: "status",
id: "deleteTags",
title: "Deleting tags",
action: async (report) => {
report({
text: `Deleting ${pluralize(ids.length, "tag")}...`
});
for (const id of ids) {
await db.tags.remove(id);
}
await appStore.refreshNavItems();
await tagStore.refresh();
await noteStore.refresh();
}
});
showToast("success", `${pluralize(ids.length, "tag")} deleted.`);
}
export const Multiselect = {
moveRemindersToTrash,
moveNotebooksToTrash,
moveNotesToTrash,
deleteAttachments
deleteAttachments,
deleteTags
};

View File

@@ -26,7 +26,7 @@ import {
QueryResult,
CompiledQuery,
Driver
} from "kysely";
} from "@streetwriters/kysely";
import { desktop } from "../desktop-bridge";
import Worker from "./sqlite.worker.desktop.ts?worker";
import type { SQLiteWorker } from "./sqlite.worker.desktop";

View File

@@ -22,7 +22,7 @@ import {
SqliteQueryCompiler,
SqliteIntrospector,
Dialect
} from "kysely";
} from "@streetwriters/kysely";
import {
WaSqliteWorkerMultipleTabDriver,
WaSqliteWorkerSingleTabDriver

View File

@@ -21,7 +21,7 @@ import type { SQLiteAPI, SQLiteCompatibleType } from "./sqlite-types";
import { Factory, SQLITE_ROW, SQLiteError } from "./sqlite-api";
import { expose, transfer } from "comlink";
import type { RunMode } from "./type";
import { QueryResult } from "kysely";
import { QueryResult } from "@streetwriters/kysely";
import { DatabaseSource } from "./sqlite-export";
import { createSharedServicePort } from "./shared-service";
import type { IDBBatchAtomicVFS } from "./IDBBatchAtomicVFS";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type { QueryResult } from "kysely";
import type { QueryResult } from "@streetwriters/kysely";
export type Promisable<T> = T | Promise<T>;

View File

@@ -17,8 +17,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type { DatabaseConnection, Driver, QueryResult } from "kysely";
import { CompiledQuery } from "kysely";
import type {
DatabaseConnection,
Driver,
QueryResult
} from "@streetwriters/kysely";
import { CompiledQuery } from "@streetwriters/kysely";
import Worker from "./sqlite.worker.ts?worker";
import type { SQLiteWorker } from "./sqlite.worker";
import SQLiteSyncURI from "./wa-sqlite.wasm?url";

View File

@@ -29,12 +29,22 @@ export type AccordionProps = {
testId?: string;
buttonSx?: FlexProps["sx"];
titleSx?: FlexProps["sx"];
containerSx?: FlexProps["sx"];
};
export default function Accordion(
props: PropsWithChildren<AccordionProps> & FlexProps
) {
const { isClosed, title, color, children, testId, sx, ...restProps } = props;
const {
isClosed,
title,
color,
children,
testId,
sx,
containerSx,
...restProps
} = props;
const [isContentHidden, setIsContentHidden] = useState(false);
useEffect(() => {
@@ -69,8 +79,9 @@ export default function Accordion(
</Flex>
<Flex
sx={{
display: isContentHidden ? "none" : "flex",
flexDirection: "column"
flexDirection: "column",
...containerSx,
display: isContentHidden ? "none" : "flex"
}}
>
{children}

View File

@@ -57,6 +57,7 @@ import { Attachment as AttachmentType } from "@notesnook/core";
import { useEditorStore } from "../../stores/editor-store";
import { PromptDialog } from "../../dialogs/prompt";
import { DialogManager } from "../../common/dialog-manager";
import { useStore as useSelectionStore } from "../../stores/selection-store";
const FILE_ICONS: Record<string, Icon> = {
"image/": FileImage,
@@ -135,6 +136,13 @@ export function Attachment({
Menu.openMenu(AttachmentMenuItems(item, status));
}}
onClick={onSelected}
onKeyPress={async (e) => {
if (e.key === "Delete") {
await Multiselect.deleteAttachments(
useSelectionStore.getState().selectedItems
);
}
}}
style={style}
ref={rowRef}
>

View File

@@ -18,13 +18,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useMemo } from "react";
import { Box, Flex, Image, Link, Text } from "@theme-ui/components";
import { useStore as useThemeStore } from "../../stores/theme-store";
import { getRandom } from "@notesnook/common";
import { Box, Button, Flex, Image, Link, Text } from "@theme-ui/components";
import { getRandom, usePromise } from "@notesnook/common";
import Grberk from "../../assets/testimonials/grberk.jpeg";
import Holenstein from "../../assets/testimonials/holenstein.jpg";
import Jason from "../../assets/testimonials/jason.jpg";
import Cameron from "../../assets/testimonials/cameron.jpg";
import hosts from "@notesnook/core/dist/utils/constants";
import { SettingsDialog } from "../../dialogs/settings";
const testimonials = [
{
@@ -74,10 +75,16 @@ function randomTitle() {
}
function AuthContainer(props) {
const colorScheme = useThemeStore((store) => store.colorScheme);
const testimonial = useMemo(() => randomTestimonial(), []);
const title = useMemo(() => randomTitle(), []);
const version = usePromise(
async () =>
await fetch(`${hosts.API_HOST}/version`)
.then((r) => r.json())
.catch(() => undefined)
);
return (
<Flex
sx={{
@@ -165,7 +172,6 @@ function AuthContainer(props) {
<Text variant={"heading"} sx={{ fontSize: 48 }}>
{title}
</Text>
<Text
variant="body"
mt={10}
@@ -193,6 +199,34 @@ function AuthContainer(props) {
<Text variant="subBody">@{testimonial.username}</Text>
</Flex>
</Flex>
<Flex
mt={2}
pt={2}
sx={{
justifyContent: "space-between",
borderTop: "1px solid var(--border)",
width: "100%"
}}
>
<Text variant={"subBody"}>
{version.status === "fulfilled" &&
version.value.instance !== "default" ? (
<>
Using{" "}
{version.value.instance + ` (v${version.value.version})`}
</>
) : (
<>Using official Notesnook instance.</>
)}
</Text>
<Button
variant="anchor"
onClick={() => SettingsDialog.show({ activeSection: "servers" })}
>
Configure
</Button>
</Flex>
</Flex>
</Box>
<Flex

View File

@@ -50,6 +50,7 @@ function Header(props: HeaderProps) {
const id =
(await db.tags.find(value))?.id ??
(await db.tags.add({ title: value }));
if (!id) return;
await db.relations.add({ id, type: "tag" }, { type: "note", id: noteId });
await useTagStore.getState().refresh();
}

View File

@@ -39,6 +39,11 @@ export function GlobalErrorHandler(props: PropsWithChildren) {
showBoundary(e.error || error);
}
function handleUnhandledRejection(e: PromiseRejectionEvent) {
if (
e.reason instanceof TypeError &&
e.reason.message === "Error in input stream"
)
return;
showBoundary(e.reason);
}
window.addEventListener("unhandledrejection", handleUnhandledRejection);

View File

@@ -215,7 +215,8 @@ import {
mdiWindowClose,
mdiFileMusicOutline,
mdiBroom,
mdiServerSecurity
mdiServerSecurity,
mdiOpenInNew
} from "@mdi/js";
import { useTheme } from "@emotion/react";
import { Theme } from "@notesnook/theme";
@@ -552,3 +553,4 @@ export const WindowRestore = createIcon(
);
export const WindowClose = createIcon(mdiWindowClose);
export const ClearCache = createIcon(mdiBroom);
export const OpenInNew = createIcon(mdiOpenInNew);

View File

@@ -50,7 +50,8 @@ import {
RemoveShortcutLink,
Plus,
Copy,
Tag as TagIcon
Tag as TagIcon,
OpenInNew
} from "../icons";
import TimeAgo from "../time-ago";
import ListItem from "../list-item";
@@ -132,8 +133,9 @@ function Note(props: NoteProps) {
onKeyPress={async (e) => {
if (e.key === "Delete") {
// @ts-expect-error write tests for this
const selectedItems = selectionStore.get().selectedItems;
await Multiselect.moveNotesToTrash([item.id, ...selectedItems]);
await Multiselect.moveNotesToTrash(
selectionStore.get().selectedItems
);
}
}}
colors={{
@@ -430,17 +432,53 @@ const menuItems: (
{
type: "button",
key: "publish",
isDisabled:
//!isSynced ||
!db.monographs.isPublished(note.id) && context?.locked,
isDisabled: !db.monographs.isPublished(note.id) && context?.locked,
icon: Publish.path,
title: "Publish",
isChecked: db.monographs.isPublished(note.id),
onClick: async () => {
const isPublished = db.monographs.isPublished(note.id);
if (isPublished) await useMonographStore.getState().unpublish(note.id);
else await showPublishView(note, "bottom");
}
menu: db.monographs.isPublished(note.id)
? {
items: [
{
type: "button",
key: "open",
title: "Open",
icon: OpenInNew.path,
onClick: async () => {
const url = `https://monogr.ph/${note.id}`;
window.open(url, "_blank");
}
},
{
type: "button",
key: "copy-link",
title: "Copy link",
icon: Copy.path,
onClick: async () => {
const url = `https://monogr.ph/${note.id}`;
await writeToClipboard({
"text/plain": url,
"text/html": `<a href="${url}">${note.title}</a>`,
"text/markdown": `[${note.title}](${url})`
});
}
},
{
type: "separator",
key: "sep"
},
{
type: "button",
key: "unpublish",
title: "Unpublish",
icon: Publish.path,
onClick: async () => {
await useMonographStore.getState().unpublish(note.id);
}
}
]
}
: undefined,
onClick: () => showPublishView(note, "bottom")
},
{
type: "button",

View File

@@ -44,6 +44,7 @@ import { Notebook as NotebookType } from "@notesnook/core";
import { handleDrop } from "../../common/drop-handler";
import { useDragHandler } from "../../hooks/use-drag-handler";
import { ConfirmDialog } from "../../dialogs/confirm";
import { useStore as useSelectionStore } from "../../stores/selection-store";
type NotebookProps = {
item: NotebookType;
@@ -80,6 +81,13 @@ function Notebook(props: NotebookProps) {
handleDrop(e.dataTransfer, notebook);
}}
onKeyPress={async (e) => {
if (e.key === "Delete") {
await Multiselect.moveNotebooksToTrash(
useSelectionStore.getState().selectedItems
);
}
}}
title={notebook.title}
body={notebook.description as string}
menuItems={notebookMenuItems}

View File

@@ -43,6 +43,7 @@ import { MenuItem } from "@notesnook/ui";
import { Reminder as ReminderType } from "@notesnook/core/dist/types";
import { ConfirmDialog } from "../../dialogs/confirm";
import { EditReminderDialog } from "../../dialogs/add-reminder-dialog";
import { useStore as useSelectionStore } from "../../stores/selection-store";
const RECURRING_MODE_MAP = {
week: "Weekly",
@@ -74,6 +75,13 @@ function Reminder(props: ReminderProps) {
isDisabled={reminder.disabled}
isCompact={compact}
onClick={() => EditReminderDialog.show({ reminderId: reminder.id })}
onKeyPress={async (e) => {
if (e.key === "Delete") {
await Multiselect.moveRemindersToTrash(
useSelectionStore.getState().selectedItems
);
}
}}
footer={
<Flex
sx={{

View File

@@ -26,7 +26,6 @@ import {
Update,
SyncError,
Alert,
Issue,
SyncOff,
Icon
} from "../icons";
@@ -40,7 +39,6 @@ import { checkForUpdate, installUpdate } from "../../utils/updater";
import { getTimeAgo, toTitleCase } from "@notesnook/common";
import { User } from "@notesnook/core";
import { showUpdateAvailableNotice } from "../../dialogs/confirm";
import { IssueDialog } from "../../dialogs/issue-dialog";
function StatusBar() {
const user = useUserStore((state) => state.user);

View File

@@ -29,6 +29,8 @@ import { useCallback, useRef } from "react";
import { handleDrop } from "../../common/drop-handler";
import { useDragHandler } from "../../hooks/use-drag-handler";
import { AddNotebookDialog } from "../../dialogs/add-notebook-dialog";
import { useStore as useSelectionStore } from "../../stores/selection-store";
import { Multiselect } from "../../common/multi-select";
type SubNotebookProps = {
item: Notebook;
@@ -112,6 +114,11 @@ function SubNotebook(props: SubNotebookProps) {
});
navigate(`/notebooks/${rootId}/${item.id}`);
}
} else if (e.code === "Delete") {
console.log("Delete", useSelectionStore.getState().selectedItems);
await Multiselect.moveNotebooksToTrash(
useSelectionStore.getState().selectedItems
);
}
}}
title={

View File

@@ -21,16 +21,14 @@ import ListItem from "../list-item";
import { navigate } from "../../navigation";
import { Text } from "@theme-ui/components";
import { store as appStore } from "../../stores/app-store";
import { store as tagStore } from "../../stores/tag-store";
import { store as noteStore } from "../../stores/note-store";
import { db } from "../../common/db";
import { Edit, Shortcut, DeleteForver } from "../icons";
import { showToast } from "../../utils/toast";
import { pluralize } from "@notesnook/common";
import { MenuItem } from "@notesnook/ui";
import { Tag as TagType } from "@notesnook/core";
import { handleDrop } from "../../common/drop-handler";
import { EditTagDialog } from "../../dialogs/item-dialog";
import { useStore as useSelectionStore } from "../../stores/selection-store";
import { Multiselect } from "../../common/multi-select";
type TagProps = { item: TagType; totalNotes: number };
function Tag(props: TagProps) {
@@ -54,6 +52,13 @@ function Tag(props: TagProps) {
{totalNotes}
</Text>
}
onKeyPress={async (e) => {
if (e.key === "Delete") {
await Multiselect.deleteTags(
useSelectionStore.getState().selectedItems
);
}
}}
menuItems={menuItems}
onClick={() => {
navigate(`/tags/${id}`);
@@ -96,11 +101,7 @@ const menuItems: (tag: TagType, ids?: string[]) => MenuItem[] = (
title: "Delete",
icon: DeleteForver.path,
onClick: async () => {
await db.tags.remove(...ids);
showToast("success", `${pluralize(ids.length, "tag")} deleted`);
await appStore.refreshNavItems();
await tagStore.refresh();
await noteStore.refresh();
await Multiselect.deleteTags(ids);
},
multiSelect: true
}

View File

@@ -28,6 +28,7 @@ import { MenuItem } from "@notesnook/ui";
import { TrashItem as TrashItemType } from "@notesnook/core/dist/types";
import { useEditorStore } from "../../stores/editor-store";
import { showMultiPermanentDeleteConfirmation } from "../../dialogs/confirm";
import { useStore as useSelectionStore } from "../../stores/selection-store";
type TrashItemProps = { item: TrashItemType; date: number };
function TrashItem(props: TrashItemProps) {
@@ -40,6 +41,11 @@ function TrashItem(props: TrashItemProps) {
item={item}
title={item.title}
body={item.itemType === "note" ? item.headline : item.description}
onKeyPress={async (e) => {
if (e.key === "Delete") {
await deleteTrash(useSelectionStore.getState().selectedItems);
}
}}
footer={
<Flex
mt={1}
@@ -87,14 +93,15 @@ const menuItems: (item: TrashItemType, ids?: string[]) => MenuItem[] = (
icon: DeleteForver.path,
variant: "dangerous",
onClick: async () => {
if (!(await showMultiPermanentDeleteConfirmation(ids.length))) return;
await store.delete(...ids);
showToast(
"success",
`${pluralize(ids.length, "item")} permanently deleted`
);
await deleteTrash(ids);
},
multiSelect: true
}
];
};
async function deleteTrash(ids: string[]) {
if (!(await showMultiPermanentDeleteConfirmation(ids.length))) return;
await store.delete(...ids);
showToast("success", `${pluralize(ids.length, "item")} permanently deleted`);
}

View File

@@ -72,6 +72,7 @@ export function VirtualizedTable<T, C>(props: VirtualizedTableProps<T, C>) {
containerRef.current?.closest(".ms-container") ||
undefined
}
increaseViewportBy={300}
computeItemKey={(index) => getItemKey(index)}
defaultItemHeight={estimatedSize}
fixedHeaderContent={() => <>{header}</>}

View File

@@ -49,6 +49,8 @@ export const AddNotebookDialog = DialogManager.register(
title: title.current,
description: description.current
});
if (!id) return;
if (parentId) {
await db.relations.add(
{ type: "notebook", id: parentId },

View File

@@ -197,14 +197,15 @@ export const AttachmentsDialog = DialogManager.register(
variant="secondary"
key={tool.title}
title={tool.title}
onClick={() =>
tool.onClick({
selected
// : attachments.filter(
// (a) => selected.indexOf(a.id) > -1
// )
})
}
onClick={() => {
try {
tool.onClick({
selected
});
} catch (e) {
showToast("error", (e as Error).message);
}
}}
disabled={!selected.length}
sx={{ bg: "transparent", p: 1 }}
>
@@ -254,7 +255,14 @@ export const AttachmentsDialog = DialogManager.register(
>
<Label>
<Checkbox
sx={{ width: 18, height: 18 }}
sx={{
width: 18,
height: 18,
color:
selected.length === attachments.length
? "accent"
: "icon"
}}
onChange={async (e) => {
setSelected(
e.currentTarget.checked
@@ -264,6 +272,7 @@ export const AttachmentsDialog = DialogManager.register(
: []
);
}}
checked={selected.length === attachments.length}
/>
</Label>
</Text>

View File

@@ -312,7 +312,7 @@ const sections: Section[] = [
icon: Pin
}
],
info: "* Free users can only create 3 notebooks (no limit on topics) and 5 tags."
info: "* Free users can only create 20 notebooks and 5 tags."
},
{
@@ -399,8 +399,7 @@ const sections: Section[] = [
{
id: "backup-encryption",
title: "Backup encryption",
icon: EncryptedBackup,
pro: true
icon: EncryptedBackup
}
]
},
@@ -408,7 +407,6 @@ const sections: Section[] = [
title: "Personalize & make Notesnook your own",
detail:
"Change app themes to match your style. Custom themes are coming soon.",
pro: true,
features: [
{
id: "10-themes",
@@ -423,7 +421,8 @@ const sections: Section[] = [
{
id: "default-home-page",
title: "Change default home page",
icon: Home
icon: Home,
pro: true
}
]
}

View File

@@ -26,6 +26,7 @@ import { db } from "../common/db";
import { getChangelog } from "../utils/version";
import { downloadUpdate } from "../utils/updater";
import { ErrorText } from "../components/error-text";
import { pluralize } from "@notesnook/common";
type Check = { text: string; default?: boolean };
export type ConfirmDialogProps<TCheckId extends string> = BaseDialogProps<
@@ -143,7 +144,7 @@ export const ConfirmDialog = DialogManager.register(function ConfirmDialog<
export function showMultiDeleteConfirmation(length: number) {
return ConfirmDialog.show({
title: `Delete ${length} items?`,
title: `Delete ${pluralize(length, "item")}?`,
message: `These items will be **kept in your Trash for ${
db.settings.getTrashCleanupInterval() || 7
} days** after which they will be permanently deleted.`,
@@ -154,7 +155,7 @@ export function showMultiDeleteConfirmation(length: number) {
export function showMultiPermanentDeleteConfirmation(length: number) {
return ConfirmDialog.show({
title: `Permanently delete ${length} items?`,
title: `Permanently delete ${pluralize(length, "item")}?`,
message:
"These items will be **permanently deleted**. This is IRREVERSIBLE.",
positiveButtonText: "Yes",

View File

@@ -36,9 +36,6 @@ const QRCode = React.lazy(() => import("../re-exports/react-qrcode-logo"));
type RecoveryKeyDialogProps = BaseDialogProps<false>;
export const RecoveryKeyDialog = DialogManager.register(
function RecoveryKeyDialog(props: RecoveryKeyDialogProps) {
const email = usePromise(() =>
db.user.getUser().then((user) => user?.email)
);
const key = usePromise(() =>
db.user.getEncryptionKey().then((key) => key?.key)
);
@@ -124,6 +121,9 @@ export const RecoveryKeyDialog = DialogManager.register(
variant="secondary"
mt={1}
onClick={async () => {
const email = await db.user
.getUser()
.then((user) => user?.email || "user");
const qrcode = document.getElementById(
"react-qrcode-logo"
) as HTMLCanvasElement | null;
@@ -143,9 +143,12 @@ export const RecoveryKeyDialog = DialogManager.register(
<Button
variant="secondary"
mt={1}
onClick={() => {
onClick={async () => {
if (!key.value)
return showToast("error", "No encryption key found.");
const email = await db.user
.getUser()
.then((user) => user?.email || "user");
FileSaver.saveAs(
new Blob([Buffer.from(key.value)]),
`${email}-notesnook-recoverykey.txt`

View File

@@ -20,11 +20,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useStore as useAppStore } from "../../../stores/app-store";
import { useCallback, useRef, useState } from "react";
import { useDropzone } from "react-dropzone";
import { Button, Flex, Input, Link, Text } from "@theme-ui/components";
import { pluralize } from "@notesnook/common";
import { Box, Button, Flex, Input, Link, Text } from "@theme-ui/components";
import { db } from "../../../common/db";
import { importFiles } from "../../../utils/importer";
import { CheckCircleOutline } from "../../../components/icons";
import Accordion from "../../../components/accordion";
type Provider = { title: string; link: string };
const POPULAR_PROVIDERS: Provider[] = [
{
title: "Evernote",
link: "https://help.notesnook.com/importing-notes/import-notes-from-evernote"
},
{
title: "Simplenote",
link: "https://help.notesnook.com/importing-notes/import-notes-from-simplenote"
},
{
title: "Google Keep",
link: "https://help.notesnook.com/importing-notes/import-notes-from-google-keep"
},
{
title: "Obsidian",
link: "https://help.notesnook.com/importing-notes/import-notes-from-obsidian"
},
{
title: "Joplin",
link: "https://help.notesnook.com/importing-notes/import-notes-from-joplin"
},
{
title: "Markdown files",
link: "https://help.notesnook.com/importing-notes/import-notes-from-markdown-files"
},
{
title: "other apps",
link: "https://help.notesnook.com/importing-notes/"
}
];
export function Importer() {
const [isDone, setIsDone] = useState(false);
@@ -114,75 +146,81 @@ export function Importer() {
</>
) : (
<>
<Flex sx={{ alignItems: "center", justifyContent: "space-between" }}>
<Flex sx={{ flexDirection: "column" }}>
<Text variant="title">
{files.length
? `${pluralize(files.length, "file")} ready for import`
: "Select files to import"}
<Accordion
isClosed={false}
title="How to import your notes from other apps?"
containerSx={{
px: 2,
pb: 2,
border: "1px solid var(--border)",
borderTopWidth: 0,
borderRadius: "default",
borderTopLeftRadius: 0,
borderTopRightRadius: 0
}}
>
<Text variant="subtitle" sx={{ mt: 2 }}>
Quick start guide:
</Text>
<Box as="ol" sx={{ my: 1 }}>
<Text as="li" variant="body">
Go to{" "}
<Link href="https://importer.notesnook.com/" target="_blank">
https://importer.notesnook.com/
</Link>
</Text>
<Text
variant={"body"}
sx={{ color: "var(--paragraph-secondary)" }}
>
Please refer to the{" "}
<Link
href="https://help.notesnook.com/importing-notes/import-notes-from-evernote"
target="_blank"
rel="noopener noreferrer"
sx={{ color: "accent" }}
>
import guide
</Link>{" "}
for help regarding how to use the Notesnook Importer.
<Text as="li" variant="body">
Select the app you want to import from.
</Text>
</Flex>
<Button
variant="accent"
onClick={async () => {
setIsDone(false);
setIsImporting(true);
<Text as="li" variant="body">
Drag drop or select the files you exported from the other app.
</Text>
<Text as="li" variant="body">
Start the importer and wait for it to complete processing.
</Text>
<Text as="li" variant="body">
Download the .zip file from the Importer.
</Text>
<Text as="li" variant="body">
Drop the .zip file below to complete your import.
</Text>
</Box>
await db.syncer?.acquireLock(async () => {
try {
for await (const message of importFiles(files)) {
switch (message.type) {
case "error":
setErrors((errors) => [...errors, message.error]);
break;
case "progress": {
const { count } = message;
if (notesCounter.current)
notesCounter.current.innerText = `${count}`;
break;
}
}
}
} catch (e) {
console.error(e);
if (e instanceof Error) {
setErrors((errors) => [...errors, e as Error]);
}
}
});
await useAppStore.getState().refresh();
setIsDone(true);
setIsImporting(false);
<Text variant={"body"} sx={{ fontWeight: "bold" }}>
For detailed steps with screenshots, refer to the help article for
each app:
</Text>
<Box
sx={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: 1,
mt: 1
}}
disabled={!files.length}
>
Start import
</Button>
</Flex>
{POPULAR_PROVIDERS.map((provider) => (
<Button
key={provider.link}
variant="icon"
sx={{
borderRadius: "default",
border: "1px solid var(--border)",
textAlign: "left"
}}
onClick={() => window.open(provider.link, "_blank")}
>
Import from {provider.title}
</Button>
))}
</Box>
</Accordion>
<Flex
{...getRootProps()}
data-test-id="import-dialog-select-files"
sx={{
justifyContent: "center",
alignItems: "center",
height: 200,
minHeight: 200,
flexShrink: 0,
width: "full",
border: "2px dashed var(--border)",
@@ -199,31 +237,75 @@ export function Importer() {
<br />
<Text variant="subBody">Only .zip files are supported.</Text>
</Text>
<Box sx={{ display: "flex", flexWrap: "wrap", mt: 2 }}>
{files.map((file, i) => (
<Text
key={file.name}
p={1}
sx={{
":hover": { bg: "hover" },
cursor: "pointer",
borderRadius: "default"
}}
onClick={() => {
setFiles((files) => {
const cloned = files.slice();
cloned.splice(i, 1);
return cloned;
});
}}
variant="body"
title="Click to remove"
>
{file.name}
</Text>
))}
</Box>
</Flex>
<Flex my={1} sx={{ flexDirection: "column" }}>
{files.map((file, i) => (
<Text
key={file.name}
p={1}
sx={{
":hover": { bg: "hover" },
cursor: "pointer",
borderRadius: "default"
}}
onClick={() => {
setFiles((files) => {
const cloned = files.slice();
cloned.splice(i, 1);
return cloned;
});
}}
variant="body"
title="Click to remove"
>
{file.name}
</Text>
))}
</Flex>
{/* <Flex my={1} sx={{ flexDirection: "column" }}>
</Flex> */}
<Button
variant="accent"
sx={{ alignSelf: "end", mt: 1 }}
onClick={async () => {
setIsDone(false);
setIsImporting(true);
await db.syncer?.acquireLock(async () => {
try {
for await (const message of importFiles(files)) {
switch (message.type) {
case "error":
setErrors((errors) => [...errors, message.error]);
break;
case "progress": {
const { count } = message;
if (notesCounter.current)
notesCounter.current.innerText = `${count}`;
break;
}
}
}
} catch (e) {
console.error(e);
if (e instanceof Error) {
setErrors((errors) => [...errors, e as Error]);
}
}
});
await useAppStore.getState().refresh();
setIsDone(true);
setIsImporting(false);
}}
disabled={!files.length}
>
{files.length > 0
? "Start import"
: "Select files to start importing"}
</Button>
</>
)}
</Flex>

View File

@@ -171,9 +171,6 @@ function ThemesList() {
{filter.title}
</Button>
))}
{themes.isLoading && !themes.isInitialLoading ? (
<Loading color="accent" />
) : null}
</Flex>
<Flex sx={{ mt: 2, gap: 1 }}>
@@ -238,6 +235,9 @@ function ThemesList() {
)}
/>
)}
{!themes.isInitialLoading && themes.isFetching ? (
<Loading color="accent" sx={{ mt: 2 }} />
) : null}
</Box>
</>
);

View File

@@ -24,7 +24,18 @@ export const ImporterSettings: SettingsGroup[] = [
{
key: "importer",
section: "importer",
header: Importer,
settings: []
header: "Notesnook Importer",
settings: [
{
key: "import-notes",
title: "",
components: [
{
type: "custom",
component: Importer
}
]
}
]
}
];

View File

@@ -77,7 +77,9 @@ import { AppLockSettings } from "./app-lock-settings";
import { BaseDialogProps, DialogManager } from "../../common/dialog-manager";
import { ServersSettings } from "./servers-settings";
type SettingsDialogProps = BaseDialogProps<false>;
type SettingsDialogProps = BaseDialogProps<false> & {
activeSection?: SectionKeys;
};
const sectionGroups: SectionGroup[] = [
{
@@ -187,7 +189,9 @@ export const SettingsDialog = DialogManager.register(function SettingsDialog(
props: SettingsDialogProps
) {
const [activeSettings, setActiveSettings] = useState<SettingsGroup[]>(
SettingsGroups.filter((g) => g.section === "profile")
SettingsGroups.filter(
(g) => g.section === (props.activeSection || "profile")
)
);
return (
@@ -205,6 +209,7 @@ export const SettingsDialog = DialogManager.register(function SettingsDialog(
}}
>
<SettingsSideBar
activeSection={props.activeSection}
onNavigate={(settings) => {
const scrollbar = document.getElementById("settings-scrollbar");
if (scrollbar !== null) scrollbar.scrollTop = 0;
@@ -233,10 +238,13 @@ export const SettingsDialog = DialogManager.register(function SettingsDialog(
);
});
type SettingsSideBarProps = { onNavigate: (settings: SettingsGroup[]) => void };
type SettingsSideBarProps = {
onNavigate: (settings: SettingsGroup[]) => void;
activeSection?: SectionKeys;
};
function SettingsSideBar(props: SettingsSideBarProps) {
const { onNavigate } = props;
const [route, setRoute] = useState<SectionKeys>("profile");
const { onNavigate, activeSection } = props;
const [route, setRoute] = useState<SectionKeys>(activeSection || "profile");
useUserStore((store) => store.isLoggedIn);
return (

View File

@@ -110,6 +110,11 @@ export async function writeEncryptedFile(
)
.pipeTo(fileHandle.writeable);
if (!(await exists(fileHandle))) {
await fileHandle.delete();
throw new Error("Failed to encrypt file. Please try again.");
}
AppEventManager.publish(AppEvents.fileEncrypted, {
hash,
total: 1,
@@ -256,7 +261,11 @@ async function uploadFile(
: await multiPartUploadFile(fileHandle, filename, requestOptions);
if (uploaded) {
await checkUpload(filename);
await checkUpload(
filename,
requestOptions.chunkSize,
fileHandle.file.size
);
await fileHandle.addAdditionalData("uploaded", true);
}
@@ -448,13 +457,21 @@ async function resetUpload(fileHandle: FileHandle) {
await fileHandle.addAdditionalData("uploaded", false);
}
async function checkUpload(filename: string) {
export async function checkUpload(
filename: string,
chunkSize: number,
expectedSize: number
) {
const size = await getUploadedFileSize(filename);
const totalChunks = Math.ceil(size / chunkSize);
const decryptedLength = size - totalChunks * ABYTES;
const error =
size === 0
? `Upload verification failed: file size is 0. Please upload this file again. (File hash: ${filename})`
? `File size is 0.`
: size === -1
? `Upload verification failed.`
? `File verification check failed.`
: expectedSize !== decryptedLength
? `File size mismatch. Expected ${size} bytes but got ${decryptedLength} bytes.`
: undefined;
if (error) throw new Error(error);
}
@@ -612,6 +629,11 @@ export async function streamingDecryptFile(
if (!fileMetadata) return false;
const fileHandle = await streamablefs.readFile(filename);
logger.info("decrypting file", {
filename,
size: fileHandle?.file.size,
actualSize: await fileHandle?.size()
});
if (!fileHandle) return false;
const { key, iv } = fileMetadata;

View File

@@ -28,6 +28,7 @@ import { AttachmentStream } from "../utils/streams/attachment-stream";
import { createZipStream } from "../utils/streams/zip-stream";
import { createWriteStream } from "../utils/stream-saver";
import { Attachment } from "@notesnook/core";
import { TaskManager } from "../common/task-manager";
let abortController: AbortController | undefined = undefined;
class AttachmentStore extends BaseStore<AttachmentStore> {
@@ -80,25 +81,36 @@ class AttachmentStore extends BaseStore<AttachmentStore> {
};
recheck = async (ids: string[]) => {
for (const id of ids) {
const attachment = await db.attachments.attachment(id);
if (!attachment) continue;
try {
this._changeWorkingStatus(attachment.hash, "recheck");
await TaskManager.startTask({
type: "status",
action: async (report) => {
let i = 0;
for (const id of ids) {
report({
text: `Checking attachments (${++i}/${ids.length})`
});
const attachment = await db.attachments.attachment(id);
if (!attachment) continue;
try {
this._changeWorkingStatus(attachment.hash, "recheck");
const { failed, success } = await checkAttachment(attachment.hash);
this._changeWorkingStatus(
attachment.hash,
undefined,
success ? undefined : failed
);
} catch (e) {
console.error(e);
this._changeWorkingStatus(attachment.hash);
if (e instanceof Error)
showToast("error", `Rechecking failed: ${e.message}`);
}
}
const { failed, success } = await checkAttachment(attachment.hash);
this._changeWorkingStatus(
attachment.hash,
undefined,
success ? undefined : failed
);
} catch (e) {
console.error(e);
this._changeWorkingStatus(attachment.hash);
if (e instanceof Error)
showToast("error", `Rechecking failed: ${e.message}`);
}
}
},
id: "checking-attachments",
title: "Checking attachments"
});
};
rename = async (hash: string, newName: string) => {

View File

@@ -802,10 +802,11 @@ class EditorStore extends BaseStore<EditorStore> {
{ type, id: currentSession.context.id },
{ id, type: "note" }
);
} else {
const defaultNotebook = db.settings.getDefaultNotebook();
if (defaultNotebook)
await db.notes.addToNotebook(defaultNotebook, id);
}
const defaultNotebook = db.settings.getDefaultNotebook();
if (defaultNotebook)
await db.notes.addToNotebook(defaultNotebook, id);
}
const attachmentsLength = await db.attachments

View File

@@ -22,7 +22,7 @@ const FEATURE_CHECKS = {
cache: false,
indexedDB: false,
clonableCryptoKey: false,
applePaySupported: window.ApplePaySession?.canMakePayments()
applePaySupported: !!window.ApplePaySession?.canMakePayments()
};
async function isOPFSSupported() {

View File

@@ -21,7 +21,8 @@ import { db } from "../common/db";
import {
Note,
Notebook,
ContentType
ContentType,
LegacyNotebook
} from "@notesnook-importer/core/dist/src/models";
import {
ATTACHMENTS_DIRECTORY_NAME,
@@ -145,6 +146,7 @@ async function processNote(entry: ZipEntry, attachments: Record<string, any>) {
(await db.tags.add({
title: tag
}));
if (!tagId) continue;
await db.relations.add(
{
@@ -166,6 +168,7 @@ async function processNote(entry: ZipEntry, attachments: Record<string, any>) {
colorCode: colorCode,
title: note.color
}));
if (!colorId) return;
await db.relations.add(
{
@@ -180,9 +183,16 @@ async function processNote(entry: ZipEntry, attachments: Record<string, any>) {
}
for (const nb of notebooks) {
const notebookId = await importNotebook(nb).catch(() => undefined);
if (!notebookId) continue;
await db.notes.addToNotebook(notebookId, noteId);
if ("notebook" in nb) {
const notebookId = await importLegacyNotebook(nb).catch(() => undefined);
if (!notebookId) continue;
await db.notes.addToNotebook(notebookId, noteId);
} else {
const notebookIds = await importNotebook(nb).catch(() => undefined);
if (!notebookIds) continue;
for (const notebookId of notebookIds)
await db.notes.addToNotebook(notebookId, noteId);
}
}
}
@@ -191,8 +201,11 @@ async function fileToJson<T>(file: ZipEntry) {
return JSON.parse(text) as T;
}
async function importNotebook(
notebook: Notebook | undefined
/**
* @deprecated
*/
async function importLegacyNotebook(
notebook: LegacyNotebook | undefined
): Promise<string | undefined> {
if (!notebook) return;
const nb = await db.notebooks.find(notebook.notebook);
@@ -202,3 +215,29 @@ async function importNotebook(
title: notebook.notebook
});
}
async function importNotebook(
notebook: Notebook,
parentId?: string
): Promise<string[]> {
if (!notebook) return [];
const id =
(await db.notebooks.find(notebook.title))?.id ||
(await db.notebooks.add({
title: notebook.title
}));
if (!id) throw new Error(`Failed to import notebook: ${notebook.title}`);
if (parentId)
await db.relations.add(
{ type: "notebook", id: parentId },
{ type: "notebook", id: id }
);
const assignedNotebooks: string[] = notebook.children.length > 0 ? [] : [id];
for (const child of notebook.children || []) {
assignedNotebooks.push(...(await importNotebook(child, id)));
}
return assignedNotebooks;
}

View File

@@ -17,12 +17,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getFileNameWithExtension } from "@notesnook/core/dist/utils/filename";
import { db } from "../../common/db";
import { lazify } from "../lazify";
import { showToast } from "../toast";
import { makeUniqueFilename } from "./utils";
import { ZipFile } from "./zip-stream";
import { Attachment } from "@notesnook/core";
import { logger } from "../logger";
export const METADATA_FILENAME = "metadata.json";
const GROUP_ID = "all-attachments";
@@ -33,66 +35,74 @@ export class AttachmentStream extends ReadableStream<ZipFile> {
signal?: AbortSignal,
onProgress?: (current: number) => void
) {
let index = 0;
const counters: Record<string, number> = {};
if (signal)
signal.onabort = async () => {
await db.fs().cancel(GROUP_ID);
};
super({
start() {},
async pull(controller) {
if (signal?.aborted) {
controller.close();
return;
}
onProgress && onProgress(index);
const attachment = await resolve(ids[index++]);
if (!attachment) return;
try {
if (
!(await db
.fs()
.downloadFile(GROUP_ID, attachment.hash, attachment.chunkSize))
)
async start(controller) {
const counters: Record<string, number> = {};
let index = 0;
for (const id of ids) {
if (signal?.aborted) {
controller.close();
return;
}
const key = await db.attachments.decryptKey(attachment.key);
if (!key) return;
onProgress && onProgress(index++);
const attachment = await resolve(id);
if (!attachment) return;
try {
if (
!(await db
.fs()
.downloadFile(GROUP_ID, attachment.hash, attachment.chunkSize))
)
return;
const file = await lazify(
import("../../interfaces/fs"),
({ decryptFile }) =>
decryptFile(attachment.hash, {
key,
iv: attachment.iv,
name: attachment.filename,
type: attachment.mimeType,
isUploaded: !!attachment.dateUploaded
})
);
const key = await db.attachments.decryptKey(attachment.key);
if (!key) return;
if (file) {
const filePath: string = attachment.filename;
controller.enqueue({
path: makeUniqueFilename(filePath, counters),
data: new Uint8Array(await file.arrayBuffer())
});
} else {
throw new Error(
`Failed to decrypt file (hash: ${attachment.hash}, filename: ${attachment.filename}).`
const file = await lazify(
import("../../interfaces/fs"),
({ decryptFile }) =>
decryptFile(attachment.hash, {
key,
iv: attachment.iv,
name: attachment.filename,
type: attachment.mimeType,
isUploaded: !!attachment.dateUploaded
})
);
if (file) {
const filePath: string =
attachment.filename === attachment.hash
? getFileNameWithExtension(
attachment.hash,
attachment.mimeType
)
: attachment.filename;
controller.enqueue({
path: makeUniqueFilename(filePath, counters),
data: new Uint8Array(await file.arrayBuffer())
});
} else {
throw new Error(
`Failed to decrypt file (hash: ${attachment.hash}, filename: ${attachment.filename}).`
);
}
} catch (e) {
logger.error(e, "Failed to download attachment");
showToast(
"error",
`Failed to download attachment: ${(e as Error).message} (hash: ${
attachment.hash
}, filename: ${attachment.filename})`
);
}
} catch (e) {
console.error(e, attachment);
showToast("error", (e as Error).message);
} finally {
if (index === ids.length) {
controller.close();
}
}
controller.close();
}
});
}

View File

@@ -24,12 +24,19 @@ import type {
} from "./task-scheduler.worker";
import { wrap, Remote } from "comlink";
import { showToast } from "./toast";
import dayjs from "dayjs";
import { logger } from "./logger";
let worker: globalThis.Worker | undefined;
let scheduler: Remote<TaskSchedulerType> | undefined;
export class TaskScheduler {
static async register(id: string, time: string, action: () => void) {
if (!dayjs(time).isValid()) {
logger.error(`Invalid cron expression: ${time}`);
return;
}
init();
worker?.addEventListener("message", function handler(ev) {

View File

@@ -118,19 +118,16 @@ export class WebExtensionServer implements Server {
content: { type: "tiptap", data: content }
});
if (id && clip.tags) {
for (const id of clip.tags) {
if (!(await db.tags.exists(id))) continue;
await db.relations.add({ id: id, type: "tag" }, { id, type: "note" });
}
}
if (clip.refs && id && !clip.note) {
for (const ref of clip.refs) {
switch (ref.type) {
case "notebook":
if (!(await db.notebooks.exists(ref.id))) continue;
await db.notes.addToNotebook(ref.id, id);
break;
case "tag":
if (!(await db.tags.exists(ref.id))) continue;
await db.relations.add(ref, { id, type: "note" });
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1 @@
# FAQs

View File

@@ -0,0 +1,18 @@
---
title: Is there an ETA for X feature?
description: We do not provide any ETAs.
---
# Is there an ETA for X feature?
![](https://imgs.xkcd.com/comics/estimating_time.png)
We maintain an up-to-date [roadmap](https://notesnook.com/roadmap) which lists everything we are working on and everything we plan on adding in the future. There is no certainty _when_ something might land, though. It can be days, months, or even years before a feature becomes generally available. Asking us for ETAs is annoying and distracts us from what really matters.
## Why we don't provide ETAs
In case you are still curious, a huge part of developing any software are **deadlines**. Giving any ETA means we want to be held accountable for when a feature might land. That is something we cannot afford because another huge part of developing any software are **delays**. As any engineer might tell you, "X will land in 1 month" almost always means "X will land in 4 months".
Users do not understand or tolerate delays, and developers do not like incessant pestering on why something didn't land on X date when we said it'll land on X date. To avoid all these headaches we simply do not give out any ETAs. Obviously, internally we do have timelines for each feature but disclosing these is unnecessary.
In short, it'll land when it'll land. No promises.

View File

@@ -0,0 +1,67 @@
---
title: What are merge conflicts?
description: Merge conflicts occur when two or more devices edit the same note and then attempt to sync these changes. Since each device has a different version of the note, Notesnook cannot automatically determine which version should take precedence, resulting in a merge conflict.
---
# What are merge conflicts?
Merge conflicts occur when two or more devices edit the same note and then attempt to sync these changes. Since each device has a different version of the note, Notesnook cannot automatically determine which version should take precedence, resulting in a merge conflict.
### Example:
Lets say youre using Notesnook on both your laptop and smartphone. You edit a note on your laptop making a lot of changes. Later, while commuting, you remember something important and edit the same note on your smartphone. When both devices eventually reconnect to the internet and sync, Notesnook detects that there are two different versions of the same note and triggers a merge conflict.
## Why do merge conflicts happen?
Merge conflicts happen because Notesnook cannot safely figure out which version of the name you want to keep. Unlike some apps that prioritize the most recent changes or attempt to merge content automatically (which can result in loss of important data or unwanted changes), Notesnook ensures you have full control over which version of a note you want to keep.
> info Both edits must be at least a minute apart
>
> The changes on both devices must be at least a minute apart for a merge conflict to occur. For example, if you are editing on both devices simultaneously (and both devices have a working sync), a merge conflict will NOT occur.
### Why doesn't Notesnook automatically resolve merge conflicts?
1. Automatic conflict resolution can lead to unintended data loss. For example, if both versions of a note contain unique but crucial information, merging them automatically might result in losing an important part of the information.
2. By allowing you to manually resolve conflicts, you can review each version of the note and decide which one is correct or if you want to keep both (i.e. both versions contain important information).
## Where do I find the conflicted notes?
Conflicted notes appear at the very top of your notes list.
1. Navigate to Notes
2. If you have any conflicts, you'll see them under the **Conflicted** group
## How to resolve merge conflicts
### [Desktop/Web](#/tab/web)
To resolve a merge conflict on your desktop or web app, follow these steps:
1. Locate the conflicted note at the top of your notes list.
2. Click on the note to open the conflict resolution screen.
3. On the conflict resolution screen, youll see two versions of your note side by side:
1. **Current Note** is the version from the device you are using.
2. **Incoming Note** is the version coming from the other device.
![](/static/merge-conflicts-resolution-screen.png)
3. The red and green highlights on the left side show the changes you made. Red indicates deletions and green indicates additions.
4. Review both versions and decide which one you want to keep.
5. Click the **Keep** button on the version you want to retain.
6. Click the **Discard** button on the version you dont want to keep, or press **Save a Copy** if you want to keep both versions.
![](/static/merge-conflicts-resolution-screen-2.png)
### [Mobile](#/tab/mobile)
To resolve a merge conflict on your mobile device, follow these steps:
1. Locate the conflicted note at the top of your notes list.
2. Tap on the note to open the conflict resolution screen.
3. On the conflict resolution screen, youll see two versions of your note, one above the other:
1. **This Device** is the version from the device you are using.
2. **Incoming** is the version coming from the other device.
<p><img src="/static/merge-conflicts-resolution-screen-mobile.png" alt="drawing" height="414"/></p>
4. Review both versions and decide which one you want to keep.
5. Press the **Keep** button on the version you want to retain.
6. Press the **Discard** button on the version you dont want to keep, or press **Save a Copy** if you want to keep both versions.
<p><img src="/static/merge-conflicts-resolution-screen-mobile-2.png" alt="drawing" height="414"/></p>
---

View File

@@ -1,63 +0,0 @@
---
title: Merge Conflicts
description: Merge conflicts occur when there are conflicting note edits on different devices for the same note.
---
# Merge Conflicts
## Why Merge Conflicts occur?
Merge conflicts occur when there are conflicting note edits on different devices for the same note.
## How Merge Conflicts occur?
Lets suppose that you have two devices running Notesnook:
1. A desktop
2. A mobile device
Suppose that one of your devices is offline. Now if you made edits to one of your (same)notes on both your devices and **synched changes** a merge conflict will occur.
> info
>
> In order for a merge conflict to occur the changes on the (same)note on both devices should occur in more than a minute
## Where do Merge conflicts show
The conflicted notes appear at the very top of the notes list. Just navigate to the Notes page and you will see them right away (If there are any).
## How to Resolve Merge Conflicts
# [Desktop/Web](#/tab/web)
Follow these steps to resolve a Merge Conflict:
1. Go to the conflicted note. It appears at the top of your note list.
2. Open the note. This will take you to a conflict resolution screen.
3. On the conflict resolution screen two versions of your note will appear side by side. One will be from the device you are using (Current Note) and one will be from the server(Incomming Note).
![](https://github.com/user-attachments/assets/7790bcd3-e87f-4a5e-a8e6-3fba1b3f3ab3)
4. Go through both versions and choose which one you want to keep.
5. Press the Keep button on the note you want to keep.
6. Press Discard button on the note you don't want to keep (you can also press the Save a Copy button if you want to keep it too).
![](https://github.com/user-attachments/assets/58558f0e-6bf1-486d-a183-702dba54dcaf)
# [Mobile](#/tab/mobile)
Follow these steps to resolve a Merge Conflict:
1. Go to the conflicted note. It appears at the top of your note list.
2. Open the note. This will take you to a conflict resolution screen.
3. On the Coflict Resolution Screen 2 versions of your note will appear above and below. One will be from the device you are using (Current Note) and one will be from the server(Incomming Note).
<img src="https://github.com/user-attachments/assets/616381b6-17dc-4d2b-98a7-e7f2629f1925" alt="drawing" width="414" style="text-align:center"/>
4. Go through both versions and choose which one you want to keep.
5. Press the Keep button on the note you want to keep.
6. And Discard button on the note you don't want to keep (you can also press the Save a Copy button if you want to keep it too).
<img src="https://github.com/user-attachments/assets/699454f9-7840-4955-9c5f-1efd8c7963ea" alt="drawing" width="414"/>
---

View File

@@ -79,4 +79,7 @@ navigation:
- path: custom-themes/create-a-theme-with-theme-builder.md
- path: custom-themes/install-a-theme-from-file.md
- path: custom-themes/publish-a-theme.md
- path: merge-conflicts.md
- path: faqs
children:
- path: faqs/what-are-merge-conflicts.md
- path: faqs/is-there-an-eta.md

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/web-clipper",
"version": "0.3.3",
"version": "0.3.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/web-clipper",
"version": "0.3.3",
"version": "0.3.4",
"license": "GPL-3.0-or-later",
"dependencies": {
"@emotion/react": "11.11.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/web-clipper",
"version": "0.3.3",
"version": "0.3.4",
"private": true,
"main": "./dist/index.js",
"dependencies": {

View File

@@ -44,17 +44,15 @@ export interface Gateway {
connect(): ClientMetadata;
}
type SelectedTopicReference = ItemReference & {
type: "topic";
parentId: string;
};
type SelectedNotebookReference = ItemReference & {
type: "notebook";
};
type SelectedTagReference = ItemReference & {
type: "tag";
};
export type SelectedReference =
| SelectedTopicReference
| SelectedTagReference
| SelectedNotebookReference;
export type Clip = {
@@ -66,7 +64,6 @@ export type Clip = {
width?: number;
height?: number;
pageTitle?: string;
tags?: string[];
note?: ItemReference;
refs?: SelectedReference[];
};

View File

@@ -19,11 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useState } from "react";
import { Flex } from "@theme-ui/components";
import { FilteredList } from "../filtered-list";
import {
NotebookReference,
ItemReference,
SelectedReference
} from "../../common/bridge";
import { NotebookReference, SelectedReference } from "../../common/bridge";
import { Icons } from "../icons";
import { useAppStore } from "../../stores/app-store";
import { Picker } from "../picker";
@@ -66,7 +62,7 @@ export const NotebookPicker = (props: NotebookPickerProps) => {
<InlineTag
key={item.id}
title={item.title}
icon={item.type === "topic" ? Icons.topic : Icons.notebook}
icon={Icons.notebook}
onClick={() =>
setSelectedItems((items) => {
const copy = items.slice();
@@ -105,14 +101,6 @@ export const NotebookPicker = (props: NotebookPickerProps) => {
renderItem={(item) => (
<Notebook
notebook={item}
isTopicSelected={(topic) =>
!!selectedItems.find(
(n) =>
n.id === topic.id &&
n.type === "topic" &&
n.parentId === item.id
)
}
isSelected={
!!selectedItems.find(
(n) => n.id === item.id && n.type === "notebook"
@@ -144,10 +132,9 @@ type NotebookProps = {
notebook: NotebookReference;
isSelected: boolean;
onSelected: (notebook: SelectedReference) => void;
isTopicSelected: (topic: ItemReference) => boolean;
};
function Notebook(props: NotebookProps) {
const { notebook, isSelected, onSelected, isTopicSelected } = props;
const { notebook, isSelected, onSelected } = props;
return (
<Flex

View File

@@ -24,25 +24,22 @@ import { useAppStore } from "../../stores/app-store";
import { Picker } from "../picker";
import { InlineTag } from "../inline-tag";
import { CheckListItem } from "../check-list-item";
import { SelectedReference } from "../../common/bridge";
type TagPickerProps = {
selectedTags: string[];
onSelected: (tags: string[]) => void;
selectedTags: SelectedReference[];
onSelected: (tags: SelectedReference[]) => void;
};
export const TagPicker = (props: TagPickerProps) => {
const { onSelected } = props;
const { selectedTags, onSelected } = props;
const [modalVisible, setModalVisible] = useState(false);
const [selectedTags, setSelectedTags] = useState<string[]>(
props.selectedTags || []
);
const close = () => {
setModalVisible(false);
};
const open = () => {
setSelectedTags(props.selectedTags || []);
setModalVisible(true);
};
@@ -57,20 +54,20 @@ export const TagPicker = (props: TagPickerProps) => {
gap: 1
}}
>
{props.selectedTags.length
? props.selectedTags.map((tag) => (
{selectedTags.length
? selectedTags.map((tag) => (
<InlineTag
key={tag}
key={tag.id}
icon={Icons.tag}
title={tag}
title={tag.title}
onClick={() => {
setSelectedTags((items) => {
const copy = items.slice();
const index = copy.indexOf(tag);
if (index > -1) copy.splice(index, 1);
onSelected(copy);
return copy;
});
const copy = selectedTags.slice();
const index = copy.findIndex(
(c) => c.type === "tag" && c.id === tag.id
);
if (index <= -1) return;
copy.splice(index, 1);
onSelected(copy);
}}
/>
))
@@ -102,18 +99,19 @@ export const TagPicker = (props: TagPickerProps) => {
<CheckListItem
title={`#${tag.title}`}
onSelected={() => {
setSelectedTags((items) => {
const copy = items.slice();
const index = copy.indexOf(tag.title);
if (index > -1) {
copy.splice(index, 1);
} else {
copy.push(tag.title);
}
return copy;
});
const copy = selectedTags.slice();
const index = copy.findIndex(
(c) => c.type === "tag" && c.id === tag.id
);
if (index <= -1) copy.push({ ...tag, type: "tag" });
else copy.splice(index, 1);
onSelected(copy);
}}
isSelected={selectedTags.indexOf(tag.title) > -1}
isSelected={
selectedTags.findIndex(
(s) => s.type === "tag" && s.id === tag.id
) > -1
}
/>
)}
/>

View File

@@ -110,7 +110,6 @@ export function Main() {
const [isClipping, setIsClipping] = useState(false);
const [note, setNote] = usePersistentState<ItemReference>("note");
const [refs, setRefs] = usePersistentState<SelectedReference[]>("refs", []);
const [tags, setTags] = usePersistentState<string[]>("tags", []);
const [clipData, setClipData] = useState<ClipData>();
const pageTitle = useRef<string>();
@@ -142,7 +141,12 @@ export function Main() {
try {
setIsClipping(true);
setClipData(
await clip(clipArea, clipMode, { ...DEFAULT_SETTINGS, ...settings })
await clip(clipArea, clipMode, {
...DEFAULT_SETTINGS,
...settings,
images: isPremium,
inlineImages: isPremium
})
);
} catch (e) {
console.error(e);
@@ -369,7 +373,7 @@ export function Main() {
Organization
</Text>
{refs?.length || tags?.length ? null : (
{refs?.length ? null : (
<NotePicker
selectedNote={note}
onSelected={(note) => setNote(note)}
@@ -377,19 +381,19 @@ export function Main() {
)}
{note ? null : (
<>
{refs?.length || tags?.length ? null : (
{refs?.length ? null : (
<Text variant="subBody" sx={{ my: 1, textAlign: "center" }}>
or
</Text>
)}
<NotebookPicker
selectedItems={refs || []}
selectedItems={refs?.filter((r) => r.type === "notebook") || []}
onSelected={(items) => setRefs(items)}
/>
<Box sx={{ mt: 1 }} />
<TagPicker
selectedTags={tags || []}
onSelected={(tags) => setTags(tags)}
selectedTags={refs?.filter((r) => r.type === "tag") || []}
onSelected={(tags) => setRefs(tags)}
/>
</>
)}
@@ -410,7 +414,6 @@ export function Main() {
title,
area: clipArea,
mode: clipMode,
tags,
note,
refs,
pageTitle: pageTitle.current,

View File

@@ -0,0 +1,3 @@
- Bug fixes and small improvements
Thank you for using Notesnook!

View File

@@ -0,0 +1,6 @@
- Fix crash when launching Notesnook from Notification tiles
- Fix app crashing on background on boot
- Fix self-hosted server urls not working
- Bug fixes and small improvements
Thank you for using Notesnook!

View File

@@ -38,7 +38,7 @@ const BLACKLIST = [CLASSES.nodeSelected, CLASSES.nodeSelectionContainer];
const inlineOptions: InlineOptions = {
fonts: false,
images: true,
images: false,
stylesheets: true
};
@@ -198,7 +198,11 @@ function enterNodeSelectionMode(doc: Document, config?: Config) {
const inlined = await getInlinedNode(node as HTMLElement, {
raster: false,
fetchOptions: resolveFetchOptions(config),
inlineOptions
inlineOptions: {
...inlineOptions,
images: config?.images,
inlineImages: config?.inlineImages
}
});
if (!inlined) continue;
div.appendChild(inlined);

View File

@@ -20,6 +20,7 @@ import { constructUrl, FetchOptions } from "./fetch";
import { compare, calculate, SpecificityArray } from "specificity";
import { tokenize } from "./css-tokenizer";
import { stringify, parse, SelectorType } from "css-what";
import { safeQuerySelectorAll } from "./utils";
const SHORTHANDS = [
"animation",
@@ -186,7 +187,8 @@ function walkRules(
for (const selector of selectors) {
if (!selector || !selector.selector.trim()) continue;
const elements = document.querySelectorAll(
const elements = safeQuerySelectorAll(
document,
selector.selector
) as NodeListOf<StyleableElement>;
@@ -210,7 +212,8 @@ function walkRules(
}
}
const elements = document.querySelectorAll(
const elements = safeQuerySelectorAll(
document,
rule.selectorText
) as NodeListOf<StyleableElement>;

View File

@@ -165,6 +165,14 @@ function getRootStylesheet() {
return null;
}
function safeQuerySelectorAll(root: Node, selector: string) {
try {
return (root as HTMLElement).querySelectorAll(selector);
} catch (e) {
return new NodeList();
}
}
export {
injectCss,
escape,
@@ -179,5 +187,6 @@ export {
asArray,
escapeXhtml,
width,
height
height,
safeQuerySelectorAll
};

View File

@@ -35,7 +35,8 @@
"@microsoft/signalr": "^8.0.0",
"@notesnook/logger": "file:../logger",
"@readme/data-urls": "^3.0.0",
"@streetwriters/showdown": "^3.0.7-alpha",
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.8-alpha",
"async-mutex": "^0.3.2",
"dayjs": "1.11.9",
"dom-serializer": "^2.0.0",
@@ -46,7 +47,6 @@
"html-to-text": "^9.0.5",
"htmlparser2": "^8.0.1",
"katex": "0.16.2",
"kysely": "^0.26.3",
"linkedom": "^0.14.17",
"liqe": "^1.13.0",
"mime-db": "1.52.0",
@@ -1828,7 +1828,8 @@
"@notesnook/crypto": "file:../crypto",
"@notesnook/logger": "file:../logger",
"@readme/data-urls": "^3.0.0",
"@streetwriters/showdown": "^3.0.7-alpha",
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.8-alpha",
"@types/better-sqlite3": "^7.6.5",
"@types/event-source-polyfill": "^1.0.1",
"@types/html-to-text": "^9.0.0",
@@ -1858,7 +1859,6 @@
"isomorphic-fetch": "^3.0.0",
"jsdom": "^22.1.0",
"katex": "0.16.2",
"kysely": "^0.26.3",
"linkedom": "^0.14.17",
"liqe": "^1.13.0",
"mime-db": "1.52.0",

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