feat: improve strings, challenges, and template readiness

This commit is contained in:
Mo Bitar
2020-09-23 22:33:33 -05:00
parent 825ec6bcbb
commit b3e5ca340d
21 changed files with 48 additions and 74 deletions

View File

@@ -1,5 +1,5 @@
import { WebDirective } from './../../types'; import { WebDirective } from './../../types';
import { isDesktopApplication, isNullOrUndefined, preventRefreshing } from '@/utils'; import { isDesktopApplication, preventRefreshing } from '@/utils';
import template from '%/directives/account-menu.pug'; import template from '%/directives/account-menu.pug';
import { ProtectedAction, ContentType } from 'snjs'; import { ProtectedAction, ContentType } from 'snjs';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';

View File

@@ -3,7 +3,7 @@ import { WebDirective } from './../../types';
import template from '%/directives/actions-menu.pug'; import template from '%/directives/actions-menu.pug';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { SNItem, Action, SNActionsExtension, UuidString } from 'snjs/dist/@types'; import { SNItem, Action, SNActionsExtension, UuidString } from 'snjs/dist/@types';
import { ActionResponse } from 'snjs/dist/@types/services/actions_service'; import { ActionResponse } from 'snjs';
import { ActionsExtensionMutator } from 'snjs/dist/@types/models/app/extension'; import { ActionsExtensionMutator } from 'snjs/dist/@types/models/app/extension';
type ActionsMenuScope = { type ActionsMenuScope = {
@@ -144,8 +144,8 @@ class ActionsMenuCtrl extends PureViewCtrl<{}, ActionsMenuState> implements Acti
} }
private async updateAction( private async updateAction(
action: Action, action: Action,
extension: SNActionsExtension, extension: SNActionsExtension,
params: UpdateActionParams params: UpdateActionParams
) { ) {
const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => { const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => {

View File

@@ -1,5 +1,5 @@
/* eslint-disable prefer-promise-reject-errors */ /* eslint-disable prefer-promise-reject-errors */
import { SNAlertService, ButtonType, DismissBlockingDialog } from 'snjs'; import { SNAlertService, ButtonType } from 'snjs';
import { SKAlert } from 'sn-stylekit'; import { SKAlert } from 'sn-stylekit';
/** @returns a promise resolving to true if the user confirmed, false if they canceled */ /** @returns a promise resolving to true if the user confirmed, false if they canceled */

View File

@@ -1,4 +1,4 @@
import { ApplicationGroup } from './../ui_models/application_group'; import { ApplicationService } from 'snjs';
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { AppStateEvent } from '@/ui_models/app_state'; import { AppStateEvent } from '@/ui_models/app_state';
@@ -13,26 +13,21 @@ const LOCK_INTERVAL_ONE_HOUR = 3600 * MILLISECONDS_PER_SECOND;
const STORAGE_KEY_AUTOLOCK_INTERVAL = "AutoLockIntervalKey"; const STORAGE_KEY_AUTOLOCK_INTERVAL = "AutoLockIntervalKey";
export class AutolockService { export class AutolockService extends ApplicationService {
private application: WebApplication
private unsubState: any private unsubState: any
private pollFocusInterval: any private pollFocusInterval: any
private lastFocusState?: 'hidden' | 'visible' private lastFocusState?: 'hidden' | 'visible'
private lockAfterDate?: Date private lockAfterDate?: Date
private lockTimeout?: any private lockTimeout?: any
constructor( onAppLaunch() {
application: WebApplication this.observeVisibility();
) { return super.onAppLaunch();
this.application = application;
setTimeout(() => {
this.observeVisibility();
}, 0);
} }
observeVisibility() { observeVisibility() {
this.unsubState = this.application.getAppState().addObserver( this.unsubState = (this.application as WebApplication).getAppState().addObserver(
async (eventName) => { async (eventName) => {
if (eventName === AppStateEvent.WindowDidBlur) { if (eventName === AppStateEvent.WindowDidBlur) {
this.documentVisibilityChanged(false); this.documentVisibilityChanged(false);

View File

@@ -1,5 +1,4 @@
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import _ from 'lodash';
import { import {
StorageValueModes, StorageValueModes,
EncryptionIntent, EncryptionIntent,

View File

@@ -46,8 +46,6 @@ export const STRING_INVALID_IMPORT_FILE = "Unable to open file. Ensure it is a p
export function StringImportError(errorCount: number) { export function StringImportError(errorCount: number) {
return `Import complete. ${errorCount} items were not imported because there was an error decrypting them. Make sure the password is correct and try again.`; return `Import complete. ${errorCount} items were not imported because there was an error decrypting them. Make sure the password is correct and try again.`;
} }
export const STRING_STORAGE_UPDATE = 'Storage Update';
export const STRING_AUTHENTICATION_REQUIRED = 'Authentication Required';
export const STRING_UNSUPPORTED_BACKUP_FILE_VERSION = 'This backup file was created using an unsupported version of the application and cannot be imported here. Please update your application and try again.'; export const STRING_UNSUPPORTED_BACKUP_FILE_VERSION = 'This backup file was created using an unsupported version of the application and cannot be imported here. Please update your application and try again.';
/** @password_change */ /** @password_change */
@@ -67,8 +65,8 @@ export const STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL =
export const STRING_UPGRADE_ACCOUNT_CONFIRM_TITLE = 'Encryption upgrade available'; export const STRING_UPGRADE_ACCOUNT_CONFIRM_TITLE = 'Encryption upgrade available';
export const STRING_UPGRADE_ACCOUNT_CONFIRM_TEXT = export const STRING_UPGRADE_ACCOUNT_CONFIRM_TEXT =
'Encryption version 004 is available for your account and local data storage. ' + 'Encryption version 004 is available. ' +
'This version strengthens the encryption algorithms for your account and ' + 'This version strengthens the encryption algorithms your account and ' +
'disk use. To learn more about this upgrade, visit our ' + 'local storage use. To learn more about this upgrade, visit our ' +
'<a href="https://standardnotes.org/help/security" target="_blank">Security Upgrade page.</a>'; '<a href="https://standardnotes.org/help/security" target="_blank">Security Upgrade page.</a>';
export const STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON = 'Upgrade'; export const STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON = 'Upgrade';

View File

@@ -4,9 +4,7 @@ import { EditorGroup } from '@/ui_models/editor_group';
import { InputModalScope } from '@/directives/views/inputModal'; import { InputModalScope } from '@/directives/views/inputModal';
import { PasswordWizardType, PasswordWizardScope } from '@/types'; import { PasswordWizardType, PasswordWizardScope } from '@/types';
import { import {
Environment,
SNApplication, SNApplication,
SNAlertService,
platformFromString, platformFromString,
Challenge, Challenge,
ProtectedAction ProtectedAction
@@ -167,21 +165,6 @@ export class WebApplication extends SNApplication {
angular.element(document.body).append(el); angular.element(document.body).append(el);
} }
async performProtocolUpgrade() {
const result = await this.upgradeProtocolVersion();
if (result.success) {
this.alertService!.alert(
"Success! Your encryption version has been upgraded." +
" You'll be asked to enter your credentials again on other devices you're signed into."
);
} else if (result.error) {
console.error(result.error);
this.alertService!.alert(
"Unable to upgrade encryption version. Please try again."
);
}
}
async presentPrivilegesModal( async presentPrivilegesModal(
action: ProtectedAction, action: ProtectedAction,
onSuccess?: any, onSuccess?: any,

View File

@@ -12,6 +12,11 @@ export class PureViewCtrl<P = CtrlProps, S = CtrlState> {
private unsubApp: any private unsubApp: any
private unsubState: any private unsubState: any
private stateTimeout?: ng.IPromise<void> private stateTimeout?: ng.IPromise<void>
/**
* Subclasses can optionally add an ng-if=ctrl.templateReady to make sure that
* no Angular handlebars/syntax render in the UI before display data is ready.
*/
protected templateReady = false
/* @ngInject */ /* @ngInject */
constructor( constructor(
@@ -28,6 +33,7 @@ export class PureViewCtrl<P = CtrlProps, S = CtrlState> {
} }
this.addAppEventObserver(); this.addAppEventObserver();
this.addAppStateObserver(); this.addAppStateObserver();
this.templateReady = true;
} }
deinit() { deinit() {
@@ -114,7 +120,7 @@ export class PureViewCtrl<P = CtrlProps, S = CtrlState> {
await this.onAppLaunch(); await this.onAppLaunch();
} else if (eventName === ApplicationEvent.CompletedIncrementalSync) { } else if (eventName === ApplicationEvent.CompletedIncrementalSync) {
this.onAppIncrementalSync(); this.onAppIncrementalSync();
} else if (eventName === ApplicationEvent.CompletedFullSync) { } else if (eventName === ApplicationEvent.CompletedFullSync) {
this.onAppFullSync(); this.onAppFullSync();
} else if (eventName === ApplicationEvent.KeyStatusChanged) { } else if (eventName === ApplicationEvent.KeyStatusChanged) {
this.onAppKeyChange(); this.onAppKeyChange();

View File

@@ -10,12 +10,10 @@ import {
PANEL_NAME_TAGS PANEL_NAME_TAGS
} from '@/views/constants'; } from '@/views/constants';
import { import {
STRING_SESSION_EXPIRED,
STRING_DEFAULT_FILE_ERROR STRING_DEFAULT_FILE_ERROR
} from '@/strings'; } from '@/strings';
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
import { PermissionDialog } from 'snjs/dist/@types/services/component_manager'; import { PermissionDialog } from 'snjs/dist/@types/services/component_manager';
import { alertDialog } from '@/services/alertService';
class ApplicationViewCtrl extends PureViewCtrl { class ApplicationViewCtrl extends PureViewCtrl {
private $compile?: ng.ICompileService private $compile?: ng.ICompileService

View File

@@ -1,15 +1,15 @@
.sk-modal-background(ng-click="ctrl.cancel()") .sk-modal-background(ng-click="ctrl.cancel()")
.challenge-modal.sk-modal-content .challenge-modal.sk-modal-content(ng-if='ctrl.templateReady')
.sn-component .sn-component
.sk-panel .sk-panel
.sk-panel-header .sk-panel-header
.sk-panel-header-title {{ctrl.modalTitle}} .sk-panel-header-title {{ctrl.challenge.modalTitle}}
.sk-panel-content .sk-panel-content
.sk-panel-section .sk-panel-section
.sk-p.sk-panel-row.centered.prompt .sk-p.sk-panel-row.centered.prompt
strong {{ctrl.state.title}} strong {{ctrl.challenge.heading}}
.sk-p.sk-panel-row.centered.subprompt(ng-if='ctrl.state.subtitle') .sk-p.sk-panel-row.centered.subprompt(ng-if='ctrl.challenge.subheading')
| {{ctrl.state.subtitle}} | {{ctrl.challenge.subheading}}
.sk-panel-section .sk-panel-section
div(ng-repeat="prompt in ctrl.state.prompts track by prompt.id") div(ng-repeat="prompt in ctrl.state.prompts track by prompt.id")
.sk-panel-row .sk-panel-row

View File

@@ -12,8 +12,6 @@ import { WebDirective } from '@/types';
import { confirmDialog } from '@/services/alertService'; import { confirmDialog } from '@/services/alertService';
import { import {
STRING_SIGN_OUT_CONFIRMATION, STRING_SIGN_OUT_CONFIRMATION,
STRING_STORAGE_UPDATE,
STRING_AUTHENTICATION_REQUIRED,
} from '@/strings'; } from '@/strings';
type InputValue = { type InputValue = {
@@ -32,8 +30,6 @@ type ChallengeModalState = {
showForgotPasscodeLink: boolean, showForgotPasscodeLink: boolean,
processingPrompts: ChallengePrompt[], processingPrompts: ChallengePrompt[],
hasAccount: boolean, hasAccount: boolean,
title: string,
subtitle: string
} }
class ChallengeModalCtrl extends PureViewCtrl<{}, ChallengeModalState> { class ChallengeModalCtrl extends PureViewCtrl<{}, ChallengeModalState> {
@@ -93,8 +89,6 @@ class ChallengeModalCtrl extends PureViewCtrl<{}, ChallengeModalState> {
forgotPasscode: false, forgotPasscode: false,
showForgotPasscodeLink, showForgotPasscodeLink,
hasAccount: this.application.hasAccount(), hasAccount: this.application.hasAccount(),
title: this.challenge.title,
subtitle: this.challenge.subtitle,
processingPrompts: [] processingPrompts: []
}); });
this.application.addChallengeObserver( this.application.addChallengeObserver(
@@ -137,14 +131,6 @@ class ChallengeModalCtrl extends PureViewCtrl<{}, ChallengeModalState> {
}); });
} }
get modalTitle(): string {
if (this.challenge.reason === ChallengeReason.Migration) {
return STRING_STORAGE_UPDATE;
} else {
return STRING_AUTHENTICATION_REQUIRED;
}
}
async destroyLocalData() { async destroyLocalData() {
if (await confirmDialog({ if (await confirmDialog({
text: STRING_SIGN_OUT_CONFIRMATION, text: STRING_SIGN_OUT_CONFIRMATION,

View File

@@ -347,7 +347,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
confirmButtonText: STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON, confirmButtonText: STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON,
})) { })) {
preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_UPGRADE, async () => { preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_UPGRADE, async () => {
await this.application.performProtocolUpgrade(); await this.application.upgradeProtocolVersion();
}); });
} }
} }

View File

@@ -1,4 +1,4 @@
import { SNNote, SNTag } from 'snjs'; import { SNNote } from 'snjs';
export enum NoteSortKey { export enum NoteSortKey {
CreatedAt = 'created_at', CreatedAt = 'created_at',

View File

@@ -13,8 +13,9 @@
.challenge-modal { .challenge-modal {
max-width: 480px; max-width: 480px;
min-width: 400px !important;
.prompt { .prompt, .subprompt {
text-align: center; text-align: center;
} }
.sk-panel .sk-panel-header { .sk-panel .sk-panel-header {

View File

@@ -57,6 +57,10 @@ $screen-md-max: ($screen-lg-min - 1) !default;
} }
} }
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
.selectable { .selectable {
user-select: text !important; user-select: text !important;
cursor: text; cursor: text;

View File

@@ -1,12 +1,11 @@
import { WebApplication } from '@/ui_models/application'; import { ApplicationService } from 'snjs';
export declare class AutolockService { export declare class AutolockService extends ApplicationService {
private application;
private unsubState; private unsubState;
private pollFocusInterval; private pollFocusInterval;
private lastFocusState?; private lastFocusState?;
private lockAfterDate?; private lockAfterDate?;
private lockTimeout?; private lockTimeout?;
constructor(application: WebApplication); onAppLaunch(): Promise<void>;
observeVisibility(): void; observeVisibility(): void;
deinit(): void; deinit(): void;
private lockApplication; private lockApplication;

View File

@@ -32,11 +32,12 @@ export declare const STRING_GENERATING_LOGIN_KEYS = "Generating Login Keys...";
export declare const STRING_GENERATING_REGISTER_KEYS = "Generating Account Keys..."; export declare const STRING_GENERATING_REGISTER_KEYS = "Generating Account Keys...";
export declare const STRING_INVALID_IMPORT_FILE = "Unable to open file. Ensure it is a proper JSON file and try again."; export declare const STRING_INVALID_IMPORT_FILE = "Unable to open file. Ensure it is a proper JSON file and try again.";
export declare function StringImportError(errorCount: number): string; export declare function StringImportError(errorCount: number): string;
export declare const STRING_STORAGE_UPDATE = "Storage Update";
export declare const STRING_AUTHENTICATION_REQUIRED = "Authentication Required";
export declare const STRING_UNSUPPORTED_BACKUP_FILE_VERSION = "This backup file was created using an unsupported version of the application and cannot be imported here. Please update your application and try again."; export declare const STRING_UNSUPPORTED_BACKUP_FILE_VERSION = "This backup file was created using an unsupported version of the application and cannot be imported here. Please update your application and try again.";
/** @password_change */ /** @password_change */
export declare const STRING_FAILED_PASSWORD_CHANGE = "There was an error re-encrypting your items. Your password was changed, but not all your items were properly re-encrypted and synced. You should try syncing again. If all else fails, you should restore your notes from backup."; export declare const STRING_FAILED_PASSWORD_CHANGE = "There was an error re-encrypting your items. Your password was changed, but not all your items were properly re-encrypted and synced. You should try syncing again. If all else fails, you should restore your notes from backup.";
export declare const STRING_CONFIRM_APP_QUIT_DURING_UPGRADE: string; export declare const STRING_CONFIRM_APP_QUIT_DURING_UPGRADE: string;
export declare const STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE: string; export declare const STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_CHANGE: string;
export declare const STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL: string; export declare const STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL: string;
export declare const STRING_UPGRADE_ACCOUNT_CONFIRM_TITLE = "Encryption upgrade available";
export declare const STRING_UPGRADE_ACCOUNT_CONFIRM_TEXT: string;
export declare const STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON = "Upgrade";

View File

@@ -42,7 +42,6 @@ export declare class WebApplication extends SNApplication {
checkForSecurityUpdate(): Promise<boolean>; checkForSecurityUpdate(): Promise<boolean>;
presentPasswordWizard(type: PasswordWizardType): void; presentPasswordWizard(type: PasswordWizardType): void;
promptForChallenge(challenge: Challenge): void; promptForChallenge(challenge: Challenge): void;
performProtocolUpgrade(): Promise<void>;
presentPrivilegesModal(action: ProtectedAction, onSuccess?: any, onCancel?: any): Promise<void>; presentPrivilegesModal(action: ProtectedAction, onSuccess?: any, onCancel?: any): Promise<void>;
presentPrivilegesManagementModal(): void; presentPrivilegesManagementModal(): void;
authenticationInProgress(): boolean; authenticationInProgress(): boolean;

View File

@@ -12,6 +12,11 @@ export declare class PureViewCtrl<P = CtrlProps, S = CtrlState> {
private unsubApp; private unsubApp;
private unsubState; private unsubState;
private stateTimeout?; private stateTimeout?;
/**
* Subclasses can optionally add an ng-if=ctrl.templateReady to make sure that
* no Angular handlebars/syntax render in the UI before display data is ready.
*/
protected templateReady: boolean;
constructor($timeout: ng.ITimeoutService, props?: P); constructor($timeout: ng.ITimeoutService, props?: P);
$onInit(): void; $onInit(): void;
deinit(): void; deinit(): void;

4
package-lock.json generated
View File

@@ -10956,8 +10956,8 @@
"from": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad" "from": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad"
}, },
"snjs": { "snjs": {
"version": "github:standardnotes/snjs#6a0e03eaca106ffda7bce7d87761a29fd8f8420d", "version": "github:standardnotes/snjs#723200296d6481b8835a8a3651130e38a9eaf449",
"from": "github:standardnotes/snjs#6a0e03eaca106ffda7bce7d87761a29fd8f8420d" "from": "github:standardnotes/snjs#723200296d6481b8835a8a3651130e38a9eaf449"
}, },
"sockjs": { "sockjs": {
"version": "0.3.20", "version": "0.3.20",

View File

@@ -68,6 +68,6 @@
}, },
"dependencies": { "dependencies": {
"sncrypto": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad", "sncrypto": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad",
"snjs": "github:standardnotes/snjs#6a0e03eaca106ffda7bce7d87761a29fd8f8420d" "snjs": "github:standardnotes/snjs#723200296d6481b8835a8a3651130e38a9eaf449"
} }
} }