mirror of
https://github.com/standardnotes/app
synced 2026-09-18 15:13:58 -04:00
Compare commits
73
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b69691c0 | ||
|
|
54af28aa04 | ||
|
|
cf4d2196de | ||
|
|
abf14d1e50 | ||
|
|
86c00056bc | ||
|
|
f77a6a4480 | ||
|
|
98038da99f | ||
|
|
b9d7f36884 | ||
|
|
19831e834e | ||
|
|
7e50b864ef | ||
|
|
687668c8e2 | ||
|
|
d135e09bda | ||
|
|
f284111a0c | ||
|
|
be109a0f6b | ||
|
|
c08d9034e1 | ||
|
|
010864881d | ||
|
|
2b41c8337b | ||
|
|
45bcc0e0b1 | ||
|
|
d928477d82 | ||
|
|
b86aebb7ab | ||
|
|
3cce44f5ab | ||
|
|
ff80775cd6 | ||
|
|
c75f655ffe | ||
|
|
87cf17d02f | ||
|
|
0d17961570 | ||
|
|
63d84725d2 | ||
|
|
9583d0db44 | ||
|
|
fa4182ba9f | ||
|
|
259017bd39 | ||
|
|
f1f9070dcc | ||
|
|
6e6b5a017b | ||
|
|
e72648d8a0 | ||
|
|
fef887ec0d | ||
|
|
62713cc49d | ||
|
|
8016cb39e9 | ||
|
|
9259cc8f32 | ||
|
|
43d31d8bb4 | ||
|
|
092dc7957f | ||
|
|
77f8bf6368 | ||
|
|
1935c98cf0 | ||
|
|
c52030a525 | ||
|
|
74923a1f6b | ||
|
|
d02e5cab74 | ||
|
|
2459e06b19 | ||
|
|
d2d10eb747 | ||
|
|
117781bb36 | ||
|
|
07f45245a3 | ||
|
|
da22238ced | ||
|
|
44bfcb2d1b | ||
|
|
555453617d | ||
|
|
f9f069f31f | ||
|
|
f776cb30d4 | ||
|
|
c2bdff0794 | ||
|
|
becf5751b2 | ||
|
|
e06d1fcd4f | ||
|
|
44fba053b1 | ||
|
|
52b052fe84 | ||
|
|
caa8eff216 | ||
|
|
c050a2cd33 | ||
|
|
5f61500ee0 | ||
|
|
782af6ecdc | ||
|
|
c493b2c2ea | ||
|
|
9c1bb35355 | ||
|
|
ddaf52d57e | ||
|
|
b49f81bf1f | ||
|
|
125aad4b3d | ||
|
|
e2250600a8 | ||
|
|
974fcef288 | ||
|
|
7bce025efb | ||
|
|
57cb8445fd | ||
|
|
165fc695d1 | ||
|
|
6ea58ca33c | ||
|
|
f8223a884c |
@@ -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.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
-1
@@ -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"
|
||||
|
||||
@@ -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.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.26.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-05-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.26.89",
|
||||
"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
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,102 @@
|
||||
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.523](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.522](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.521](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.520](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/clipper",
|
||||
"description": "Web clipper browser extension for Standard Notes",
|
||||
"version": "1.1.520",
|
||||
"version": "1.1.544",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
|
||||
|
||||
@@ -3,6 +3,105 @@
|
||||
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
|
||||
|
||||
## [3.110.128](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.127](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.126](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.125](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)
|
||||
|
||||
**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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.110.125",
|
||||
"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",
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
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.21.108](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.107](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-05-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.21.107",
|
||||
"version": "1.21.111",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
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.28.128](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.127](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-04-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.28.127",
|
||||
"version": "1.28.131",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
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.20.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.20.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-05-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.20.10",
|
||||
"version": "1.20.14",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,118 @@
|
||||
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
|
||||
|
||||
## [3.58.185](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.184](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.183](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.182](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.58.181](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)
|
||||
|
||||
**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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.58.181",
|
||||
"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-*",
|
||||
@@ -63,7 +63,7 @@
|
||||
"react-native-flag-secure-android": "standardnotes/react-native-flag-secure-android#cb08e74583c22a5d912842459b35ebbbb4bcd852",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-iap": "^12.16.2",
|
||||
"react-native-keychain": "10.0.0",
|
||||
"react-native-keychain": "standardnotes/react-native-keychain#618c3e1f253e6980866ee02a80c3ea66fa6f5bad",
|
||||
"react-native-mmkv": "^3.2.0",
|
||||
"react-native-privacy-snapshot": "standardnotes/react-native-privacy-snapshot#653e904c90fc6f2b578da59138f2bfe5d7f942fe",
|
||||
"react-native-share": "^12.0.9",
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
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.57.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
### Features
|
||||
|
||||
* Added image alignment options and preference in Super notes ([#2903](https://github.com/standardnotes/app/issues/2903)) ([7bce025](https://github.com/standardnotes/app/commit/7bce025efbab6d57c4dabb8354d400c87eb90032))
|
||||
|
||||
## [1.56.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-05-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.56.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 {
|
||||
|
||||
@@ -43,6 +43,7 @@ export const PrefDefaults = {
|
||||
[PrefKey.SuperNoteExportEmbedBehavior]: 'reference',
|
||||
[PrefKey.SuperNoteExportUseMDFrontmatter]: true,
|
||||
[PrefKey.SuperNoteExportPDFPageSize]: 'A4',
|
||||
[PrefKey.SuperNoteImageAlignment]: 'left',
|
||||
[PrefKey.SystemViewPreferences]: {},
|
||||
[PrefKey.AuthenticatorNames]: '',
|
||||
[PrefKey.ComponentPreferences]: {},
|
||||
|
||||
@@ -36,6 +36,7 @@ export enum PrefKey {
|
||||
SuperNoteExportEmbedBehavior = 'superNoteExportEmbedBehavior',
|
||||
SuperNoteExportUseMDFrontmatter = 'superNoteExportUseMDFrontmatter',
|
||||
SuperNoteExportPDFPageSize = 'superNoteExportPDFPageSize',
|
||||
SuperNoteImageAlignment = 'superNoteImageAlignment',
|
||||
AuthenticatorNames = 'authenticatorNames',
|
||||
PaneGesturesEnabled = 'paneGesturesEnabled',
|
||||
ComponentPreferences = 'componentPreferences',
|
||||
@@ -101,4 +102,5 @@ export type PrefValue = {
|
||||
[PrefKey.AddImportsToTag]: boolean
|
||||
[PrefKey.AlwaysCreateNewTagForImports]: boolean
|
||||
[PrefKey.ExistingTagForImports]: string | undefined
|
||||
[PrefKey.SuperNoteImageAlignment]: 'left' | 'center' | 'right'
|
||||
}
|
||||
|
||||
@@ -3,6 +3,110 @@
|
||||
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.4.825](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.824](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.823](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.822](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.821](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.821",
|
||||
"version": "1.4.847",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -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.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.71.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.71.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-05-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.71.5",
|
||||
"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,
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
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
|
||||
|
||||
## [2.209.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.209.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-05-02)
|
||||
|
||||
**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
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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>>
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.209.8",
|
||||
"version": "2.209.13",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
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.38.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.38.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-05-02)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.38.6",
|
||||
"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>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.17.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.17.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2024-05-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/utils",
|
||||
"version": "1.17.13",
|
||||
"version": "1.17.14",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { sanitize } from 'dompurify'
|
||||
import { find, isArray, mergeWith, remove, uniq, uniqWith } from 'lodash'
|
||||
import { escape, find, isArray, mergeWith, remove, uniq, uniqWith } from 'lodash'
|
||||
import { AnyRecord } from '@standardnotes/common'
|
||||
|
||||
const collator = typeof Intl !== 'undefined' ? new Intl.Collator('en', { numeric: true }) : undefined
|
||||
@@ -612,6 +612,10 @@ export function sanitizeHtmlString(html: string): string {
|
||||
return sanitize(html)
|
||||
}
|
||||
|
||||
export function escapeHtmlString(html: string): string {
|
||||
return escape(html)
|
||||
}
|
||||
|
||||
let sharedDateFormatter: unknown
|
||||
export function dateToLocalizedString(date: Date): string {
|
||||
if (typeof Intl !== 'undefined' && Intl.DateTimeFormat && typeof navigator !== 'undefined') {
|
||||
|
||||
@@ -3,6 +3,130 @@
|
||||
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
|
||||
|
||||
## [3.197.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
# [3.197.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)
|
||||
|
||||
### Features
|
||||
|
||||
* Added image alignment options and preference in Super notes ([#2903](https://github.com/standardnotes/app/issues/2903)) ([7bce025](https://github.com/standardnotes/app/commit/7bce025efbab6d57c4dabb8354d400c87eb90032))
|
||||
|
||||
## [3.196.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.196.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
@@ -1,5 +1,310 @@
|
||||
{
|
||||
"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)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.197.1",
|
||||
"title": "[3.197.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-18)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.197.0",
|
||||
"title": "[3.197.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-16)",
|
||||
"date": null,
|
||||
"body": "### Features\n\n* Added image alignment options and preference in Super notes ([#2903](https://github.com/standardnotes/app/issues/2903)) ([7bce025](https://github.com/standardnotes/app/commit/7bce025efbab6d57c4dabb8354d400c87eb90032))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Added image alignment options and preference in Super notes (#2903) (7bce025)"
|
||||
],
|
||||
"Features": [
|
||||
"Added image alignment options and preference in Super notes (#2903) (7bce025)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.196.9",
|
||||
"title": "[3.196.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-12)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.196.8",
|
||||
"title": "[3.196.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-06-05)",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.196.8",
|
||||
"version": "3.198.17",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FunctionComponent, MouseEventHandler } from 'react'
|
||||
import { ComponentPropsWithoutRef, ForwardedRef, forwardRef, MouseEventHandler } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
|
||||
type Props = {
|
||||
interface Props extends ComponentPropsWithoutRef<'button'> {
|
||||
onClick: MouseEventHandler<HTMLButtonElement>
|
||||
className?: string
|
||||
icon: IconType
|
||||
@@ -12,32 +12,31 @@ type Props = {
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const IconButton: FunctionComponent<Props> = ({
|
||||
onClick,
|
||||
className = '',
|
||||
icon,
|
||||
title,
|
||||
focusable,
|
||||
iconClassName = '',
|
||||
disabled = false,
|
||||
}) => {
|
||||
const click: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
e.preventDefault()
|
||||
onClick(e)
|
||||
}
|
||||
const focusableClass = focusable ? '' : 'focus:shadow-none'
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
title={title}
|
||||
className={`no-border flex cursor-pointer flex-row items-center bg-transparent ${focusableClass} ${className}`}
|
||||
onClick={click}
|
||||
disabled={disabled}
|
||||
aria-label={title}
|
||||
>
|
||||
<Icon type={icon} className={iconClassName} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
const IconButton = forwardRef(
|
||||
(
|
||||
{ onClick, className = '', icon, title, focusable, iconClassName = '', disabled = false, ...rest }: Props,
|
||||
ref: ForwardedRef<HTMLButtonElement>,
|
||||
) => {
|
||||
const click: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
e.preventDefault()
|
||||
onClick(e)
|
||||
}
|
||||
const focusableClass = focusable ? '' : 'focus:shadow-none'
|
||||
return (
|
||||
<button
|
||||
{...rest}
|
||||
type="button"
|
||||
title={title}
|
||||
className={`no-border flex cursor-pointer flex-row items-center bg-transparent ${focusableClass} ${className}`}
|
||||
onClick={click}
|
||||
disabled={disabled}
|
||||
aria-label={title}
|
||||
ref={ref}
|
||||
>
|
||||
<Icon type={icon} className={iconClassName} />
|
||||
</button>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default IconButton
|
||||
|
||||
@@ -13,15 +13,23 @@ import { isFileTypePreviewable } from './isFilePreviewable'
|
||||
import PreviewComponent from './PreviewComponent'
|
||||
import Button from '../Button/Button'
|
||||
import { ProtectedIllustration } from '@standardnotes/icons'
|
||||
import { ImageZoomLevelProps } from './ImageZoomLevelProps'
|
||||
import { OptionalSuperEmbeddedImageProps } from './OptionalSuperEmbeddedImageProps'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
file: FileItem
|
||||
isEmbeddedInSuper?: boolean
|
||||
} & ImageZoomLevelProps
|
||||
} & OptionalSuperEmbeddedImageProps
|
||||
|
||||
const FilePreview = ({ file, application, isEmbeddedInSuper = false, imageZoomLevel, setImageZoomLevel }: Props) => {
|
||||
const FilePreview = ({
|
||||
file,
|
||||
application,
|
||||
isEmbeddedInSuper = false,
|
||||
imageZoomLevel,
|
||||
setImageZoomLevel,
|
||||
alignment,
|
||||
changeAlignment,
|
||||
}: Props) => {
|
||||
const [isAuthorized, setIsAuthorized] = useState(application.isAuthorizedToRenderItem(file))
|
||||
|
||||
const isFilePreviewable = useMemo(() => {
|
||||
@@ -137,6 +145,8 @@ const FilePreview = ({ file, application, isEmbeddedInSuper = false, imageZoomLe
|
||||
isEmbeddedInSuper={isEmbeddedInSuper}
|
||||
imageZoomLevel={imageZoomLevel}
|
||||
setImageZoomLevel={setImageZoomLevel}
|
||||
alignment={alignment}
|
||||
changeAlignment={changeAlignment}
|
||||
/>
|
||||
) : (
|
||||
<FilePreviewError
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { classNames, IconType } from '@standardnotes/snjs'
|
||||
import IconButton from '@/Components/Button/IconButton'
|
||||
import StyledTooltip from '@/Components/StyledTooltip/StyledTooltip'
|
||||
import { ElementFormatType } from 'lexical'
|
||||
|
||||
export function getCSSValueFromAlignment(format: ElementFormatType) {
|
||||
switch (format) {
|
||||
case 'start':
|
||||
case 'left':
|
||||
return 'start'
|
||||
case 'right':
|
||||
case 'end':
|
||||
return 'end'
|
||||
default:
|
||||
return 'center'
|
||||
}
|
||||
}
|
||||
|
||||
const Options = [
|
||||
{
|
||||
alignment: 'left',
|
||||
label: 'Left align',
|
||||
},
|
||||
{
|
||||
alignment: 'center',
|
||||
label: 'Center align',
|
||||
},
|
||||
{
|
||||
alignment: 'right',
|
||||
label: 'Right align',
|
||||
},
|
||||
]
|
||||
|
||||
export function ImageAlignmentOptions({
|
||||
alignment: currentAlignment,
|
||||
changeAlignment,
|
||||
}: {
|
||||
alignment: ElementFormatType
|
||||
changeAlignment: (format: ElementFormatType) => void
|
||||
}) {
|
||||
return Options.map(({ alignment, label }) => (
|
||||
<StyledTooltip label={label} key={alignment}>
|
||||
<IconButton
|
||||
className={classNames(
|
||||
alignment === currentAlignment && '!bg-info text-info-contrast',
|
||||
'rounded p-1 hover:bg-contrast',
|
||||
)}
|
||||
icon={`format-align-${alignment}` as IconType}
|
||||
title={label}
|
||||
focusable={true}
|
||||
onClick={(e) => {
|
||||
// the preventDefault and stopPropagation for these events are required
|
||||
// so that the keyboard doesn't jump when you select another option
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
changeAlignment(alignment as ElementFormatType)
|
||||
}}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
/>
|
||||
</StyledTooltip>
|
||||
))
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
import { classNames, IconType } from '@standardnotes/snjs'
|
||||
import { IconType, PrefKey } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
import IconButton from '../Button/IconButton'
|
||||
import { ImageZoomLevelProps } from './ImageZoomLevelProps'
|
||||
import IconButton from '@/Components/Button/IconButton'
|
||||
import { OptionalSuperEmbeddedImageProps } from './OptionalSuperEmbeddedImageProps'
|
||||
import usePreference from '@/Hooks/usePreference'
|
||||
import { getCSSValueFromAlignment, ImageAlignmentOptions } from './ImageAlignmentOptions'
|
||||
import { ElementIds } from '../../Constants/ElementIDs'
|
||||
import { getOverflows } from '@/Components/Popover/Utils/Collisions'
|
||||
|
||||
type Props = {
|
||||
objectUrl: string
|
||||
isEmbeddedInSuper: boolean
|
||||
} & ImageZoomLevelProps
|
||||
} & OptionalSuperEmbeddedImageProps
|
||||
|
||||
const MinimumZoomPercent = 10
|
||||
const DefaultZoomPercent = 100
|
||||
@@ -19,6 +23,8 @@ const ImagePreview: FunctionComponent<Props> = ({
|
||||
isEmbeddedInSuper,
|
||||
imageZoomLevel,
|
||||
setImageZoomLevel,
|
||||
alignment,
|
||||
changeAlignment,
|
||||
}) => {
|
||||
const [imageWidth, setImageWidth] = useState(0)
|
||||
const [imageHeight, setImageHeight] = useState<number>(0)
|
||||
@@ -48,8 +54,96 @@ const ImagePreview: FunctionComponent<Props> = ({
|
||||
|
||||
const widthIfEmbedded = imageWidth * (imageZoomPercent / PercentageDivisor)
|
||||
|
||||
const imageResizer = (
|
||||
<>
|
||||
<span className="mr-1.5">{isEmbeddedInSuper ? 'Size' : 'Zoom'}:</span>
|
||||
<IconButton
|
||||
className="rounded p-1 hover:bg-contrast"
|
||||
icon={'subtract' as IconType}
|
||||
title={isEmbeddedInSuper ? 'Decrease size' : 'Zoom Out'}
|
||||
focusable={true}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const newPercent = imageZoomPercent - ZoomPercentModifier
|
||||
if (newPercent >= ZoomPercentModifier) {
|
||||
setImageZoom(newPercent)
|
||||
} else {
|
||||
setImageZoom(imageZoomPercent)
|
||||
}
|
||||
}}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
/>
|
||||
{isZoomInputVisible ? (
|
||||
<div className="mx-2">
|
||||
<input
|
||||
type="number"
|
||||
className="w-10 bg-default text-center"
|
||||
defaultValue={imageZoomPercent}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation()
|
||||
if (event.key === 'Enter') {
|
||||
const value = parseInt(event.currentTarget.value)
|
||||
if (value >= MinimumZoomPercent && value <= MaximumZoomPercent) {
|
||||
setImageZoom(value)
|
||||
}
|
||||
setIsZoomInputVisible(false)
|
||||
}
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
setIsZoomInputVisible(false)
|
||||
const value = parseInt(event.currentTarget.value)
|
||||
if (value >= MinimumZoomPercent && value <= MaximumZoomPercent) {
|
||||
setImageZoom(value)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
%
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="mx-1 rounded px-1.5 py-1 hover:bg-contrast"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setIsZoomInputVisible((visible) => !visible)
|
||||
}}
|
||||
>
|
||||
{imageZoomPercent}%
|
||||
</button>
|
||||
)}
|
||||
<IconButton
|
||||
className="rounded p-1 hover:bg-contrast"
|
||||
icon="add"
|
||||
title={isEmbeddedInSuper ? 'Increase size' : 'Zoom In'}
|
||||
focusable={true}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setImageZoom(imageZoomPercent + ZoomPercentModifier)
|
||||
}}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
const defaultSuperImageAlignment = usePreference(PrefKey.SuperNoteImageAlignment)
|
||||
const finalAlignment = alignment || defaultSuperImageAlignment
|
||||
const justifyContent = isEmbeddedInSuper ? getCSSValueFromAlignment(finalAlignment) : 'center'
|
||||
|
||||
return (
|
||||
<div className="group relative flex h-full min-h-0 w-full items-center justify-center">
|
||||
<div
|
||||
className="group relative flex h-full min-h-0 w-full items-center"
|
||||
style={{ justifyContent }}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="relative flex h-full w-full items-center justify-center overflow-auto"
|
||||
style={{
|
||||
@@ -78,71 +172,37 @@ const ImagePreview: FunctionComponent<Props> = ({
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
isEmbeddedInSuper ? 'hidden focus-within:flex group-hover:flex' : '',
|
||||
'absolute bottom-6 left-1/2 flex -translate-x-1/2 items-center rounded border border-solid border-border bg-default px-3 py-1',
|
||||
)}
|
||||
>
|
||||
<span className="mr-1.5">{isEmbeddedInSuper ? 'Size' : 'Zoom'}:</span>
|
||||
<IconButton
|
||||
className="rounded p-1 hover:bg-contrast"
|
||||
icon={'subtract' as IconType}
|
||||
title={isEmbeddedInSuper ? 'Decrease size' : 'Zoom Out'}
|
||||
focusable={true}
|
||||
onClick={() => {
|
||||
const newPercent = imageZoomPercent - ZoomPercentModifier
|
||||
if (newPercent >= ZoomPercentModifier) {
|
||||
setImageZoom(newPercent)
|
||||
} else {
|
||||
setImageZoom(imageZoomPercent)
|
||||
{!isEmbeddedInSuper && (
|
||||
<div className="absolute bottom-6 left-1/2 flex -translate-x-1/2 items-center rounded border border-solid border-border bg-default px-3 py-1">
|
||||
{imageResizer}
|
||||
</div>
|
||||
)}
|
||||
{isEmbeddedInSuper && (
|
||||
<div
|
||||
className="invisible absolute bottom-full left-1/2 z-10 w-max -translate-x-1/2 px-1 pb-1 focus-within:visible group-hover:visible [.embedBlockFocused_&]:visible"
|
||||
ref={(popover) => {
|
||||
const editorRoot = document.getElementById(ElementIds.SuperEditorContent)
|
||||
if (!popover || !editorRoot) {
|
||||
return
|
||||
}
|
||||
const editorRootRect = editorRoot.getBoundingClientRect()
|
||||
const popoverRect = popover.getBoundingClientRect()
|
||||
const overflows = getOverflows(popoverRect, editorRootRect)
|
||||
if (overflows.top > 0) {
|
||||
popover.style.setProperty('--tw-translate-y', `${overflows.top}px`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{isZoomInputVisible ? (
|
||||
<div className="mx-2">
|
||||
<input
|
||||
type="number"
|
||||
className="w-10 bg-default text-center"
|
||||
defaultValue={imageZoomPercent}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation()
|
||||
if (event.key === 'Enter') {
|
||||
const value = parseInt(event.currentTarget.value)
|
||||
if (value >= MinimumZoomPercent && value <= MaximumZoomPercent) {
|
||||
setImageZoom(value)
|
||||
}
|
||||
setIsZoomInputVisible(false)
|
||||
}
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
setIsZoomInputVisible(false)
|
||||
const value = parseInt(event.currentTarget.value)
|
||||
if (value >= MinimumZoomPercent && value <= MaximumZoomPercent) {
|
||||
setImageZoom(value)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
%
|
||||
>
|
||||
<div className="flex divide-x divide-border rounded border border-border bg-default">
|
||||
{changeAlignment && (
|
||||
<div className="flex items-center gap-1 px-1 py-0.5">
|
||||
<ImageAlignmentOptions alignment={finalAlignment} changeAlignment={changeAlignment} />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center px-2 py-0.5 text-sm">{imageResizer}</div>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="mx-1 rounded px-1.5 py-1 hover:bg-contrast"
|
||||
onClick={() => setIsZoomInputVisible((visible) => !visible)}
|
||||
>
|
||||
{imageZoomPercent}%
|
||||
</button>
|
||||
)}
|
||||
<IconButton
|
||||
className="rounded p-1 hover:bg-contrast"
|
||||
icon="add"
|
||||
title={isEmbeddedInSuper ? 'Increase size' : 'Zoom In'}
|
||||
focusable={true}
|
||||
onClick={() => {
|
||||
setImageZoom(imageZoomPercent + ZoomPercentModifier)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export type ImageZoomLevelProps = {
|
||||
imageZoomLevel?: number
|
||||
setImageZoomLevel?: (zoomLevel: number) => void
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { ElementFormatType } from 'lexical'
|
||||
|
||||
export type OptionalSuperEmbeddedImageProps = {
|
||||
imageZoomLevel?: number
|
||||
setImageZoomLevel?: (zoomLevel: number) => void
|
||||
alignment?: ElementFormatType | null
|
||||
changeAlignment?: (alignment: ElementFormatType) => void
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'reac
|
||||
import Button from '../Button/Button'
|
||||
import { createObjectURLWithRef } from './CreateObjectURLWithRef'
|
||||
import ImagePreview from './ImagePreview'
|
||||
import { ImageZoomLevelProps } from './ImageZoomLevelProps'
|
||||
import { OptionalSuperEmbeddedImageProps } from './OptionalSuperEmbeddedImageProps'
|
||||
import { PreviewableTextFileTypes, RequiresNativeFilePreview } from './isFilePreviewable'
|
||||
import TextPreview from './TextPreview'
|
||||
import { parseFileName, sanitizeFileName } from '@standardnotes/utils'
|
||||
@@ -16,7 +16,7 @@ type Props = {
|
||||
file: FileItem
|
||||
bytes: Uint8Array
|
||||
isEmbeddedInSuper: boolean
|
||||
} & ImageZoomLevelProps
|
||||
} & OptionalSuperEmbeddedImageProps
|
||||
|
||||
const PreviewComponent: FunctionComponent<Props> = ({
|
||||
application,
|
||||
@@ -25,6 +25,8 @@ const PreviewComponent: FunctionComponent<Props> = ({
|
||||
isEmbeddedInSuper,
|
||||
imageZoomLevel,
|
||||
setImageZoomLevel,
|
||||
alignment,
|
||||
changeAlignment,
|
||||
}) => {
|
||||
const objectUrlRef = useRef<string>()
|
||||
|
||||
@@ -84,6 +86,8 @@ const PreviewComponent: FunctionComponent<Props> = ({
|
||||
isEmbeddedInSuper={isEmbeddedInSuper}
|
||||
imageZoomLevel={imageZoomLevel}
|
||||
setImageZoomLevel={setImageZoomLevel}
|
||||
alignment={alignment}
|
||||
changeAlignment={changeAlignment}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -109,7 +111,7 @@ const LinkedItemBubble = ({
|
||||
ref={(el) => (ref.current = el as HTMLElement)}
|
||||
tabIndex={0}
|
||||
className={classNames(
|
||||
'group cursor-pointer rounded align-middle [&>*]:align-middle',
|
||||
'group cursor-pointer rounded ',
|
||||
'bg-passive-4-opacity-variant outline-1 outline-info hover:bg-contrast focus:bg-contrast focus:outline',
|
||||
'whitespace-pre-wrap text-left text-sm text-text hover:no-underline focus:no-underline lg:text-xs',
|
||||
'py-1 pl-1 pr-2',
|
||||
@@ -121,7 +123,7 @@ const LinkedItemBubble = ({
|
||||
title={tagTitle ? tagTitle.longTitle : link.item.title}
|
||||
onKeyDown={onKeyDown}
|
||||
>
|
||||
<Icon type={icon} className={classNames('mr-1 inline', iconClassName)} size="small" />
|
||||
<Icon type={icon} className={classNames('mr-1 inline h-[1.15em] align-text-top', iconClassName)} size="small" />
|
||||
{tagTitle && <span className="text-passive-1">{tagTitle.titlePrefix}</span>}
|
||||
{link.type === 'linked-by' && link.item.content_type !== ContentType.TYPES.Tag && (
|
||||
<span className={!isBidirectional ? 'hidden group-focus:inline' : ''}>Linked By:</span>
|
||||
@@ -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"
|
||||
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" />
|
||||
|
||||
+1
-3
@@ -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={{
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { PrefKey, Platform } from '@standardnotes/snjs'
|
||||
import { PrefKey, Platform, PrefValue } from '@standardnotes/snjs'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { FunctionComponent, useState } from 'react'
|
||||
import { FunctionComponent, useMemo, useState } from 'react'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import usePreference from '@/Hooks/usePreference'
|
||||
import Dropdown from '@/Components/Dropdown/Dropdown'
|
||||
import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
|
||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
|
||||
type Props = {
|
||||
@@ -27,6 +29,27 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
const addNoteToParentFolders = usePreference(PrefKey.NoteAddToParentFolders)
|
||||
|
||||
const alwaysShowSuperToolbar = usePreference(PrefKey.AlwaysShowSuperToolbar)
|
||||
const defaultSuperImageAlignment = usePreference(PrefKey.SuperNoteImageAlignment)
|
||||
const imageAlignmentOptions = useMemo(
|
||||
(): DropdownItem[] => [
|
||||
{
|
||||
icon: 'format-align-left',
|
||||
label: 'Left align',
|
||||
value: 'left',
|
||||
},
|
||||
{
|
||||
icon: 'format-align-center',
|
||||
label: 'Center align',
|
||||
value: 'center',
|
||||
},
|
||||
{
|
||||
icon: 'format-align-right',
|
||||
label: 'Right align',
|
||||
value: 'right',
|
||||
},
|
||||
],
|
||||
[],
|
||||
)
|
||||
|
||||
const toggleSpellcheck = () => {
|
||||
application.toggleGlobalSpellcheck().catch(console.error)
|
||||
@@ -79,23 +102,46 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
{!isMobile && (
|
||||
<div className="flex justify-between gap-2 md:items-center">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Use always-visible toolbar in Super notes</Subtitle>
|
||||
<Text>
|
||||
When enabled, the Super toolbar will always be shown at the top of the note. It can be temporarily
|
||||
toggled using Cmd/Ctrl+Shift+K. When disabled, the Super toolbar will only be shown as a floating
|
||||
toolbar when text is selected.
|
||||
</Text>
|
||||
<>
|
||||
<div className="flex justify-between gap-2 md:items-center">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Use always-visible toolbar in Super notes</Subtitle>
|
||||
<Text>
|
||||
When enabled, the Super toolbar will always be shown at the top of the note. It can be temporarily
|
||||
toggled using Cmd/Ctrl+Shift+K. When disabled, the Super toolbar will only be shown as a floating
|
||||
toolbar when text is selected.
|
||||
</Text>
|
||||
</div>
|
||||
<Switch
|
||||
onChange={() => {
|
||||
application
|
||||
.setPreference(PrefKey.AlwaysShowSuperToolbar, !alwaysShowSuperToolbar)
|
||||
.catch(console.error)
|
||||
}}
|
||||
checked={alwaysShowSuperToolbar}
|
||||
/>
|
||||
</div>
|
||||
<Switch
|
||||
onChange={() => {
|
||||
application.setPreference(PrefKey.AlwaysShowSuperToolbar, !alwaysShowSuperToolbar).catch(console.error)
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
</>
|
||||
)}
|
||||
<div>
|
||||
<Subtitle>Default image alignment in Super notes</Subtitle>
|
||||
<div className="mt-2">
|
||||
<Dropdown
|
||||
label="Default image alignment in super notes"
|
||||
items={imageAlignmentOptions}
|
||||
value={defaultSuperImageAlignment}
|
||||
onChange={(alignment) => {
|
||||
application
|
||||
.setPreference(
|
||||
PrefKey.SuperNoteImageAlignment,
|
||||
alignment as PrefValue[PrefKey.SuperNoteImageAlignment],
|
||||
)
|
||||
.catch(console.error)
|
||||
}}
|
||||
checked={alwaysShowSuperToolbar}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
|
||||
@@ -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 />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user