diff --git a/app/assets/javascripts/ui_models/app_state/app_state.ts b/app/assets/javascripts/ui_models/app_state/app_state.ts
index b31de83182e..4be81e02866 100644
--- a/app/assets/javascripts/ui_models/app_state/app_state.ts
+++ b/app/assets/javascripts/ui_models/app_state/app_state.ts
@@ -431,6 +431,10 @@ export class AppState {
}
public async createNewTag() {
+ if (this.templateTag) {
+ return;
+ }
+
const newTag = (await this.application.createTemplateItem(
ContentType.Tag
)) as SNTag;
diff --git a/app/assets/javascripts/ui_models/app_state/features_state.ts b/app/assets/javascripts/ui_models/app_state/features_state.ts
index aebe2f88a40..ca022d8b4d0 100644
--- a/app/assets/javascripts/ui_models/app_state/features_state.ts
+++ b/app/assets/javascripts/ui_models/app_state/features_state.ts
@@ -6,50 +6,50 @@ import {
import { computed, makeObservable, observable, runInAction } from 'mobx';
import { WebApplication } from '../application';
+export const TAG_FOLDERS_FEATURE_NAME = 'Tag folders';
+export const TAG_FOLDERS_FEATURE_TOOLTIP =
+ 'A Plus or Pro plan is required to enable Tag folders.';
+
/**
* Holds state for premium/non premium features for the current user features,
* and eventually for in-development features (feature flags).
*/
export class FeaturesState {
- readonly hasUnfinishedFeatures: boolean = window?._enable_unfinished_features;
+ readonly enableUnfinishedFeatures: boolean =
+ window?._enable_unfinished_features;
_hasFolders = false;
private unsub: () => void;
constructor(private application: WebApplication) {
- this._hasFolders = this.hasFoldersFeature();
+ this._hasFolders = this.hasNativeFolders();
makeObservable(this, {
_hasFolders: observable,
hasFolders: computed,
- hasUnfinishedFoldersFeature: computed,
+ enableNativeFoldersFeature: computed,
});
- this.unsub = this.application.addEventObserver(async () => {
- runInAction(() => {
- this._hasFolders = this.hasFoldersFeature();
- });
- }, ApplicationEvent.FeaturesUpdated);
+ this.unsub = this.application.addEventObserver(async (eventName) => {
+ switch (eventName) {
+ case ApplicationEvent.FeaturesUpdated:
+ case ApplicationEvent.Launched:
+ runInAction(() => {
+ this._hasFolders = this.hasNativeFolders();
+ });
+ break;
+ default:
+ break;
+ }
+ });
}
public deinit() {
this.unsub();
}
- public get hasUnfinishedFoldersFeature(): boolean {
- return this.hasUnfinishedFeatures;
- }
-
- public hasFoldersFeature(): boolean {
- if (!this.hasUnfinishedFoldersFeature) {
- return false;
- }
-
- const status = this.application.getFeatureStatus(
- FeatureIdentifier.TagNesting
- );
-
- return status === FeatureStatus.Entitled;
+ public get enableNativeFoldersFeature(): boolean {
+ return this.enableUnfinishedFeatures;
}
public get hasFolders(): boolean {
@@ -62,9 +62,9 @@ export class FeaturesState {
return;
}
- if (!this.hasFoldersFeature()) {
+ if (!this.hasNativeFolders()) {
this.application.alertService?.alert(
- 'Tag Folders requires at least a Plus Subscription.'
+ `${TAG_FOLDERS_FEATURE_NAME} requires at least a Plus Subscription.`
);
this._hasFolders = false;
return;
@@ -72,4 +72,16 @@ export class FeaturesState {
this._hasFolders = hasFolders;
}
+
+ private hasNativeFolders(): boolean {
+ if (!this.enableNativeFoldersFeature) {
+ return false;
+ }
+
+ const status = this.application.getFeatureStatus(
+ FeatureIdentifier.TagNesting
+ );
+
+ return status === FeatureStatus.Entitled;
+ }
}
diff --git a/app/assets/javascripts/views/application/application-view.pug b/app/assets/javascripts/views/application/application-view.pug
index 785ce2df5b5..4783b1a5b7e 100644
--- a/app/assets/javascripts/views/application/application-view.pug
+++ b/app/assets/javascripts/views/application/application-view.pug
@@ -3,14 +3,14 @@
)
#app.app(
ng-class='self.state.appClass',
- ng-if='!self.state.needsUnlock && self.state.ready'
+ ng-if='!self.state.needsUnlock && self.state.launched'
)
tags-view(application='self.application')
notes-view(application='self.application')
editor-group-view.flex-grow(application='self.application')
footer-view(
- ng-if='!self.state.needsUnlock && self.state.ready'
+ ng-if='!self.state.needsUnlock && self.state.launched'
application='self.application'
)
diff --git a/app/assets/javascripts/views/application/application_view.ts b/app/assets/javascripts/views/application/application_view.ts
index 91cd5e52125..fa8681ac1d7 100644
--- a/app/assets/javascripts/views/application/application_view.ts
+++ b/app/assets/javascripts/views/application/application_view.ts
@@ -3,25 +3,29 @@ import { WebDirective } from '@/types';
import { getPlatformString } from '@/utils';
import template from './application-view.pug';
import { AppStateEvent, PanelResizedData } from '@/ui_models/app_state';
-import { ApplicationEvent, Challenge, removeFromArray } from '@standardnotes/snjs';
import {
- PANEL_NAME_NOTES,
- PANEL_NAME_TAGS
-} from '@/views/constants';
-import {
- STRING_DEFAULT_FILE_ERROR
-} from '@/strings';
+ ApplicationEvent,
+ Challenge,
+ removeFromArray,
+} from '@standardnotes/snjs';
+import { PANEL_NAME_NOTES, PANEL_NAME_TAGS } from '@/views/constants';
+import { STRING_DEFAULT_FILE_ERROR } from '@/strings';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { alertDialog } from '@/services/alertService';
-class ApplicationViewCtrl extends PureViewCtrl {
- public platformString: string
- private notesCollapsed = false
- private tagsCollapsed = false
+class ApplicationViewCtrl extends PureViewCtrl<
+ unknown,
+ {
+ started?: boolean;
+ launched?: boolean;
+ needsUnlock?: boolean;
+ appClass: string;
+ }
+> {
+ public platformString: string;
+ private notesCollapsed = false;
+ private tagsCollapsed = false;
+
/**
* To prevent stale state reads (setState is async),
* challenges is a mutable array
@@ -76,7 +80,7 @@ class ApplicationViewCtrl extends PureViewCtrl {
this.challenges.push(challenge);
});
- }
+ },
});
await this.application.launch();
}
@@ -90,14 +94,17 @@ class ApplicationViewCtrl extends PureViewCtrl .tag-icon {
- width: 10px;
- font-size: var(--sn-stylekit-font-size-h2);
- font-weight: bold;
- margin-right: 6px;
+ svg {
+ display: block;
+ margin: auto;
+ }
&.draggable {
cursor: move;
diff --git a/package.json b/package.json
index 6f7358fdbea..73b501b4001 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,7 @@
"pug-loader": "^2.4.0",
"sass-loader": "^12.2.0",
"serve-static": "^1.14.1",
- "sn-stylekit": "5.2.17",
+ "sn-stylekit": "5.2.20",
"svg-jest": "^1.0.1",
"ts-jest": "^27.0.7",
"ts-loader": "^9.2.6",
@@ -86,7 +86,7 @@
"@standardnotes/features": "1.10.2",
"@reach/tooltip": "^0.16.2",
"@standardnotes/sncrypto-web": "1.5.3",
- "@standardnotes/snjs": "2.23.2",
+ "@standardnotes/snjs": "2.24.0",
"mobx": "^6.3.5",
"mobx-react-lite": "^3.2.2",
"preact": "^10.5.15",
diff --git a/yarn.lock b/yarn.lock
index cdf97cbbafd..43cadd87692 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2623,7 +2623,7 @@
dependencies:
"@standardnotes/auth" "^3.8.1"
-"@standardnotes/features@1.10.2", "@standardnotes/features@^1.10.2":
+"@standardnotes/features@1.10.2":
version "1.10.2"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.10.2.tgz#a0783f66c00e21cb7692edc0cea95ec25a0253a5"
integrity sha512-Zh6EMjli4mL6jlXEhMyU3qYIKFJj5kuhbxtHXiErUGIDy+s1hHY+THFFO53Jdga2+8wgcATWlmSBY7dieVA8uA==
@@ -2631,6 +2631,14 @@
"@standardnotes/auth" "3.8.3"
"@standardnotes/common" "^1.2.1"
+"@standardnotes/features@^1.10.3":
+ version "1.10.3"
+ resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.10.3.tgz#f5824342446e69f006ea8ac8916203d1d3992f21"
+ integrity sha512-PU4KthoDr6NL1bOfKnYV1WXYqRu1/IcdkZkJa2LHcYMPduUjDUKO6qRK73dF0+EEI1U+YXY/9rHyfadGwd0Ymg==
+ dependencies:
+ "@standardnotes/auth" "3.8.3"
+ "@standardnotes/common" "^1.2.1"
+
"@standardnotes/settings@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.2.1.tgz#4c7656ea86d784a2f77c70acc89face5d28da024"
@@ -2650,15 +2658,15 @@
buffer "^6.0.3"
libsodium-wrappers "^0.7.9"
-"@standardnotes/snjs@2.23.2":
- version "2.23.2"
- resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.23.2.tgz#16f76c7e4278be9f315e90b96dabfcee2d6b7961"
- integrity sha512-CPLvizemAYRO0XaDOD8pnjrzYSkvcw/UI0V6hlfe9VkJ2jLHotbDSeHdzFotjosX5leGB4UXemjd09EzDNdqpA==
+"@standardnotes/snjs@2.24.0":
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.24.0.tgz#28dce92d4f0a1108d5edf032a7bea1997d276dfd"
+ integrity sha512-R2LPLAx5q06BZ3qLF5AMXI62PFlEgj5i1wj5tEWglWxug+c478A6y+L1+ROTz1GIjv+vmn4bJ7M1MBbYnJgQaw==
dependencies:
"@standardnotes/auth" "^3.8.1"
"@standardnotes/common" "^1.2.1"
"@standardnotes/domain-events" "^2.5.1"
- "@standardnotes/features" "^1.10.2"
+ "@standardnotes/features" "^1.10.3"
"@standardnotes/settings" "^1.2.1"
"@standardnotes/sncrypto-common" "^1.5.2"
@@ -9170,10 +9178,10 @@ slice-ansi@^5.0.0:
ansi-styles "^6.0.0"
is-fullwidth-code-point "^4.0.0"
-sn-stylekit@5.2.17:
- version "5.2.17"
- resolved "https://registry.yarnpkg.com/sn-stylekit/-/sn-stylekit-5.2.17.tgz#5d8ceefacc044d24f71f99c343bc4e0a9f867e3b"
- integrity sha512-YjIstWUjkRYc0zWKxTcLDk8ZKfb9nskQAbsNsihKbJsko1tQbDywrvoQff8TmsE8kXedTd7z/8yUYrYlqgKp6g==
+sn-stylekit@5.2.20:
+ version "5.2.20"
+ resolved "https://registry.yarnpkg.com/sn-stylekit/-/sn-stylekit-5.2.20.tgz#c18f40ff3aaf4c59af89152439a8efbdde35f2dd"
+ integrity sha512-JymHBiZOzQPfCqHYgnVPSA2PwJqiKR268qqQoEMqI85MMAWSG3WYzuKEbd0LgfIQAKLElCxJjeZkrhejyRg+2A==
dependencies:
"@reach/listbox" "^0.15.0"
"@reach/menu-button" "^0.15.1"