Compare commits

...
Author SHA1 Message Date
StandardNotes CI f5b69691c0 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-26 12:13:01 +00:00
Antonella Sgarlatta 54af28aa04 chore: Add serverPassword param to endpoints (#2919) [skip e2e]
* chore: send server password param to delete account endpoint

* chore: send server password param to disable mfa endpoint

* chore: modify tests

* chore: force challenge prompt for mfa disable

* chore: fix eslint errors

* chore: add server passsword to get recovery codes

* chore: fix tests

* chore: pass server password as header
2025-08-26 09:04:03 -03:00
StandardNotes CI cf4d2196de chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-25 11:33:29 +00:00
Antonella Sgarlatta abf14d1e50 chore: trigger release [skip e2e] 2025-08-25 08:24:22 -03:00
Antonella Sgarlatta 86c00056bc chore: trigger release [skip e2e] 2025-08-25 07:59:48 -03:00
Antonella Sgarlatta f77a6a4480 chore: trigger release
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
2025-08-21 15:15:51 -03:00
StandardNotes CI 98038da99f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-21 14:53:47 +00:00
Antonella Sgarlatta b9d7f36884 chore: trigger release [skip e2e] 2025-08-21 11:44:33 -03:00
Antonella Sgarlatta 19831e834e chore: use next storage implementation for asyncstorage (#2931)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
* chore: use next storage implementation for asyncstorage

* chore: trigger release
2025-08-20 14:52:30 -03:00
StandardNotes CI 7e50b864ef chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-11 17:47:42 +00:00
Antonella Sgarlatta 687668c8e2 chore: trigger release [skip e2e] 2025-08-11 14:38:25 -03:00
Antonella Sgarlatta d135e09bda fix: Fixes Share note option not working on Android for note titles with special characters (#2928) 2025-08-11 14:24:28 -03:00
Antonella Sgarlatta f284111a0c chore: remove folders migration prompt (#2927)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
* chore: remove folders migration prompt

* chore: remove unused imports
2025-08-08 10:13:37 -03:00
StandardNotes CI be109a0f6b chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-05 14:27:15 +00:00
Antonella Sgarlatta c08d9034e1 chore: trigger release [skip e2e] 2025-08-05 11:17:58 -03:00
Antonella Sgarlatta 010864881d fix: Fixes Back and Navigation buttons not working on mobile view when panels explicitly collapsed (#2926)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
2025-08-05 10:31:48 -03:00
Antonella Sgarlatta 2b41c8337b fix: Fixes portions of window not being draggable on desktop (#2925) 2025-08-05 10:31:25 -03:00
Antonella Sgarlatta 45bcc0e0b1 fix: Fixes issue where plaintext backups would use invalid special characters for filenames (#2924) 2025-08-05 10:31:15 -03:00
StandardNotes CI d928477d82 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-08-04 13:53:41 +00:00
Antonella Sgarlatta b86aebb7ab chore: trigger release [skip e2e] 2025-08-04 10:36:32 -03:00
Antonella Sgarlatta 3cce44f5ab Merge pull request #2923 from standardnotes/fix/prevent-quick-type-suggestions
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
fix: Prevents quick type suggestions on iOS for password input
2025-08-01 11:09:06 -03:00
Antonella Sgarlatta ff80775cd6 fix: Prevents quick type suggestions on iOS for password input 2025-07-31 14:24:27 -03:00
StandardNotes CI c75f655ffe chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-07-29 16:00:49 +00:00
Antonella Sgarlatta 87cf17d02f Merge pull request #2921 from standardnotes/fix/disable-quick-type-suggestions-password-field
fix: disable quick type suggestions for password field
2025-07-29 12:31:28 -03:00
Antonella Sgarlatta 0d17961570 fix: Fixed font size not updating on plain editor when changing it from Preferences (#2920) 2025-07-29 12:30:29 -03:00
Antonella Sgarlatta 63d84725d2 fix: Fixes extra bottom padding in account modal 2025-07-28 00:33:22 -03:00
Antonella Sgarlatta 9583d0db44 fix: Fixes quick type suggestions showing up in iOS for password field 2025-07-28 00:32:51 -03:00
StandardNotes CI fa4182ba9f chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-07-23 00:23:53 +00:00
Antonella Sgarlatta 259017bd39 chore: revert some release workflow steps 2025-07-22 20:53:51 -03:00
StandardNotes CI f1f9070dcc chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2025-07-22 22:30:34 +00:00
Antonella Sgarlatta 6e6b5a017b chore: revert some release workflow steps
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
2025-07-22 19:01:40 -03:00
StandardNotes CI e72648d8a0 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
2025-07-22 21:03:37 +00:00
Antonella Sgarlatta fef887ec0d chore: readd workflow steps 2025-07-22 16:48:38 -03:00
StandardNotes CI 62713cc49d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
2025-07-22 19:31:14 +00:00
Antonella Sgarlatta 8016cb39e9 chore: Improve release workflows (#2916) 2025-07-22 16:02:50 -03:00
StandardNotes CI 9259cc8f32 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
2025-07-22 00:17:51 +00:00
Antonella Sgarlatta 43d31d8bb4 fix: Fixed issues with embedded linked items in Super editor (#2918)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
* Fixed items being embedded twice when linking them in a Super note
* Fixed Remove button not working for embedded linked items in Super editor
2025-07-21 10:49:02 -03:00
Aman Harwara 092dc7957f chore: remove options to add new embeds and render existing twitter embeds as links (#2917) 2025-07-21 10:47:53 -03:00
StandardNotes CI 77f8bf6368 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2025-07-19 19:19:28 +00:00
Antonella Sgarlatta 1935c98cf0 chore: trigger release [skip e2e] 2025-07-19 16:10:10 -03:00
Antonella Sgarlatta c52030a525 fix: Remove extra bottom padding on Android (#2915)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
2025-07-18 11:16:30 -03:00
StandardNotes CI 74923a1f6b chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2025-07-15 19:50:22 +00:00
Antonella Sgarlatta d02e5cab74 fix: Prevent text from hiding behind navbar in Android (#2914) 2025-07-15 16:21:08 -03:00
Antonella Sgarlatta 2459e06b19 fix: Prevent setting negative item created_at_timestamp values (#2913)
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
* fix: Prevent setting negative item created at timestamps
* chore: add unit tests for PurePayload
2025-07-09 11:26:51 -03:00
StandardNotes CI d2d10eb747 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2025-07-04 09:32:58 +00:00
Antonella Sgarlatta 117781bb36 fix: Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift (#2912) 2025-07-04 14:34:55 +05:30
StandardNotes CI 07f45245a3 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2025-07-01 19:47:40 +00:00
Antonella Sgarlatta da22238ced chore: update react-native-safe-area-context (#2911) 2025-07-02 00:49:18 +05:30
StandardNotes CI 44bfcb2d1b chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2025-06-26 03:33:36 +00:00
Antonella Sgarlatta 555453617d chore: fix simplenote converter test (#2910) 2025-06-26 00:05:26 -03:00
Antonella Sgarlatta f9f069f31f Merge pull request #2909 from standardnotes/fix/fix-simplenote-converter
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
fix: fix simplenote converter
2025-06-25 16:55:20 -03:00
Antonella Sgarlatta f776cb30d4 fix: fix simplenote converter 2025-06-24 23:15:22 -03:00
StandardNotes CI c2bdff0794 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2025-06-24 14:05:47 +00:00
Antonella Sgarlatta becf5751b2 Merge pull request #2908 from standardnotes/chore/update-code-editor-version
chore: update code editor version
2025-06-24 10:36:06 -03:00
Antonella Sgarlatta e06d1fcd4f chore: update code editor version 2025-06-24 10:35:16 -03:00
StandardNotes CI 44fba053b1 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected].0
2025-06-24 07:57:49 +00:00
Aman Harwara 52b052fe84 chore: trigger release (skip e2e) 2025-06-24 13:17:48 +05:30
Aman Harwara caa8eff216 feat: Tag search will now only show the direct tag results instead of also showing the parent and siblings (#2906) 2025-06-24 12:32:27 +05:30
Antonella Sgarlatta c050a2cd33 fix: Fixed issue with UI sometimes getting shifted up on iOS 2025-06-24 12:23:36 +05:30
StandardNotes CI 5f61500ee0 chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2025-06-22 19:36:49 +00:00
Aman Harwara 782af6ecdc chore: fix menus not having correct max height on mobile web browsers 2025-06-23 00:38:05 +05:30
StandardNotes CI c493b2c2ea chore(release): publish
CodeQL / Analyze (javascript) (push) Has been cancelled
Sync Repo / git-sync (push) Has been cancelled
Publish Packages / Build & Test (push) Has been cancelled
Publish Packages / Build Docker Image (push) Has been cancelled
Publish Packages / E2E Base Test Suite (push) Has been cancelled
Publish Packages / E2E Vaults Test Suite (push) Has been cancelled
Publish Packages / Build and publish Docker Image for Web App (push) Has been cancelled
Publish Packages / Publish to NPM (push) Has been cancelled
Publish Packages / Publish to Docker Hub (push) Has been cancelled
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2025-06-19 20:43:38 +00:00
Antonella Sgarlatta 9c1bb35355 fix: Fixed issue where Android app would crash on screen rotation (#2905) 2025-06-20 01:43:53 +05:30
106 changed files with 1750 additions and 786 deletions
+15 -8
View File
@@ -88,11 +88,18 @@ jobs:
- name: Compile for AppImage
run: yarn run webpack --config desktop.webpack.prod.js
- name: AppImage
run: yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
run: |
yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
- name: AppImageX64
run: yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
run: |
yarn run electron-builder --linux --x64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
- name: AppImageArm64
run: yarn run electron-builder --linux --arm64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
run: |
yarn workspace @standardnotes/desktop rebuild:home-server --arch arm64
yarn run electron-builder --linux --arm64 -c.linux.target=AppImage --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
env:
npm_config_target_arch: 'arm64'
- name: Upload
uses: actions/[email protected]
@@ -138,6 +145,7 @@ jobs:
yarn run electron-builder --linux --x64 -c.linux.target=dir --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
- name: DirArm64
run: |
yarn workspace @standardnotes/desktop rebuild:home-server --arch arm64
yarn run webpack --config desktop.webpack.prod.js
yarn run electron-builder --linux --arm64 -c.linux.target=dir --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
env:
@@ -181,6 +189,7 @@ jobs:
npm_config_target_arch: 'arm64'
USE_SYSTEM_FPM: 'true'
run: |
yarn workspace @standardnotes/desktop rebuild:home-server --arch arm64
yarn run webpack --config desktop.webpack.prod.js --env deb
yarn run electron-builder --linux --arm64 -c.linux.target=deb --publish=never --c.extraMetadata.version=${{ env.APP_VERSION }}
@@ -317,7 +326,7 @@ jobs:
- name: Certificates Sync
run: |
smctl windows certsync
smctl windows certsync
shell: cmd
- name: Build & Sign With Electron Builder
@@ -373,8 +382,8 @@ jobs:
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.CI_PAT_TOKEN }}
tag_name: "@standardnotes/desktop@${{ env.APP_VERSION }}"
name: "Desktop ${{ env.APP_VERSION }}"
tag_name: '@standardnotes/desktop@${{ env.APP_VERSION }}'
name: 'Desktop ${{ env.APP_VERSION }}'
body: ${{ steps.release-notes.outputs.result }}
prerelease: true
draft: false
@@ -395,5 +404,3 @@ jobs:
token: ${{ secrets.CI_PAT_TOKEN }}
repository: ${{ secrets.RELEASES_EVENT_RECEIVING_REPO }}
event-type: releases-updated-event
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@standardnotes/app-monorepo",
"version": "0.0.1",
"private": true,
"author": "Standard Notes.",
"author": "Standard Notes",
"repository": {
"type": "git",
"url": "git://github.com/standardnotes/app"
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.26.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/api
## [1.26.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/api
## [1.26.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/api
## [1.26.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/api
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.91",
"version": "1.26.94",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -22,7 +22,9 @@ export class AuthApiService implements AuthApiServiceInterface {
this.operationsInProgress = new Map()
}
async generateRecoveryCodes(): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
async generateRecoveryCodes(dto: {
serverPassword: string
}): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
if (this.operationsInProgress.get(AuthApiOperations.GenerateRecoveryCodes)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
@@ -30,7 +32,9 @@ export class AuthApiService implements AuthApiServiceInterface {
this.operationsInProgress.set(AuthApiOperations.GenerateRecoveryCodes, true)
try {
const response = await this.authServer.generateRecoveryCodes()
const response = await this.authServer.generateRecoveryCodes({
headers: [{ key: 'x-server-password', value: dto.serverPassword }],
})
return response
} catch (error) {
@@ -6,7 +6,7 @@ import {
} from '../../Response'
export interface AuthApiServiceInterface {
generateRecoveryCodes(): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>>
generateRecoveryCodes(dto: { serverPassword: string }): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>>
recoveryKeyParams(dto: {
username: string
codeChallenge: string
@@ -27,13 +27,19 @@ export class UserApiService implements UserApiServiceInterface {
this.operationsInProgress = new Map()
}
async deleteAccount(userUuid: string): Promise<HttpResponse<UserDeletionResponseBody>> {
async deleteAccount(dto: {
userUuid: string
serverPassword: string
}): Promise<HttpResponse<UserDeletionResponseBody>> {
this.lockOperation(UserApiOperations.DeletingAccount)
try {
const response = await this.userServer.deleteAccount({
userUuid: userUuid,
})
const response = await this.userServer.deleteAccount(
{
userUuid: dto.userUuid,
},
{ headers: [{ key: 'x-server-password', value: dto.serverPassword }] },
)
this.unlockOperation(UserApiOperations.DeletingAccount)
@@ -22,5 +22,8 @@ export interface UserApiServiceInterface {
requestType: UserRequestType
}): Promise<HttpResponse<UserRequestResponseBody>>
deleteAccount(userUuid: string): Promise<HttpResponse<UserDeletionResponseBody>>
deleteAccount(dto: {
userUuid: string
serverPassword: string | undefined
}): Promise<HttpResponse<UserDeletionResponseBody>>
}
@@ -91,6 +91,7 @@ export class HttpService implements HttpServiceInterface {
params,
verb: HttpVerb.Get,
authentication: options?.authentication ?? this.getSessionAccessToken(),
customHeaders: options?.headers,
})
}
@@ -123,6 +124,7 @@ export class HttpService implements HttpServiceInterface {
params,
verb: HttpVerb.Put,
authentication: options?.authentication ?? this.getSessionAccessToken(),
customHeaders: options?.headers,
})
}
@@ -141,6 +143,7 @@ export class HttpService implements HttpServiceInterface {
params,
verb: HttpVerb.Delete,
authentication: options?.authentication ?? this.getSessionAccessToken(),
customHeaders: options?.headers,
})
}
@@ -0,0 +1,3 @@
export interface GenerateRecoveryCodesRequestParams {
serverPassword: string
}
+1
View File
@@ -2,6 +2,7 @@ export * from './Authenticator/DeleteAuthenticatorRequestParams'
export * from './Authenticator/GenerateAuthenticatorAuthenticationOptionsRequestParams'
export * from './Authenticator/ListAuthenticatorsRequestParams'
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseRequestParams'
export * from './Recovery/GenerateRecoveryCodesRequestParams'
export * from './Recovery/RecoveryKeyParamsRequestParams'
export * from './Recovery/SignInWithRecoveryCodesRequestParams'
export * from './Revision/DeleteRevisionRequestParams'
@@ -8,12 +8,13 @@ import {
} from '../../Response'
import { AuthServerInterface } from './AuthServerInterface'
import { Paths } from './Paths'
import { HttpRequestOptions } from '../../Http/HttpRequestOptions'
export class AuthServer implements AuthServerInterface {
constructor(private httpService: HttpServiceInterface) {}
async generateRecoveryCodes(): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
return this.httpService.post(Paths.v1.generateRecoveryCodes)
async generateRecoveryCodes(options?: HttpRequestOptions): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
return this.httpService.post(Paths.v1.generateRecoveryCodes, undefined, options)
}
async recoveryKeyParams(
@@ -5,9 +5,10 @@ import {
RecoveryKeyParamsResponseBody,
SignInWithRecoveryCodesResponseBody,
} from '../../Response'
import { HttpRequestOptions } from '../../Http/HttpRequestOptions'
export interface AuthServerInterface {
generateRecoveryCodes(): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>>
generateRecoveryCodes(options?: HttpRequestOptions): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>>
recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise<HttpResponse<RecoveryKeyParamsResponseBody>>
signInWithRecoveryCodes(
params: SignInWithRecoveryCodesRequestParams,
@@ -8,12 +8,16 @@ import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrati
import { Paths } from './Paths'
import { UserServerInterface } from './UserServerInterface'
import { UserUpdateRequestParams } from '../../Request/User/UserUpdateRequestParams'
import { HttpRequestOptions } from '../../Http/HttpRequestOptions'
export class UserServer implements UserServerInterface {
constructor(private httpService: HttpServiceInterface) {}
async deleteAccount(params: UserDeletionRequestParams): Promise<HttpResponse<UserDeletionResponseBody>> {
return this.httpService.delete(Paths.v1.deleteAccount(params.userUuid), params)
async deleteAccount(
params: UserDeletionRequestParams,
options?: HttpRequestOptions,
): Promise<HttpResponse<UserDeletionResponseBody>> {
return this.httpService.delete(Paths.v1.deleteAccount(params.userUuid), params, options)
}
async register(params: UserRegistrationRequestParams): Promise<HttpResponse<UserRegistrationResponseBody>> {
@@ -5,9 +5,13 @@ import { UserDeletionResponseBody } from '../../Response/User/UserDeletionRespon
import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody'
import { UserUpdateResponse } from '../../Response/User/UserUpdateResponse'
import { UserUpdateRequestParams } from '../../Request/User/UserUpdateRequestParams'
import { HttpRequestOptions } from '../../Http/HttpRequestOptions'
export interface UserServerInterface {
register(params: UserRegistrationRequestParams): Promise<HttpResponse<UserRegistrationResponseBody>>
deleteAccount(params: UserDeletionRequestParams): Promise<HttpResponse<UserDeletionResponseBody>>
deleteAccount(
params: UserDeletionRequestParams,
options?: HttpRequestOptions,
): Promise<HttpResponse<UserDeletionResponseBody>>
update(params: UserUpdateRequestParams): Promise<HttpResponse<UserUpdateResponse>>
}
+80
View File
@@ -3,6 +3,86 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.544](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.543](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.542](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.541](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.540](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.539](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.538](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.537](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.536](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.535](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.534](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.533](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.532](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.531](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.530](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.529](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.528](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.527](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.526](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.525](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.524](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/clipper
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/clipper",
"description": "Web clipper browser extension for Standard Notes",
"version": "1.1.524",
"version": "1.1.544",
"private": true,
"scripts": {
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
+83
View File
@@ -3,6 +3,89 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.110.149](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.148](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.147](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.146](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)
### Bug Fixes
* Fixes issue where plaintext backups would use invalid special characters for filenames ([#2924](https://github.com/standardnotes/app/issues/2924)) ([45bcc0e](https://github.com/standardnotes/app/commit/45bcc0e0b1541558ecf410e9a92bc2db192cfe93))
* Fixes portions of window not being draggable on desktop ([#2925](https://github.com/standardnotes/app/issues/2925)) ([2b41c83](https://github.com/standardnotes/app/commit/2b41c8337b1408209dc4903cacbc701b73c590b0))
## [3.110.145](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.144](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.143](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.142](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.141](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.140](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.139](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.138](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.135](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.134](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.133](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.132](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.131](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.130](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/desktop
## [3.110.129](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/desktop
@@ -17,6 +17,7 @@ import { FileReadOperation } from './FileReadOperation'
import { Paths } from '../Types/Paths'
import { MessageToWebApp } from '../../Shared/IpcMessages'
import { FilesManagerInterface } from '../File/FilesManagerInterface'
import { sanitizeFileName } from '@standardnotes/utils'
const TextBackupFileExtension = '.txt'
@@ -316,7 +317,8 @@ export class FilesBackupManager implements FileBackupsDevice {
const relativePath = forTag ?? ''
const filenameWithSlashesEscaped = filename.replace(/\//g, '\u2215')
const fileAbsolutePath = path.join(absolutePath, relativePath, filenameWithSlashesEscaped)
const sanitizedFilename = sanitizeFileName(filenameWithSlashesEscaped)
const fileAbsolutePath = path.join(absolutePath, relativePath, sanitizedFilename)
await this.filesManager.writeFile(fileAbsolutePath, data)
const existingRecord = findMappingRecord(forTag)
@@ -70,12 +70,19 @@
/* https://github.com/electron/electron/issues/37789 */
.mac-desktop #navigation,
.mac-desktop #items-column,
.mac-desktop #editor-column,
.mac-desktop #items-title-bar,
.mac-desktop #editor-title-bar,
.mac-desktop [data-preferences-header] {
-webkit-app-region: drag;
}
.mac-desktop #items-column > *:not(#items-title-bar),
.mac-desktop #editor-column > *:not(#editor-title-bar) {
-webkit-app-region: no-drag;
}
.mac-desktop.focus-mode #editor-title-bar {
-webkit-app-region: no-drag;
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.110.129",
"version": "3.110.149",
"license": "AGPL-3.0",
"author": "Standard Notes.",
"private": true,
@@ -55,7 +55,7 @@
"@babel/core": "*",
"@babel/preset-env": "*",
"@electron/notarize": "^3.0.0",
"@electron/rebuild": "3.6.0",
"@electron/rebuild": "3.6.1",
"@types/fs-extra": "^11.0.1",
"@types/lodash": "^4.14.189",
"@types/mime-types": "^2.1.1",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.111](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.110](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.109](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/encryption
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.21.109",
"version": "1.21.111",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.28.131](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.130](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.129](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/filepicker
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.28.129",
"version": "1.28.131",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.20.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/files
## [1.20.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/files
## [1.20.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/files
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.20.12",
"version": "1.20.14",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+92
View File
@@ -3,6 +3,98 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.58.207](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.206](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.205](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-21)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.204](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.203](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.202](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.201](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.200](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.199](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.198](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.197](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.196](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.195](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)
### Bug Fixes
* Remove extra bottom padding on Android ([#2915](https://github.com/standardnotes/app/issues/2915)) ([c52030a](https://github.com/standardnotes/app/commit/c52030a525eaf3c8488c19beb84229911bcda8fc))
## [3.58.194](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.193](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)
### Bug Fixes
* Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift ([#2912](https://github.com/standardnotes/app/issues/2912)) ([117781b](https://github.com/standardnotes/app/commit/117781bb3655a2bd6b9b0ca5a4d12f7bbefd164e))
## [3.58.192](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.191](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.190](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.189](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
### Bug Fixes
* Fixed issue with UI sometimes getting shifted up on iOS ([c050a2c](https://github.com/standardnotes/app/commit/c050a2cd339bb7a8fd482904216de1db2b8fe568))
## [3.58.188](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.58.187](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
### Bug Fixes
* Fixed issue where Android app would crash on screen rotation ([#2905](https://github.com/standardnotes/app/issues/2905)) ([9c1bb35](https://github.com/standardnotes/app/commit/9c1bb353550c0256b4e6dcbee1e087cc9ffdd628))
## [3.58.186](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/mobile
@@ -37,13 +37,6 @@ public class MainActivity extends ReactActivity {
DefaultNewArchitectureEntryPoint.getFabricEnabled());
}
// Fix for Dark theme subscriptions https://github.com/facebook/react-native/issues/28823#issuecomment-642032481
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactInstanceManager().onConfigurationChanged(this, newConfig);
}
/*
On back button press, background app instead of quitting it
https://github.com/facebook/react-native/issues/13775
+4 -2
View File
@@ -38,8 +38,10 @@ newArchEnabled=true
# If set to false, you will be using JSC instead.
hermesEnabled=true
# Set AsyncStorage limit
AsyncStorage_db_size_in_MB=50
# Use Next storage implementation for AsyncStorage
AsyncStorage_useNextStorage=true
AsyncStorage_kotlinVersion=2.0.21
AsyncStorage_next_kspVersion=2.0.21-1.0.28
# The URL of the server
host=https://app.standardnotes.com
+1 -1
View File
@@ -68,7 +68,7 @@ platform :ios do
run_precheck_before_submit: false,
submission_information: { add_id_info_uses_idfa: false },
release_notes: {
'default': 'Fixes and improvements.'
'en-US': 'Fixes and improvements.'
}
)
end
+6 -6
View File
@@ -1261,7 +1261,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context (5.4.0):
- react-native-safe-area-context (5.5.1):
- DoubleConversion
- glog
- hermes-engine
@@ -1274,8 +1274,8 @@ PODS:
- React-featureflags
- React-graphics
- React-ImageManager
- react-native-safe-area-context/common (= 5.4.0)
- react-native-safe-area-context/fabric (= 5.4.0)
- react-native-safe-area-context/common (= 5.5.1)
- react-native-safe-area-context/fabric (= 5.5.1)
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
@@ -1284,7 +1284,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context/common (5.4.0):
- react-native-safe-area-context/common (5.5.1):
- DoubleConversion
- glog
- hermes-engine
@@ -1305,7 +1305,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context/fabric (5.4.0):
- react-native-safe-area-context/fabric (5.5.1):
- DoubleConversion
- glog
- hermes-engine
@@ -2040,7 +2040,7 @@ SPEC CHECKSUMS:
React-microtasksnativemodule: b740ebae7fad70aa78bc24cc0dfc15ac9637b6eb
react-native-fingerprint-scanner: 562585260768cad51ae48e4b505d28c8731aecfa
react-native-mmkv: 24917f0685641ccfd37c9b7004b26c00551128be
react-native-safe-area-context: afcc2e2b3e78ae8ef90d81e658aacee34ebc27ea
react-native-safe-area-context: 143faa2b60b6cc3e06e966d5fa23af6b31326814
react-native-version-info: f0b04e16111c4016749235ff6d9a757039189141
react-native-webview: 5095dd03fc98a529e44a6bb81aed21062b5f879e
React-NativeModulesApple: af0571ac115d09c9a669ed45ce6a4ca960598a2d
+4 -4
View File
@@ -1,13 +1,13 @@
{
"name": "@standardnotes/mobile",
"version": "3.58.186",
"version": "3.58.207",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0",
"scripts": {
"android-dev": "react-native run-android --mode devDebug --appIdSuffix dev",
"android-prod-debug": "react-native run-android --variant prodDebug",
"android-prod-release": "yarn run android:bundle && react-native run-android --variant prodRelease",
"android-prod-debug": "react-native run-android --mode prodDebug",
"android-prod-release": "yarn run android:bundle && react-native run-android --mode prodRelease",
"android:bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/build/intermediates/res/merged/release/",
"build": "yarn bundle:web && yarn install:pods && yarn android:bundle",
"clear-cache": "watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-*",
@@ -76,7 +76,7 @@
},
"dependencies": {
"@notifee/react-native": "^9.1.8",
"react-native-safe-area-context": "^5.4.0",
"react-native-safe-area-context": "^5.5.1",
"react-native-store-review": "^0.4.3"
}
}
+12 -17
View File
@@ -43,6 +43,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
const _reviewService = useRef(new ReviewService(device))
const [showAndroidWebviewUpdatePrompt, setShowAndroidWebviewUpdatePrompt] = useState(false)
const [didLoadEnd, setDidLoadEnd] = useState(false)
const insets = useSafeAreaInsets()
@@ -136,7 +137,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
keyboardDidHideListener.remove()
keyboardWillChangeFrame.remove()
}
}, [webViewRef, stateService, device, androidBackHandlerService, colorSchemeService])
}, [webViewRef, stateService, device, androidBackHandlerService, colorSchemeService, insets.bottom])
useEffect(() => {
return notifee.onForegroundEvent(({ type, detail }) => {
@@ -354,30 +355,24 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
}
}, [])
const [didAppLaunch, setDidAppLaunch] = useState(false)
useEffect(() => {
return device.addApplicationEventReceiver((event) => {
if (event === ApplicationEvent.Launched) {
receivedSharedItemsHandler.current.setIsApplicationLaunched(true)
setDidAppLaunch(true)
}
})
}, [device])
useEffect(() => {
if (!didAppLaunch) {
return
}
webViewRef.current?.postMessage(
JSON.stringify({
reactNativeEvent: ReactNativeToWebEvent.UpdateSafeAreaInsets,
messageType: 'event',
messageData: insets,
}),
)
}, [didAppLaunch, insets])
const [didLoadEnd, setDidLoadEnd] = useState(false)
const injectJS = `
document.documentElement.style.setProperty('--safe-area-inset-top', '${insets.top}px');
document.documentElement.style.setProperty('--safe-area-inset-bottom', '${insets.bottom}px');
document.documentElement.style.setProperty('--safe-area-inset-left', '${insets.left}px');
document.documentElement.style.setProperty('--safe-area-inset-right', '${insets.right}px');
true;
`
if (Platform.OS === 'android') {
webViewRef.current?.injectJavaScript(injectJS)
}
if (showAndroidWebviewUpdatePrompt) {
return (
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.58.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
### Bug Fixes
* Prevent setting negative item created_at_timestamp values ([#2913](https://github.com/standardnotes/app/issues/2913)) ([2459e06](https://github.com/standardnotes/app/commit/2459e06b19f54a5a35b6dde11f361dc5c60ab7f5))
# [1.58.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
### Features
* Tag search will now only show the direct tag results instead of also showing the parent and siblings ([#2906](https://github.com/standardnotes/app/issues/2906)) ([caa8eff](https://github.com/standardnotes/app/commit/caa8eff216b2d7a47f849f85f1eb2248eea10c62))
## [1.57.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/models
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.57.1",
"version": "1.58.1",
"publishConfig": {
"access": "public"
},
@@ -0,0 +1,438 @@
import { deepFreeze, useBoolean } from '@standardnotes/utils'
import { PayloadSource } from '../Types/PayloadSource'
import { TransferPayload } from '../../TransferPayload/Interfaces/TransferPayload'
import { ItemContent, FillItemContent } from '../../Content/ItemContent'
import { PurePayload } from './PurePayload'
import { SyncResolvedParams, SyncResolvedPayload } from '../../../Runtime/Deltas/Utilities/SyncResolvedPayload'
import { PersistentSignatureData } from '../../../Runtime/Encryption/PersistentSignatureData'
import { ContentType } from '@standardnotes/domain-core'
// Mock the utils functions
jest.mock('@standardnotes/utils', () => ({
deepFreeze: jest.fn(),
useBoolean: jest.fn((value, defaultValue) => value !== undefined ? !!value : defaultValue),
}))
// Mock the content type encryption check
jest.mock('../../../Runtime/Encryption/ContentTypeUsesRootKeyEncryption', () => ({
ContentTypeUsesRootKeyEncryption: jest.fn((contentType: string) => {
const rootKeyTypes = [
ContentType.TYPES.RootKey,
ContentType.TYPES.ItemsKey,
ContentType.TYPES.EncryptedStorage,
ContentType.TYPES.TrustedContact,
ContentType.TYPES.KeySystemRootKey,
]
return rootKeyTypes.includes(contentType)
}),
}))
class TestPurePayload extends PurePayload<TransferPayload<ItemContent>, ItemContent> {
copy(override?: Partial<TransferPayload>, source?: PayloadSource): this {
const newPayload = {
...this.ejected(),
...override,
}
return new TestPurePayload(newPayload, source || this.source) as this
}
copyAsSyncResolved(override?: Partial<TransferPayload<ItemContent>> & SyncResolvedParams, source?: PayloadSource): SyncResolvedPayload {
const newPayload = {
...this.ejected(),
...override,
}
return new TestPurePayload(newPayload, source || this.source) as any
}
}
describe('PurePayload', () => {
const mockDeepFreeze = deepFreeze as jest.MockedFunction<typeof deepFreeze>
const mockUseBoolean = useBoolean as jest.MockedFunction<typeof useBoolean>
beforeEach(() => {
jest.clearAllMocks()
mockDeepFreeze.mockImplementation((obj) => obj)
mockUseBoolean.mockImplementation((value, defaultValue) => value !== undefined ? !!value : defaultValue)
})
const createValidRawPayload = (overrides: Partial<TransferPayload<ItemContent>> = {}): TransferPayload<ItemContent> => ({
uuid: '123e4567-e89b-12d3-a456-426614174000',
content_type: ContentType.TYPES.Note,
content: FillItemContent({}),
deleted: false,
updated_at: new Date('2023-01-01T12:00:00Z'),
created_at: new Date('2023-01-01T10:00:00Z'),
created_at_timestamp: 1672570800000,
updated_at_timestamp: 1672578000000,
...overrides,
})
describe('constructor', () => {
it('should throw error when uuid is null', () => {
const rawPayload = createValidRawPayload({ uuid: null as any })
expect(() => new TestPurePayload(rawPayload)).toThrow(
'Attempting to construct payload with null uuid'
)
})
it('should throw error when uuid is undefined', () => {
const rawPayload = createValidRawPayload({ uuid: undefined as any })
expect(() => new TestPurePayload(rawPayload)).toThrow(
'Attempting to construct payload with null uuid'
)
})
it('should throw error when content type uses root key encryption but has key_system_identifier', () => {
const rawPayload = createValidRawPayload({
content_type: ContentType.TYPES.RootKey,
key_system_identifier: 'some-key-system-id'
})
expect(() => new TestPurePayload(rawPayload)).toThrow(
'Rootkey-encrypted payload should not have a key system identifier'
)
})
it('should allow key_system_identifier for non-root-key content types', () => {
const rawPayload = createValidRawPayload({
content_type: ContentType.TYPES.Note,
key_system_identifier: 'some-key-system-id'
})
expect(() => new TestPurePayload(rawPayload)).not.toThrow()
})
it('should set all properties correctly from raw payload', () => {
const rawPayload = createValidRawPayload({
uuid: 'test-uuid',
content_type: ContentType.TYPES.Note,
content: FillItemContent({ references: [] }),
deleted: true,
dirty: true,
duplicate_of: 'original-uuid',
user_uuid: 'user-uuid',
key_system_identifier: 'key-system-id',
shared_vault_uuid: 'vault-uuid',
last_edited_by_uuid: 'editor-uuid',
dirtyIndex: 5,
globalDirtyIndexAtLastSync: 3,
lastSyncBegan: new Date('2023-01-01T11:00:00Z'),
lastSyncEnd: new Date('2023-01-01T11:30:00Z'),
})
const payload = new TestPurePayload(rawPayload, PayloadSource.LocalDatabaseLoaded)
expect(payload.uuid).toBe('test-uuid')
expect(payload.content_type).toBe(ContentType.TYPES.Note)
expect(payload.content).toEqual(rawPayload.content)
expect(payload.deleted).toBe(true)
expect(payload.dirty).toBe(true)
expect(payload.duplicate_of).toBe('original-uuid')
expect(payload.user_uuid).toBe('user-uuid')
expect(payload.key_system_identifier).toBe('key-system-id')
expect(payload.shared_vault_uuid).toBe('vault-uuid')
expect(payload.last_edited_by_uuid).toBe('editor-uuid')
expect(payload.dirtyIndex).toBe(5)
expect(payload.globalDirtyIndexAtLastSync).toBe(3)
expect(payload.source).toBe(PayloadSource.LocalDatabaseLoaded)
})
it('should use default PayloadSource.Constructor when source is not provided', () => {
const rawPayload = createValidRawPayload()
const payload = new TestPurePayload(rawPayload)
expect(payload.source).toBe(PayloadSource.Constructor)
})
it('should call useBoolean for deleted field', () => {
const rawPayload = createValidRawPayload({ deleted: true })
mockUseBoolean.mockReturnValue(true)
const payload = new TestPurePayload(rawPayload)
expect(mockUseBoolean).toHaveBeenCalledWith(true, false)
expect(payload.deleted).toBe(true)
})
it('should use false as default for deleted when undefined', () => {
const rawPayload = createValidRawPayload({ deleted: undefined })
mockUseBoolean.mockReturnValue(false)
const payload = new TestPurePayload(rawPayload)
expect(mockUseBoolean).toHaveBeenCalledWith(undefined, false)
expect(payload.deleted).toBe(false)
})
it('should handle optional properties as undefined when not provided', () => {
const rawPayload = createValidRawPayload()
const payload = new TestPurePayload(rawPayload)
expect(payload.user_uuid).toBeUndefined()
expect(payload.key_system_identifier).toBeUndefined()
expect(payload.shared_vault_uuid).toBeUndefined()
expect(payload.last_edited_by_uuid).toBeUndefined()
expect(payload.dirty).toBeUndefined()
expect(payload.duplicate_of).toBeUndefined()
expect(payload.dirtyIndex).toBeUndefined()
expect(payload.globalDirtyIndexAtLastSync).toBeUndefined()
})
it('should schedule deepFreeze to be called', (done) => {
const rawPayload = createValidRawPayload()
const payload = new TestPurePayload(rawPayload)
setTimeout(() => {
expect(mockDeepFreeze).toHaveBeenCalledWith(payload)
done()
}, 10)
})
})
describe('date handling', () => {
it('should handle valid dates correctly', () => {
const createdAt = new Date('2023-01-01T10:00:00Z')
const updatedAt = new Date('2023-01-01T12:00:00Z')
const rawPayload = createValidRawPayload({
created_at: createdAt,
updated_at: updatedAt,
created_at_timestamp: createdAt.getTime(),
updated_at_timestamp: updatedAt.getTime(),
})
const payload = new TestPurePayload(rawPayload)
expect(payload.created_at).toEqual(createdAt)
expect(payload.updated_at).toEqual(updatedAt)
expect(payload.created_at_timestamp).toBe(createdAt.getTime())
expect(payload.updated_at_timestamp).toBe(updatedAt.getTime())
})
it('should handle negative updated_at dates by resetting to epoch', () => {
const rawPayload = createValidRawPayload({
updated_at: new Date(-1000),
updated_at_timestamp: -1000,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.updated_at).toEqual(new Date(0))
expect(payload.updated_at_timestamp).toBe(0)
})
it('should handle negative created_at dates by using updated_at values', () => {
const updatedAt = new Date('2023-01-01T12:00:00Z')
const rawPayload = createValidRawPayload({
created_at: new Date(-1000),
created_at_timestamp: -1000,
updated_at: updatedAt,
updated_at_timestamp: updatedAt.getTime(),
})
const payload = new TestPurePayload(rawPayload)
expect(payload.created_at).toEqual(updatedAt)
expect(payload.created_at_timestamp).toBe(updatedAt.getTime())
})
it('should use current date for created_at when not provided', () => {
const rawPayload = createValidRawPayload({
created_at: undefined as any,
created_at_timestamp: undefined as any,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.created_at).toBeInstanceOf(Date)
expect(payload.created_at.getTime()).toBeGreaterThan(0)
})
it('should use epoch date for updated_at when not provided', () => {
const rawPayload = createValidRawPayload({
updated_at: undefined as any,
updated_at_timestamp: undefined as any,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.updated_at).toEqual(new Date(0))
expect(payload.updated_at_timestamp).toBe(0)
})
it('should handle sync dates correctly', () => {
const syncBegan = new Date('2023-01-01T11:00:00Z')
const syncEnd = new Date('2023-01-01T11:30:00Z')
const rawPayload = createValidRawPayload({
lastSyncBegan: syncBegan,
lastSyncEnd: syncEnd,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.lastSyncBegan).toEqual(syncBegan)
expect(payload.lastSyncEnd).toEqual(syncEnd)
})
it('should handle undefined sync dates', () => {
const rawPayload = createValidRawPayload({
lastSyncBegan: undefined,
lastSyncEnd: undefined,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.lastSyncBegan).toBeUndefined()
expect(payload.lastSyncEnd).toBeUndefined()
})
})
describe('ejected method', () => {
it('should return comprehensive TransferPayload', () => {
const rawPayload = createValidRawPayload({
uuid: 'test-uuid',
content_type: ContentType.TYPES.Note,
content: FillItemContent({ references: [] }),
deleted: true,
dirty: true,
duplicate_of: 'original-uuid',
user_uuid: 'user-uuid',
key_system_identifier: 'key-system-id',
shared_vault_uuid: 'vault-uuid',
last_edited_by_uuid: 'editor-uuid',
dirtyIndex: 5,
globalDirtyIndexAtLastSync: 3,
lastSyncBegan: new Date('2023-01-01T11:00:00Z'),
lastSyncEnd: new Date('2023-01-01T11:30:00Z'),
})
const payload = new TestPurePayload(rawPayload)
const ejected = payload.ejected()
expect(ejected.uuid).toBe('test-uuid')
expect(ejected.content_type).toBe(ContentType.TYPES.Note)
expect(ejected.content).toEqual(rawPayload.content)
expect(ejected.deleted).toBe(true)
expect(ejected.dirty).toBe(true)
expect(ejected.duplicate_of).toBe('original-uuid')
expect(ejected.user_uuid).toBe('user-uuid')
expect(ejected.key_system_identifier).toBe('key-system-id')
expect(ejected.shared_vault_uuid).toBe('vault-uuid')
expect(ejected.last_edited_by_uuid).toBe('editor-uuid')
expect(ejected.dirtyIndex).toBe(5)
expect(ejected.globalDirtyIndexAtLastSync).toBe(3)
expect(ejected.lastSyncBegan).toEqual(new Date('2023-01-01T11:00:00Z'))
expect(ejected.lastSyncEnd).toEqual(new Date('2023-01-01T11:30:00Z'))
})
it('should include undefined values in ejected payload', () => {
const rawPayload = createValidRawPayload()
const payload = new TestPurePayload(rawPayload)
const ejected = payload.ejected()
expect(ejected.user_uuid).toBeUndefined()
expect(ejected.key_system_identifier).toBeUndefined()
expect(ejected.shared_vault_uuid).toBeUndefined()
expect(ejected.last_edited_by_uuid).toBeUndefined()
expect(ejected.dirty).toBeUndefined()
expect(ejected.duplicate_of).toBeUndefined()
expect(ejected.dirtyIndex).toBeUndefined()
expect(ejected.globalDirtyIndexAtLastSync).toBeUndefined()
})
})
describe('getters', () => {
it('should return correct serverUpdatedAt', () => {
const updatedAt = new Date('2023-01-01T12:00:00Z')
const rawPayload = createValidRawPayload({ updated_at: updatedAt })
const payload = new TestPurePayload(rawPayload)
expect(payload.serverUpdatedAt).toEqual(updatedAt)
})
it('should return correct serverUpdatedAtTimestamp', () => {
const timestamp = 1672578000000
const rawPayload = createValidRawPayload({ updated_at_timestamp: timestamp })
const payload = new TestPurePayload(rawPayload)
expect(payload.serverUpdatedAtTimestamp).toBe(timestamp)
})
})
describe('signature data', () => {
it('should handle signature data correctly', () => {
const signatureData: PersistentSignatureData = {
signature: 'test-signature',
publicKey: 'test-public-key',
} as any
const rawPayload = createValidRawPayload({ signatureData })
const payload = new TestPurePayload(rawPayload)
expect(payload.signatureData).toEqual(signatureData)
})
it('should handle undefined signature data', () => {
const rawPayload = createValidRawPayload({ signatureData: undefined })
const payload = new TestPurePayload(rawPayload)
expect(payload.signatureData).toBeUndefined()
})
})
describe('error handling', () => {
it('should include content_type in error message when uuid is null', () => {
const rawPayload = createValidRawPayload({
uuid: null as any,
content_type: ContentType.TYPES.Note,
})
expect(() => new TestPurePayload(rawPayload)).toThrow(
/Content type: Note/
)
})
})
describe('edge cases', () => {
it('should handle empty string content', () => {
const rawPayload = createValidRawPayload({ content: '' })
const payload = new TestPurePayload(rawPayload)
expect(payload.content).toBe('')
})
it('should handle string content', () => {
const rawPayload = createValidRawPayload({ content: 'encrypted-content' })
const payload = new TestPurePayload(rawPayload)
expect(payload.content).toBe('encrypted-content')
})
it('should handle zero timestamps', () => {
const rawPayload = createValidRawPayload({
created_at_timestamp: 0,
updated_at_timestamp: 0,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.created_at_timestamp).toBe(0)
expect(payload.updated_at_timestamp).toBe(0)
})
it('should handle null/undefined nullish coalescing correctly', () => {
const rawPayload = createValidRawPayload({
user_uuid: null as any,
key_system_identifier: null as any,
shared_vault_uuid: null as any,
last_edited_by_uuid: null as any,
})
const payload = new TestPurePayload(rawPayload)
expect(payload.user_uuid).toBeUndefined()
expect(payload.key_system_identifier).toBeUndefined()
expect(payload.shared_vault_uuid).toBeUndefined()
expect(payload.last_edited_by_uuid).toBeUndefined()
})
})
})
@@ -65,7 +65,7 @@ export abstract class PurePayload<T extends TransferPayload<C>, C extends ItemCo
this.updated_at = new Date(rawPayload.updated_at || 0)
this.updated_at_timestamp = rawPayload.updated_at_timestamp || 0
if (this.updated_at_timestamp < 0) {
if (this.updated_at < new Date(0) || this.updated_at_timestamp < 0) {
this.updated_at_timestamp = 0
this.updated_at = new Date(0)
}
@@ -73,7 +73,7 @@ export abstract class PurePayload<T extends TransferPayload<C>, C extends ItemCo
this.created_at = new Date(rawPayload.created_at || new Date())
this.created_at_timestamp = rawPayload.created_at_timestamp || 0
if (this.created_at_timestamp < 0) {
if (this.created_at < new Date(0) || this.created_at_timestamp < 0) {
this.created_at_timestamp = this.updated_at_timestamp
this.created_at = this.updated_at
}
@@ -38,8 +38,11 @@ export function itemMatchesQuery(
searchQuery: SearchQuery,
collection: ReferenceLookupCollection,
): boolean {
const shouldCheckForSomeTagMatches = searchQuery.shouldCheckForSomeTagMatches ?? true
const itemTags = collection.elementsReferencingElement(itemToMatch, ContentType.TYPES.Tag) as SNTag[]
const someTagsMatches = itemTags.some((tag) => matchResultForStringQuery(tag, searchQuery.query) !== MatchResult.None)
const someTagsMatches =
shouldCheckForSomeTagMatches &&
itemTags.some((tag) => matchResultForStringQuery(tag, searchQuery.query) !== MatchResult.None)
if (itemToMatch.protected && !searchQuery.includeProtectedNoteText) {
const match = matchResultForStringQuery(itemToMatch, searchQuery.query)
@@ -5,6 +5,7 @@ import { SearchableItem } from './SearchableItem'
export type SearchQuery = {
query: string
includeProtectedNoteText: boolean
shouldCheckForSomeTagMatches?: boolean
}
export interface ReferenceLookupCollection {
+84
View File
@@ -3,6 +3,90 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.4.847](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.846](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.845](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-21)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.844](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.843](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.842](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.841](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.840](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.839](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.838](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.837](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.836](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.835](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.834](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.833](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.832](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.831](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.830](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.829](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.828](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.827](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.826](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.826",
"version": "1.4.847",
"license": "AGPL-3.0",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.71.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/services
## [1.71.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/services
## [1.71.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/services
## [1.71.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.71.7",
"version": "1.71.10",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -2,7 +2,7 @@ import { AnyKeyParamsContent } from '@standardnotes/common'
import { SessionBody } from '@standardnotes/responses'
export interface AuthClientInterface {
generateRecoveryCodes(): Promise<string | false>
generateRecoveryCodes(dto: { serverPassword: string }): Promise<string | false>
recoveryKeyParams(dto: {
username: string
codeChallenge: string
@@ -14,9 +14,9 @@ export class AuthManager extends AbstractService implements AuthClientInterface
super(internalEventBus)
}
async generateRecoveryCodes(): Promise<string | false> {
async generateRecoveryCodes(dto: { serverPassword: string }): Promise<string | false> {
try {
const result = await this.authApiService.generateRecoveryCodes()
const result = await this.authApiService.generateRecoveryCodes(dto)
if (isErrorResponse(result)) {
return false
@@ -1,6 +1,6 @@
import { ApplicationServiceInterface } from './../Service/ApplicationServiceInterface'
import { DecryptedItem, DecryptedItemInterface, FileItem, SNNote } from '@standardnotes/models'
import { ChallengeInterface, ChallengeReason } from '../Challenge'
import { ChallengeInterface, ChallengeReason, ChallengeResponseInterface } from '../Challenge'
import { MobileUnlockTiming } from './MobileUnlockTiming'
import { TimingDisplayOption } from './TimingDisplayOption'
import { ProtectionEvent } from './ProtectionEvent'
@@ -28,6 +28,10 @@ export interface ProtectionsClientInterface extends ApplicationServiceInterface<
reason: ChallengeReason,
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
): Promise<boolean>
authorizeActionWithChallengeResponse(
reason: ChallengeReason,
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
): Promise<{ success: boolean; challengeResponse?: ChallengeResponseInterface }>
authorizeAddingPasscode(): Promise<boolean>
authorizeRemovingPasscode(): Promise<boolean>
authorizeChangingPasscode(): Promise<boolean>
@@ -36,7 +40,8 @@ export interface ProtectionsClientInterface extends ApplicationServiceInterface<
authorizeAutolockIntervalChange(): Promise<boolean>
authorizeSearchingProtectedNotesText(): Promise<boolean>
authorizeBackupCreation(): Promise<boolean>
authorizeMfaDisable(): Promise<boolean>
authorizeMfaDisable(): Promise<{ success: boolean; challengeResponse?: ChallengeResponseInterface }>
authorizeAccountDeletion(): Promise<{ success: boolean; challengeResponse?: ChallengeResponseInterface }>
protectItems<I extends DecryptedItemInterface>(items: I[]): Promise<I[]>
unprotectItems<I extends DecryptedItemInterface>(items: I[], reason: ChallengeReason): Promise<I[] | undefined>
@@ -237,13 +237,9 @@ export class UserService
error: boolean
message?: string
}> {
if (
!(await this.protections.authorizeAction(ChallengeReason.DeleteAccount, {
fallBackToAccountPassword: true,
requireAccountPassword: true,
forcePrompt: false,
}))
) {
const { success, challengeResponse } = await this.protections.authorizeAccountDeletion()
if (!success) {
return {
error: true,
message: Messages.INVALID_PASSWORD,
@@ -251,7 +247,13 @@ export class UserService
}
const uuid = this.sessions.getSureUser().uuid
const response = await this.userApi.deleteAccount(uuid)
const password = challengeResponse?.getValueForType(ChallengeValidation.AccountPassword).value as string
const currentRootKey = await this.encryption.computeRootKey(
password,
this.encryption.getRootKeyParams() as SNRootKeyParams,
)
const serverPassword = currentRootKey.serverPassword
const response = await this.userApi.deleteAccount({ userUuid: uuid, serverPassword: serverPassword })
if (isErrorResponse(response)) {
return {
error: true,
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.209.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/snjs
## [2.209.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/snjs
## [2.209.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
### Bug Fixes
* Fixed issue with UI sometimes getting shifted up on iOS ([c050a2c](https://github.com/standardnotes/app/commit/c050a2cd339bb7a8fd482904216de1db2b8fe568))
## [2.209.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/snjs
@@ -1026,6 +1026,7 @@ export class Dependencies {
return new GetRecoveryCodes(
this.get<AuthManager>(TYPES.AuthManager),
this.get<SettingsService>(TYPES.SettingsService),
this.get<EncryptionService>(TYPES.EncryptionService),
)
})
@@ -1231,6 +1232,7 @@ export class Dependencies {
this.get<PureCryptoInterface>(TYPES.Crypto),
this.get<FeaturesService>(TYPES.FeaturesService),
this.get<ProtectionsClientInterface>(TYPES.ProtectionService),
this.get<EncryptionService>(TYPES.EncryptionService),
this.get<InternalEventBus>(TYPES.InternalEventBus),
)
})
@@ -10,7 +10,6 @@ export enum ReactNativeToWebEvent {
KeyboardWillHide = 'KeyboardWillHide',
KeyboardDidShow = 'KeyboardDidShow',
KeyboardDidHide = 'KeyboardDidHide',
UpdateSafeAreaInsets = 'UpdateSafeAreaInsets',
ReceivedFile = 'ReceivedFile',
ReceivedLink = 'ReceivedLink',
ReceivedText = 'ReceivedText',
@@ -1,4 +1,4 @@
import { AuthClientInterface } from '@standardnotes/services'
import { AuthClientInterface, EncryptionService } from '@standardnotes/services'
import { SettingsClientInterface } from '@Lib/Services/Settings/SettingsClientInterface'
import { GetRecoveryCodes } from './GetRecoveryCodes'
@@ -6,8 +6,9 @@ import { GetRecoveryCodes } from './GetRecoveryCodes'
describe('GetRecoveryCodes', () => {
let authClient: AuthClientInterface
let settingsClient: SettingsClientInterface
let encryption: EncryptionService
const createUseCase = () => new GetRecoveryCodes(authClient, settingsClient)
const createUseCase = () => new GetRecoveryCodes(authClient, settingsClient, encryption)
beforeEach(() => {
authClient = {} as jest.Mocked<AuthClientInterface>
@@ -15,12 +16,16 @@ describe('GetRecoveryCodes', () => {
settingsClient = {} as jest.Mocked<SettingsClientInterface>
settingsClient.getSetting = jest.fn().mockResolvedValue('existing-recovery-codes')
encryption = {} as jest.Mocked<EncryptionService>
encryption.computeRootKey = jest.fn().mockResolvedValue({ serverPassword: 'test-server-password' })
encryption.getRootKeyParams = jest.fn().mockReturnValue({ algorithm: 'test-algorithm' })
})
it('should return existing recovery code if they exist', async () => {
const useCase = createUseCase()
const result = await useCase.execute()
const result = await useCase.execute({ password: 'test-password' })
expect(result.getValue()).toBe('existing-recovery-codes')
})
@@ -30,7 +35,7 @@ describe('GetRecoveryCodes', () => {
const useCase = createUseCase()
const result = await useCase.execute()
const result = await useCase.execute({ password: 'test-password' })
expect(result.getValue()).toBe('recovery-codes')
})
@@ -41,7 +46,7 @@ describe('GetRecoveryCodes', () => {
const useCase = createUseCase()
const result = await useCase.execute()
const result = await useCase.execute({ password: 'test-password' })
expect(result.isFailed()).toBe(true)
})
@@ -1,23 +1,40 @@
import { AuthClientInterface } from '@standardnotes/services'
import { AuthClientInterface, EncryptionService } from '@standardnotes/services'
import { Result, SettingName, UseCaseInterface } from '@standardnotes/domain-core'
import { SettingsClientInterface } from '@Lib/Services/Settings/SettingsClientInterface'
import { GetRecoveryCodesDTO } from './GetRecoveryCodesDTO'
import { SNRootKeyParams } from '@standardnotes/encryption'
export class GetRecoveryCodes implements UseCaseInterface<string> {
constructor(
private authClient: AuthClientInterface,
private settingsClient: SettingsClientInterface,
private encryption: EncryptionService,
) {}
async execute(): Promise<Result<string>> {
async execute(dto: GetRecoveryCodesDTO): Promise<Result<string>> {
if (!dto.password) {
return Result.fail('Password is required to get recovery code.')
}
const currentRootKey = await this.encryption.computeRootKey(
dto.password,
this.encryption.getRootKeyParams() as SNRootKeyParams,
)
const serverPassword = currentRootKey.serverPassword
if (!serverPassword) {
return Result.fail('Could not compute server password')
}
const existingRecoveryCodes = await this.settingsClient.getSetting(
SettingName.create(SettingName.NAMES.RecoveryCodes).getValue(),
serverPassword,
)
if (existingRecoveryCodes !== undefined) {
return Result.ok(existingRecoveryCodes)
}
const generatedRecoveryCodes = await this.authClient.generateRecoveryCodes()
const generatedRecoveryCodes = await this.authClient.generateRecoveryCodes({ serverPassword })
if (generatedRecoveryCodes === false) {
return Result.fail('Could not generate recovery code')
}
@@ -0,0 +1,3 @@
export interface GetRecoveryCodesDTO {
password?: string
}
+14 -2
View File
@@ -578,12 +578,18 @@ export class LegacyApiService
})
}
async getSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<GetSettingResponse>> {
async getSetting(
userUuid: UuidString,
settingName: string,
serverPassword?: string,
): Promise<HttpResponse<GetSettingResponse>> {
const customHeaders = serverPassword ? [{ key: 'x-server-password', value: serverPassword }] : undefined
return await this.tokenRefreshableRequest<GetSettingResponse>({
verb: HttpVerb.Get,
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName.toLowerCase())),
authentication: this.getSessionAccessToken(),
fallbackErrorMessage: API_MESSAGE_FAILED_GET_SETTINGS,
customHeaders,
})
}
@@ -616,12 +622,18 @@ export class LegacyApiService
})
}
async deleteSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<DeleteSettingResponse>> {
async deleteSetting(
userUuid: UuidString,
settingName: string,
serverPassword?: string,
): Promise<HttpResponse<DeleteSettingResponse>> {
const customHeaders = serverPassword ? [{ key: 'x-server-password', value: serverPassword }] : undefined
return this.tokenRefreshableRequest<DeleteSettingResponse>({
verb: HttpVerb.Delete,
url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName)),
authentication: this.getSessionAccessToken(),
fallbackErrorMessage: API_MESSAGE_FAILED_UPDATE_SETTINGS,
customHeaders,
})
}
+18 -2
View File
@@ -6,9 +6,12 @@ import {
InternalEventBusInterface,
MfaServiceInterface,
ProtectionsClientInterface,
EncryptionService,
SignInStrings,
ChallengeValidation,
} from '@standardnotes/services'
import { SettingName } from '@standardnotes/domain-core'
import { SNRootKeyParams } from '@standardnotes/encryption'
export class MfaService extends AbstractService implements MfaServiceInterface {
constructor(
@@ -16,6 +19,7 @@ export class MfaService extends AbstractService implements MfaServiceInterface {
private crypto: PureCryptoInterface,
private featuresService: FeaturesService,
private protections: ProtectionsClientInterface,
private encryption: EncryptionService,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
@@ -55,11 +59,23 @@ export class MfaService extends AbstractService implements MfaServiceInterface {
}
async disableMfa(): Promise<void> {
if (!(await this.protections.authorizeMfaDisable())) {
const { success, challengeResponse } = await this.protections.authorizeMfaDisable()
if (!success) {
return
}
return await this.settingsService.deleteSetting(SettingName.create(SettingName.NAMES.MfaSecret).getValue())
const password = challengeResponse?.getValueForType(ChallengeValidation.AccountPassword).value as string
const currentRootKey = await this.encryption.computeRootKey(
password,
this.encryption.getRootKeyParams() as SNRootKeyParams,
)
const serverPassword = currentRootKey.serverPassword
return await this.settingsService.deleteSetting(
SettingName.create(SettingName.NAMES.MfaSecret).getValue(),
serverPassword,
)
}
override deinit(): void {
@@ -34,6 +34,7 @@ import {
import { ContentType } from '@standardnotes/domain-core'
import { isValidProtectionSessionLength } from './isValidProtectionSessionLength'
import { UnprotectedAccessSecondsDuration } from './UnprotectedAccessSecondsDuration'
import { ChallengeResponse } from '../Challenge'
/**
* Enforces certain actions to require extra authentication,
@@ -246,11 +247,11 @@ export class ProtectionService
})
}
async authorizeMfaDisable(): Promise<boolean> {
return this.authorizeAction(ChallengeReason.DisableMfa, {
async authorizeMfaDisable(): Promise<{ success: boolean; challengeResponse?: ChallengeResponse }> {
return this.authorizeActionWithChallengeResponse(ChallengeReason.DisableMfa, {
fallBackToAccountPassword: true,
requireAccountPassword: true,
forcePrompt: false,
forcePrompt: true,
})
}
@@ -278,6 +279,14 @@ export class ProtectionService
})
}
async authorizeAccountDeletion(): Promise<{ success: boolean; challengeResponse?: ChallengeResponse }> {
return this.authorizeActionWithChallengeResponse(ChallengeReason.DeleteAccount, {
fallBackToAccountPassword: true,
requireAccountPassword: true,
forcePrompt: true,
})
}
async authorizeAction(
reason: ChallengeReason,
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
@@ -285,6 +294,13 @@ export class ProtectionService
return this.validateOrRenewSession(reason, dto)
}
async authorizeActionWithChallengeResponse(
reason: ChallengeReason,
dto: { fallBackToAccountPassword: boolean; requireAccountPassword: boolean; forcePrompt: boolean },
): Promise<{ success: boolean; challengeResponse?: ChallengeResponse }> {
return this.validateOrRenewSessionWithChallengeResponse(reason, dto)
}
getMobilePasscodeTimingOptions(): TimingDisplayOption[] {
return [
{
@@ -353,8 +369,20 @@ export class ProtectionService
reason: ChallengeReason,
{ fallBackToAccountPassword = true, requireAccountPassword = false, forcePrompt = false } = {},
): Promise<boolean> {
const response = await this.validateOrRenewSessionWithChallengeResponse(reason, {
fallBackToAccountPassword,
requireAccountPassword,
forcePrompt,
})
return response.success
}
private async validateOrRenewSessionWithChallengeResponse(
reason: ChallengeReason,
{ fallBackToAccountPassword = true, requireAccountPassword = false, forcePrompt = false } = {},
): Promise<{ success: boolean; challengeResponse?: ChallengeResponse }> {
if (this.getSessionExpiryDate() > new Date() && !forcePrompt) {
return true
return { success: true }
}
const prompts: ChallengePrompt[] = []
@@ -378,9 +406,10 @@ export class ProtectionService
if (fallBackToAccountPassword && this.encryption.hasAccount()) {
prompts.push(new ChallengePrompt(ChallengeValidation.AccountPassword))
} else {
return true
return { success: true }
}
}
const lastSessionLength = this.getLastSessionLength()
const chosenSessionLength = isValidProtectionSessionLength(lastSessionLength)
? lastSessionLength
@@ -407,9 +436,9 @@ export class ProtectionService
} else {
this.setSessionLength(length as UnprotectedAccessSecondsDuration)
}
return true
return { success: true, challengeResponse: response }
} else {
return false
return { success: false }
}
}
@@ -30,8 +30,8 @@ export class SettingsService extends AbstractService implements SettingsClientIn
return this.provider.listSettings()
}
async getSetting(name: SettingName) {
return this.provider.getSetting(name)
async getSetting(name: SettingName, serverPassword?: string) {
return this.provider.getSetting(name, serverPassword)
}
async getSubscriptionSetting(name: SettingName) {
@@ -50,8 +50,8 @@ export class SettingsService extends AbstractService implements SettingsClientIn
return this.provider.getDoesSensitiveSettingExist(name)
}
async deleteSetting(name: SettingName) {
return this.provider.deleteSetting(name)
async deleteSetting(name: SettingName, serverPassword?: string) {
return this.provider.deleteSetting(name, serverPassword)
}
getEmailBackupFrequencyOptionLabel(frequency: EmailBackupFrequency): string {
@@ -5,13 +5,13 @@ import { SettingName } from '@standardnotes/domain-core'
export interface SettingsClientInterface {
listSettings(): Promise<SettingsList>
getSetting(name: SettingName): Promise<string | undefined>
getSetting(name: SettingName, serverPassword?: string): Promise<string | undefined>
getDoesSensitiveSettingExist(name: SettingName): Promise<boolean>
updateSetting(name: SettingName, payload: string, sensitive?: boolean): Promise<void>
deleteSetting(name: SettingName): Promise<void>
deleteSetting(name: SettingName, serverPassword?: string): Promise<void>
getEmailBackupFrequencyOptionLabel(frequency: EmailBackupFrequency): string
}
@@ -45,8 +45,8 @@ export class SettingsGateway {
return settings
}
async getSetting(name: SettingName): Promise<string | undefined> {
const response = await this.settingsApi.getSetting(this.userUuid, name.value)
async getSetting(name: SettingName, serverPassword?: string): Promise<string | undefined> {
const response = await this.settingsApi.getSetting(this.userUuid, name.value, serverPassword)
if (response.status === HttpStatusCode.BadRequest) {
return undefined
@@ -109,8 +109,8 @@ export class SettingsGateway {
}
}
async deleteSetting(name: SettingName): Promise<void> {
const response = await this.settingsApi.deleteSetting(this.userUuid, name.value)
async deleteSetting(name: SettingName, serverPassword?: string): Promise<void> {
const response = await this.settingsApi.deleteSetting(this.userUuid, name.value, serverPassword)
if (isErrorResponse(response)) {
throw new Error(getErrorFromErrorResponse(response).message)
}
@@ -17,7 +17,11 @@ export interface SettingsServerInterface {
sensitive: boolean,
): Promise<HttpResponse<UpdateSettingResponse>>
getSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<GetSettingResponse>>
getSetting(
userUuid: UuidString,
settingName: string,
serverPassword?: string,
): Promise<HttpResponse<GetSettingResponse>>
getSubscriptionSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<GetSettingResponse>>
@@ -28,5 +32,9 @@ export interface SettingsServerInterface {
sensitive: boolean,
): Promise<HttpResponse<UpdateSettingResponse>>
deleteSetting(userUuid: UuidString, settingName: string): Promise<HttpResponse<DeleteSettingResponse>>
deleteSetting(
userUuid: UuidString,
settingName: string,
serverPassword?: string,
): Promise<HttpResponse<DeleteSettingResponse>>
}
+47 -1
View File
@@ -549,6 +549,24 @@ describe('basic auth', function () {
expect(sendChallengeSpy.callCount).to.equal(1)
}).timeout(Factory.TenSecondTimeout)
it('should send server password when deleting account', async function () {
Factory.handlePasswordChallenges(context.application, context.password)
const userApiService = context.application.dependencies.get(TYPES.UserApiService)
const deleteAccountSpy = sinon.spy(userApiService, 'deleteAccount')
await context.application.user.deleteAccount()
expect(deleteAccountSpy.callCount).to.equal(1)
const deleteAccountCall = deleteAccountSpy.getCall(0)
const callArgs = deleteAccountCall.args[0]
expect(callArgs).to.have.property('serverPassword')
expect(callArgs.serverPassword).to.not.be.undefined
expect(typeof callArgs.serverPassword).to.equal('string')
expect(callArgs.serverPassword.length).to.be.above(0)
}).timeout(Factory.TenSecondTimeout)
it('deleting account should sign out current user', async function () {
Factory.handlePasswordChallenges(context.application, context.password)
@@ -567,12 +585,40 @@ describe('basic auth', function () {
const response = await context.application.dependencies
.get(TYPES.UserApiService)
.deleteAccount(registerResponse.user.uuid)
.deleteAccount({
userUuid: registerResponse.user.uuid,
serverPassword: 'dummy-password'
})
expect(response.status).to.equal(401)
expect(response.data.error.message).to.equal('Operation not allowed.')
await secondContext.deinit()
})
it('should not allow deleting account if server password is not sent', async function () {
Factory.handlePasswordChallenges(context.application, context.password)
const response = await context.application.dependencies
.get(TYPES.UserApiService)
.deleteAccount({
userUuid: context.application.user.uuid,
})
expect(response.status).to.equal(400)
}).timeout(Factory.TenSecondTimeout)
it('should not allow deleting account if server password is incorrect', async function () {
Factory.handlePasswordChallenges(context.application, context.password)
const response = await context.application.dependencies
.get(TYPES.UserApiService)
.deleteAccount({
userUuid: context.application.user.uuid,
serverPassword: 'wrong-password'
})
expect(response.status).to.equal(400)
}).timeout(Factory.TenSecondTimeout)
})
})
+61
View File
@@ -65,6 +65,7 @@ describe('mfa service', () => {
const token = await application.mfa.getOtpToken(secret)
sinon.spy(application.challenges, 'sendChallenge')
await application.mfa.enableMfa(secret, token)
await application.mfa.disableMfa()
@@ -73,4 +74,64 @@ describe('mfa service', () => {
expect(challenge.prompts).to.have.lengthOf(2)
expect(challenge.prompts[0].validation).to.equal(ChallengeValidation.AccountPassword)
}).timeout(Factory.TenSecondTimeout)
it('sends server password when disabling mfa', async () => {
await registerApp(application)
Factory.handlePasswordChallenges(application, accountPassword)
const secret = await application.mfa.generateMfaSecret()
const token = await application.mfa.getOtpToken(secret)
await application.mfa.enableMfa(secret, token)
sinon.spy(application.settings.settingsApi, 'deleteSetting')
await application.mfa.disableMfa()
const deleteSettingCall = application.settings.settingsApi.deleteSetting.getCall(0)
const [serverPassword] = deleteSettingCall.args
expect(typeof serverPassword).to.equal('string')
expect(serverPassword.length).to.be.above(0)
}).timeout(Factory.TenSecondTimeout)
it('should not allow disabling mfa if server password is not sent', async function () {
await registerApp(application)
Factory.handlePasswordChallenges(application, accountPassword)
const secret = await application.mfa.generateMfaSecret()
const token = await application.mfa.getOtpToken(secret)
await application.mfa.enableMfa(secret, token)
const response = await application.dependencies
.get(TYPES.SettingsApiService)
.deleteSetting({
userUuid: application.user.uuid,
settingName: 'MFA_SECRET',
})
expect(response.status).to.equal(400)
}).timeout(Factory.TenSecondTimeout)
it('should not allow disabling mfa if server password is incorrect', async function () {
await registerApp(application)
Factory.handlePasswordChallenges(application, accountPassword)
const secret = await application.mfa.generateMfaSecret()
const token = await application.mfa.getOtpToken(secret)
await application.mfa.enableMfa(secret, token)
const response = await application.dependencies
.get(TYPES.SettingsApiService)
.deleteSetting({
userUuid: application.user.uuid,
settingName: 'MFA_SECRET',
serverPassword: 'wrong-password'
})
expect(response.status).to.equal(400)
}).timeout(Factory.TenSecondTimeout)
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.209.10",
"version": "2.209.13",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.38.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.38.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.38.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
### Bug Fixes
* fix simplenote converter ([f776cb3](https://github.com/standardnotes/app/commit/f776cb30d488d70994afdc174bb8035cf100b810))
## [1.38.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
### Bug Fixes
* Fixed issue with UI sometimes getting shifted up on iOS ([c050a2c](https://github.com/standardnotes/app/commit/c050a2cd339bb7a8fd482904216de1db2b8fe568))
## [1.38.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
**Note:** Version bump only for package @standardnotes/ui-services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.38.8",
"version": "1.38.12",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -22,7 +22,7 @@ describe('SimplenoteConverter', () => {
it('should parse', async () => {
const converter = new SimplenoteConverter()
const result = await converter.parse(data, createNote)
const result = await converter.parse(data, createNote, (markdown) => markdown)
expect(result).not.toBeNull()
expect(result?.length).toBe(3)
@@ -50,10 +50,10 @@ export class SimplenoteConverter implements Converter {
return false
}
convert: Converter['convert'] = async (file, { insertNote: createNote, readFileAsText }) => {
convert: Converter['convert'] = async (file, { insertNote: createNote, convertMarkdownToSuper, readFileAsText }) => {
const content = await readFileAsText(file)
const notes = await this.parse(content, createNote)
const notes = await this.parse(content, createNote, convertMarkdownToSuper)
if (!notes) {
throw new Error('Could not parse notes')
@@ -65,13 +65,18 @@ export class SimplenoteConverter implements Converter {
}
}
createNoteFromItem(item: SimplenoteItem, trashed: boolean, createNote: InsertNoteFn): ReturnType<InsertNoteFn> {
createNoteFromItem(
item: SimplenoteItem,
trashed: boolean,
createNote: InsertNoteFn,
convertMarkdownToSuper: (markdown: string) => string,
): ReturnType<InsertNoteFn> {
const createdAtDate = new Date(item.creationDate)
const updatedAtDate = new Date(item.lastModified)
const splitContent = splitAtFirst(item.content, '\r\n')
const title = splitContent[0] ?? createdAtDate.toLocaleString()
const text = splitContent[1] ?? item.content
const text = convertMarkdownToSuper(splitContent[1] ?? item.content)
return createNote({
createdAt: createdAtDate,
@@ -83,14 +88,18 @@ export class SimplenoteConverter implements Converter {
})
}
async parse(data: string, createNote: InsertNoteFn) {
async parse(data: string, createNote: InsertNoteFn, convertMarkdownToSuper: (markdown: string) => string) {
try {
const parsed = JSON.parse(data) as SimplenoteData
const activeNotes = await Promise.all(
parsed.activeNotes.reverse().map((item) => this.createNoteFromItem(item, false, createNote)),
parsed.activeNotes
.reverse()
.map((item) => this.createNoteFromItem(item, false, createNote, convertMarkdownToSuper)),
)
const trashedNotes = await Promise.all(
parsed.trashedNotes.reverse().map((item) => this.createNoteFromItem(item, true, createNote)),
parsed.trashedNotes
.reverse()
.map((item) => this.createNoteFromItem(item, true, createNote, convertMarkdownToSuper)),
)
return [...activeNotes, ...trashedNotes]
@@ -21,7 +21,6 @@ export interface WebApplicationInterface extends ApplicationInterface {
isFloatingKeyboard: boolean
}): void
handleMobileKeyboardDidHideEvent(): void
handleUpdateSafeAreaInsets(insets: { top: number; bottom: number; left: number; right: number }): void
handleReceivedFileEvent(file: { name: string; mimeType: string; data: string }): void
handleReceivedTextEvent(item: { text: string; title?: string }): Promise<void>
handleReceivedLinkEvent(item: { link: string; title: string }): Promise<void>
+106
View File
@@ -3,6 +3,112 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.198.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)
**Note:** Version bump only for package @standardnotes/web
## [3.198.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)
**Note:** Version bump only for package @standardnotes/web
## [3.198.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)
### Bug Fixes
* Fixes Share note option not working on Android for note titles with special characters ([#2928](https://github.com/standardnotes/app/issues/2928)) ([d135e09](https://github.com/standardnotes/app/commit/d135e09bda39814585a3d76b0544ed8b5834b4d0))
## [3.198.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)
### Bug Fixes
* Fixes Back and Navigation buttons not working on mobile view when panels explicitly collapsed ([#2926](https://github.com/standardnotes/app/issues/2926)) ([0108648](https://github.com/standardnotes/app/commit/010864881d0c056e88dae2394fb398c0f1e822a5))
## [3.198.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)
### Bug Fixes
* Prevents quick type suggestions on iOS for password input ([ff80775](https://github.com/standardnotes/app/commit/ff80775cd6f09863429f053e590a054c6e45722c))
## [3.198.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)
### Bug Fixes
* Fixed font size not updating on plain editor when changing it from Preferences ([#2920](https://github.com/standardnotes/app/issues/2920)) ([0d17961](https://github.com/standardnotes/app/commit/0d17961570cdadbbb909709075bdef3b8d77434b))
* Fixes extra bottom padding in account modal ([63d8472](https://github.com/standardnotes/app/commit/63d84725d2084d014de6aa73e74ba77a7e343484))
* Fixes quick type suggestions showing up in iOS for password field ([9583d0d](https://github.com/standardnotes/app/commit/9583d0db44ba315e125fbc36b50a8da527ae3a89))
## [3.198.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)
**Note:** Version bump only for package @standardnotes/web
## [3.198.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/web
## [3.198.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/web
## [3.198.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
**Note:** Version bump only for package @standardnotes/web
## [3.198.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)
### Bug Fixes
* Fixed issues with embedded linked items in Super editor ([#2918](https://github.com/standardnotes/app/issues/2918)) ([43d31d8](https://github.com/standardnotes/app/commit/43d31d8bb44644b0d78d8a7f543da790b30e1eea))
## [3.198.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)
### Bug Fixes
* Remove extra bottom padding on Android ([#2915](https://github.com/standardnotes/app/issues/2915)) ([c52030a](https://github.com/standardnotes/app/commit/c52030a525eaf3c8488c19beb84229911bcda8fc))
## [3.198.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)
### Bug Fixes
* Prevent text from hiding behind navbar in Android ([#2914](https://github.com/standardnotes/app/issues/2914)) ([d02e5ca](https://github.com/standardnotes/app/commit/d02e5cab7462ea4754a3e650be571a16f6c9c7b4))
## [3.198.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)
### Bug Fixes
* Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift ([#2912](https://github.com/standardnotes/app/issues/2912)) ([117781b](https://github.com/standardnotes/app/commit/117781bb3655a2bd6b9b0ca5a4d12f7bbefd164e))
## [3.198.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)
**Note:** Version bump only for package @standardnotes/web
## [3.198.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)
**Note:** Version bump only for package @standardnotes/web
## [3.198.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
**Note:** Version bump only for package @standardnotes/web
# [3.198.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)
### Bug Fixes
* Fixed issue with UI sometimes getting shifted up on iOS ([c050a2c](https://github.com/standardnotes/app/commit/c050a2cd339bb7a8fd482904216de1db2b8fe568))
### Features
* Tag search will now only show the direct tag results instead of also showing the parent and siblings ([#2906](https://github.com/standardnotes/app/issues/2906)) ([caa8eff](https://github.com/standardnotes/app/commit/caa8eff216b2d7a47f849f85f1eb2248eea10c62))
## [3.197.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)
**Note:** Version bump only for package @standardnotes/web
## [3.197.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
### Bug Fixes
* Fixed issue where Android app would crash on screen rotation ([#2905](https://github.com/standardnotes/app/issues/2905)) ([9c1bb35](https://github.com/standardnotes/app/commit/9c1bb353550c0256b4e6dcbee1e087cc9ffdd628))
## [3.197.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)
**Note:** Version bump only for package @standardnotes/web
+258
View File
@@ -1,5 +1,263 @@
{
"versions": [
{
"version": "3.198.17",
"title": "[3.198.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-26)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.16",
"title": "[3.198.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-25)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.15",
"title": "[3.198.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-11)",
"date": null,
"body": "### Bug Fixes\n\n* Fixes Share note option not working on Android for note titles with special characters ([#2928](https://github.com/standardnotes/app/issues/2928)) ([d135e09](https://github.com/standardnotes/app/commit/d135e09bda39814585a3d76b0544ed8b5834b4d0))",
"parsed": {
"_": [
"Fixes Share note option not working on Android for note titles with special characters (#2928) (d135e09)"
],
"Bug Fixes": [
"Fixes Share note option not working on Android for note titles with special characters (#2928) (d135e09)"
]
}
},
{
"version": "3.198.14",
"title": "[3.198.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-05)",
"date": null,
"body": "### Bug Fixes\n\n* Fixes Back and Navigation buttons not working on mobile view when panels explicitly collapsed ([#2926](https://github.com/standardnotes/app/issues/2926)) ([0108648](https://github.com/standardnotes/app/commit/010864881d0c056e88dae2394fb398c0f1e822a5))",
"parsed": {
"_": [
"Fixes Back and Navigation buttons not working on mobile view when panels explicitly collapsed (#2926) (0108648)"
],
"Bug Fixes": [
"Fixes Back and Navigation buttons not working on mobile view when panels explicitly collapsed (#2926) (0108648)"
]
}
},
{
"version": "3.198.13",
"title": "[3.198.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-08-04)",
"date": null,
"body": "### Bug Fixes\n\n* Prevents quick type suggestions on iOS for password input ([ff80775](https://github.com/standardnotes/app/commit/ff80775cd6f09863429f053e590a054c6e45722c))",
"parsed": {
"_": [
"Prevents quick type suggestions on iOS for password input (ff80775)"
],
"Bug Fixes": [
"Prevents quick type suggestions on iOS for password input (ff80775)"
]
}
},
{
"version": "3.198.12",
"title": "[3.198.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-29)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed font size not updating on plain editor when changing it from Preferences ([#2920](https://github.com/standardnotes/app/issues/2920)) ([0d17961](https://github.com/standardnotes/app/commit/0d17961570cdadbbb909709075bdef3b8d77434b))\n* Fixes extra bottom padding in account modal ([63d8472](https://github.com/standardnotes/app/commit/63d84725d2084d014de6aa73e74ba77a7e343484))\n* Fixes quick type suggestions showing up in iOS for password field ([9583d0d](https://github.com/standardnotes/app/commit/9583d0db44ba315e125fbc36b50a8da527ae3a89))",
"parsed": {
"_": [
"Fixed font size not updating on plain editor when changing it from Preferences (#2920) (0d17961)",
"Fixes extra bottom padding in account modal (63d8472)",
"Fixes quick type suggestions showing up in iOS for password field (9583d0d)"
],
"Bug Fixes": [
"Fixed font size not updating on plain editor when changing it from Preferences (#2920) (0d17961)",
"Fixes extra bottom padding in account modal (63d8472)",
"Fixes quick type suggestions showing up in iOS for password field (9583d0d)"
]
}
},
{
"version": "3.198.11",
"title": "[3.198.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-23)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.10",
"title": "[3.198.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.9",
"title": "[3.198.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.8",
"title": "[3.198.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.7",
"title": "[3.198.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-22)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issues with embedded linked items in Super editor ([#2918](https://github.com/standardnotes/app/issues/2918)) ([43d31d8](https://github.com/standardnotes/app/commit/43d31d8bb44644b0d78d8a7f543da790b30e1eea))",
"parsed": {
"_": [
"Fixed issues with embedded linked items in Super editor (#2918) (43d31d8)"
],
"Bug Fixes": [
"Fixed issues with embedded linked items in Super editor (#2918) (43d31d8)"
]
}
},
{
"version": "3.198.6",
"title": "[3.198.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-19)",
"date": null,
"body": "### Bug Fixes\n\n* Remove extra bottom padding on Android ([#2915](https://github.com/standardnotes/app/issues/2915)) ([c52030a](https://github.com/standardnotes/app/commit/c52030a525eaf3c8488c19beb84229911bcda8fc))",
"parsed": {
"_": [
"Remove extra bottom padding on Android (#2915) (c52030a)"
],
"Bug Fixes": [
"Remove extra bottom padding on Android (#2915) (c52030a)"
]
}
},
{
"version": "3.198.5",
"title": "[3.198.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-15)",
"date": null,
"body": "### Bug Fixes\n\n* Prevent text from hiding behind navbar in Android ([#2914](https://github.com/standardnotes/app/issues/2914)) ([d02e5ca](https://github.com/standardnotes/app/commit/d02e5cab7462ea4754a3e650be571a16f6c9c7b4))",
"parsed": {
"_": [
"Prevent text from hiding behind navbar in Android (#2914) (d02e5ca)"
],
"Bug Fixes": [
"Prevent text from hiding behind navbar in Android (#2914) (d02e5ca)"
]
}
},
{
"version": "3.198.4",
"title": "[3.198.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-04)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift ([#2912](https://github.com/standardnotes/app/issues/2912)) ([117781b](https://github.com/standardnotes/app/commit/117781bb3655a2bd6b9b0ca5a4d12f7bbefd164e))",
"parsed": {
"_": [
"Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift (#2912) (117781b)"
],
"Bug Fixes": [
"Fixed issue where safe area insets were not always applying properly on iOS, causing a UI shift (#2912) (117781b)"
]
}
},
{
"version": "3.198.3",
"title": "[3.198.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-07-01)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.2",
"title": "[3.198.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-26)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.1",
"title": "[3.198.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.198.0",
"title": "[3.198.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-24)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issue with UI sometimes getting shifted up on iOS ([c050a2c](https://github.com/standardnotes/app/commit/c050a2cd339bb7a8fd482904216de1db2b8fe568))\n\n### Features\n\n* Tag search will now only show the direct tag results instead of also showing the parent and siblings ([#2906](https://github.com/standardnotes/app/issues/2906)) ([caa8eff](https://github.com/standardnotes/app/commit/caa8eff216b2d7a47f849f85f1eb2248eea10c62))",
"parsed": {
"_": [
"Fixed issue with UI sometimes getting shifted up on iOS (c050a2c)",
"Tag search will now only show the direct tag results instead of also showing the parent and siblings (#2906) (caa8eff)"
],
"Bug Fixes": [
"Fixed issue with UI sometimes getting shifted up on iOS (c050a2c)"
],
"Features": [
"Tag search will now only show the direct tag results instead of also showing the parent and siblings (#2906) (caa8eff)"
]
}
},
{
"version": "3.197.4",
"title": "[3.197.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-22)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.197.3",
"title": "[3.197.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issue where Android app would crash on screen rotation ([#2905](https://github.com/standardnotes/app/issues/2905)) ([9c1bb35](https://github.com/standardnotes/app/commit/9c1bb353550c0256b4e6dcbee1e087cc9ffdd628))",
"parsed": {
"_": [
"Fixed issue where Android app would crash on screen rotation (#2905) (9c1bb35)"
],
"Bug Fixes": [
"Fixed issue where Android app would crash on screen rotation (#2905) (9c1bb35)"
]
}
},
{
"version": "3.197.2",
"title": "[3.197.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-19)",
+3 -3
View File
@@ -1,9 +1,9 @@
{
"name": "@standardnotes/web",
"version": "3.197.2",
"version": "3.198.17",
"license": "AGPL-3.0",
"main": "dist/app.js",
"author": "Standard Notes",
"author": "Standard Notes.",
"private": true,
"files": [
"dist"
@@ -33,7 +33,7 @@
"@standardnotes/authenticator": "^2.4.0",
"@standardnotes/autobiography-theme": "^1.2.7",
"@standardnotes/bold-editor": "^1.6.4",
"@standardnotes/classic-code-editor": "^1.5.7",
"@standardnotes/classic-code-editor": "^1.6.2",
"@standardnotes/dynamic-theme": "^1.2.8",
"@standardnotes/filepicker": "workspace:*",
"@standardnotes/focus-theme": "^1.4.6",
@@ -361,12 +361,6 @@ export class WebApplication extends SNApplication implements WebApplicationInter
setCustomViewportHeight(100, 'vh', true)
}
handleUpdateSafeAreaInsets(insets: { top: number; bottom: number; left: number; right: number }) {
for (const [key, value] of Object.entries(insets)) {
document.documentElement.style.setProperty(`--safe-area-inset-${key}`, `${value}px`)
}
}
handleOpenFilePreviewEvent({ id }: { id: string }): void {
const file = this.items.findItem<FileItem>(id)
if (!file) {
@@ -75,6 +75,8 @@ const DecoratedInput = forwardRef(
<input
autoComplete={autocomplete ? 'on' : 'off'}
autoCorrect={autocomplete ? 'on' : 'off'}
autoCapitalize={autocomplete ? 'on' : 'off'}
autoFocus={autofocus}
className={`${computedClassNames.input} ${disabled ? computedClassNames.disabled : ''} ${className?.input}`}
data-lpignore={type !== 'password' ? true : false}
@@ -30,6 +30,8 @@ const DecoratedPasswordInput = forwardRef((props: DecoratedInputProps, ref: Ref<
{...props}
ref={ref}
type={isToggled ? 'text' : 'password'}
autocomplete={false}
spellcheck={false}
right={[...rightSideDecorations, <Toggle isToggled={isToggled} setIsToggled={setIsToggled} />]}
/>
)
@@ -56,8 +56,10 @@ const LinkedItemBubble = ({
setShowUnlinkButton(true)
}
const onBlur = () => {
setShowUnlinkButton(false)
const onBlur: React.FocusEventHandler<HTMLButtonElement | HTMLAnchorElement> = (event) => {
if (!event.currentTarget.contains(event.relatedTarget)) {
setShowUnlinkButton(false)
}
setWasClicked(false)
}
@@ -131,7 +133,7 @@ const LinkedItemBubble = ({
<button
ref={(el) => (unlinkButtonRef.current = el as HTMLElement)}
role="button"
className="-mr-1 ml-2 inline-flex cursor-pointer border-0 bg-transparent p-0 h-[1.15em] align-middle"
className="-mr-1 ml-2 inline-flex h-[1.15em] cursor-pointer border-0 bg-transparent p-0 align-middle"
onClick={onUnlinkClick}
>
<Icon type="close" className="text-neutral hover:text-info" size="small" />
@@ -6,11 +6,9 @@ import { useAvailableSafeAreaPadding } from '@/Hooks/useSafeAreaPadding'
export const EditorContentWithSafeAreaPadding = forwardRef(function EditorContentWithSafeAreaPadding(
{
isNoteLocked,
editorLineWidth,
children,
}: {
isNoteLocked: boolean
editorLineWidth: EditorLineWidth
children: NonNullable<ReactNode>
},
@@ -24,7 +22,7 @@ export const EditorContentWithSafeAreaPadding = forwardRef(function EditorConten
className={classNames(
ElementIds.EditorContent,
'z-editor-content overflow-auto sm:[&>*]:mx-[var(--editor-margin)] sm:[&>*]:max-w-[var(--editor-max-width)]',
hasBottomInset && isNoteLocked && 'pb-safe-bottom',
hasBottomInset && 'pb-safe-bottom',
)}
style={
{
@@ -955,11 +955,7 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
</div>
)}
<EditorContentWithSafeAreaPadding
isNoteLocked={this.state.noteLocked}
editorLineWidth={this.state.editorLineWidth}
ref={this.editorContentRef}
>
<EditorContentWithSafeAreaPadding editorLineWidth={this.state.editorLineWidth} ref={this.editorContentRef}>
{editorMode === 'component' && this.state.editorComponentViewer && (
<div className="component-view relative flex-grow">
{this.state.paneGestureEnabled && <div className="absolute left-0 top-0 h-full w-[20px] md:hidden" />}
@@ -190,8 +190,11 @@ export const PlainEditor = forwardRef<PlainEditorInterface, Props>(
useEffect(() => {
reloadPreferences()
return application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
reloadPreferences()
return application.addEventObserver(async (event) => {
const events = [ApplicationEvent.PreferencesChanged, ApplicationEvent.LocalPreferencesChanged]
if (events.includes(event)) {
reloadPreferences()
}
})
}, [reloadPreferences, application])
@@ -11,6 +11,7 @@ import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/u
import { SupportsPassiveListeners } from '@/Constants/Constants'
import { useLifecycleAnimation } from '@/Hooks/useLifecycleAnimation'
import { getScrollParent } from '@/Utils'
import { useAvailableSafeAreaPadding } from '@/Hooks/useSafeAreaPadding'
const DisableScroll = () => {
useDisableBodyScrollOnMobile()
@@ -63,6 +64,8 @@ const MobilePopoverContent = ({
},
})
const { hasBottomInset } = useAvailableSafeAreaPadding()
useEffect(() => {
if (!element) {
return
@@ -181,7 +184,8 @@ const MobilePopoverContent = ({
<div
ref={mergeRefs([setPopoverElement, addCloseMethod])}
className={classNames(
'z-1 absolute bottom-0 flex max-h-[calc(100%_-_max(var(--safe-area-inset-top),2rem))] min-h-[40%] w-full flex-col rounded-t-xl bg-passive-5 pb-safe-bottom',
'z-1 absolute bottom-0 flex max-h-[calc(100%_-_max(var(--safe-area-inset-top),2rem))] min-h-[40%] w-full flex-col rounded-t-xl bg-passive-5',
hasBottomInset && 'pb-safe-bottom',
forceFullHeightOnMobile && 'h-full',
)}
style={{
@@ -10,13 +10,13 @@ const RecoveryCodeBanner = ({ application }: { application: WebApplication }) =>
const [errorMessage, setErrorMessage] = useState<string>()
const onClickShow = async () => {
const authorized = await application.challenges.promptForAccountPassword()
const password = await application.challenges.promptForAccountPassword()
if (!authorized) {
if (!password) {
return
}
const recoveryCodeOrError = await application.getRecoveryCodes.execute()
const recoveryCodeOrError = await application.getRecoveryCodes.execute({ password })
if (recoveryCodeOrError.isFailed()) {
setErrorMessage(recoveryCodeOrError.getError())
return
@@ -12,9 +12,6 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin'
import { ListPlugin } from '@lexical/react/LexicalListPlugin'
import { EditorState, LexicalEditor } from 'lexical'
import HorizontalRulePlugin from './Plugins/HorizontalRulePlugin'
import TwitterPlugin from './Plugins/TwitterPlugin'
import YouTubePlugin from './Plugins/YouTubePlugin'
import AutoEmbedPlugin from './Plugins/AutoEmbedPlugin'
import CollapsiblePlugin from './Plugins/CollapsiblePlugin'
import DraggableBlockPlugin from './Plugins/DraggableBlockPlugin'
import CodeHighlightPlugin from './Plugins/CodeHighlightPlugin'
@@ -125,9 +122,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
<CodeHighlightPlugin />
<LinkPlugin />
<HashtagPlugin />
<AutoEmbedPlugin />
<TwitterPlugin />
<YouTubePlugin />
<CollapsiblePlugin />
<TabIndentationPlugin />
<RemoveBrokenTablesPlugin />
@@ -20,22 +20,6 @@ import type {
import { BlockWithAlignableContents } from '@lexical/react/LexicalBlockWithAlignableContents'
import { DecoratorBlockNode, SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode'
import { useCallback, useEffect, useRef, useState } from 'react'
const WIDGET_SCRIPT_URL = '/dist/twitter-widgets.js'
type TweetComponentProps = Readonly<{
className: Readonly<{
base: string
focus: string
}>
format: ElementFormatType | null
loadingComponent?: JSX.Element | string
nodeKey: NodeKey
onError?: (error: string) => void
onLoad?: () => void
tweetID: string
}>
function convertTweetElement(domNode: HTMLDivElement): DOMConversionOutput | null {
const id = domNode.getAttribute('data-lexical-tweet-id')
@@ -46,71 +30,6 @@ function convertTweetElement(domNode: HTMLDivElement): DOMConversionOutput | nul
return null
}
let isTwitterScriptLoading = true
function TweetComponent({
className,
format,
loadingComponent,
nodeKey,
onError,
onLoad,
tweetID,
}: TweetComponentProps) {
const containerRef = useRef<HTMLDivElement | null>(null)
const previousTweetIDRef = useRef<string>('')
const [isTweetLoading, setIsTweetLoading] = useState(false)
const createTweet = useCallback(async () => {
try {
// @ts-expect-error Twitter is attached to the window.
await window.twttr.widgets.createTweet(tweetID, containerRef.current)
setIsTweetLoading(false)
isTwitterScriptLoading = false
if (onLoad) {
onLoad()
}
} catch (error) {
if (onError) {
onError(String(error))
}
}
}, [onError, onLoad, tweetID])
useEffect(() => {
if (tweetID !== previousTweetIDRef.current) {
setIsTweetLoading(true)
if (isTwitterScriptLoading) {
const script = document.createElement('script')
script.src = WIDGET_SCRIPT_URL
script.async = true
document.body?.appendChild(script)
script.onload = createTweet
if (onError) {
script.onerror = onError as OnErrorEventHandler
}
} else {
createTweet().catch(console.error)
}
if (previousTweetIDRef) {
previousTweetIDRef.current = tweetID
}
}
}, [createTweet, onError, tweetID])
return (
<BlockWithAlignableContents className={className} format={format} nodeKey={nodeKey}>
{isTweetLoading ? loadingComponent : null}
<div style={{ display: 'inline-block', width: '550px' }} ref={containerRef} />
</BlockWithAlignableContents>
)
}
export type SerializedTweetNode = Spread<
{
id: string
@@ -172,7 +91,7 @@ export class TweetNode extends DecoratorBlockNode {
}
override getTextContent(_includeInert?: boolean | undefined, _includeDirectionless?: false | undefined): string {
return `https://twitter.com/i/web/status/${this.__id}`
return `https://x.com/i/web/status/${this.__id}`
}
override decorate(_: LexicalEditor, config: EditorConfig): JSX.Element {
@@ -181,14 +100,13 @@ export class TweetNode extends DecoratorBlockNode {
base: embedBlockTheme.base || '',
focus: embedBlockTheme.focus || '',
}
const link = this.getTextContent()
return (
<TweetComponent
className={className}
format={this.__format}
loadingComponent="Loading..."
nodeKey={this.getKey()}
tweetID={this.__id}
/>
<BlockWithAlignableContents className={className} format={this.__format} nodeKey={this.getKey()}>
<a href={link} target="_blank" rel="noreferrer noopener">
{link}
</a>
</BlockWithAlignableContents>
)
}
@@ -1,306 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalEditor } from 'lexical'
import {
AutoEmbedOption,
EmbedConfig,
EmbedMatchResult,
LexicalAutoEmbedPlugin,
URL_MATCHER,
} from '@lexical/react/LexicalAutoEmbedPlugin'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { useCallback, useMemo, useState } from 'react'
import * as ReactDOM from 'react-dom'
import useModal from '../../Lexical/Hooks/useModal'
import { INSERT_TWEET_COMMAND } from '../TwitterPlugin'
import { INSERT_YOUTUBE_COMMAND } from '../YouTubePlugin'
import { classNames } from '@standardnotes/snjs'
import DecoratedInput from '@/Components/Input/DecoratedInput'
import Button from '@/Components/Button/Button'
import { isMobileScreen } from '../../../../Utils'
interface PlaygroundEmbedConfig extends EmbedConfig {
// Human readable name of the embeded content e.g. Tweet or Google Map.
contentName: string
// Icon for display.
icon?: JSX.Element
iconName: string
// An example of a matching url https://twitter.com/jack/status/20
exampleUrl: string
// For extra searching.
keywords: Array<string>
// Embed a Figma Project.
description?: string
}
export const YoutubeEmbedConfig: PlaygroundEmbedConfig = {
contentName: 'Youtube Video',
exampleUrl: 'https://www.youtube.com/watch?v=jNQXAC9IVRw',
// Icon for display.
icon: <i className="icon youtube" />,
iconName: 'youtube',
insertNode: (editor: LexicalEditor, result: EmbedMatchResult) => {
editor.dispatchCommand(INSERT_YOUTUBE_COMMAND, result.id)
},
keywords: ['youtube', 'video'],
// Determine if a given URL is a match and return url data.
parseUrl: (url: string) => {
const match = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/.exec(url)
const id = match ? (match?.[2].length === 11 ? match[2] : null) : null
if (id != null) {
return {
id,
url,
}
}
return null
},
type: 'youtube-video',
}
export const TwitterEmbedConfig: PlaygroundEmbedConfig = {
// e.g. Tweet or Google Map.
contentName: 'Tweet',
exampleUrl: 'https://twitter.com/jack/status/20',
// Icon for display.
icon: <i className="icon tweet" />,
iconName: 'tweet',
// Create the Lexical embed node from the url data.
insertNode: (editor: LexicalEditor, result: EmbedMatchResult) => {
editor.dispatchCommand(INSERT_TWEET_COMMAND, result.id)
},
// For extra searching.
keywords: ['tweet', 'twitter'],
// Determine if a given URL is a match and return url data.
parseUrl: (text: string) => {
const match = /^https:\/\/twitter\.com\/(#!\/)?(\w+)\/status(es)*\/(\d+)$/.exec(text)
if (match != null) {
return {
id: match[4],
url: match[0],
}
}
return null
},
type: 'tweet',
}
export const EmbedConfigs = [TwitterEmbedConfig, YoutubeEmbedConfig]
function AutoEmbedMenuItem({
index,
isSelected,
onClick,
onMouseEnter,
option,
}: {
index: number
isSelected: boolean
onClick: () => void
onMouseEnter: () => void
option: AutoEmbedOption
}) {
return (
<li
key={option.key}
tabIndex={-1}
className={classNames('cursor-pointer rounded px-2 py-1', isSelected && 'bg-info-backdrop')}
ref={option.setRefElement}
role="option"
aria-selected={isSelected}
id={'typeahead-item-' + index}
onMouseEnter={onMouseEnter}
onClick={onClick}
>
<span className="text">{option.title}</span>
</li>
)
}
function AutoEmbedMenu({
options,
selectedItemIndex,
onOptionClick,
onOptionMouseEnter,
}: {
selectedItemIndex: number | null
onOptionClick: (option: AutoEmbedOption, index: number) => void
onOptionMouseEnter: (index: number) => void
options: Array<AutoEmbedOption>
}) {
return (
<div className="typeahead-popover min-w-max rounded border border-border bg-default p-1">
<ul className="list-none">
{options.map((option: AutoEmbedOption, i: number) => (
<AutoEmbedMenuItem
index={i}
isSelected={selectedItemIndex === i}
onClick={() => onOptionClick(option, i)}
onMouseEnter={() => onOptionMouseEnter(i)}
key={option.key}
option={option}
/>
))}
</ul>
</div>
)
}
const debounce = (callback: (text: string) => void, delay: number) => {
let timeoutId: number
return (text: string) => {
window.clearTimeout(timeoutId)
timeoutId = window.setTimeout(() => {
callback(text)
}, delay)
}
}
export function AutoEmbedDialog({
embedConfig,
onClose,
}: {
embedConfig: PlaygroundEmbedConfig
onClose: () => void
}): JSX.Element {
const [text, setText] = useState('')
const [editor] = useLexicalComposerContext()
const [embedResult, setEmbedResult] = useState<EmbedMatchResult | null>(null)
const validateText = useMemo(
() =>
debounce((inputText: string) => {
const urlMatch = URL_MATCHER.exec(inputText)
if (embedConfig != null && inputText != null && urlMatch != null) {
void Promise.resolve(embedConfig.parseUrl(inputText)).then((parseResult) => {
setEmbedResult(parseResult)
})
} else if (embedResult != null) {
setEmbedResult(null)
}
}, 200),
[embedConfig, embedResult],
)
const onClick = () => {
if (embedResult != null) {
embedConfig.insertNode(editor, embedResult)
onClose()
}
}
const focusOnMount = useCallback((element: HTMLInputElement | null) => {
if (element) {
setTimeout(() => element.focus())
}
}, [])
return (
<>
<label className="flex flex-col gap-1.5">
URL:
<DecoratedInput
value={text}
onChange={(text) => {
setText(text)
validateText(text)
}}
ref={focusOnMount}
/>
</label>
<div className="mt-2.5 flex justify-end">
<Button disabled={!embedResult} onClick={onClick} small={isMobileScreen()}>
Embed
</Button>
</div>
</>
)
}
export default function AutoEmbedPlugin(): JSX.Element {
const [modal, showModal] = useModal()
const openEmbedModal = (embedConfig: PlaygroundEmbedConfig) => {
showModal(`Embed ${embedConfig.contentName}`, (onClose) => (
<AutoEmbedDialog embedConfig={embedConfig} onClose={onClose} />
))
}
const getMenuOptions = (activeEmbedConfig: PlaygroundEmbedConfig, embedFn: () => void, dismissFn: () => void) => {
return [
new AutoEmbedOption('Dismiss', {
onSelect: dismissFn,
}),
new AutoEmbedOption(`Embed ${activeEmbedConfig.contentName}`, {
onSelect: embedFn,
}),
]
}
return (
<>
{modal}
<LexicalAutoEmbedPlugin<PlaygroundEmbedConfig>
embedConfigs={EmbedConfigs}
onOpenEmbedModalForConfig={openEmbedModal}
getMenuOptions={getMenuOptions}
menuRenderFn={(anchorElementRef, { selectedIndex, options, selectOptionAndCleanUp, setHighlightedIndex }) => {
return anchorElementRef.current
? ReactDOM.createPortal(
<div
className="typeahead-popover auto-embed-menu"
style={{
marginLeft: anchorElementRef.current.style.width,
}}
>
<AutoEmbedMenu
options={options}
selectedItemIndex={selectedIndex}
onOptionClick={(option: AutoEmbedOption, index: number) => {
setHighlightedIndex(index)
selectOptionAndCleanUp(option)
}}
onOptionMouseEnter={(index: number) => {
setHighlightedIndex(index)
}}
/>
</div>,
anchorElementRef.current,
)
: null
}}
/>
</>
)
}
@@ -28,7 +28,6 @@ import { GetCodeBlockOption } from '../Blocks/Code'
import { GetQuoteBlockOption } from '../Blocks/Quote'
import { GetDividerBlockOption } from '../Blocks/Divider'
import { GetCollapsibleBlockOption } from '../Blocks/Collapsible'
import { GetEmbedsBlockOptions } from '../Blocks/Embeds'
import { GetUploadFileOption } from '../Blocks/File'
export default function BlockPickerMenuPlugin({ popoverZIndex }: { popoverZIndex?: string }): JSX.Element {
@@ -72,7 +71,6 @@ export default function BlockPickerMenuPlugin({ popoverZIndex }: { popoverZIndex
GetJustifyAlignBlockOption(editor),
GetPasswordBlockOption(editor),
GetCollapsibleBlockOption(editor),
...GetEmbedsBlockOptions(editor),
]
const dynamicOptions = [
@@ -1,25 +0,0 @@
import { LexicalEditor } from 'lexical'
import { INSERT_EMBED_COMMAND } from '@lexical/react/LexicalAutoEmbedPlugin'
import { EmbedConfigs } from '../AutoEmbedPlugin'
import { LexicalIconName } from '@/Components/Icon/LexicalIcons'
import { BlockPickerOption } from '../BlockPickerPlugin/BlockPickerOption'
export function GetEmbedsBlocks(editor: LexicalEditor) {
return EmbedConfigs.map((embedConfig) => ({
name: `Embed ${embedConfig.contentName}`,
iconName: embedConfig.iconName as LexicalIconName,
keywords: [...embedConfig.keywords, 'embed'],
onSelect: () => editor.dispatchCommand(INSERT_EMBED_COMMAND, embedConfig.type),
}))
}
export function GetEmbedsBlockOptions(editor: LexicalEditor) {
return GetEmbedsBlocks(editor).map(
(block) =>
new BlockPickerOption(block.name, {
iconName: block.iconName as LexicalIconName,
keywords: block.keywords,
onSelect: block.onSelect,
}),
)
}
@@ -30,15 +30,11 @@ export function BubbleComponent({ itemUuid, node }: BubbleComponentProps) {
[toggleAppPane, linkingController],
)
const unlinkPressed = useCallback(
async (itemToUnlink: LinkableItem) => {
linkingController.unlinkItemFromSelectedItem(itemToUnlink).catch(console.error)
editor.update(() => {
node.remove()
})
},
[linkingController, node, editor],
)
const unlinkPressed = useCallback(async () => {
editor.update(() => {
node.remove()
})
}, [linkingController, node, editor])
if (!item) {
return <div>Unable to find item {itemUuid}</div>
@@ -32,13 +32,7 @@ export function ItemSelectionItemComponent({ index, isSelected, onClick, onMouse
onClick={onClick}
>
{option.item && <LinkedItemMeta item={option.item} searchQuery={searchQuery} />}
{!option.item && (
<LinkedItemSearchResultsAddTagOption
searchQuery={searchQuery}
onClickCallback={onClick}
isFocused={isSelected}
/>
)}
{!option.item && <LinkedItemSearchResultsAddTagOption searchQuery={searchQuery} isFocused={isSelected} />}
</li>
)
}
@@ -1,39 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { $insertNodeToNearestRoot } from '@lexical/utils'
import { COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand } from 'lexical'
import { useEffect } from 'react'
import { $createTweetNode, TweetNode } from '../../Lexical/Nodes/TweetNode'
export const INSERT_TWEET_COMMAND: LexicalCommand<string> = createCommand('INSERT_TWEET_COMMAND')
export default function TwitterPlugin(): JSX.Element | null {
const [editor] = useLexicalComposerContext()
useEffect(() => {
if (!editor.hasNodes([TweetNode])) {
throw new Error('TwitterPlugin: TweetNode not registered on editor')
}
return editor.registerCommand<string>(
INSERT_TWEET_COMMAND,
(payload) => {
const tweetNode = $createTweetNode(payload)
$insertNodeToNearestRoot(tweetNode)
return true
},
COMMAND_PRIORITY_EDITOR,
)
}, [editor])
return null
}
@@ -1,39 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { $insertNodeToNearestRoot } from '@lexical/utils'
import { COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand } from 'lexical'
import { useEffect } from 'react'
import { $createYouTubeNode, YouTubeNode } from '../../Lexical/Nodes/YouTubeNode'
export const INSERT_YOUTUBE_COMMAND: LexicalCommand<string> = createCommand('INSERT_YOUTUBE_COMMAND')
export default function YouTubePlugin(): JSX.Element | null {
const [editor] = useLexicalComposerContext()
useEffect(() => {
if (!editor.hasNodes([YouTubeNode])) {
throw new Error('YouTubePlugin: YouTubeNode not registered on editor')
}
return editor.registerCommand<string>(
INSERT_YOUTUBE_COMMAND,
(payload) => {
const youTubeNode = $createYouTubeNode(payload)
$insertNodeToNearestRoot(youTubeNode)
return true
},
COMMAND_PRIORITY_EDITOR,
)
}, [editor])
return null
}
@@ -6,16 +6,26 @@ import { TagListSectionType } from './TagListSection'
import { TagsListItem } from './TagsListItem'
import { useApplication } from '../ApplicationProvider'
import { useListKeyboardNavigation } from '@/Hooks/useListKeyboardNavigation'
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
type Props = {
type: TagListSectionType
}
function getAllTagsForType(controller: NavigationController, type: TagListSectionType) {
if (type === 'all') {
if (controller.isSearching) {
return controller.tags
}
return controller.allLocalRootTags
}
return controller.starredTags
}
const TagsList: FunctionComponent<Props> = ({ type }: Props) => {
const application = useApplication()
const allTags =
type === 'all' ? application.navigationController.allLocalRootTags : application.navigationController.starredTags
const allTags = getAllTagsForType(application.navigationController, type)
const openTagContextMenu = useCallback(
(x: number, y: number) => {
@@ -26,6 +26,8 @@ import { log, LoggingDomain } from '@/Logging'
import { NoteDragDataFormat, TagDragDataFormat } from './DragNDrop'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { useApplication } from '../ApplicationProvider'
import { mergeRefs } from '../../Hooks/mergeRefs'
import { getTitleForLinkedTag } from '../../Utils/Items/Display/getTitleForLinkedTag'
type Props = {
tag: SNTag
@@ -46,6 +48,8 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const [title, setTitle] = useState(tag.title || '')
const [subtagTitle, setSubtagTitle] = useState('')
const tagRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
const subtagInputRef = useRef<HTMLInputElement>(null)
const menuButtonRef = useRef<HTMLAnchorElement>(null)
@@ -75,6 +79,8 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const [isBeingDraggedOver, setIsBeingDraggedOver] = useState(false)
const tagHierarchyPrefix = navigationController.isSearching && getTitleForLinkedTag(tag, application)?.titlePrefix
useEffect(() => {
if (!hadChildren && hasChildren) {
setShowChildren(true)
@@ -117,6 +123,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
const selectCurrentTag = useCallback(async () => {
await navigationController.setSelectedTag(tag, type, {
userTriggered: true,
scrollIntoView: false,
})
}, [navigationController, tag, type])
const clearSearchAndSelectCurrentTag = useCallback(async () => {
if (!navigationController.isSearching) {
return
}
navigationController.setSearchQuery('')
await navigationController.setSelectedTag(tag, type, {
userTriggered: true,
scrollIntoView: true,
})
}, [navigationController, tag, type])
@@ -196,8 +214,6 @@ export const TagsListItem: FunctionComponent<Props> = observer(
[navigationController, onContextMenu, tag, type],
)
const tagRef = useRef<HTMLDivElement>(null)
const { addDragTarget, removeDragTarget } = useFileDragNDrop()
useEffect(() => {
@@ -292,6 +308,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
isBeingDraggedOver && 'is-drag-over',
)}
onClick={selectCurrentTag}
onDoubleClick={clearSearchAndSelectCurrentTag}
onKeyDown={(event) => {
if (event.key === KeyboardKey.Enter || event.key === KeyboardKey.Space) {
selectCurrentTag().catch(console.error)
@@ -301,7 +318,18 @@ export const TagsListItem: FunctionComponent<Props> = observer(
setTagExpanded(true)
}
}}
ref={tagRef}
ref={mergeRefs([
tagRef,
function scrollIntoViewIfNeeded(el) {
if (!el || navigationController.tagToScrollIntoView !== tag) {
return
}
el.scrollIntoView({
block: 'center',
})
navigationController.tagToScrollIntoView = undefined
},
])}
style={{
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
@@ -330,9 +358,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(
{isEditing && (
<input
className={
'title editing overflow-hidden text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item'
}
className="title editing min-w-0 overflow-hidden text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item"
id={`react-tag-${tag.uuid}-${type}`}
onBlur={onBlur}
onInput={onInput}
@@ -346,11 +372,10 @@ export const TagsListItem: FunctionComponent<Props> = observer(
{!isEditing && (
<>
<div
className={
'title overflow-hidden text-left text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item'
}
className="title overflow-hidden text-left text-mobile-navigation-list-item focus:shadow-none focus:outline-none lg:text-navigation-list-item"
id={`react-tag-${tag.uuid}-${type}`}
>
{tagHierarchyPrefix && <span className="opacity-50">{tagHierarchyPrefix}</span>}
{title}
</div>
</>
@@ -1,7 +1,6 @@
import TagsList from '@/Components/Tags/TagsList'
import { ApplicationEvent } from '@/__mocks__/@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
import { FunctionComponent } from 'react'
import TagsSectionAddButton from './TagsSectionAddButton'
import TagsSectionTitle from './TagsSectionTitle'
import { useApplication } from '../ApplicationProvider'
@@ -9,47 +8,6 @@ import { useApplication } from '../ApplicationProvider'
const TagsSection: FunctionComponent = () => {
const application = useApplication()
const [hasMigration, setHasMigration] = useState<boolean>(false)
const checkIfMigrationNeeded = useCallback(() => {
setHasMigration(application.items.hasTagsNeedingFoldersMigration())
}, [application])
useEffect(() => {
const removeObserver = application.addEventObserver(async (event) => {
const events = [ApplicationEvent.CompletedInitialSync, ApplicationEvent.SignedIn]
if (events.includes(event)) {
checkIfMigrationNeeded()
}
})
return () => {
removeObserver()
}
}, [application, checkIfMigrationNeeded])
const runMigration = useCallback(async () => {
if (
await application.alerts.confirm(
'<i>Introducing native, built-in nested tags without requiring the legacy Folders extension.</i><br/></br> ' +
" To get started, we'll need to migrate any tags containing a dot character to the new system.<br/></br> " +
' This migration will convert any tags with dots appearing in their name into a natural' +
' hierarchy that is compatible with the new nested tags feature.' +
' Running this migration will remove any "." characters appearing in tag names.',
'New: Folders to Nested Tags',
'Run Migration',
)
) {
application.mutator
.migrateTagsToFolders()
.then(() => {
void application.sync.sync()
checkIfMigrationNeeded()
})
.catch(console.error)
}
}, [application, checkIfMigrationNeeded])
return (
<>
{application.navigationController.starredTags.length > 0 && (
@@ -68,11 +26,7 @@ const TagsSection: FunctionComponent = () => {
<section>
<div className={'section-title-bar'}>
<div className="section-title-bar-header">
<TagsSectionTitle
features={application.featuresController}
hasMigration={hasMigration}
onClickMigration={runMigration}
/>
<TagsSectionTitle features={application.featuresController} />
{!application.navigationController.isSearching && (
<TagsSectionAddButton tags={application.navigationController} features={application.featuresController} />
)}
@@ -7,11 +7,9 @@ import StyledTooltip from '../StyledTooltip/StyledTooltip'
type Props = {
features: FeaturesController
hasMigration: boolean
onClickMigration: () => void
}
const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, onClickMigration }) => {
const TagsSectionTitle: FunctionComponent<Props> = ({ features }) => {
const entitledToFolders = features.hasFolders
const modal = usePremiumModal()
@@ -24,11 +22,6 @@ const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, on
<>
<div className="title text-base md:text-sm">
<span className="font-bold">Folders</span>
{hasMigration && (
<label className="ml-1 cursor-pointer font-bold text-info" onClick={onClickMigration}>
Migration Available
</label>
)}
</div>
</>
)
@@ -59,6 +59,7 @@ export class NavigationController
previouslySelected_: AnyTag | undefined = undefined
editing_: SNTag | SmartView | undefined = undefined
addingSubtagTo: SNTag | undefined = undefined
tagToScrollIntoView: AnyTag | undefined = undefined
contextMenuOpen = false
contextMenuClickLocation: { x: number; y: number } = { x: 0, y: 0 }
@@ -390,10 +391,14 @@ export class NavigationController
return []
}
if (this.isSearching) {
return []
}
const children = this.items.getTagChildren(tag)
const childrenUuids = children.map((childTag) => childTag.uuid)
const childrenTags = this.isSearching ? children : this.tags.filter((tag) => childrenUuids.includes(tag.uuid))
const childrenTags = this.tags.filter((tag) => childrenUuids.includes(tag.uuid))
return childrenTags
}
@@ -479,8 +484,9 @@ export class NavigationController
public async setSelectedTag(
tag: AnyTag | undefined,
location: TagListSectionType,
{ userTriggered } = { userTriggered: false },
options?: { userTriggered: boolean; scrollIntoView?: boolean },
) {
const { userTriggered = false, scrollIntoView = false } = options || {}
if (tag && tag.conflictOf) {
this._changeAndSaveItem
.execute(tag, (mutator) => {
@@ -512,6 +518,9 @@ export class NavigationController
},
InternalEventPublishStrategy.SEQUENCE,
)
if (userTriggered && scrollIntoView) {
this.tagToScrollIntoView = tag
}
})
}
@@ -678,6 +687,7 @@ export class NavigationController
searchQuery: {
query: this.searchQuery,
includeProtectedNoteText: false,
shouldCheckForSomeTagMatches: false,
},
})
this.reloadTags()
@@ -213,11 +213,15 @@ export class PaneController extends AbstractViewController implements InternalEv
const panes = this._panesForLayout.execute(layout).getValue()
if (panes.includes(AppPaneId.Items) && this.listPaneExplicitelyCollapsed) {
if (panes.includes(AppPaneId.Items) && this.listPaneExplicitelyCollapsed && layout !== PaneLayout.ItemSelection) {
removeFromArray(panes, AppPaneId.Items)
}
if (panes.includes(AppPaneId.Navigation) && this.navigationPaneExplicitelyCollapsed) {
if (
panes.includes(AppPaneId.Navigation) &&
this.navigationPaneExplicitelyCollapsed &&
layout !== PaneLayout.TagSelection
) {
removeFromArray(panes, AppPaneId.Navigation)
}

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