mirror of
https://github.com/standardnotes/app
synced 2026-09-16 00:46:00 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39fdac270e | ||
|
|
66d364ff36 | ||
|
|
27b7f4e597 | ||
|
|
8d04c2fb55 | ||
|
|
55b1409a80 | ||
|
|
2b830c0fae | ||
|
|
39d0ee9181 | ||
|
|
9fa093280d | ||
|
|
73ef93c1db |
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
"build:mobile": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/mobile --exclude @standardnotes/components-meta run build",
|
||||
"build:snjs": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/snjs --exclude @standardnotes/components-meta run build",
|
||||
"build:services": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/services --exclude @standardnotes/components-meta run build",
|
||||
"build:api": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/api --exclude @standardnotes/components-meta run build",
|
||||
"start:server:web": "lerna run start --scope=@standardnotes/web",
|
||||
"start:server:e2e": "lerna run start:test-server --scope=@standardnotes/snjs",
|
||||
"prepare": "husky install",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.7.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
# [1.7.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.6.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.6.2",
|
||||
"version": "1.7.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -35,12 +35,11 @@
|
||||
"ts-jest": "^28.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/encryption": "workspace:*",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/security": "^1.1.0",
|
||||
"@standardnotes/services": "workspace:*",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Environment } from '@standardnotes/services'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
import { HttpResponseMeta } from './HttpResponseMeta'
|
||||
import { HttpService } from './HttpService'
|
||||
|
||||
@@ -24,4 +25,14 @@ describe('HttpService', () => {
|
||||
|
||||
expect(service['host']).toEqual('http://foo')
|
||||
})
|
||||
|
||||
it('should set and use the authorization token', () => {
|
||||
const service = createService()
|
||||
|
||||
expect(service['authorizationToken']).toBeUndefined()
|
||||
|
||||
service.setAuthorizationToken('foo-bar')
|
||||
|
||||
expect(service['authorizationToken']).toEqual('foo-bar')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isString, joinPaths } from '@standardnotes/utils'
|
||||
import { Environment } from '@standardnotes/services'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { HttpRequestParams } from './HttpRequestParams'
|
||||
import { HttpVerb } from './HttpVerb'
|
||||
import { HttpRequest } from './HttpRequest'
|
||||
@@ -12,6 +12,8 @@ import { HttpResponseMeta } from './HttpResponseMeta'
|
||||
import { HttpErrorResponseBody } from './HttpErrorResponseBody'
|
||||
|
||||
export class HttpService implements HttpServiceInterface {
|
||||
private authorizationToken?: string
|
||||
|
||||
constructor(
|
||||
private environment: Environment,
|
||||
private appVersion: string,
|
||||
@@ -20,28 +22,57 @@ export class HttpService implements HttpServiceInterface {
|
||||
private updateMetaCallback: (meta: HttpResponseMeta) => void,
|
||||
) {}
|
||||
|
||||
setAuthorizationToken(authorizationToken: string): void {
|
||||
this.authorizationToken = authorizationToken
|
||||
}
|
||||
|
||||
setHost(host: string): void {
|
||||
this.host = host
|
||||
}
|
||||
|
||||
async get(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Get, authentication })
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Get,
|
||||
authentication: authentication ?? this.authorizationToken,
|
||||
})
|
||||
}
|
||||
|
||||
async post(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Post, authentication })
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Post,
|
||||
authentication: authentication ?? this.authorizationToken,
|
||||
})
|
||||
}
|
||||
|
||||
async put(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Put, authentication })
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Put,
|
||||
authentication: authentication ?? this.authorizationToken,
|
||||
})
|
||||
}
|
||||
|
||||
async patch(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Patch, authentication })
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Patch,
|
||||
authentication: authentication ?? this.authorizationToken,
|
||||
})
|
||||
}
|
||||
|
||||
async delete(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse> {
|
||||
return this.runHttp({ url: joinPaths(this.host, path), params, verb: HttpVerb.Delete, authentication })
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Delete,
|
||||
authentication: authentication ?? this.authorizationToken,
|
||||
})
|
||||
}
|
||||
|
||||
private async runHttp(httpRequest: HttpRequest): Promise<HttpResponse> {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { HttpResponse } from './HttpResponse'
|
||||
|
||||
export interface HttpServiceInterface {
|
||||
setHost(host: string): void
|
||||
setAuthorizationToken(authorizationToken: string): void
|
||||
get(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||
post(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||
put(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { SubscriptionInviteAcceptResponseBody } from './SubscriptionInviteAcceptResponseBody'
|
||||
|
||||
export interface SubscriptionInviteAcceptResponse extends HttpResponse {
|
||||
data: SubscriptionInviteAcceptResponseBody | HttpErrorResponseBody
|
||||
data: Either<SubscriptionInviteAcceptResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { SubscriptionInviteCancelResponseBody } from './SubscriptionInviteCancelResponseBody'
|
||||
|
||||
export interface SubscriptionInviteCancelResponse extends HttpResponse {
|
||||
data: SubscriptionInviteCancelResponseBody | HttpErrorResponseBody
|
||||
data: Either<SubscriptionInviteCancelResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { SubscriptionInviteDeclineResponseBody } from './SubscriptionInviteDeclineResponseBody'
|
||||
|
||||
export interface SubscriptionInviteDeclineResponse extends HttpResponse {
|
||||
data: SubscriptionInviteDeclineResponseBody | HttpErrorResponseBody
|
||||
data: Either<SubscriptionInviteDeclineResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { SubscriptionInviteListResponseBody } from './SubscriptionInviteListResponseBody'
|
||||
|
||||
export interface SubscriptionInviteListResponse extends HttpResponse {
|
||||
data: SubscriptionInviteListResponseBody | HttpErrorResponseBody
|
||||
data: Either<SubscriptionInviteListResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { SubscriptionInviteResponseBody } from './SubscriptionInviteResponseBody'
|
||||
|
||||
export interface SubscriptionInviteResponse extends HttpResponse {
|
||||
data: SubscriptionInviteResponseBody | HttpErrorResponseBody
|
||||
data: Either<SubscriptionInviteResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './User/Paths'
|
||||
export * from './Subscription/SubscriptionServer'
|
||||
export * from './Subscription/SubscriptionServerInterface'
|
||||
export * from './User/UserServer'
|
||||
export * from './User/UserServerInterface'
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.7.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
## [2.7.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
## [2.7.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
+3
-3
@@ -90,9 +90,9 @@
|
||||
"binary": "54a01414a21e46c67fa59c69189a3d34a6548de7539699f2cf0248f9c5059d37"
|
||||
},
|
||||
"org.standardnotes.advanced-checklist": {
|
||||
"version": "0.2.4",
|
||||
"base64": "eaa8225677b18448cf6e8191cbf8a23c012590054d60434730cad20fd5b056f0",
|
||||
"binary": "22db0aba7937234f8e0617a508a46de6a517c3e34be7deee87bc80533065f36c"
|
||||
"version": "0.2.5",
|
||||
"base64": "077a56ef75958105bc9dc16376bcea2e89aee57b512b43f9e1b33e1d32ea8358",
|
||||
"binary": "e903a5c592bd03ca28d205d09dcbc7e4329c7cd57fb74b4e0e5fa724c2321a61"
|
||||
},
|
||||
"org.standardnotes.file-safe": {
|
||||
"version": "2.0.16",
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/components-meta",
|
||||
"version": "2.7.10",
|
||||
"version": "2.7.12",
|
||||
"private": true,
|
||||
"author": "Standard Notes.",
|
||||
"main": "dist",
|
||||
|
||||
+4
@@ -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.
|
||||
|
||||
## [0.2.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/advanced-checklist
|
||||
|
||||
## [0.2.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/advanced-checklist
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/advanced-checklist",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.5",
|
||||
"description": "A task editor with grouping functionality.",
|
||||
"author": "Standard Notes.",
|
||||
"keywords": [
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [3.23.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.116](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.115](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.114](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.113](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.23.113",
|
||||
"version": "3.23.117",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.15.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
# [1.15.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.14.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.14.4",
|
||||
"version": "1.15.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -35,7 +35,7 @@
|
||||
"typescript": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/sncrypto-common": "workspace:*",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* **features:** add subscription sharing ([66d364f](https://github.com/standardnotes/app/commit/66d364ff369afa0dcd11ac835512a7af9b25c8d2))
|
||||
|
||||
# [1.51.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.50.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.50.5",
|
||||
"version": "1.52.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/auth": "^3.19.4",
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/security": "^1.2.0",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@ export enum FeatureIdentifier {
|
||||
SmartFilters = 'org.standardnotes.smart-filters',
|
||||
TagNesting = 'org.standardnotes.tag-nesting',
|
||||
TwoFactorAuth = 'org.standardnotes.two-factor-auth',
|
||||
SubscriptionSharing = 'org.standardnotes.subscription-sharing',
|
||||
|
||||
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
|
||||
DynamicTheme = 'org.standardnotes.theme-dynamic',
|
||||
|
||||
@@ -60,5 +60,10 @@ export function serverFeatures(): ServerFeatureDescription[] {
|
||||
identifier: FeatureIdentifier.FilesLowStorageTier,
|
||||
permission_name: PermissionName.FilesLowStorageTier,
|
||||
},
|
||||
{
|
||||
availableInSubscriptions: [SubscriptionName.ProPlan],
|
||||
identifier: FeatureIdentifier.SubscriptionSharing,
|
||||
permission_name: PermissionName.SubscriptionSharing,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,4 +39,5 @@ export enum PermissionName {
|
||||
TitaniumTheme = 'theme:titanium',
|
||||
TokenVaultEditor = 'editor:token-vault',
|
||||
TwoFactorAuth = 'server:two-factor-auth',
|
||||
SubscriptionSharing = 'server:subscription-sharing',
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.23.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
# [1.23.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.22.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.22.4",
|
||||
"version": "1.23.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -31,7 +31,7 @@
|
||||
"ts-node": "^10.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/files": "workspace:*",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
# [1.10.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.9.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.9.4",
|
||||
"version": "1.10.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -30,7 +30,7 @@
|
||||
"ts-jest": "^28.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/encryption": "workspace:*",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [3.32.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.32.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.32.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.32.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
# [3.32.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.32.0",
|
||||
"version": "3.32.4",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.18.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
# [1.18.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
# [1.17.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-31)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.17.0",
|
||||
"version": "1.18.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -32,7 +32,7 @@
|
||||
"typescript": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum Environment {
|
||||
Web = 1,
|
||||
Desktop = 2,
|
||||
Mobile = 3,
|
||||
NativeMobileWeb = 4,
|
||||
}
|
||||
-7
@@ -1,10 +1,3 @@
|
||||
export enum Environment {
|
||||
Web = 1,
|
||||
Desktop = 2,
|
||||
Mobile = 3,
|
||||
NativeMobileWeb = 4,
|
||||
}
|
||||
|
||||
export enum Platform {
|
||||
Ios = 1,
|
||||
Android = 2,
|
||||
@@ -28,6 +28,8 @@ export * from './Api/Subscription/Invitation'
|
||||
export * from './Api/Subscription/InvitationStatus'
|
||||
export * from './Api/Subscription/InviteeIdentifierType'
|
||||
export * from './Api/Subscription/InviterIdentifierType'
|
||||
export * from './Device/Environment'
|
||||
export * from './Device/Platform'
|
||||
export * from './Local/KeyParams/RootKeyParamsInterface'
|
||||
export * from './Local/RootKey/KeychainTypes'
|
||||
export * from './Local/RootKey/RootKeyContent'
|
||||
|
||||
@@ -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.3.40](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.39](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.37](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.3.36",
|
||||
"version": "1.3.40",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
# [1.10.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.9.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.9.4",
|
||||
"version": "1.10.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -31,7 +31,7 @@
|
||||
"ts-jest": "^28.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
"@standardnotes/security": "^1.1.0",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.19.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
# [1.19.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
# [1.18.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -11,8 +11,8 @@ module.exports = {
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 9,
|
||||
functions: 9,
|
||||
lines: 16,
|
||||
functions: 10,
|
||||
lines: 17,
|
||||
statements: 16
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.18.0",
|
||||
"version": "1.19.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -20,11 +20,13 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"test": "jest spec --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/api": "workspace:^",
|
||||
"@standardnotes/auth": "^3.19.4",
|
||||
"@standardnotes/common": "^1.30.0",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/encryption": "workspace:^",
|
||||
"@standardnotes/files": "workspace:^",
|
||||
"@standardnotes/models": "workspace:^",
|
||||
@@ -37,6 +39,7 @@
|
||||
"@types/jest": "^28.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"eslint": "^8.23.1",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { ApplicationIdentifier, ContentType } from '@standardnotes/common'
|
||||
import { BackupFile, DecryptedItemInterface, ItemStream, PrefKey, PrefValue } from '@standardnotes/models'
|
||||
import { BackupFile, DecryptedItemInterface, ItemStream, Platform, PrefKey, PrefValue } from '@standardnotes/models'
|
||||
import { FilesClientInterface } from '@standardnotes/files'
|
||||
import { AlertService } from '../Alert/AlertService'
|
||||
|
||||
import { ComponentManagerInterface } from '../Component/ComponentManagerInterface'
|
||||
import { Platform } from '../Device/Environments'
|
||||
import { ApplicationEvent } from '../Event/ApplicationEvent'
|
||||
import { ApplicationEventCallback } from '../Event/ApplicationEventCallback'
|
||||
import { FeaturesClientInterface } from '../Feature/FeaturesClientInterface'
|
||||
import { SubscriptionClientInterface } from '../Subscription/SubscriptionClientInterface'
|
||||
import { ItemsClientInterface } from '../Item/ItemsClientInterface'
|
||||
import { MutatorClientInterface } from '../Mutator/MutatorClientInterface'
|
||||
import { StorageValueModes } from '../Storage/StorageTypes'
|
||||
@@ -48,6 +48,7 @@ export interface ApplicationInterface {
|
||||
get mutator(): MutatorClientInterface
|
||||
get user(): UserClientInterface
|
||||
get files(): FilesClientInterface
|
||||
get subscriptions(): SubscriptionClientInterface
|
||||
readonly identifier: ApplicationIdentifier
|
||||
readonly platform: Platform
|
||||
deviceInterface: DeviceInterface
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
import { WebClientRequiresDesktopMethods } from './DesktopWebCommunication'
|
||||
import { DeviceInterface } from './DeviceInterface'
|
||||
import { Environment } from './Environments'
|
||||
import { WebOrDesktopDeviceInterface } from './WebOrDesktopDeviceInterface'
|
||||
|
||||
/* istanbul ignore file */
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Environment } from './Environments'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import {
|
||||
FullyFormedTransferPayload,
|
||||
TransferPayload,
|
||||
LegacyRawKeychainValue,
|
||||
NamespacedRootKeyInKeychain,
|
||||
Environment,
|
||||
} from '@standardnotes/models'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DeviceInterface } from './DeviceInterface'
|
||||
import { Environment } from './Environments'
|
||||
import { RawKeychainValue } from '@standardnotes/models'
|
||||
import { Environment, RawKeychainValue } from '@standardnotes/models'
|
||||
|
||||
export interface MobileDeviceInterface extends DeviceInterface {
|
||||
environment: Environment.Mobile
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
import { DeviceInterface } from './DeviceInterface'
|
||||
import { Environment } from './Environments'
|
||||
import { MobileDeviceInterface } from './MobileDeviceInterface'
|
||||
import { isMobileDevice } from './TypeCheck'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Environment } from './Environments'
|
||||
import { MobileDeviceInterface } from './MobileDeviceInterface'
|
||||
import { DeviceInterface } from './DeviceInterface'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
/* istanbul ignore file */
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { Invitation } from '@standardnotes/models'
|
||||
|
||||
export interface SubscriptionClientInterface {
|
||||
listSubscriptionInvitations(): Promise<Invitation[]>
|
||||
inviteToSubscription(inviteeEmail: string): Promise<boolean>
|
||||
cancelInvitation(inviteUuid: Uuid): Promise<boolean>
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { SubscriptionApiServiceInterface } from '@standardnotes/api'
|
||||
import { Invitation } from '@standardnotes/models'
|
||||
import { InternalEventBusInterface } from '..'
|
||||
import { SubscriptionManager } from './SubscriptionManager'
|
||||
|
||||
describe('SubscriptionManager', () => {
|
||||
let subscriptionApiService: SubscriptionApiServiceInterface
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
|
||||
const createManager = () => new SubscriptionManager(subscriptionApiService, internalEventBus)
|
||||
|
||||
beforeEach(() => {
|
||||
subscriptionApiService = {} as jest.Mocked<SubscriptionApiServiceInterface>
|
||||
subscriptionApiService.cancelInvite = jest.fn()
|
||||
subscriptionApiService.invite = jest.fn()
|
||||
subscriptionApiService.listInvites = jest.fn()
|
||||
|
||||
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
|
||||
})
|
||||
|
||||
it('should invite user by email to a shared subscription', async () => {
|
||||
subscriptionApiService.invite = jest.fn().mockReturnValue({ data: { success: true } })
|
||||
|
||||
expect(await createManager().inviteToSubscription('[email protected]')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should not invite user by email if the api fails to do so', async () => {
|
||||
subscriptionApiService.invite = jest.fn().mockReturnValue({ data: { error: 'foobar' } })
|
||||
|
||||
expect(await createManager().inviteToSubscription('[email protected]')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should not invite user by email if the api throws an error', async () => {
|
||||
subscriptionApiService.invite = jest.fn().mockImplementation(() => {
|
||||
throw new Error('Oops')
|
||||
})
|
||||
|
||||
expect(await createManager().inviteToSubscription('[email protected]')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should cancel invite to a shared subscription', async () => {
|
||||
subscriptionApiService.cancelInvite = jest.fn().mockReturnValue({ data: { success: true } })
|
||||
|
||||
expect(await createManager().cancelInvitation('1-2-3')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should not cancel invite if the api fails to do so', async () => {
|
||||
subscriptionApiService.cancelInvite = jest.fn().mockReturnValue({ data: { error: 'foobar' } })
|
||||
|
||||
expect(await createManager().cancelInvitation('1-2-3')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should not cancel invite if the api throws an error', async () => {
|
||||
subscriptionApiService.cancelInvite = jest.fn().mockImplementation(() => {
|
||||
throw new Error('Oops')
|
||||
})
|
||||
|
||||
expect(await createManager().cancelInvitation('1-2-3')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should list invites to a shared subscription', async () => {
|
||||
const invitation = {
|
||||
uuid: '1-2-3',
|
||||
} as jest.Mocked<Invitation>
|
||||
subscriptionApiService.listInvites = jest.fn().mockReturnValue({ data: { invitations: [invitation] } })
|
||||
|
||||
expect(await createManager().listSubscriptionInvitations()).toEqual([invitation])
|
||||
})
|
||||
|
||||
it('should return an empty list of invites if the api fails to fetch them', async () => {
|
||||
subscriptionApiService.listInvites = jest.fn().mockReturnValue({ data: { error: 'foobar' } })
|
||||
|
||||
expect(await createManager().listSubscriptionInvitations()).toEqual([])
|
||||
})
|
||||
|
||||
it('should return an empty list of invites if the api throws an error', async () => {
|
||||
subscriptionApiService.listInvites = jest.fn().mockImplementation(() => {
|
||||
throw new Error('Oops')
|
||||
})
|
||||
|
||||
expect(await createManager().listSubscriptionInvitations()).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Invitation } from '@standardnotes/models'
|
||||
import { SubscriptionApiServiceInterface } from '@standardnotes/api'
|
||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||
import { AbstractService } from '../Service/AbstractService'
|
||||
import { SubscriptionClientInterface } from './SubscriptionClientInterface'
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
|
||||
export class SubscriptionManager extends AbstractService implements SubscriptionClientInterface {
|
||||
constructor(
|
||||
private subscriptionApiService: SubscriptionApiServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
}
|
||||
|
||||
async listSubscriptionInvitations(): Promise<Invitation[]> {
|
||||
try {
|
||||
const response = await this.subscriptionApiService.listInvites()
|
||||
|
||||
return response.data.invitations ?? []
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async inviteToSubscription(inviteeEmail: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await this.subscriptionApiService.invite(inviteeEmail)
|
||||
|
||||
return result.data.success === true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async cancelInvitation(inviteUuid: Uuid): Promise<boolean> {
|
||||
try {
|
||||
const result = await this.subscriptionApiService.cancelInvite(inviteUuid)
|
||||
|
||||
return result.data.success === true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ export * from './Device/DesktopDeviceInterface'
|
||||
export * from './Device/DesktopManagerInterface'
|
||||
export * from './Device/DesktopWebCommunication'
|
||||
export * from './Device/DeviceInterface'
|
||||
export * from './Device/Environments'
|
||||
export * from './Device/MobileDeviceInterface'
|
||||
export * from './Device/TypeCheck'
|
||||
export * from './Device/WebOrDesktopDeviceInterface'
|
||||
@@ -67,6 +66,8 @@ export * from './Storage/InMemoryStore'
|
||||
export * from './Storage/KeyValueStoreInterface'
|
||||
export * from './Storage/StorageServiceInterface'
|
||||
export * from './Storage/StorageTypes'
|
||||
export * from './Subscription/SubscriptionClientInterface'
|
||||
export * from './Subscription/SubscriptionManager'
|
||||
export * from './Sync/SyncMode'
|
||||
export * from './Sync/SyncOptions'
|
||||
export * from './Sync/SyncQueueStrategy'
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.127.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
# [2.127.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
# [2.126.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { SNLog } from './../Log'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import {
|
||||
AlertService,
|
||||
DeviceInterface,
|
||||
Environment,
|
||||
namespacedKey,
|
||||
Platform,
|
||||
RawStorageKey,
|
||||
} from '@standardnotes/services'
|
||||
import { AlertService, DeviceInterface, namespacedKey, RawStorageKey } from '@standardnotes/services'
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
import { SNApplication } from './Application'
|
||||
|
||||
describe('application', () => {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import {
|
||||
HttpService,
|
||||
HttpServiceInterface,
|
||||
SubscriptionApiService,
|
||||
SubscriptionApiServiceInterface,
|
||||
SubscriptionServer,
|
||||
SubscriptionServerInterface,
|
||||
UserApiService,
|
||||
UserApiServiceInterface,
|
||||
UserRegistrationResponseBody,
|
||||
@@ -23,9 +27,7 @@ import {
|
||||
ChallengeValidation,
|
||||
ComponentManagerInterface,
|
||||
DiagnosticInfo,
|
||||
Environment,
|
||||
isDesktopDevice,
|
||||
Platform,
|
||||
ChallengeValue,
|
||||
StorageKey,
|
||||
ChallengeReason,
|
||||
@@ -37,11 +39,20 @@ import {
|
||||
EncryptionServiceEvent,
|
||||
FilesBackupService,
|
||||
FileService,
|
||||
SubscriptionClientInterface,
|
||||
SubscriptionManager,
|
||||
} from '@standardnotes/services'
|
||||
import { FilesClientInterface } from '@standardnotes/files'
|
||||
import { ComputePrivateWorkspaceIdentifier } from '@standardnotes/encryption'
|
||||
import { useBoolean } from '@standardnotes/utils'
|
||||
import { BackupFile, DecryptedItemInterface, EncryptedItemInterface, ItemStream } from '@standardnotes/models'
|
||||
import {
|
||||
BackupFile,
|
||||
DecryptedItemInterface,
|
||||
EncryptedItemInterface,
|
||||
Environment,
|
||||
ItemStream,
|
||||
Platform,
|
||||
} from '@standardnotes/models'
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
|
||||
import { SnjsVersion } from './../Version'
|
||||
@@ -92,6 +103,9 @@ export class SNApplication
|
||||
private apiService!: InternalServices.SNApiService
|
||||
private declare userApiService: UserApiServiceInterface
|
||||
private declare userServer: UserServerInterface
|
||||
private declare subscriptionApiService: SubscriptionApiServiceInterface
|
||||
private declare subscriptionServer: SubscriptionServerInterface
|
||||
private declare subscriptionManager: SubscriptionClientInterface
|
||||
private sessionManager!: InternalServices.SNSessionManager
|
||||
private syncService!: InternalServices.SNSyncService
|
||||
private challengeService!: InternalServices.ChallengeService
|
||||
@@ -187,6 +201,10 @@ export class SNApplication
|
||||
this.defineInternalEventHandlers()
|
||||
}
|
||||
|
||||
get subscriptions(): ExternalServices.SubscriptionClientInterface {
|
||||
return this.subscriptionManager
|
||||
}
|
||||
|
||||
public get files(): FilesClientInterface {
|
||||
return this.fileService
|
||||
}
|
||||
@@ -1031,6 +1049,9 @@ export class SNApplication
|
||||
this.createHttpService()
|
||||
this.createUserServer()
|
||||
this.createUserApiService()
|
||||
this.createSubscriptionServer()
|
||||
this.createSubscriptionApiService()
|
||||
this.createSubscriptionManager()
|
||||
this.createWebSocketsService()
|
||||
this.createSessionManager()
|
||||
this.createHistoryManager()
|
||||
@@ -1069,6 +1090,9 @@ export class SNApplication
|
||||
;(this.apiService as unknown) = undefined
|
||||
;(this.userApiService as unknown) = undefined
|
||||
;(this.userServer as unknown) = undefined
|
||||
;(this.subscriptionApiService as unknown) = undefined
|
||||
;(this.subscriptionServer as unknown) = undefined
|
||||
;(this.subscriptionManager as unknown) = undefined
|
||||
;(this.sessionManager as unknown) = undefined
|
||||
;(this.syncService as unknown) = undefined
|
||||
;(this.challengeService as unknown) = undefined
|
||||
@@ -1262,6 +1286,18 @@ export class SNApplication
|
||||
this.userServer = new UserServer(this.httpService)
|
||||
}
|
||||
|
||||
private createSubscriptionApiService() {
|
||||
this.subscriptionApiService = new SubscriptionApiService(this.subscriptionServer)
|
||||
}
|
||||
|
||||
private createSubscriptionServer() {
|
||||
this.subscriptionServer = new SubscriptionServer(this.httpService)
|
||||
}
|
||||
|
||||
private createSubscriptionManager() {
|
||||
this.subscriptionManager = new SubscriptionManager(this.subscriptionApiService, this.internalEventBus)
|
||||
}
|
||||
|
||||
private createItemManager() {
|
||||
this.itemManager = new InternalServices.ItemManager(this.payloadManager, this.options, this.internalEventBus)
|
||||
this.services.push(this.itemManager)
|
||||
@@ -1377,6 +1413,7 @@ export class SNApplication
|
||||
this.protocolService,
|
||||
this.challengeService,
|
||||
this.webSocketsService,
|
||||
this.httpService,
|
||||
this.internalEventBus,
|
||||
)
|
||||
this.serviceObservers.push(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { AlertService, DeviceInterface, Environment, Platform } from '@standardnotes/services'
|
||||
import { AlertService, DeviceInterface } from '@standardnotes/services'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
|
||||
export interface RequiredApplicationOptions {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Environment, Platform } from '@standardnotes/services'
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
|
||||
export function platformFromString(string: string) {
|
||||
const map: Record<string, Platform> = {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { DeviceInterface, InternalEventBusInterface, EncryptionService } from '@standardnotes/services'
|
||||
|
||||
import { SNSessionManager } from '../Services/Session/SessionManager'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { DeviceInterface, InternalEventBusInterface, Environment, EncryptionService } from '@standardnotes/services'
|
||||
import { ChallengeService, SNSingletonManager, SNFeaturesService, DiskStorageService } from '@Lib/Services'
|
||||
|
||||
export type MigrationServices = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { compareSemVersions, isRightVersionGreaterThanLeft } from '@Lib/Version'
|
||||
import { DeviceInterface, Environment } from '@standardnotes/services'
|
||||
import { DeviceInterface } from '@standardnotes/services'
|
||||
import { StorageReader } from './Reader'
|
||||
import * as ReaderClasses from './Versions'
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { DeviceInterface, Environment } from '@standardnotes/services'
|
||||
import { DeviceInterface } from '@standardnotes/services'
|
||||
|
||||
/**
|
||||
* A storage reader reads storage via a device interface
|
||||
|
||||
@@ -2,7 +2,8 @@ import { API_MESSAGE_RATE_LIMITED, UNKNOWN_ERROR } from './Messages'
|
||||
import { HttpResponse, StatusCode } from '@standardnotes/responses'
|
||||
import { isString } from '@standardnotes/utils'
|
||||
import { SnjsVersion } from '@Lib/Version'
|
||||
import { AbstractService, InternalEventBusInterface, Environment } from '@standardnotes/services'
|
||||
import { AbstractService, InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
export enum HttpVerb {
|
||||
Get = 'GET',
|
||||
|
||||
@@ -11,14 +11,8 @@ import {
|
||||
FeatureIdentifier,
|
||||
} from '@standardnotes/features'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { GenericItem, SNComponent } from '@standardnotes/models'
|
||||
import {
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
Environment,
|
||||
Platform,
|
||||
AlertService,
|
||||
} from '@standardnotes/services'
|
||||
import { GenericItem, SNComponent, Environment, Platform } from '@standardnotes/models'
|
||||
import { DesktopManagerInterface, InternalEventBusInterface, AlertService } from '@standardnotes/services'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { SNComponentManager } from './ComponentManager'
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
ComponentMutator,
|
||||
PayloadEmitSource,
|
||||
PermissionDialog,
|
||||
Environment,
|
||||
Platform,
|
||||
} from '@standardnotes/models'
|
||||
import { SNSyncService } from '@Lib/Services/Sync/SyncService'
|
||||
import find from 'lodash/find'
|
||||
@@ -26,8 +28,6 @@ import {
|
||||
ComponentViewerInterface,
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
Environment,
|
||||
Platform,
|
||||
AlertService,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
|
||||
@@ -2,10 +2,8 @@ import { SNPreferencesService } from '../Preferences/PreferencesService'
|
||||
import {
|
||||
ComponentViewerInterface,
|
||||
ComponentViewerError,
|
||||
Environment,
|
||||
FeatureStatus,
|
||||
FeaturesEvent,
|
||||
Platform,
|
||||
AlertService,
|
||||
} from '@standardnotes/services'
|
||||
import { SNFeaturesService } from '@Lib/Services'
|
||||
@@ -34,6 +32,8 @@ import {
|
||||
PayloadTimestampDefaults,
|
||||
IncomingComponentItemPayload,
|
||||
MessageData,
|
||||
Environment,
|
||||
Platform,
|
||||
} from '@standardnotes/models'
|
||||
import find from 'lodash/find'
|
||||
import uniq from 'lodash/uniq'
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
ApiCallError,
|
||||
ErrorMessage,
|
||||
HttpErrorResponseBody,
|
||||
HttpServiceInterface,
|
||||
UserApiServiceInterface,
|
||||
UserRegistrationResponseBody,
|
||||
} from '@standardnotes/api'
|
||||
@@ -77,6 +78,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
private protocolService: EncryptionService,
|
||||
private challengeService: ChallengeService,
|
||||
private webSocketsService: SNWebSocketsService,
|
||||
private httpService: HttpServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -617,6 +619,10 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
|
||||
void this.apiService.setHost(host)
|
||||
|
||||
this.httpService.setHost(host)
|
||||
|
||||
this.httpService.setAuthorizationToken(session.authorizationValue)
|
||||
|
||||
await this.setSession(session)
|
||||
|
||||
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SNLog } from '../../Log'
|
||||
import { isErrorDecryptingParameters, SNRootKey } from '@standardnotes/encryption'
|
||||
import * as Encryption from '@standardnotes/encryption'
|
||||
import * as Services from '@standardnotes/services'
|
||||
import { DiagnosticInfo, Environment } from '@standardnotes/services'
|
||||
import { DiagnosticInfo } from '@standardnotes/services'
|
||||
import {
|
||||
CreateDecryptedLocalStorageContextPayload,
|
||||
CreateDeletedLocalStorageContextPayload,
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
DeletedPayloadInterface,
|
||||
PayloadTimestampDefaults,
|
||||
LocalStorageEncryptedContextualPayload,
|
||||
Environment,
|
||||
} from '@standardnotes/models'
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('subscriptions', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let application
|
||||
let context
|
||||
let subscriptionManager
|
||||
|
||||
afterEach(async function () {
|
||||
await Factory.safeDeinit(application)
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createAppContextWithFakeCrypto()
|
||||
|
||||
await context.launch()
|
||||
|
||||
application = context.application
|
||||
subscriptionManager = context.application.subscriptionManager
|
||||
|
||||
const result = await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: context.email,
|
||||
password: context.password,
|
||||
})
|
||||
|
||||
await Factory.publishMockedEvent('SUBSCRIPTION_PURCHASED', {
|
||||
userEmail: context.email,
|
||||
subscriptionId: 1,
|
||||
subscriptionName: 'PRO_PLAN',
|
||||
subscriptionExpiresAt: (new Date().getTime() + 3_600_000) * 1_000,
|
||||
timestamp: Date.now(),
|
||||
offline: false,
|
||||
})
|
||||
await Factory.sleep(0.25)
|
||||
})
|
||||
|
||||
it('should invite a user by email to a shared subscription', async () => {
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
|
||||
const existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
const newlyCreatedInvite = existingInvites.find(invite => invite.inviteeIdentifier === '[email protected]')
|
||||
|
||||
expect(newlyCreatedInvite.status).to.equal('sent')
|
||||
})
|
||||
|
||||
it('should not invite a user by email if the limit of shared subscription is breached', async () => {
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
|
||||
let existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect(existingInvites.length).to.equal(5)
|
||||
|
||||
expect(await subscriptionManager.inviteToSubscription('[email protected]')).to.equal(false)
|
||||
|
||||
existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect(existingInvites.length).to.equal(5)
|
||||
})
|
||||
|
||||
it('should cancel a user invitation to a shared subscription', async () => {
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
|
||||
let existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect (existingInvites.length).to.equal(2)
|
||||
|
||||
const newlyCreatedInvite = existingInvites.find(invite => invite.inviteeIdentifier === '[email protected]')
|
||||
|
||||
await subscriptionManager.cancelInvitation(newlyCreatedInvite.uuid)
|
||||
|
||||
existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect (existingInvites.length).to.equal(2)
|
||||
|
||||
expect(existingInvites.filter(invite => invite.status === 'canceled').length).to.equal(1)
|
||||
})
|
||||
|
||||
it('should invite a user by email if the limit of shared subscription is restored', async () => {
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
await subscriptionManager.inviteToSubscription('[email protected]')
|
||||
|
||||
let existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect(existingInvites.length).to.equal(5)
|
||||
|
||||
await subscriptionManager.cancelInvitation(existingInvites[0].uuid)
|
||||
|
||||
expect(await subscriptionManager.inviteToSubscription('[email protected]')).to.equal(true)
|
||||
|
||||
existingInvites = await subscriptionManager.listSubscriptionInvitations()
|
||||
|
||||
expect(existingInvites.find(invite => invite.inviteeIdentifier === '[email protected]')).not.to.equal(undefined)
|
||||
})
|
||||
})
|
||||
@@ -91,6 +91,7 @@
|
||||
<script type="module" src="session-sharing.test.js"></script>
|
||||
<script type="module" src="files.test.js"></script>
|
||||
<script type="module" src="session.test.js"></script>
|
||||
<script type="module" src="subscriptions.test.js"></script>
|
||||
<script type="module">
|
||||
mocha.run();
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.126.0",
|
||||
"version": "2.127.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -24,6 +24,7 @@
|
||||
"tsc": "tsc --project lib/tsconfig.json && tscpaths -p lib/tsconfig.json -s lib -o dist/@types",
|
||||
"lint": "yarn lint:tsc && yarn lint:eslint",
|
||||
"lint:eslint": "eslint --ext .ts lib/",
|
||||
"lint:fix": "eslint --fix --ext .ts lib/",
|
||||
"lint:tsc": "tsc --noEmit --emitDeclarationOnly false --project lib/tsconfig.json",
|
||||
"test": "jest spec --coverage",
|
||||
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand"
|
||||
@@ -67,7 +68,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/api": "workspace:*",
|
||||
"@standardnotes/common": "^1.25.0",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/domain-events": "^2.39.0",
|
||||
"@standardnotes/encryption": "workspace:*",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.2.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
# [1.2.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.1.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.1.6",
|
||||
"version": "1.2.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -23,7 +23,7 @@
|
||||
"test": "jest spec --coverage --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.30.0",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"@standardnotes/filepicker": "workspace:^",
|
||||
"@standardnotes/services": "workspace:^",
|
||||
"@standardnotes/styles": "workspace:^",
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.9.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* add subscription manager to handle subscription sharing ([#1517](https://github.com/standardnotes/app/issues/1517)) ([55b1409](https://github.com/standardnotes/app/commit/55b1409a805c21ada70bf482a02cfe718a4c6576))
|
||||
|
||||
## [1.8.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/utils",
|
||||
"version": "1.8.3",
|
||||
"version": "1.9.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -25,7 +25,7 @@
|
||||
"test": "jest spec"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
"dompurify": "^2.3.8",
|
||||
"lodash": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [3.46.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.46.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
# [3.46.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
### Features
|
||||
|
||||
* update mobile design ([#1526](https://github.com/standardnotes/app/issues/1526)) ([39d0ee9](https://github.com/standardnotes/app/commit/39d0ee9181255ad71500f4322f63b962af92b861))
|
||||
|
||||
## [3.45.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ability to open a new tab on iOS Safari ([#1516](https://github.com/standardnotes/app/issues/1516)) ([73ef93c](https://github.com/standardnotes/app/commit/73ef93c1db0c1d073ddd110459848740ba2f8543))
|
||||
|
||||
## [3.45.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.45.17",
|
||||
"version": "3.46.2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
@@ -14,6 +14,7 @@
|
||||
"format": "prettier --write src/javascripts",
|
||||
"lint": "NODE_OPTIONS=\"--max-old-space-size=4096\" eslint src/javascripts",
|
||||
"start": "webpack-dev-server --config web.webpack.dev.js",
|
||||
"start-secure": "yarn start --server-type https",
|
||||
"test": "jest --config jest.config.js --coverage",
|
||||
"tsc": "tsc --project tsconfig.json",
|
||||
"upgrade:snjs": "ncu -u '@standardnotes/*'",
|
||||
|
||||
@@ -66,6 +66,7 @@ const startApplication: StartApplication = async function startApplication(
|
||||
root = createRoot(appendedRootNode)
|
||||
|
||||
disableIosTextFieldZoom()
|
||||
document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`)
|
||||
|
||||
root.render(
|
||||
<ApplicationGroupView
|
||||
|
||||
@@ -68,7 +68,7 @@ const ContentList: FunctionComponent<Props> = ({
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'infinite-scroll max-h-[75vh] overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
|
||||
'infinite-scroll overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
|
||||
'md:max-h-full md:overflow-y-hidden md:hover:overflow-y-auto',
|
||||
'md:hover:[overflow-y:_overlay]',
|
||||
)}
|
||||
|
||||
@@ -185,13 +185,13 @@ const ContentListView: FunctionComponent<Props> = ({
|
||||
<div
|
||||
id="items-column"
|
||||
className={classNames(
|
||||
'sn-component section app-column flex flex-col border-b border-solid border-border ',
|
||||
'sn-component section app-column flex h-screen flex-col md:h-full',
|
||||
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full pointer-coarse:md-only:!w-52 pointer-coarse:lg-only:!w-52',
|
||||
)}
|
||||
aria-label={'Notes & Files'}
|
||||
ref={itemsViewPanelRef}
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items} contentClassName="min-h-[85vh]">
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items} className="min-h-[85vh]">
|
||||
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
|
||||
<div id="items-title-bar-container">
|
||||
<input
|
||||
|
||||
+3
-1
@@ -4,6 +4,7 @@ import Icon from '../../Icon/Icon'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Popover from '@/Components/Popover/Popover'
|
||||
import DisplayOptionsMenu from './DisplayOptionsMenu'
|
||||
import { NavigationMenuButton } from '@/Components/NavigationMenu/NavigationMenu'
|
||||
|
||||
type Props = {
|
||||
application: {
|
||||
@@ -35,7 +36,8 @@ const ContentListHeader = ({
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="section-title-bar-header gap-1">
|
||||
<div className="section-title-bar-header items-start gap-1">
|
||||
<NavigationMenuButton />
|
||||
<div className="flex flex-grow flex-col">
|
||||
<div className="text-lg font-semibold text-text">{panelTitle}</div>
|
||||
{optionsSubtitle && <div className="text-xs text-passive-0">{optionsSubtitle}</div>}
|
||||
|
||||
@@ -60,7 +60,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex min-h-screen flex-col md:min-h-full md:flex-grow">
|
||||
<div className="flex min-h-0 flex-grow flex-col">
|
||||
<FilePreview file={file} application={application} key={file.uuid} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,11 +30,11 @@ const AccountMenuButton = ({
|
||||
onClick={toggleMenu}
|
||||
className={classNames(
|
||||
isOpen ? 'bg-border' : '',
|
||||
'flex h-full w-12 cursor-pointer items-center justify-center rounded-full md:w-8',
|
||||
'flex h-full w-8 cursor-pointer items-center justify-center rounded-full',
|
||||
)}
|
||||
>
|
||||
<div className={hasError ? 'text-danger' : user ? 'text-info' : 'text-neutral'}>
|
||||
<Icon type="account-circle" className="h-6 w-6 hover:text-info md:h-5 md:w-5" />
|
||||
<Icon type="account-circle" className="h-5 w-5 hover:text-info" />
|
||||
</div>
|
||||
</button>
|
||||
<Popover anchorElement={buttonRef.current} open={isOpen} togglePopover={toggleMenu} side="top" className="py-2">
|
||||
|
||||
@@ -341,7 +341,7 @@ class Footer extends PureComponent<Props, State> {
|
||||
<div className="sn-component">
|
||||
<footer
|
||||
id="footer-bar"
|
||||
className="z-footer-bar flex h-12 w-full select-none items-center justify-between border-t border-border bg-contrast pl-3.5 pr-6 text-text md:h-8 md:px-3"
|
||||
className="z-footer-bar hidden h-8 w-full select-none items-center justify-between border-t border-border bg-contrast px-3 text-text md:flex"
|
||||
>
|
||||
<div className="left flex h-full">
|
||||
<div className="sk-app-bar-item relative z-footer-bar-item ml-0 select-none">
|
||||
|
||||
@@ -28,7 +28,7 @@ const QuickSettingsButton = ({
|
||||
<>
|
||||
<button
|
||||
onClick={toggleMenu}
|
||||
className="flex h-full w-12 cursor-pointer items-center justify-center md:w-8"
|
||||
className="flex h-full w-8 cursor-pointer items-center justify-center"
|
||||
ref={buttonRef}
|
||||
>
|
||||
<div className="h-5">
|
||||
|
||||
@@ -11,6 +11,7 @@ export const ICONS = {
|
||||
'check-bold': icons.CheckBoldIcon,
|
||||
'check-circle': icons.CheckCircleIcon,
|
||||
'chevron-down': icons.ChevronDownIcon,
|
||||
'chevron-left': icons.ChevronLeftIcon,
|
||||
'chevron-right': icons.ChevronRightIcon,
|
||||
'clear-circle-filled': icons.ClearCircleFilledIcon,
|
||||
'cloud-off': icons.CloudOffIcon,
|
||||
@@ -33,6 +34,7 @@ export const ICONS = {
|
||||
'menu-arrow-down': icons.MenuArrowDownIcon,
|
||||
'menu-arrow-right': icons.MenuArrowRightIcon,
|
||||
'menu-close': icons.MenuCloseIcon,
|
||||
'menu-variant': icons.MenuVariantIcon,
|
||||
'notes-filled': icons.NotesFilledIcon,
|
||||
'pencil-filled': icons.PencilFilledIcon,
|
||||
'pencil-off': icons.PencilOffIcon,
|
||||
|
||||
@@ -9,6 +9,8 @@ import PanelResizer, { PanelSide, ResizeFinishCallback, PanelResizeType } from '
|
||||
import ResponsivePaneContent from '@/Components/ResponsivePane/ResponsivePaneContent'
|
||||
import { AppPaneId } from '@/Components/ResponsivePane/AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -18,6 +20,7 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
const viewControllerManager = useMemo(() => application.getViewControllerManager(), [application])
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [panelWidth, setPanelWidth] = useState<number>(0)
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
useEffect(() => {
|
||||
const removeObserver = application.addEventObserver(async () => {
|
||||
@@ -48,31 +51,58 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
return (
|
||||
<div
|
||||
id="navigation"
|
||||
className={'sn-component section app-column w-[220px] xsm-only:!w-full sm-only:!w-full'}
|
||||
className="sn-component section app-column h-screen max-h-screen w-[220px] overflow-hidden pb-8 md:h-full md:min-h-0 md:py-0 xsm-only:!w-full sm-only:!w-full"
|
||||
ref={ref}
|
||||
>
|
||||
<ResponsivePaneContent
|
||||
paneId={AppPaneId.Navigation}
|
||||
contentElementId="navigation-content"
|
||||
contentClassName="min-h-[85vh]"
|
||||
>
|
||||
<div className={'section-title-bar'}>
|
||||
<div className="section-title-bar-header">
|
||||
<div className="title text-sm">
|
||||
<span className="font-bold">Views</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Navigation} contentElementId="navigation-content">
|
||||
<div
|
||||
className={classNames(
|
||||
'h-full overflow-y-auto overflow-x-hidden',
|
||||
'md:overflow-y-hidden md:hover:overflow-y-auto',
|
||||
'flex-grow overflow-y-auto overflow-x-hidden md:overflow-y-hidden md:hover:overflow-y-auto',
|
||||
'md:hover:[overflow-y:_overlay]',
|
||||
)}
|
||||
>
|
||||
<div className={'section-title-bar'}>
|
||||
<div className="section-title-bar-header">
|
||||
<div className="title text-sm">
|
||||
<span className="font-bold">Views</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SmartViewsSection viewControllerManager={viewControllerManager} />
|
||||
<TagsSection viewControllerManager={viewControllerManager} />
|
||||
</div>
|
||||
<div className="flex items-center border-t border-border px-3.5 pt-2.5 md:hidden">
|
||||
<button
|
||||
className="flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
>
|
||||
<Icon type="chevron-left" />
|
||||
</button>
|
||||
<button
|
||||
className="ml-auto flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.toggleShow()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
>
|
||||
<Icon type="account-circle" />
|
||||
</button>
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.quickSettingsMenuController.toggle()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
</button>
|
||||
</div>
|
||||
</ResponsivePaneContent>
|
||||
{ref.current && (
|
||||
<PanelResizer
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import Icon from '../Icon/Icon'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
|
||||
export const NavigationMenuButton = () => {
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
return (
|
||||
<button
|
||||
className="bg-text-padding mr-3 inline-flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border align-middle text-neutral hover:bg-contrast focus:bg-contrast md:hidden"
|
||||
onClick={() => {
|
||||
toggleAppPane(AppPaneId.Navigation)
|
||||
}}
|
||||
title="Navigation menu"
|
||||
aria-label="Navigation menu"
|
||||
>
|
||||
<Icon type="menu-variant" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,27 @@ import FileView from '@/Components/FileView/FileView'
|
||||
import { FileDnDContext } from '@/Components/FileDragNDropProvider/FileDragNDropProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
import ResponsivePaneContent from '../ResponsivePane/ResponsivePaneContent'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
|
||||
const MobileItemsListButton = () => {
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
return (
|
||||
<div className="px-3.5 pt-2.5 md:hidden">
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
>
|
||||
<Icon type="chevron-left" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type State = {
|
||||
showMultipleSelectedNotes: boolean
|
||||
@@ -89,8 +110,12 @@ class NoteGroupView extends PureComponent<Props, State> {
|
||||
!this.state.showMultipleSelectedNotes && !this.state.showMultipleSelectedFiles
|
||||
|
||||
return (
|
||||
<div id={ElementIds.EditorColumn} className="app-column app-column-third h-full">
|
||||
<ResponsivePaneContent paneId={AppPaneId.Editor}>
|
||||
<div
|
||||
id={ElementIds.EditorColumn}
|
||||
className="app-column app-column-third flex min-h-screen flex-col md:h-full md:min-h-0"
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Editor} className="flex-grow">
|
||||
<MobileItemsListButton />
|
||||
{this.state.showMultipleSelectedNotes && (
|
||||
<MultipleSelectedNotes
|
||||
application={this.application}
|
||||
|
||||
@@ -890,207 +890,201 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
||||
|
||||
return (
|
||||
<div aria-label="Note" className="section editor sn-component">
|
||||
<div className="flex-grow flex-col md:flex">
|
||||
{this.state.noteLocked && (
|
||||
<EditingDisabledBanner
|
||||
onMouseLeave={() => {
|
||||
this.setState({
|
||||
lockText: NOTE_EDITING_DISABLED_TEXT,
|
||||
showLockedIcon: true,
|
||||
})
|
||||
}}
|
||||
onMouseOver={() => {
|
||||
this.setState({
|
||||
lockText: 'Enable editing',
|
||||
showLockedIcon: false,
|
||||
})
|
||||
}}
|
||||
onClick={() => this.viewControllerManager.notesController.setLockSelectedNotes(!this.state.noteLocked)}
|
||||
showLockedIcon={this.state.showLockedIcon}
|
||||
lockText={this.state.lockText}
|
||||
{this.state.noteLocked && (
|
||||
<EditingDisabledBanner
|
||||
onMouseLeave={() => {
|
||||
this.setState({
|
||||
lockText: NOTE_EDITING_DISABLED_TEXT,
|
||||
showLockedIcon: true,
|
||||
})
|
||||
}}
|
||||
onMouseOver={() => {
|
||||
this.setState({
|
||||
lockText: 'Enable editing',
|
||||
showLockedIcon: false,
|
||||
})
|
||||
}}
|
||||
onClick={() => this.viewControllerManager.notesController.setLockSelectedNotes(!this.state.noteLocked)}
|
||||
showLockedIcon={this.state.showLockedIcon}
|
||||
lockText={this.state.lockText}
|
||||
/>
|
||||
)}
|
||||
|
||||
{this.note && (
|
||||
<div id="editor-title-bar" className="content-title-bar section-title-bar z-editor-title-bar w-full">
|
||||
<div className="mb-2 flex flex-wrap items-start justify-between gap-2 md:mb-0 md:flex-nowrap md:gap-0 xl:items-center">
|
||||
<div className={(this.state.noteLocked ? 'locked' : '') + ' flex-grow'}>
|
||||
<div className="title overflow-auto">
|
||||
<input
|
||||
className="input text-lg"
|
||||
disabled={this.state.noteLocked}
|
||||
id={ElementIds.NoteTitleEditor}
|
||||
onChange={this.onTitleChange}
|
||||
onFocus={(event) => {
|
||||
event.target.select()
|
||||
}}
|
||||
onKeyUp={this.onTitleEnter}
|
||||
spellCheck={false}
|
||||
value={this.state.editorTitle}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-col flex-wrap items-start gap-3 md:flex-col-reverse md:items-end',
|
||||
'xl:flex-row xl:flex-nowrap xl:items-center',
|
||||
)}
|
||||
>
|
||||
{this.state.noteStatus?.message?.length && (
|
||||
<div id="save-status-container" className={'xl:mr-5 xl:max-w-[16ch]'}>
|
||||
<div id="save-status">
|
||||
<div
|
||||
className={
|
||||
(this.state.syncTakingTooLong ? 'font-bold text-warning ' : '') +
|
||||
(this.state.saveError ? 'font-bold text-danger ' : '') +
|
||||
'message text-xs'
|
||||
}
|
||||
>
|
||||
{this.state.noteStatus?.message}
|
||||
</div>
|
||||
{this.state.noteStatus?.desc && <div className="desc text-xs">{this.state.noteStatus.desc}</div>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-3">
|
||||
<AttachedFilesButton
|
||||
application={this.application}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
featuresController={this.viewControllerManager.featuresController}
|
||||
filePreviewModalController={this.viewControllerManager.filePreviewModalController}
|
||||
filesController={this.viewControllerManager.filesController}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
selectionController={this.viewControllerManager.selectionController}
|
||||
/>
|
||||
<ChangeEditorButton
|
||||
application={this.application}
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
<PinNoteButton
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
<NotesOptionsPanel
|
||||
application={this.application}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
noteTagsController={this.viewControllerManager.noteTagsController}
|
||||
historyModalController={this.viewControllerManager.historyModalController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NoteTagsContainer viewControllerManager={this.viewControllerManager} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
id={ElementIds.EditorContent}
|
||||
className={`${ElementIds.EditorContent} z-editor-content`}
|
||||
ref={this.editorContentRef}
|
||||
>
|
||||
{this.state.marginResizersEnabled && this.editorContentRef.current ? (
|
||||
<PanelResizer
|
||||
minWidth={300}
|
||||
hoverable={true}
|
||||
collapsable={false}
|
||||
panel={this.editorContentRef.current}
|
||||
side={PanelSide.Left}
|
||||
type={PanelResizeType.OffsetAndWidth}
|
||||
left={this.state.leftResizerOffset}
|
||||
width={this.state.leftResizerWidth}
|
||||
resizeFinishCallback={this.onPanelResizeFinish}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{this.state.editorComponentViewer && (
|
||||
<div className="component-view">
|
||||
<ComponentView
|
||||
key={this.state.editorComponentViewer.identifier}
|
||||
componentViewer={this.state.editorComponentViewer}
|
||||
onLoad={this.onEditorComponentLoad}
|
||||
requestReload={this.editorComponentViewerRequestsReload}
|
||||
application={this.application}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{this.state.editorStateDidLoad && !this.state.editorComponentViewer && !this.state.textareaUnloading && (
|
||||
<AutoresizingNoteViewTextarea
|
||||
autoComplete="off"
|
||||
dir="auto"
|
||||
id={ElementIds.NoteTextEditor}
|
||||
onChange={this.onTextAreaChange}
|
||||
value={this.state.editorText}
|
||||
readOnly={this.state.noteLocked}
|
||||
onFocus={this.onContentFocus}
|
||||
spellCheck={this.state.spellcheck}
|
||||
ref={(ref) => ref && this.onSystemEditorLoad(ref)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{this.note && (
|
||||
<div id="editor-title-bar" className="content-title-bar section-title-bar z-editor-title-bar w-full">
|
||||
<div className="mb-2 flex flex-wrap items-start justify-between gap-2 md:mb-0 md:flex-nowrap md:gap-0 xl:items-center">
|
||||
<div className={(this.state.noteLocked ? 'locked' : '') + ' flex-grow'}>
|
||||
<div className="title overflow-auto">
|
||||
<input
|
||||
className="input text-lg"
|
||||
disabled={this.state.noteLocked}
|
||||
id={ElementIds.NoteTitleEditor}
|
||||
onChange={this.onTitleChange}
|
||||
onFocus={(event) => {
|
||||
event.target.select()
|
||||
{this.state.marginResizersEnabled && this.editorContentRef.current ? (
|
||||
<PanelResizer
|
||||
minWidth={300}
|
||||
hoverable={true}
|
||||
collapsable={false}
|
||||
panel={this.editorContentRef.current}
|
||||
side={PanelSide.Right}
|
||||
type={PanelResizeType.OffsetAndWidth}
|
||||
left={this.state.rightResizerOffset}
|
||||
width={this.state.rightResizerWidth}
|
||||
resizeFinishCallback={this.onPanelResizeFinish}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div id="editor-pane-component-stack">
|
||||
{this.state.availableStackComponents.length > 0 && (
|
||||
<div
|
||||
id="component-stack-menu-bar"
|
||||
className="flex h-6 w-full items-center justify-between border-t border-solid border-border bg-contrast px-2 py-0 text-text"
|
||||
>
|
||||
<div className="flex h-full">
|
||||
{this.state.availableStackComponents.map((component) => {
|
||||
return (
|
||||
<div
|
||||
key={component.uuid}
|
||||
onClick={() => {
|
||||
this.toggleStackComponent(component).catch(console.error)
|
||||
}}
|
||||
onKeyUp={this.onTitleEnter}
|
||||
spellCheck={false}
|
||||
value={this.state.editorTitle}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-col flex-wrap items-start gap-3 md:flex-col-reverse md:items-end',
|
||||
'xl:flex-row xl:flex-nowrap xl:items-center',
|
||||
)}
|
||||
>
|
||||
{this.state.noteStatus?.message?.length && (
|
||||
<div id="save-status-container" className={'xl:mr-5 xl:max-w-[16ch]'}>
|
||||
<div id="save-status">
|
||||
<div
|
||||
className={
|
||||
(this.state.syncTakingTooLong ? 'font-bold text-warning ' : '') +
|
||||
(this.state.saveError ? 'font-bold text-danger ' : '') +
|
||||
'message text-xs'
|
||||
}
|
||||
>
|
||||
{this.state.noteStatus?.message}
|
||||
</div>
|
||||
{this.state.noteStatus?.desc && (
|
||||
<div className="desc text-xs">{this.state.noteStatus.desc}</div>
|
||||
)}
|
||||
className="flex flex-grow cursor-pointer items-center justify-center [&:not(:first-child)]:ml-3"
|
||||
>
|
||||
<div className="flex h-full items-center [&:not(:first-child)]:ml-2">
|
||||
{this.stackComponentExpanded(component) && component.active && <IndicatorCircle style="info" />}
|
||||
{!this.stackComponentExpanded(component) && <IndicatorCircle style="neutral" />}
|
||||
</div>
|
||||
<div className="flex h-full items-center [&:not(:first-child)]:ml-2">
|
||||
<div className="whitespace-nowrap text-xs font-bold">{component.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-3">
|
||||
<AttachedFilesButton
|
||||
application={this.application}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
featuresController={this.viewControllerManager.featuresController}
|
||||
filePreviewModalController={this.viewControllerManager.filePreviewModalController}
|
||||
filesController={this.viewControllerManager.filesController}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
selectionController={this.viewControllerManager.selectionController}
|
||||
/>
|
||||
<ChangeEditorButton
|
||||
application={this.application}
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
<PinNoteButton
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
<NotesOptionsPanel
|
||||
application={this.application}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
noteTagsController={this.viewControllerManager.noteTagsController}
|
||||
historyModalController={this.viewControllerManager.historyModalController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<NoteTagsContainer viewControllerManager={this.viewControllerManager} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
id={ElementIds.EditorContent}
|
||||
className={`${ElementIds.EditorContent} z-editor-content`}
|
||||
ref={this.editorContentRef}
|
||||
>
|
||||
{this.state.marginResizersEnabled && this.editorContentRef.current ? (
|
||||
<PanelResizer
|
||||
minWidth={300}
|
||||
hoverable={true}
|
||||
collapsable={false}
|
||||
panel={this.editorContentRef.current}
|
||||
side={PanelSide.Left}
|
||||
type={PanelResizeType.OffsetAndWidth}
|
||||
left={this.state.leftResizerOffset}
|
||||
width={this.state.leftResizerWidth}
|
||||
resizeFinishCallback={this.onPanelResizeFinish}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{this.state.editorComponentViewer && (
|
||||
<div className="component-view">
|
||||
<ComponentView
|
||||
key={this.state.editorComponentViewer.identifier}
|
||||
componentViewer={this.state.editorComponentViewer}
|
||||
onLoad={this.onEditorComponentLoad}
|
||||
requestReload={this.editorComponentViewerRequestsReload}
|
||||
application={this.application}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{this.state.editorStateDidLoad && !this.state.editorComponentViewer && !this.state.textareaUnloading && (
|
||||
<AutoresizingNoteViewTextarea
|
||||
autoComplete="off"
|
||||
dir="auto"
|
||||
id={ElementIds.NoteTextEditor}
|
||||
onChange={this.onTextAreaChange}
|
||||
value={this.state.editorText}
|
||||
readOnly={this.state.noteLocked}
|
||||
onFocus={this.onContentFocus}
|
||||
spellCheck={this.state.spellcheck}
|
||||
ref={(ref) => ref && this.onSystemEditorLoad(ref)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{this.state.marginResizersEnabled && this.editorContentRef.current ? (
|
||||
<PanelResizer
|
||||
minWidth={300}
|
||||
hoverable={true}
|
||||
collapsable={false}
|
||||
panel={this.editorContentRef.current}
|
||||
side={PanelSide.Right}
|
||||
type={PanelResizeType.OffsetAndWidth}
|
||||
left={this.state.rightResizerOffset}
|
||||
width={this.state.rightResizerWidth}
|
||||
resizeFinishCallback={this.onPanelResizeFinish}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div id="editor-pane-component-stack">
|
||||
{this.state.availableStackComponents.length > 0 && (
|
||||
<div
|
||||
id="component-stack-menu-bar"
|
||||
className="flex h-6 w-full items-center justify-between border-t border-solid border-border bg-contrast px-2 py-0 text-text"
|
||||
>
|
||||
<div className="flex h-full">
|
||||
{this.state.availableStackComponents.map((component) => {
|
||||
return (
|
||||
<div
|
||||
key={component.uuid}
|
||||
onClick={() => {
|
||||
this.toggleStackComponent(component).catch(console.error)
|
||||
}}
|
||||
className="flex flex-grow cursor-pointer items-center justify-center [&:not(:first-child)]:ml-3"
|
||||
>
|
||||
<div className="flex h-full items-center [&:not(:first-child)]:ml-2">
|
||||
{this.stackComponentExpanded(component) && component.active && (
|
||||
<IndicatorCircle style="info" />
|
||||
)}
|
||||
{!this.stackComponentExpanded(component) && <IndicatorCircle style="neutral" />}
|
||||
</div>
|
||||
<div className="flex h-full items-center [&:not(:first-child)]:ml-2">
|
||||
<div className="whitespace-nowrap text-xs font-bold">{component.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div className="sn-component">
|
||||
{this.state.stackComponentViewers.map((viewer) => {
|
||||
return (
|
||||
<div className="component-view component-stack-item" key={viewer.identifier}>
|
||||
<ComponentView key={viewer.identifier} componentViewer={viewer} application={this.application} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="sn-component">
|
||||
{this.state.stackComponentViewers.map((viewer) => {
|
||||
return (
|
||||
<div className="component-view component-stack-item" key={viewer.identifier}>
|
||||
<ComponentView key={viewer.identifier} componentViewer={viewer} application={this.application} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,43 +1,27 @@
|
||||
import { useMemo, ReactNode } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { AppPaneIcons, AppPaneId, AppPaneTitles } from './AppPaneMetadata'
|
||||
import { AppPaneId } from './AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import { useResponsiveAppPane } from './ResponsivePaneProvider'
|
||||
|
||||
type Props = {
|
||||
children: ReactNode
|
||||
contentClassName?: string
|
||||
className?: string
|
||||
contentElementId?: string
|
||||
paneId: AppPaneId
|
||||
}
|
||||
|
||||
const ResponsivePaneContent = ({ children, contentClassName, contentElementId, paneId }: Props) => {
|
||||
const { selectedPane, toggleAppPane: togglePane } = useResponsiveAppPane()
|
||||
const ResponsivePaneContent = ({ children, className, contentElementId, paneId }: Props) => {
|
||||
const { selectedPane } = useResponsiveAppPane()
|
||||
|
||||
const isSelectedPane = useMemo(() => selectedPane === paneId, [paneId, selectedPane])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={classNames(
|
||||
'flex w-full items-center justify-between border-b border-solid border-border px-4 py-2 focus:shadow-none focus:outline-none md:hidden',
|
||||
isSelectedPane ? 'bg-contrast' : 'bg-default',
|
||||
)}
|
||||
onClick={() => togglePane(paneId)}
|
||||
>
|
||||
<div className="flex items-center gap-2 font-semibold">
|
||||
<Icon type={AppPaneIcons[paneId]} />
|
||||
<span>{AppPaneTitles[paneId]}</span>
|
||||
</div>
|
||||
<Icon type="chevron-down" />
|
||||
</button>
|
||||
<div
|
||||
id={contentElementId}
|
||||
className={classNames('content flex flex-col', isSelectedPane ? 'h-full' : 'hidden md:flex', contentClassName)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
<div
|
||||
id={contentElementId}
|
||||
className={classNames('content flex flex-col', isSelectedPane ? 'h-full' : 'hidden md:flex', className)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState }) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames('tag', isSelected && 'selected', isFaded && 'opacity-50')}
|
||||
className={classNames('tag py-2 px-3.5 md:py-1', isSelected && 'selected', isFaded && 'opacity-50')}
|
||||
onClick={selectCurrentTag}
|
||||
style={{
|
||||
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
|
||||
|
||||
@@ -22,6 +22,7 @@ import { useDrag, useDrop } from 'react-dnd'
|
||||
import { DropItem, DropProps, ItemTypes } from './DragNDrop'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
type Props = {
|
||||
tag: SNTag
|
||||
@@ -202,7 +203,11 @@ export const TagsListItem: FunctionComponent<Props> = observer(({ tag, features,
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={`tag focus:shadow-inner ${isSelected ? 'selected' : ''} ${readyToDrop ? 'is-drag-over' : ''}`}
|
||||
className={classNames(
|
||||
'tag py-2 px-3.5 focus:shadow-inner md:py-1',
|
||||
isSelected && 'selected',
|
||||
readyToDrop && 'is-drag-over',
|
||||
)}
|
||||
onClick={selectCurrentTag}
|
||||
ref={dragRef}
|
||||
style={{
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { SNApplication } from '@standardnotes/snjs'
|
||||
|
||||
export function openSubscriptionDashboard(application: SNApplication): void {
|
||||
const windowProxy = window.open('', '_blank')
|
||||
application
|
||||
.getNewSubscriptionToken()
|
||||
.then((token) => {
|
||||
if (!token) {
|
||||
return
|
||||
}
|
||||
window.open(`${window.dashboardUrl}?subscription_token=${token}`)
|
||||
;(windowProxy as WindowProxy).location = `${window.dashboardUrl}?subscription_token=${token}`
|
||||
})
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
}
|
||||
|
||||
&:not(.selected) {
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
border-bottom: 1px solid var(--sn-stylekit-border-color);
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user