feat: snjs app groups (#468)
* feat: snjs app groups * fix: update snjs version to point to wip commit * wip: account switcher * feat: rename lock manager to auto lock service * fix: more relevant sign out copy * chore(deps): update snjs * fix: use setTimeout instead of setImmediate * feat: make account switcher expiremental feature * chore(deps): upgrade snjs
This commit is contained in:
@@ -7,6 +7,7 @@ import angular from 'angular';
|
||||
import { configRoutes } from './routes';
|
||||
|
||||
import { ApplicationGroup } from './ui_models/application_group';
|
||||
import { AccountSwitcher } from './views/account_switcher/account_switcher';
|
||||
|
||||
import {
|
||||
ApplicationGroupView,
|
||||
@@ -104,6 +105,7 @@ function startApplication(
|
||||
angular
|
||||
.module('app')
|
||||
.directive('accountMenu', () => new AccountMenu())
|
||||
.directive('accountSwitcher', () => new AccountSwitcher())
|
||||
.directive('actionsMenu', () => new ActionsMenu())
|
||||
.directive('challengeModal', () => new ChallengeModal())
|
||||
.directive('componentModal', () => new ComponentModal())
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { SNAlertService } from "@node_modules/snjs/dist/@types";
|
||||
import { SNAlertService } from "snjs/dist/@types";
|
||||
|
||||
const DB_NAME = 'standardnotes';
|
||||
const STORE_NAME = 'items';
|
||||
const READ_WRITE = 'readwrite';
|
||||
|
||||
@@ -17,18 +16,18 @@ const DB_DELETION_BLOCKED =
|
||||
const QUOTE_EXCEEDED_ERROR = 'QuotaExceededError';
|
||||
|
||||
export class Database {
|
||||
|
||||
private locked = true
|
||||
private alertService?: SNAlertService
|
||||
private db?: IDBDatabase
|
||||
|
||||
public deinit() {
|
||||
this.alertService = undefined;
|
||||
this.db = undefined;
|
||||
constructor(
|
||||
public databaseName: string,
|
||||
private alertService: SNAlertService) {
|
||||
|
||||
}
|
||||
|
||||
public setAlertService(alertService: SNAlertService) {
|
||||
this.alertService = alertService;
|
||||
public deinit() {
|
||||
(this.alertService as any) = undefined;
|
||||
this.db = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +40,7 @@ export class Database {
|
||||
/**
|
||||
* Opens the database natively, or returns the existing database object if already opened.
|
||||
* @param onNewDatabase - Callback to invoke when a database has been created
|
||||
* as part of the open process. This can happen on new application sessions, or if the
|
||||
* as part of the open process. This can happen on new application sessions, or if the
|
||||
* browser deleted the database without the user being aware.
|
||||
*/
|
||||
public async openDatabase(onNewDatabase?: () => void): Promise<IDBDatabase | undefined> {
|
||||
@@ -51,7 +50,7 @@ export class Database {
|
||||
if (this.db) {
|
||||
return this.db;
|
||||
}
|
||||
const request = window.indexedDB.open(DB_NAME, 1);
|
||||
const request = window.indexedDB.open(this.databaseName, 1);
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onerror = (event) => {
|
||||
const target = event!.target! as any;
|
||||
@@ -181,7 +180,7 @@ export class Database {
|
||||
}
|
||||
|
||||
public async clearAllPayloads(): Promise<void> {
|
||||
const deleteRequest = window.indexedDB.deleteDatabase(DB_NAME);
|
||||
const deleteRequest = window.indexedDB.deleteDatabase(this.databaseName);
|
||||
return new Promise((resolve, reject) => {
|
||||
deleteRequest.onerror = () => {
|
||||
reject(Error('Error deleting database.'));
|
||||
|
||||
@@ -7,9 +7,9 @@ export function selectOnFocus($window: ng.IWindowService) {
|
||||
if (!$window.getSelection()!.toString()) {
|
||||
const input = element[0] as HTMLInputElement;
|
||||
/** Allow text to populate */
|
||||
setImmediate(() => {
|
||||
setTimeout(() => {
|
||||
input.setSelectionRange(0, input.value.length);
|
||||
})
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ type AccountMenuState = {
|
||||
class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
|
||||
|
||||
public appVersion: string
|
||||
private syncStatus?: SyncOpStatus
|
||||
/** @template */
|
||||
syncStatus?: SyncOpStatus
|
||||
private closeFunction?: () => void
|
||||
|
||||
/* @ngInject */
|
||||
@@ -86,7 +87,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
|
||||
getInitialState() {
|
||||
return {
|
||||
appVersion: 'v' + ((window as any).electronAppVersion || this.appVersion),
|
||||
passcodeAutoLockOptions: this.application!.getLockService().getAutoLockIntervalOptions(),
|
||||
passcodeAutoLockOptions: this.application!.getAutolockService().getAutoLockIntervalOptions(),
|
||||
user: this.application!.getUser(),
|
||||
formData: {
|
||||
mergeLocal: true,
|
||||
@@ -463,7 +464,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
|
||||
}
|
||||
|
||||
async reloadAutoLockInterval() {
|
||||
const interval = await this.application!.getLockService().getAutoLockInterval();
|
||||
const interval = await this.application!.getAutolockService().getAutoLockInterval();
|
||||
this.setState({
|
||||
selectedAutoLockInterval: interval
|
||||
});
|
||||
@@ -471,7 +472,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
|
||||
|
||||
async selectAutoLockInterval(interval: number) {
|
||||
const run = async () => {
|
||||
await this.application!.getLockService().setAutoLockInterval(interval);
|
||||
await this.application!.getAutolockService().setAutoLockInterval(interval);
|
||||
this.reloadAutoLockInterval();
|
||||
};
|
||||
const needsPrivilege = await this.application!.privilegesService!.actionRequiresPrivilege(
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SNComponent, SNItem, ComponentArea } from 'snjs';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import template from '%/directives/editor-menu.pug';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { ComponentMutator } from '@node_modules/snjs/dist/@types/models';
|
||||
import { ComponentMutator } from 'snjs/dist/@types/models';
|
||||
|
||||
interface EditorMenuScope {
|
||||
callback: (component: SNComponent) => void
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebDirective } from '../../types';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import template from '%/directives/history-menu.pug';
|
||||
import { SNItem, ItemHistoryEntry } from '@node_modules/snjs/dist/@types';
|
||||
import { SNItem, ItemHistoryEntry } from 'snjs/dist/@types';
|
||||
import { PureViewCtrl } from '@/views';
|
||||
import { ItemSessionHistory } from 'snjs/dist/@types/services/history/session/item_session_history';
|
||||
import { RemoteHistoryList, RemoteHistoryListEntry } from 'snjs/dist/@types/services/history/history_manager';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { WebApplication } from '@/ui_models/application';
|
||||
import template from '%/directives/privileges-management-modal.pug';
|
||||
import { PrivilegeCredential, ProtectedAction, SNPrivileges, PrivilegeSessionLength } from 'snjs';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { PrivilegeMutator } from '@node_modules/snjs/dist/@types/models';
|
||||
import { PrivilegeMutator } from 'snjs/dist/@types/models';
|
||||
|
||||
type DisplayInfo = {
|
||||
label: string
|
||||
@@ -32,7 +32,7 @@ class PrivilegesManagementModalCtrl extends PureViewCtrl {
|
||||
super($timeout);
|
||||
this.$element = $element;
|
||||
}
|
||||
|
||||
|
||||
async onAppLaunch() {
|
||||
super.onAppLaunch();
|
||||
this.hasPasscode = this.application.hasPasscode();
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ComponentArea
|
||||
} from 'snjs';
|
||||
import template from '%/directives/revision-preview-modal.pug';
|
||||
import { PayloadContent } from '@node_modules/snjs/dist/@types/protocol/payloads/generator';
|
||||
import { PayloadContent } from 'snjs/dist/@types/protocol/payloads/generator';
|
||||
import { confirmDialog } from '@/services/alertService';
|
||||
|
||||
interface RevisionPreviewScope {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ApplicationGroup } from './../ui_models/application_group';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import { AppStateEvent } from '@/ui_models/app_state';
|
||||
@@ -12,7 +13,7 @@ const LOCK_INTERVAL_ONE_HOUR = 3600 * MILLISECONDS_PER_SECOND;
|
||||
|
||||
const STORAGE_KEY_AUTOLOCK_INTERVAL = "AutoLockIntervalKey";
|
||||
|
||||
export class LockManager {
|
||||
export class AutolockService {
|
||||
|
||||
private application: WebApplication
|
||||
private unsubState: any
|
||||
@@ -21,11 +22,13 @@ export class LockManager {
|
||||
private lockAfterDate?: Date
|
||||
private lockTimeout?: any
|
||||
|
||||
constructor(application: WebApplication) {
|
||||
constructor(
|
||||
application: WebApplication
|
||||
) {
|
||||
this.application = application;
|
||||
setImmediate(() => {
|
||||
setTimeout(() => {
|
||||
this.observeVisibility();
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
observeVisibility() {
|
||||
@@ -50,6 +53,10 @@ export class LockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private lockApplication() {
|
||||
this.application.lock();
|
||||
}
|
||||
|
||||
async setAutoLockInterval(interval: number) {
|
||||
return this.application!.setValue(
|
||||
STORAGE_KEY_AUTOLOCK_INTERVAL,
|
||||
@@ -118,7 +125,7 @@ export class LockManager {
|
||||
this.lockAfterDate &&
|
||||
new Date() > this.lockAfterDate
|
||||
) {
|
||||
this.application.lock();
|
||||
this.lockApplication();
|
||||
}
|
||||
this.cancelAutoLockTimer();
|
||||
} else {
|
||||
@@ -132,9 +139,9 @@ export class LockManager {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Use a timeout if possible, but if the computer is put to sleep, timeouts won't
|
||||
* work. Need to set a date as backup. this.lockAfterDate does not need to be
|
||||
* persisted, as living in memory is sufficient. If memory is cleared, then the
|
||||
* Use a timeout if possible, but if the computer is put to sleep, timeouts won't
|
||||
* work. Need to set a date as backup. this.lockAfterDate does not need to be
|
||||
* persisted, as living in memory is sufficient. If memory is cleared, then the
|
||||
* application will lock anyway.
|
||||
*/
|
||||
const addToNow = (seconds: number) => {
|
||||
@@ -145,7 +152,7 @@ export class LockManager {
|
||||
this.lockAfterDate = addToNow(interval / MILLISECONDS_PER_SECOND);
|
||||
this.lockTimeout = setTimeout(() => {
|
||||
this.cancelAutoLockTimer();
|
||||
this.application.lock();
|
||||
this.lockApplication();
|
||||
this.lockAfterDate = undefined;
|
||||
}, interval);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ export { AlertService } from './alertService';
|
||||
export { ArchiveManager } from './archiveManager';
|
||||
export { DesktopManager } from './desktopManager';
|
||||
export { KeyboardManager } from './keyboardManager';
|
||||
export { LockManager } from './lockManager';
|
||||
export { AutolockService } from './autolock_service';
|
||||
export { NativeExtManager } from './nativeExtManager';
|
||||
export { PreferencesManager } from './preferencesManager';
|
||||
export { StatusManager } from './statusManager';
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
Copy,
|
||||
dictToArray
|
||||
} from 'snjs';
|
||||
import { PayloadContent } from '@node_modules/snjs/dist/@types/protocol/payloads/generator';
|
||||
import { ComponentPermission } from '@node_modules/snjs/dist/@types/models/app/component';
|
||||
import { PayloadContent } from 'snjs/dist/@types/protocol/payloads/generator';
|
||||
import { ComponentPermission } from 'snjs/dist/@types/models/app/component';
|
||||
|
||||
/** A class for handling installation of system extensions */
|
||||
export class NativeExtManager extends ApplicationService {
|
||||
|
||||
@@ -46,7 +46,7 @@ export const STRING_INVALID_IMPORT_FILE = "Unable to open file. Ensure it is a p
|
||||
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.`;
|
||||
}
|
||||
export const STRING_ENTER_ACCOUNT_PASSCODE = 'Enter your application passcode to decrypt your data and unlock the application';
|
||||
export const STRING_ENTER_ACCOUNT_PASSCODE = 'Enter your application passcode to unlock the application';
|
||||
export const STRING_ENTER_ACCOUNT_PASSWORD = 'Enter your account password';
|
||||
export const STRING_ENTER_PASSCODE_FOR_MIGRATION = 'Your application passcode is required to perform an upgrade of your local data storage structure.';
|
||||
export const STRING_ENTER_PASSCODE_FOR_LOGIN_REGISTER = 'Enter your application passcode before signing in or registering';
|
||||
|
||||
@@ -27,6 +27,10 @@ export interface PermissionsModalScope extends Partial<ng.IScope> {
|
||||
callback: (approved: boolean) => void
|
||||
}
|
||||
|
||||
export interface AccountSwitcherScope extends Partial<ng.IScope> {
|
||||
application: any
|
||||
}
|
||||
|
||||
export type PanelPuppet = {
|
||||
onReady?: () => void
|
||||
ready?: boolean
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { AccountSwitcherScope } from './../types';
|
||||
import { ComponentGroup } from './component_group';
|
||||
import { EditorGroup } from '@/ui_models/editor_group';
|
||||
import { InputModalScope } from '@/directives/views/inputModal';
|
||||
@@ -16,7 +17,7 @@ import { AlertService } from '@/services/alertService';
|
||||
import { WebDeviceInterface } from '@/web_device_interface';
|
||||
import {
|
||||
DesktopManager,
|
||||
LockManager,
|
||||
AutolockService,
|
||||
ArchiveManager,
|
||||
NativeExtManager,
|
||||
StatusManager,
|
||||
@@ -27,11 +28,12 @@ import {
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { SNWebCrypto } from 'sncrypto/dist/sncrypto-web';
|
||||
import { Bridge } from '@/services/bridge';
|
||||
import { DeinitSource } from 'snjs/dist/@types/types';
|
||||
|
||||
type WebServices = {
|
||||
appState: AppState
|
||||
desktopService: DesktopManager
|
||||
lockService: LockManager
|
||||
autolockService: AutolockService
|
||||
archiveService: ArchiveManager
|
||||
nativeExtService: NativeExtManager
|
||||
statusService: StatusManager
|
||||
@@ -44,7 +46,6 @@ export class WebApplication extends SNApplication {
|
||||
|
||||
private $compile?: ng.ICompileService
|
||||
private scope?: ng.IScope
|
||||
private onDeinit?: (app: WebApplication) => void
|
||||
private webServices!: WebServices
|
||||
private currentAuthenticationElement?: JQLite
|
||||
public editorGroup: EditorGroup
|
||||
@@ -52,38 +53,33 @@ export class WebApplication extends SNApplication {
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
deviceInterface: WebDeviceInterface,
|
||||
identifier: string,
|
||||
$compile: ng.ICompileService,
|
||||
$timeout: ng.ITimeoutService,
|
||||
scope: ng.IScope,
|
||||
onDeinit: (app: WebApplication) => void,
|
||||
defaultSyncServerHost: string,
|
||||
bridge: Bridge,
|
||||
) {
|
||||
const deviceInterface = new WebDeviceInterface(
|
||||
$timeout,
|
||||
bridge
|
||||
);
|
||||
super(
|
||||
bridge.environment,
|
||||
platformFromString(getPlatformString()),
|
||||
deviceInterface,
|
||||
new SNWebCrypto(),
|
||||
new AlertService(),
|
||||
undefined,
|
||||
identifier,
|
||||
undefined,
|
||||
undefined,
|
||||
defaultSyncServerHost
|
||||
);
|
||||
this.$compile = $compile;
|
||||
this.scope = scope;
|
||||
this.onDeinit = onDeinit;
|
||||
deviceInterface.setApplication(this);
|
||||
this.editorGroup = new EditorGroup(this);
|
||||
this.componentGroup = new ComponentGroup(this);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
deinit() {
|
||||
deinit(source: DeinitSource) {
|
||||
for (const key of Object.keys(this.webServices)) {
|
||||
const service = (this.webServices as any)[key];
|
||||
if (service.deinit) {
|
||||
@@ -92,8 +88,6 @@ export class WebApplication extends SNApplication {
|
||||
service.application = undefined;
|
||||
}
|
||||
this.webServices = {} as WebServices;
|
||||
this.onDeinit!(this);
|
||||
this.onDeinit = undefined;
|
||||
this.$compile = undefined;
|
||||
this.editorGroup.deinit();
|
||||
this.componentGroup.deinit();
|
||||
@@ -102,9 +96,9 @@ export class WebApplication extends SNApplication {
|
||||
this.scope = undefined;
|
||||
/** Allow our Angular directives to be destroyed and any pending digest cycles
|
||||
* to complete before destroying the global application instance and all its services */
|
||||
setImmediate(() => {
|
||||
super.deinit();
|
||||
})
|
||||
setTimeout(() => {
|
||||
super.deinit(source);
|
||||
}, 0)
|
||||
}
|
||||
|
||||
setWebServices(services: WebServices) {
|
||||
@@ -119,8 +113,8 @@ export class WebApplication extends SNApplication {
|
||||
return this.webServices.desktopService;
|
||||
}
|
||||
|
||||
public getLockService() {
|
||||
return this.webServices.lockService;
|
||||
public getAutolockService() {
|
||||
return this.webServices.autolockService;
|
||||
}
|
||||
|
||||
public getArchiveService() {
|
||||
@@ -257,4 +251,15 @@ export class WebApplication extends SNApplication {
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
public openAccountSwitcher() {
|
||||
const scope = this.scope!.$new(true) as Partial<AccountSwitcherScope>;
|
||||
scope.application = this;
|
||||
const el = this.$compile!(
|
||||
"<account-switcher application='application' "
|
||||
+ "class='sk-modal'></account-switcher>"
|
||||
)(scope as any);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { WebDeviceInterface } from '@/web_device_interface';
|
||||
import { WebApplication } from './application';
|
||||
import { removeFromArray } from 'snjs';
|
||||
import { ApplicationDescriptor, SNApplicationGroup, DeviceInterface } from 'snjs';
|
||||
import {
|
||||
ArchiveManager,
|
||||
DesktopManager,
|
||||
KeyboardManager,
|
||||
LockManager,
|
||||
AutolockService,
|
||||
NativeExtManager,
|
||||
PreferencesManager,
|
||||
StatusManager,
|
||||
@@ -13,16 +14,11 @@ import {
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { Bridge } from '@/services/bridge';
|
||||
|
||||
type AppManagerChangeCallback = () => void
|
||||
|
||||
export class ApplicationGroup {
|
||||
export class ApplicationGroup extends SNApplicationGroup {
|
||||
|
||||
$compile: ng.ICompileService
|
||||
$rootScope: ng.IRootScopeService
|
||||
$timeout: ng.ITimeoutService
|
||||
applications: WebApplication[] = []
|
||||
changeObservers: AppManagerChangeCallback[] = []
|
||||
activeApplication?: WebApplication
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
@@ -32,46 +28,35 @@ export class ApplicationGroup {
|
||||
private defaultSyncServerHost: string,
|
||||
private bridge: Bridge,
|
||||
) {
|
||||
super(new WebDeviceInterface(
|
||||
$timeout,
|
||||
bridge
|
||||
));
|
||||
this.$compile = $compile;
|
||||
this.$timeout = $timeout;
|
||||
this.$rootScope = $rootScope;
|
||||
this.onApplicationDeinit = this.onApplicationDeinit.bind(this);
|
||||
this.createDefaultApplication();
|
||||
}
|
||||
|
||||
async initialize(callback?: any) {
|
||||
await super.initialize({
|
||||
applicationCreator: this.createApplication
|
||||
});
|
||||
|
||||
/** FIXME(baptiste): rely on a less fragile method to detect Electron */
|
||||
if ((window as any).isElectron) {
|
||||
Object.defineProperty(window, 'desktopManager', {
|
||||
get: () => this.activeApplication?.getDesktopService()
|
||||
get: () => (this.primaryApplication as WebApplication).getDesktopService()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createDefaultApplication() {
|
||||
this.activeApplication = this.createNewApplication();
|
||||
this.applications.push(this.activeApplication!);
|
||||
this.notifyObserversOfAppChange();
|
||||
}
|
||||
|
||||
/** @callback */
|
||||
onApplicationDeinit(application: WebApplication) {
|
||||
removeFromArray(this.applications, application);
|
||||
if (this.activeApplication === application) {
|
||||
this.activeApplication = undefined;
|
||||
}
|
||||
if (this.applications.length === 0) {
|
||||
this.createDefaultApplication();
|
||||
} else {
|
||||
this.notifyObserversOfAppChange();
|
||||
}
|
||||
}
|
||||
|
||||
private createNewApplication() {
|
||||
private createApplication = (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
const application = new WebApplication(
|
||||
deviceInterface as WebDeviceInterface,
|
||||
descriptor.identifier,
|
||||
this.$compile,
|
||||
this.$timeout,
|
||||
scope,
|
||||
this.onApplicationDeinit,
|
||||
this.defaultSyncServerHost,
|
||||
this.bridge,
|
||||
);
|
||||
@@ -90,7 +75,7 @@ export class ApplicationGroup {
|
||||
this.bridge,
|
||||
);
|
||||
const keyboardService = new KeyboardManager();
|
||||
const lockService = new LockManager(
|
||||
const autolockService = new AutolockService(
|
||||
application
|
||||
);
|
||||
const nativeExtService = new NativeExtManager(
|
||||
@@ -108,7 +93,7 @@ export class ApplicationGroup {
|
||||
archiveService,
|
||||
desktopService,
|
||||
keyboardService,
|
||||
lockService,
|
||||
autolockService,
|
||||
nativeExtService,
|
||||
prefsService,
|
||||
statusService,
|
||||
@@ -116,34 +101,4 @@ export class ApplicationGroup {
|
||||
});
|
||||
return application;
|
||||
}
|
||||
|
||||
get application() {
|
||||
return this.activeApplication;
|
||||
}
|
||||
|
||||
public getApplications() {
|
||||
return this.applications.slice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies observer when the active application has changed.
|
||||
* Any application which is no longer active is destroyed, and
|
||||
* must be removed from the interface.
|
||||
*/
|
||||
public addApplicationChangeObserver(callback: AppManagerChangeCallback) {
|
||||
this.changeObservers.push(callback);
|
||||
if (this.application) {
|
||||
callback();
|
||||
}
|
||||
|
||||
return () => {
|
||||
removeFromArray(this.changeObservers, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private notifyObserversOfAppChange() {
|
||||
for (const observer of this.changeObservers) {
|
||||
observer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SNComponent, ComponentArea, removeFromArray, addIfUnique } from 'snjs';
|
||||
import { WebApplication } from './application';
|
||||
import { UuidString } from '@node_modules/snjs/dist/@types/types';
|
||||
import { UuidString } from 'snjs/dist/@types/types';
|
||||
|
||||
/** Areas that only allow a single component to be active */
|
||||
const SingleComponentAreas = [
|
||||
@@ -48,8 +48,8 @@ export class ComponentGroup {
|
||||
}
|
||||
removeFromArray(this.activeComponents, component.uuid);
|
||||
/** If this function is called as part of global application deinit (locking),
|
||||
* componentManager can be destroyed. In this case, it's harmless to not take any
|
||||
* action since the componentManager will be destroyed, and the component will
|
||||
* componentManager can be destroyed. In this case, it's harmless to not take any
|
||||
* action since the componentManager will be destroyed, and the component will
|
||||
* essentially be deregistered. */
|
||||
if(this.componentManager) {
|
||||
await this.componentManager.deactivateComponent(component.uuid);
|
||||
|
||||
@@ -63,9 +63,15 @@ export class PureViewCtrl<P = CtrlProps, S = CtrlState> {
|
||||
if (!this.$timeout) {
|
||||
return;
|
||||
}
|
||||
this.state = Object.freeze(Object.assign({}, this.state, state));
|
||||
return new Promise((resolve) => {
|
||||
this.stateTimeout = this.$timeout(resolve);
|
||||
this.stateTimeout = this.$timeout(() => {
|
||||
/**
|
||||
* State changes must be *inside* the timeout block for them to be affected in the UI
|
||||
* Otherwise UI controllers will need to use $timeout everywhere
|
||||
*/
|
||||
this.state = Object.freeze(Object.assign({}, this.state, state));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
.sk-modal-background(ng-click="ctrl.dismiss()")
|
||||
#account-switcher.sk-modal-content
|
||||
.sn-component
|
||||
.sk-menu-panel#menu-panel
|
||||
.sk-menu-panel-header
|
||||
.sk-menu-panel-column
|
||||
.sk-menu-panel-header-title Account Switcher
|
||||
.sk-menu-panel-column
|
||||
a.sk-label.info(ng-click='ctrl.addNewApplication()') Add Account
|
||||
.sk-menu-panel-row(
|
||||
ng-repeat='descriptor in ctrl.state.descriptors track by descriptor.identifier'
|
||||
ng-click='ctrl.selectDescriptor(descriptor)'
|
||||
)
|
||||
.sk-menu-panel-column.stretch
|
||||
.left
|
||||
.sk-menu-panel-column(ng-if='descriptor.identifier == ctrl.activeApplication.identifier')
|
||||
.sk-circle.small.success
|
||||
.sk-menu-panel-column.stretch
|
||||
input.sk-label.clickable(
|
||||
ng-model='descriptor.label'
|
||||
ng-disabled='descriptor != ctrl.state.editingDescriptor'
|
||||
ng-keyup='$event.keyCode == 13 && ctrl.submitRename($event)',
|
||||
ng-attr-id='input-{{descriptor.identifier}}'
|
||||
spellcheck="false"
|
||||
)
|
||||
.sk-sublabel(ng-if='descriptor.identifier == ctrl.activeApplication.identifier')
|
||||
| Current Application
|
||||
.sk-menu-panel-column(ng-if='descriptor.identifier == ctrl.activeApplication.identifier')
|
||||
.sk-button.success(
|
||||
ng-click='ctrl.renameDescriptor($event, descriptor)'
|
||||
)
|
||||
.sk-label Rename
|
||||
@@ -0,0 +1,105 @@
|
||||
import { ApplicationGroup } from '@/ui_models/application_group';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import template from './account-switcher.pug';
|
||||
import {
|
||||
ApplicationDescriptor,
|
||||
} from 'snjs';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { WebDirective } from '@/types';
|
||||
|
||||
class AccountSwitcherCtrl extends PureViewCtrl<{}, {
|
||||
descriptors: ApplicationDescriptor[];
|
||||
editingDescriptor?: ApplicationDescriptor
|
||||
}> {
|
||||
private $element: JQLite
|
||||
application!: WebApplication
|
||||
private removeAppGroupObserver: any;
|
||||
/** @template */
|
||||
activeApplication!: WebApplication
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$element: JQLite,
|
||||
$timeout: ng.ITimeoutService,
|
||||
private mainApplicationGroup: ApplicationGroup
|
||||
) {
|
||||
super($timeout);
|
||||
this.$element = $element;
|
||||
this.removeAppGroupObserver = mainApplicationGroup.addApplicationChangeObserver(() => {
|
||||
this.activeApplication = mainApplicationGroup.primaryApplication as WebApplication;
|
||||
this.reloadApplications();
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
}
|
||||
|
||||
reloadApplications() {
|
||||
this.setState({
|
||||
descriptors: this.mainApplicationGroup.getDescriptors()
|
||||
})
|
||||
}
|
||||
|
||||
/** @template */
|
||||
addNewApplication() {
|
||||
this.dismiss();
|
||||
this.mainApplicationGroup.addNewApplication();
|
||||
}
|
||||
|
||||
/** @template */
|
||||
selectDescriptor(descriptor: ApplicationDescriptor) {
|
||||
this.dismiss();
|
||||
this.mainApplicationGroup.loadApplicationForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
inputForDescriptor(descriptor: ApplicationDescriptor) {
|
||||
return document.getElementById(`input-${descriptor.identifier}`);
|
||||
}
|
||||
|
||||
/** @template */
|
||||
renameDescriptor($event: Event, descriptor: ApplicationDescriptor) {
|
||||
$event.stopPropagation();
|
||||
this.setState({ editingDescriptor: descriptor }).then(() => {
|
||||
const input = this.inputForDescriptor(descriptor);
|
||||
input?.focus();
|
||||
})
|
||||
}
|
||||
|
||||
/** @template */
|
||||
submitRename() {
|
||||
this.mainApplicationGroup.renameDescriptor(
|
||||
this.state.editingDescriptor!,
|
||||
this.state.editingDescriptor!.label
|
||||
)
|
||||
this.setState({ editingDescriptor: undefined });
|
||||
}
|
||||
|
||||
deinit() {
|
||||
(this.application as any) = undefined;
|
||||
super.deinit();
|
||||
this.removeAppGroupObserver();
|
||||
this.removeAppGroupObserver = undefined;
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export class AccountSwitcher extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.restrict = 'E';
|
||||
this.template = template;
|
||||
this.controller = AccountSwitcherCtrl;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
ng-class='self.platformString'
|
||||
)
|
||||
#app.app(
|
||||
ng-class='self.state.appClass',
|
||||
ng-class='self.state.appClass',
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
)
|
||||
tags-view(application='self.application')
|
||||
@@ -14,4 +14,13 @@
|
||||
footer-view(
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
application='self.application'
|
||||
)
|
||||
)
|
||||
|
||||
svg(data-ionicons="5.1.2", style="display: none")
|
||||
symbol#people-circle-outline.ionicon(viewbox="0 0 512 512")
|
||||
path(d="M256 464c-114.69 0-208-93.31-208-208S141.31 48 256 48s208 93.31 208 208-93.31 208-208 208zm0-384c-97 0-176 79-176 176s79 176 176 176 176-78.95 176-176S353.05 80 256 80z")
|
||||
path(d="M323.67 292c-17.4 0-34.21-7.72-47.34-21.73a83.76 83.76 0 01-22-51.32c-1.47-20.7 4.88-39.75 17.88-53.62S303.38 144 323.67 144c20.14 0 38.37 7.62 51.33 21.46s19.47 33 18 53.51a84 84 0 01-22 51.3C357.86 284.28 341.06 292 323.67 292zm55.81-74zM163.82 295.36c-29.76 0-55.93-27.51-58.33-61.33-1.23-17.32 4.15-33.33 15.17-45.08s26.22-18 43.15-18 32.12 6.44 43.07 18.14 16.5 27.82 15.25 45c-2.44 33.77-28.6 61.27-58.31 61.27zM420.37 355.28c-1.59-4.7-5.46-9.71-13.22-14.46-23.46-14.33-52.32-21.91-83.48-21.91-30.57 0-60.23 7.9-83.53 22.25-26.25 16.17-43.89 39.75-51 68.18-1.68 6.69-4.13 19.14-1.51 26.11a192.18 192.18 0 00232.75-80.17zM163.63 401.37c7.07-28.21 22.12-51.73 45.47-70.75a8 8 0 00-2.59-13.77c-12-3.83-25.7-5.88-42.69-5.88-23.82 0-49.11 6.45-68.14 18.17-5.4 3.33-10.7 4.61-14.78 5.75a192.84 192.84 0 0077.78 86.64l1.79-.14a102.82 102.82 0 013.16-20.02z")
|
||||
|
||||
symbol#layers-sharp.ionicon(viewbox="0 0 512 512")
|
||||
path(d="M480 150L256 48 32 150l224 104 224-104zM255.71 392.95l-144.81-66.2L32 362l224 102 224-102-78.69-35.3-145.6 66.25z")
|
||||
path(d="M480 256l-75.53-33.53L256.1 290.6l-148.77-68.17L32 256l224 102 224-102z")
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
STRING_DEFAULT_FILE_ERROR
|
||||
} from '@/strings';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { PermissionDialog } from '@node_modules/snjs/dist/@types/services/component_manager';
|
||||
import { PermissionDialog } from 'snjs/dist/@types/services/component_manager';
|
||||
import { alertDialog } from '@/services/alertService';
|
||||
|
||||
class ApplicationViewCtrl extends PureViewCtrl {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
application-view(
|
||||
ng-repeat='application in self.applications',
|
||||
ng-if='application == self.activeApplication'
|
||||
application='application'
|
||||
)
|
||||
@@ -7,7 +7,8 @@ class ApplicationGroupViewCtrl {
|
||||
|
||||
private $timeout: ng.ITimeoutService
|
||||
private applicationGroup: ApplicationGroup
|
||||
public applications: WebApplication[] = []
|
||||
applications!: WebApplication[]
|
||||
activeApplication!: WebApplication
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
@@ -19,11 +20,13 @@ class ApplicationGroupViewCtrl {
|
||||
this.applicationGroup.addApplicationChangeObserver(() => {
|
||||
this.reload();
|
||||
});
|
||||
this.applicationGroup.initialize();
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.$timeout(() => {
|
||||
this.applications = this.applicationGroup.getApplications();
|
||||
this.activeApplication = this.applicationGroup.primaryApplication as WebApplication;
|
||||
this.applications = this.applicationGroup.getApplications() as WebApplication[];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -33,7 +36,7 @@ export class ApplicationGroupView extends WebDirective {
|
||||
super();
|
||||
this.template = template;
|
||||
this.controller = ApplicationGroupViewCtrl;
|
||||
this.replace = true;
|
||||
this.replace = false;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.left
|
||||
.sk-app-bar-item(
|
||||
click-outside='ctrl.clickOutsideAccountMenu()',
|
||||
is-open='ctrl.showAccountMenu',
|
||||
is-open='ctrl.showAccountMenu',
|
||||
ng-click='ctrl.accountMenuPressed()'
|
||||
)
|
||||
.sk-app-bar-item-column
|
||||
@@ -13,15 +13,15 @@
|
||||
.sk-app-bar-item-column
|
||||
.sk-label.title(ng-class='{red: ctrl.hasError}') Account
|
||||
account-menu(
|
||||
close-function='ctrl.closeAccountMenu()',
|
||||
ng-click='$event.stopPropagation()',
|
||||
close-function='ctrl.closeAccountMenu()',
|
||||
ng-click='$event.stopPropagation()',
|
||||
ng-if='ctrl.showAccountMenu',
|
||||
application='ctrl.application'
|
||||
)
|
||||
.sk-app-bar-item
|
||||
a.no-decoration.sk-label.title(
|
||||
href='https://standardnotes.org/help',
|
||||
rel='noopener',
|
||||
href='https://standardnotes.org/help',
|
||||
rel='noopener',
|
||||
target='_blank'
|
||||
)
|
||||
| Help
|
||||
@@ -30,8 +30,8 @@
|
||||
.sk-app-bar-item-column(ng-click='ctrl.selectRoom(room)')
|
||||
.sk-label {{room.name}}
|
||||
component-modal(
|
||||
component-uuid='room.uuid',
|
||||
ng-if='ctrl.roomShowState[room.uuid]',
|
||||
component-uuid='room.uuid',
|
||||
ng-if='ctrl.roomShowState[room.uuid]',
|
||||
on-dismiss='ctrl.onRoomDismiss(room)',
|
||||
application='ctrl.application'
|
||||
)
|
||||
@@ -41,12 +41,12 @@
|
||||
span.neutral.sk-label {{ctrl.arbitraryStatusMessage}}
|
||||
.right
|
||||
.sk-app-bar-item(
|
||||
ng-click='ctrl.openSecurityUpdate()',
|
||||
ng-click='ctrl.openSecurityUpdate()',
|
||||
ng-if='ctrl.state.dataUpgradeAvailable'
|
||||
)
|
||||
span.success.sk-label Encryption upgrade available.
|
||||
.sk-app-bar-item(
|
||||
ng-click='ctrl.clickedNewUpdateAnnouncement()',
|
||||
ng-click='ctrl.clickedNewUpdateAnnouncement()',
|
||||
ng-if='ctrl.newUpdateAvailable == true'
|
||||
)
|
||||
span.info.sk-label New update available.
|
||||
@@ -56,13 +56,13 @@
|
||||
.sk-label.subtle(ng-if='!ctrl.offline')
|
||||
| Last refreshed {{ctrl.lastSyncDate}}
|
||||
.sk-app-bar-item(
|
||||
ng-click='ctrl.toggleSyncResolutionMenu()',
|
||||
ng-click='ctrl.toggleSyncResolutionMenu()',
|
||||
ng-if='(ctrl.state.outOfSync && !ctrl.isRefreshing) || ctrl.showSyncResolution'
|
||||
)
|
||||
.sk-label.warning(ng-if='ctrl.state.outOfSync') Potentially Out of Sync
|
||||
sync-resolution-menu(
|
||||
close-function='ctrl.toggleSyncResolutionMenu()',
|
||||
ng-click='$event.stopPropagation();',
|
||||
close-function='ctrl.toggleSyncResolutionMenu()',
|
||||
ng-click='$event.stopPropagation();',
|
||||
ng-if='ctrl.showSyncResolution',
|
||||
application='ctrl.application'
|
||||
)
|
||||
@@ -70,27 +70,35 @@
|
||||
.sk-spinner.small
|
||||
.sk-app-bar-item(ng-if='ctrl.offline')
|
||||
.sk-label Offline
|
||||
.sk-app-bar-item(ng-click='ctrl.refreshData()', ng-if='!ctrl.offline')
|
||||
.sk-app-bar-item(ng-click='ctrl.refreshData()' ng-if='!ctrl.offline')
|
||||
.sk-label Refresh
|
||||
.sk-app-bar-item.border(ng-if='ctrl.state.dockShortcuts.length > 0')
|
||||
.sk-app-bar-item.dock-shortcut(ng-repeat='shortcut in ctrl.state.dockShortcuts')
|
||||
.sk-app-bar-item-column(
|
||||
ng-class="{'underline': shortcut.component.active}",
|
||||
ng-class="{'underline': shortcut.component.active}",
|
||||
ng-click='ctrl.selectShortcut(shortcut)'
|
||||
)
|
||||
.div(ng-if="shortcut.icon.type == 'circle'", title='{{shortcut.name}}')
|
||||
.div(ng-if="shortcut.icon.type == 'circle'" title='{{shortcut.name}}')
|
||||
.sk-circle.small(
|
||||
ng-style="{'background-color': shortcut.icon.background_color, 'border-color': shortcut.icon.border_color}"
|
||||
)
|
||||
.div(ng-if="shortcut.icon.type == 'svg'", title='{{shortcut.name}}')
|
||||
.div(ng-if="shortcut.icon.type == 'svg'" title='{{shortcut.name}}')
|
||||
.svg-item(
|
||||
elem-ready='ctrl.initSvgForShortcut(shortcut)',
|
||||
elem-ready='ctrl.initSvgForShortcut(shortcut)',
|
||||
ng-attr-id='dock-svg-{{shortcut.component.uuid}}'
|
||||
)
|
||||
.sk-app-bar-item.border(ng-if='ctrl.state.hasAccountSwitcher')
|
||||
.sk-app-bar-item(
|
||||
ng-if='ctrl.state.hasAccountSwitcher'
|
||||
ng-click='ctrl.openAccountSwitcher()',
|
||||
)
|
||||
#account-switcher-icon(ng-class='{"alone": !ctrl.state.hasPasscode}')
|
||||
svg.info.ionicon
|
||||
use(href="#layers-sharp")
|
||||
.sk-app-bar-item.border(ng-if='ctrl.state.hasPasscode')
|
||||
#lock-item.sk-app-bar-item(
|
||||
ng-click='ctrl.lockApp()',
|
||||
ng-if='ctrl.state.hasPasscode',
|
||||
ng-click='ctrl.lockApp()',
|
||||
ng-if='ctrl.state.hasPasscode',
|
||||
title='Locks application and wipes unencrypted data from memory.'
|
||||
)
|
||||
.sk-label
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ApplicationGroup } from '@/ui_models/application_group';
|
||||
import { FooterStatus, WebDirective } from '@/types';
|
||||
import { dateToLocalizedString, preventRefreshing } from '@/utils';
|
||||
import {
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
ComponentAction,
|
||||
topLevelCompare,
|
||||
CollectionSort,
|
||||
ComponentMutator,
|
||||
ComponentMutator
|
||||
} from 'snjs';
|
||||
import template from './footer-view.pug';
|
||||
import { AppStateEvent, EventSource } from '@/ui_models/app_state';
|
||||
@@ -22,6 +23,14 @@ import {
|
||||
} from '@/strings';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
|
||||
/**
|
||||
* Disable before production release.
|
||||
* Anyone who used the beta will still have access to
|
||||
* the account switcher in production via local storage flag
|
||||
*/
|
||||
const ACCOUNT_SWITCHER_ENABLED = true;
|
||||
const ACCOUNT_SWITCHER_FEATURE_KEY = 'account_switcher';
|
||||
|
||||
type DockShortcut = {
|
||||
name: string,
|
||||
component: SNComponent,
|
||||
@@ -37,8 +46,8 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
hasPasscode: boolean;
|
||||
dataUpgradeAvailable: boolean;
|
||||
dockShortcuts: DockShortcut[];
|
||||
hasAccountSwitcher: boolean
|
||||
}> {
|
||||
|
||||
private $rootScope: ng.IRootScopeService
|
||||
private rooms: SNComponent[] = []
|
||||
private themesWithIcons: SNTheme[] = []
|
||||
@@ -66,6 +75,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
constructor(
|
||||
$rootScope: ng.IRootScopeService,
|
||||
$timeout: ng.ITimeoutService,
|
||||
private mainApplicationGroup: ApplicationGroup
|
||||
) {
|
||||
super($timeout);
|
||||
this.$rootScope = $rootScope;
|
||||
@@ -92,11 +102,22 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.application!.getStatusService().addStatusObserver((string: string) => {
|
||||
this.application.getStatusService().addStatusObserver((string: string) => {
|
||||
this.$timeout(() => {
|
||||
this.arbitraryStatusMessage = string;
|
||||
});
|
||||
});
|
||||
this.loadAccountSwitcherState();
|
||||
}
|
||||
|
||||
loadAccountSwitcherState() {
|
||||
const stringValue = localStorage.getItem(ACCOUNT_SWITCHER_FEATURE_KEY);
|
||||
if (!stringValue && ACCOUNT_SWITCHER_ENABLED) {
|
||||
/** Enable permanently for this user so they don't lose the feature after its disabled */
|
||||
localStorage.setItem(ACCOUNT_SWITCHER_FEATURE_KEY, JSON.stringify(true));
|
||||
}
|
||||
const hasAccountSwitcher = stringValue ? JSON.parse(stringValue) : ACCOUNT_SWITCHER_ENABLED;
|
||||
this.setState({ hasAccountSwitcher });
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
@@ -105,17 +126,24 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
dataUpgradeAvailable: false,
|
||||
hasPasscode: false,
|
||||
dockShortcuts: [],
|
||||
descriptors: this.mainApplicationGroup.getDescriptors(),
|
||||
hasAccountSwitcher: false
|
||||
};
|
||||
}
|
||||
|
||||
reloadUpgradeStatus() {
|
||||
this.application!.checkForSecurityUpdate().then((available) => {
|
||||
this.application.checkForSecurityUpdate().then((available) => {
|
||||
this.setState({
|
||||
dataUpgradeAvailable: available
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** @template */
|
||||
openAccountSwitcher() {
|
||||
this.application.openAccountSwitcher();
|
||||
}
|
||||
|
||||
async onAppLaunch() {
|
||||
super.onAppLaunch();
|
||||
this.reloadPasscodeStatus();
|
||||
@@ -128,11 +156,11 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
reloadUser() {
|
||||
this.user = this.application!.getUser();
|
||||
this.user = this.application.getUser();
|
||||
}
|
||||
|
||||
async reloadPasscodeStatus() {
|
||||
const hasPasscode = this.application!.hasPasscode();
|
||||
const hasPasscode = this.application.hasPasscode();
|
||||
this.setState({
|
||||
hasPasscode: hasPasscode
|
||||
});
|
||||
@@ -157,23 +185,23 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
this.closeAccountMenu();
|
||||
}
|
||||
} else if (eventName === AppStateEvent.BeganBackupDownload) {
|
||||
this.backupStatus = this.application!.getStatusService().addStatusFromString(
|
||||
this.backupStatus = this.application.getStatusService().addStatusFromString(
|
||||
"Saving local backup..."
|
||||
);
|
||||
} else if (eventName === AppStateEvent.EndedBackupDownload) {
|
||||
if (data.success) {
|
||||
this.backupStatus = this.application!.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus!,
|
||||
"Successfully saved backup."
|
||||
);
|
||||
} else {
|
||||
this.backupStatus = this.application!.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus!,
|
||||
"Unable to save local backup."
|
||||
);
|
||||
}
|
||||
this.$timeout(() => {
|
||||
this.backupStatus = this.application!.getStatusService().removeStatus(this.backupStatus!);
|
||||
this.backupStatus = this.application.getStatusService().removeStatus(this.backupStatus!);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
@@ -199,7 +227,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
} else if (eventName === ApplicationEvent.CompletedFullSync) {
|
||||
if (!this.didCheckForOffline) {
|
||||
this.didCheckForOffline = true;
|
||||
if (this.offline && this.application!.getNoteCount() === 0) {
|
||||
if (this.offline && this.application.getNoteCount() === 0) {
|
||||
this.showAccountMenu = true;
|
||||
}
|
||||
}
|
||||
@@ -230,10 +258,10 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
)
|
||||
|
||||
this.observerRemovers.push(this.application!.streamItems(
|
||||
this.observerRemovers.push(this.application.streamItems(
|
||||
ContentType.Component,
|
||||
async () => {
|
||||
const components = this.application!.getItems(ContentType.Component) as SNComponent[];
|
||||
const components = this.application.getItems(ContentType.Component) as SNComponent[];
|
||||
this.rooms = components.filter((candidate) => {
|
||||
return candidate.area === ComponentArea.Rooms && !candidate.deleted;
|
||||
});
|
||||
@@ -244,10 +272,10 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
));
|
||||
|
||||
this.observerRemovers.push(this.application!.streamItems(
|
||||
this.observerRemovers.push(this.application.streamItems(
|
||||
ContentType.Theme,
|
||||
async () => {
|
||||
const themes = this.application!.getDisplayableItems(ContentType.Theme) as SNTheme[];
|
||||
const themes = this.application.getDisplayableItems(ContentType.Theme) as SNTheme[];
|
||||
this.themesWithIcons = themes;
|
||||
this.reloadDockShortcuts();
|
||||
}
|
||||
@@ -255,14 +283,14 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
registerComponentHandler() {
|
||||
this.unregisterComponent = this.application!.componentManager!.registerHandler({
|
||||
this.unregisterComponent = this.application.componentManager!.registerHandler({
|
||||
identifier: 'room-bar',
|
||||
areas: [ComponentArea.Rooms, ComponentArea.Modal],
|
||||
actionHandler: (component, action, data) => {
|
||||
if (action === ComponentAction.SetSize) {
|
||||
/** Do comparison to avoid repetitive calls by arbitrary component */
|
||||
if (!topLevelCompare(component.getLastSize(), data)) {
|
||||
this.application!.changeItem<ComponentMutator>(component.uuid, (mutator) => {
|
||||
this.application.changeItem<ComponentMutator>(component.uuid, (mutator) => {
|
||||
mutator.setLastSize(data);
|
||||
})
|
||||
}
|
||||
@@ -288,7 +316,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
* then closing it after a short delay.
|
||||
*/
|
||||
const extWindow = this.rooms.find((room) => {
|
||||
return room.package_info.identifier === this.application!
|
||||
return room.package_info.identifier === this.application
|
||||
.getNativeExtService().extManagerId;
|
||||
});
|
||||
if (!extWindow) {
|
||||
@@ -305,17 +333,17 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
updateOfflineStatus() {
|
||||
this.offline = this.application!.noAccount();
|
||||
this.offline = this.application.noAccount();
|
||||
}
|
||||
|
||||
async openSecurityUpdate() {
|
||||
preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_UPGRADE, async () => {
|
||||
await this.application!.performProtocolUpgrade();
|
||||
await this.application.performProtocolUpgrade();
|
||||
});
|
||||
}
|
||||
|
||||
findErrors() {
|
||||
this.hasError = this.application!.getSyncStatus().hasError();
|
||||
this.hasError = this.application.getSyncStatus().hasError();
|
||||
}
|
||||
|
||||
accountMenuPressed() {
|
||||
@@ -332,12 +360,12 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
lockApp() {
|
||||
this.application!.lock();
|
||||
this.application.lock();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
this.isRefreshing = true;
|
||||
this.application!.sync({
|
||||
this.application.sync({
|
||||
queueStrategy: SyncQueueStrategy.ForceSpawnNew,
|
||||
checkIntegrity: true
|
||||
}).then((response) => {
|
||||
@@ -345,7 +373,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
this.isRefreshing = false;
|
||||
}, 200);
|
||||
if (response && response.error) {
|
||||
this.application!.alertService!.alert(
|
||||
this.application.alertService!.alert(
|
||||
STRING_GENERIC_SYNC_ERROR
|
||||
);
|
||||
} else {
|
||||
@@ -355,7 +383,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
syncUpdated() {
|
||||
this.lastSyncDate = dateToLocalizedString(this.application!.getLastSyncDate()!);
|
||||
this.lastSyncDate = dateToLocalizedString(this.application.getLastSyncDate()!);
|
||||
}
|
||||
|
||||
onNewUpdateAvailable() {
|
||||
@@ -364,7 +392,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
|
||||
clickedNewUpdateAnnouncement() {
|
||||
this.newUpdateAvailable = false;
|
||||
this.application!.alertService!.alert(
|
||||
this.application.alertService!.alert(
|
||||
STRING_NEW_UPDATE_READY
|
||||
);
|
||||
}
|
||||
@@ -409,7 +437,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
selectShortcut(shortcut: DockShortcut) {
|
||||
this.application!.toggleComponent(shortcut.component);
|
||||
this.application.toggleComponent(shortcut.component);
|
||||
}
|
||||
|
||||
onRoomDismiss(room: SNComponent) {
|
||||
@@ -430,12 +458,12 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
};
|
||||
|
||||
if (!this.roomShowState[room.uuid]) {
|
||||
const requiresPrivilege = await this.application!.privilegesService!
|
||||
const requiresPrivilege = await this.application.privilegesService!
|
||||
.actionRequiresPrivilege(
|
||||
ProtectedAction.ManageExtensions
|
||||
);
|
||||
if (requiresPrivilege) {
|
||||
this.application!.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedAction.ManageExtensions,
|
||||
run
|
||||
);
|
||||
@@ -448,7 +476,7 @@ class FooterViewCtrl extends PureViewCtrl<{}, {
|
||||
}
|
||||
|
||||
clickOutsideAccountMenu() {
|
||||
if (this.application && this.application!.authenticationInProgress()) {
|
||||
if (this.application && this.application.authenticationInProgress()) {
|
||||
return;
|
||||
}
|
||||
this.showAccountMenu = false;
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
NoteSortKey,
|
||||
notePassesFilter
|
||||
} from './note_utils';
|
||||
import { UuidString } from '@node_modules/snjs/dist/@types/types';
|
||||
import { UuidString } from 'snjs/dist/@types/types';
|
||||
|
||||
type NotesState = {
|
||||
panelTitle: string
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { DeviceInterface, getGlobalScope, SNApplication } from 'snjs';
|
||||
import { DeviceInterface, getGlobalScope, SNApplication, ApplicationIdentifier } from 'snjs';
|
||||
import { Database } from '@/database';
|
||||
import { Bridge } from './services/bridge';
|
||||
|
||||
export class WebDeviceInterface extends DeviceInterface {
|
||||
|
||||
private database: Database
|
||||
private databases: Database[] = []
|
||||
|
||||
constructor(
|
||||
timeout: any,
|
||||
@@ -14,16 +14,23 @@ export class WebDeviceInterface extends DeviceInterface {
|
||||
timeout || setTimeout.bind(getGlobalScope()),
|
||||
setInterval.bind(getGlobalScope())
|
||||
);
|
||||
this.database = new Database();
|
||||
}
|
||||
|
||||
setApplication(application: SNApplication) {
|
||||
this.database.setAlertService(application.alertService!);
|
||||
const database = new Database(application.identifier, application.alertService!);
|
||||
this.databases.push(database);
|
||||
}
|
||||
|
||||
private databaseForIdentifier(identifier: ApplicationIdentifier) {
|
||||
return this.databases.find(database => database.databaseName === identifier)!;
|
||||
}
|
||||
|
||||
deinit() {
|
||||
super.deinit();
|
||||
this.database.deinit();
|
||||
for(const database of this.databases) {
|
||||
database.deinit();
|
||||
}
|
||||
this.databases = [];
|
||||
}
|
||||
|
||||
async getRawStorageValue(key: string) {
|
||||
@@ -53,10 +60,10 @@ export class WebDeviceInterface extends DeviceInterface {
|
||||
localStorage.clear();
|
||||
}
|
||||
|
||||
async openDatabase() {
|
||||
this.database.unlock();
|
||||
async openDatabase(identifier: ApplicationIdentifier) {
|
||||
this.databaseForIdentifier(identifier).unlock();
|
||||
return new Promise((resolve, reject) => {
|
||||
this.database.openDatabase(() => {
|
||||
this.databaseForIdentifier(identifier).openDatabase(() => {
|
||||
resolve({ isNewDatabase: true });
|
||||
}).then(() => {
|
||||
resolve({ isNewDatabase: false });
|
||||
@@ -66,63 +73,51 @@ export class WebDeviceInterface extends DeviceInterface {
|
||||
}) as Promise<{ isNewDatabase?: boolean } | undefined>;
|
||||
}
|
||||
|
||||
private getDatabaseKeyPrefix() {
|
||||
if (this.namespace) {
|
||||
return `${this.namespace}-item-`;
|
||||
} else {
|
||||
return `item-`;
|
||||
}
|
||||
async getAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).getAllPayloads();
|
||||
}
|
||||
|
||||
private keyForPayloadId(id: string) {
|
||||
return `${this.getDatabaseKeyPrefix()}${id}`;
|
||||
async saveRawDatabasePayload(payload: any, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayload(payload);
|
||||
}
|
||||
|
||||
async getAllRawDatabasePayloads() {
|
||||
return this.database.getAllPayloads();
|
||||
async saveRawDatabasePayloads(payloads: any[], identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayloads(payloads);
|
||||
}
|
||||
|
||||
async saveRawDatabasePayload(payload: any) {
|
||||
return this.database.savePayload(payload);
|
||||
async removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).deletePayload(id);
|
||||
}
|
||||
|
||||
async saveRawDatabasePayloads(payloads: any[]) {
|
||||
return this.database.savePayloads(payloads);
|
||||
async removeAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).clearAllPayloads();
|
||||
}
|
||||
|
||||
async removeRawDatabasePayloadWithId(id: string) {
|
||||
return this.database.deletePayload(id);
|
||||
}
|
||||
|
||||
async removeAllRawDatabasePayloads() {
|
||||
return this.database.clearAllPayloads();
|
||||
}
|
||||
|
||||
async getNamespacedKeychainValue() {
|
||||
async getNamespacedKeychainValue(identifier: ApplicationIdentifier) {
|
||||
const keychain = await this.getRawKeychainValue();
|
||||
if (!keychain) {
|
||||
return;
|
||||
}
|
||||
return keychain[this.namespace!.identifier];
|
||||
return keychain[identifier];
|
||||
}
|
||||
|
||||
async setNamespacedKeychainValue(value: any) {
|
||||
async setNamespacedKeychainValue(value: any, identifier: ApplicationIdentifier) {
|
||||
let keychain = await this.getRawKeychainValue();
|
||||
if (!keychain) {
|
||||
keychain = {};
|
||||
}
|
||||
this.bridge.setKeychainValue({
|
||||
...keychain,
|
||||
[this.namespace!.identifier]: value
|
||||
[identifier]: value
|
||||
});
|
||||
}
|
||||
|
||||
async clearNamespacedKeychainValue() {
|
||||
async clearNamespacedKeychainValue(identifier: ApplicationIdentifier) {
|
||||
const keychain = await this.getRawKeychainValue();
|
||||
if (!keychain) {
|
||||
return;
|
||||
}
|
||||
delete keychain[this.namespace!.identifier];
|
||||
delete keychain[identifier];
|
||||
this.bridge.setKeychainValue(keychain);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,18 +31,28 @@
|
||||
border-bottom: 2px solid var(--sn-stylekit-info-color);
|
||||
}
|
||||
|
||||
svg {
|
||||
.ionicon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
fill: var(--sn-stylekit-foreground-color);
|
||||
fill: var(--sn-stylekit-secondary-foreground-color);
|
||||
|
||||
&:hover {
|
||||
fill: var(--sn-stylekit-info-color);
|
||||
fill: var(--sn-stylekit-info-color) !important;
|
||||
color: var(--sn-stylekit-info-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#account-panel, #sync-resolution-menu {
|
||||
#account-switcher-icon {
|
||||
// When this icon is alone in the footer bar, it is displayed with too little
|
||||
// padding on the right, possibly due to the fact it is a raw SVG.
|
||||
&.alone {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
#account-panel,
|
||||
#sync-resolution-menu {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,22 +12,30 @@
|
||||
Modified icons to fit ionicon’s grid from original.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: "Ionicons";
|
||||
src: url("../fonts/ionicons.eot?v=2.0.0");
|
||||
src: url("../fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"),
|
||||
url("../fonts/ionicons.ttf?v=2.0.1") format("truetype"),
|
||||
url("../fonts/ionicons.woff?v=2.0.1") format("woff"),
|
||||
url("../fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg");
|
||||
font-family: 'Ionicons';
|
||||
src: url('../fonts/ionicons.eot?v=2.0.0');
|
||||
src: url('../fonts/ionicons.eot?v=2.0.1#iefix') format('embedded-opentype'),
|
||||
url('../fonts/ionicons.ttf?v=2.0.1') format('truetype'),
|
||||
url('../fonts/ionicons.woff?v=2.0.1') format('woff'),
|
||||
url('../fonts/ionicons.svg?v=2.0.1#Ionicons') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.ionicon-fill-none {
|
||||
fill: none;
|
||||
}
|
||||
.ionicon-stroke-width {
|
||||
stroke-width: 32px;
|
||||
}
|
||||
|
||||
|
||||
.ion,
|
||||
.ionicons,
|
||||
.ion-locked:before,
|
||||
.ion-plus:before {
|
||||
display: inline-block;
|
||||
font-family: "Ionicons";
|
||||
font-family: 'Ionicons';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
@@ -41,11 +49,11 @@
|
||||
}
|
||||
|
||||
.ion-locked:before {
|
||||
content: "\f200";
|
||||
content: '\f200';
|
||||
}
|
||||
|
||||
.ion-plus:before {
|
||||
content: "\f218";
|
||||
content: '\f218';
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=ionicons.css.map */
|
||||
|
||||
@@ -25,6 +25,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
#account-switcher {
|
||||
min-width: 400px;
|
||||
max-width: 580px;
|
||||
input, input:disabled {
|
||||
width: 100%;
|
||||
border: none;
|
||||
background-color: transparent !important;
|
||||
color: inherit;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
input.clickable:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#privileges-modal {
|
||||
min-width: 400px;
|
||||
max-width: 700px;
|
||||
@@ -50,7 +66,8 @@
|
||||
background-color: var(--sn-stylekit-background-color);
|
||||
color: var(--sn-stylekit-contrast-foreground-color);
|
||||
|
||||
th, td {
|
||||
th,
|
||||
td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid var(--sn-stylekit-contrast-border-color);
|
||||
}
|
||||
@@ -65,7 +82,7 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.priv-header {
|
||||
.priv-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -157,9 +174,9 @@
|
||||
padding-bottom: 0;
|
||||
min-width: 300px;
|
||||
|
||||
-webkit-box-shadow: 0px 2px 35px 0px rgba(0,0,0,0.19);
|
||||
-moz-box-shadow: 0px 2px 35px 0px rgba(0,0,0,0.19);
|
||||
box-shadow: 0px 2px 35px 0px rgba(0,0,0,0.19);
|
||||
-webkit-box-shadow: 0px 2px 35px 0px rgba(0, 0, 0, 0.19);
|
||||
-moz-box-shadow: 0px 2px 35px 0px rgba(0, 0, 0, 0.19);
|
||||
box-shadow: 0px 2px 35px 0px rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
.sk-panel-content
|
||||
.sk-panel-section.sk-panel-hero(
|
||||
ng-if=`
|
||||
!self.state.user &&
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showRegister &&
|
||||
!self.state.user &&
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showRegister &&
|
||||
!self.state.formData.mfa`
|
||||
)
|
||||
.sk-panel-row
|
||||
@@ -20,10 +20,10 @@
|
||||
.sk-button.info.featured(ng-click='self.state.formData.showRegister = true')
|
||||
.sk-label Register
|
||||
.sk-panel-row.sk-p
|
||||
| Standard Notes is free on every platform, and comes
|
||||
| Standard Notes is free on every platform, and comes
|
||||
| standard with sync and encryption.
|
||||
.sk-panel-section(ng-if=`
|
||||
self.state.formData.showLogin ||
|
||||
self.state.formData.showLogin ||
|
||||
self.state.formData.showRegister`
|
||||
)
|
||||
.sk-panel-section-title
|
||||
@@ -31,31 +31,31 @@
|
||||
form.sk-panel-form(ng-submit='self.submitAuthForm()')
|
||||
.sk-panel-section
|
||||
input.sk-input.contrast(
|
||||
name='email',
|
||||
ng-model='self.state.formData.email',
|
||||
ng-model-options='{allowInvalid: true}',
|
||||
placeholder='Email',
|
||||
required='',
|
||||
should-focus='true',
|
||||
sn-autofocus='true',
|
||||
spellcheck='false',
|
||||
name='email',
|
||||
ng-model='self.state.formData.email',
|
||||
ng-model-options='{allowInvalid: true}',
|
||||
placeholder='Email',
|
||||
required='',
|
||||
should-focus='true',
|
||||
sn-autofocus='true',
|
||||
spellcheck='false',
|
||||
type='email'
|
||||
)
|
||||
input.sk-input.contrast(
|
||||
name='password',
|
||||
ng-model='self.state.formData.user_password',
|
||||
placeholder='Password',
|
||||
required='',
|
||||
sn-enter='self.submitAuthForm()',
|
||||
name='password',
|
||||
ng-model='self.state.formData.user_password',
|
||||
placeholder='Password',
|
||||
required='',
|
||||
sn-enter='self.submitAuthForm()',
|
||||
type='password'
|
||||
)
|
||||
input.sk-input.contrast(
|
||||
name='password_conf',
|
||||
ng-if='self.state.formData.showRegister',
|
||||
ng-model='self.state.formData.password_conf',
|
||||
placeholder='Confirm Password',
|
||||
required='',
|
||||
sn-enter='self.submitAuthForm()',
|
||||
name='password_conf',
|
||||
ng-if='self.state.formData.showRegister',
|
||||
ng-model='self.state.formData.password_conf',
|
||||
placeholder='Confirm Password',
|
||||
required='',
|
||||
sn-enter='self.submitAuthForm()',
|
||||
type='password'
|
||||
)
|
||||
.sk-panel-row
|
||||
@@ -73,11 +73,11 @@
|
||||
.bordered-row.padded-row
|
||||
label.sk-label Sync Server Domain
|
||||
input.sk-input.mt-5.sk-base(
|
||||
name='server',
|
||||
ng-model='self.state.formData.url',
|
||||
name='server',
|
||||
ng-model='self.state.formData.url',
|
||||
ng-change='self.onHostInputChange()'
|
||||
placeholder='Server URL',
|
||||
required='',
|
||||
placeholder='Server URL',
|
||||
required='',
|
||||
type='text'
|
||||
)
|
||||
label.sk-label.padded-row.sk-panel-row.justify-left(
|
||||
@@ -85,28 +85,28 @@
|
||||
)
|
||||
.sk-horizontal-group.tight
|
||||
input.sk-input(
|
||||
ng-model='self.state.formData.strictSignin',
|
||||
ng-model='self.state.formData.strictSignin',
|
||||
type='checkbox'
|
||||
)
|
||||
p.sk-p Use strict sign in
|
||||
span
|
||||
a.info(
|
||||
href='https://standardnotes.org/help/security',
|
||||
rel='noopener',
|
||||
href='https://standardnotes.org/help/security',
|
||||
rel='noopener',
|
||||
target='_blank'
|
||||
) (Learn more)
|
||||
.sk-panel-section.form-submit(ng-if='!self.state.formData.authenticating')
|
||||
.sk-button-group.stretch
|
||||
.sk-button.info.featured(
|
||||
ng-click='self.submitAuthForm()',
|
||||
ng-click='self.submitAuthForm()',
|
||||
ng-disabled='self.state.formData.authenticating'
|
||||
)
|
||||
.sk-label {{self.state.formData.showLogin ? "Sign In" : "Register"}}
|
||||
.sk-notification.neutral(ng-if='self.state.formData.showRegister')
|
||||
.sk-notification-title No Password Reset.
|
||||
.sk-notification-text
|
||||
| Because your notes are encrypted using your password,
|
||||
| Standard Notes does not have a password reset option.
|
||||
| Because your notes are encrypted using your password,
|
||||
| Standard Notes does not have a password reset option.
|
||||
| You cannot forget your password.
|
||||
.sk-panel-section.no-bottom-pad(ng-if='self.state.formData.status')
|
||||
.sk-horizontal-group
|
||||
@@ -116,18 +116,18 @@
|
||||
label.sk-panel-row.justify-left
|
||||
.sk-horizontal-group.tight
|
||||
input(
|
||||
ng-false-value='true',
|
||||
ng-model='self.state.formData.ephemeral',
|
||||
ng-true-value='false',
|
||||
ng-false-value='true',
|
||||
ng-model='self.state.formData.ephemeral',
|
||||
ng-true-value='false',
|
||||
type='checkbox'
|
||||
)
|
||||
p.sk-p Stay signed in
|
||||
label.sk-panel-row.justify-left(ng-if='self.notesAndTagsCount() > 0')
|
||||
.sk-horizontal-group.tight
|
||||
input(
|
||||
ng-bind='true',
|
||||
ng-change='self.mergeLocalChanged()',
|
||||
ng-model='self.state.formData.mergeLocal',
|
||||
ng-bind='true',
|
||||
ng-change='self.mergeLocalChanged()',
|
||||
ng-model='self.state.formData.mergeLocal',
|
||||
type='checkbox'
|
||||
)
|
||||
p.sk-p Merge local data ({{self.notesAndTagsCount()}} notes and tags)
|
||||
@@ -136,12 +136,12 @@
|
||||
.sk-p.sk-panel-row {{self.state.formData.mfa.message}}
|
||||
.sk-panel-row
|
||||
input.sk-input.contrast(
|
||||
autofocus='true',
|
||||
name='mfa',
|
||||
ng-model='self.state.formData.userMfaCode',
|
||||
placeholder='Enter Code',
|
||||
required='',
|
||||
should-focus='true',
|
||||
autofocus='true',
|
||||
name='mfa',
|
||||
ng-model='self.state.formData.userMfaCode',
|
||||
placeholder='Enter Code',
|
||||
required='',
|
||||
should-focus='true',
|
||||
sn-autofocus='true'
|
||||
)
|
||||
.sk-button-group.stretch.sk-panel-row.form-submit(
|
||||
@@ -157,19 +157,19 @@
|
||||
.sk-label {{self.state.formData.status}}
|
||||
div(
|
||||
ng-if=`
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showRegister &&
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showRegister &&
|
||||
!self.state.formData.mfa`
|
||||
)
|
||||
.sk-panel-section(ng-if='self.state.user')
|
||||
.sk-notification.danger(ng-if='self.syncStatus.error')
|
||||
.sk-notification-title Sync Unreachable
|
||||
.sk-notification-text
|
||||
| Hmm...we can't seem to sync your account.
|
||||
| Hmm...we can't seem to sync your account.
|
||||
| The reason: {{self.syncStatus.error.message}}
|
||||
a.sk-a.info-contrast.sk-bold.sk-panel-row(
|
||||
href='https://standardnotes.org/help',
|
||||
rel='noopener',
|
||||
href='https://standardnotes.org/help',
|
||||
rel='noopener',
|
||||
target='_blank'
|
||||
) Need help?
|
||||
.sk-panel-row
|
||||
@@ -177,8 +177,8 @@
|
||||
.sk-h1.sk-bold.wrap {{self.state.user.email}}
|
||||
.sk-subtitle.subtle.normal {{self.state.server}}
|
||||
.sk-horizontal-group(
|
||||
delay='1000',
|
||||
delay-hide='true',
|
||||
delay='1000',
|
||||
delay-hide='true',
|
||||
show='self.syncStatus.syncOpInProgress || self.syncStatus.needsMoreSync'
|
||||
)
|
||||
.sk-spinner.small.info
|
||||
@@ -193,7 +193,7 @@
|
||||
)
|
||||
| Change Password
|
||||
a.sk-a.info.sk-panel-row.condensed(
|
||||
ng-click="self.openPrivilegesModal('')",
|
||||
ng-click="self.openPrivilegesModal('')",
|
||||
ng-show='self.state.user'
|
||||
)
|
||||
| Manage Privileges
|
||||
@@ -212,28 +212,28 @@
|
||||
ng-click='self.addPasscodeClicked(); $event.stopPropagation();'
|
||||
)
|
||||
.sk-label Add Passcode
|
||||
p.sk-p
|
||||
| Add a passcode to lock the application and
|
||||
p.sk-p
|
||||
| Add a passcode to lock the application and
|
||||
| encrypt on-device key storage.
|
||||
div(ng-if='!self.state.canAddPasscode')
|
||||
p.sk-p
|
||||
| Adding a passcode is not supported in temporary sessions. Please sign
|
||||
| Adding a passcode is not supported in temporary sessions. Please sign
|
||||
| out, then sign back in with the "Stay signed in" option checked.
|
||||
form.sk-panel-form(
|
||||
ng-if='self.state.formData.showPasscodeForm',
|
||||
ng-if='self.state.formData.showPasscodeForm',
|
||||
ng-submit='self.submitPasscodeForm()'
|
||||
)
|
||||
.sk-panel-row
|
||||
input.sk-input.contrast(
|
||||
ng-model='self.state.formData.passcode',
|
||||
placeholder='Passcode',
|
||||
should-focus='true',
|
||||
sn-autofocus='true',
|
||||
ng-model='self.state.formData.passcode',
|
||||
placeholder='Passcode',
|
||||
should-focus='true',
|
||||
sn-autofocus='true',
|
||||
type='password'
|
||||
)
|
||||
input.sk-input.contrast(
|
||||
ng-model='self.state.formData.confirmPasscode',
|
||||
placeholder='Confirm Passcode',
|
||||
ng-model='self.state.formData.confirmPasscode',
|
||||
placeholder='Confirm Passcode',
|
||||
type='password'
|
||||
)
|
||||
.sk-button-group.stretch.sk-panel-row.form-submit
|
||||
@@ -254,15 +254,15 @@
|
||||
a.sk-a.info(
|
||||
ng-class=`{
|
||||
'boxed' : option.value == self.state.selectedAutoLockInterval
|
||||
}`,
|
||||
ng-click='self.selectAutoLockInterval(option.value)',
|
||||
}`,
|
||||
ng-click='self.selectAutoLockInterval(option.value)',
|
||||
ng-repeat='option in self.state.passcodeAutoLockOptions'
|
||||
)
|
||||
| {{option.label}}
|
||||
.sk-p The autolock timer begins when the window or tab loses focus.
|
||||
.sk-panel-row
|
||||
a.sk-a.info.sk-panel-row.condensed(
|
||||
ng-click="self.openPrivilegesModal('')",
|
||||
ng-click="self.openPrivilegesModal('')",
|
||||
ng-show='!self.state.user'
|
||||
) Manage Privileges
|
||||
a.sk-a.info.sk-panel-row.condensed(
|
||||
@@ -280,17 +280,17 @@
|
||||
.sk-input-group
|
||||
label.sk-horizontal-group.tight
|
||||
input(
|
||||
ng-change='self.state.mutable.backupEncrypted = true',
|
||||
ng-model='self.state.mutable.backupEncrypted',
|
||||
ng-value='true',
|
||||
ng-change='self.state.mutable.backupEncrypted = true',
|
||||
ng-model='self.state.mutable.backupEncrypted',
|
||||
ng-value='true',
|
||||
type='radio'
|
||||
)
|
||||
p.sk-p Encrypted
|
||||
label.sk-horizontal-group.tight
|
||||
input(
|
||||
ng-change='self.state.mutable.backupEncrypted = false',
|
||||
ng-model='self.state.mutable.backupEncrypted',
|
||||
ng-value='false',
|
||||
ng-change='self.state.mutable.backupEncrypted = false',
|
||||
ng-model='self.state.mutable.backupEncrypted',
|
||||
ng-value='false',
|
||||
type='radio'
|
||||
)
|
||||
p.sk-p Decrypted
|
||||
@@ -300,32 +300,32 @@
|
||||
.sk-label Download Backup
|
||||
label.sk-button.info
|
||||
input(
|
||||
file-change='->',
|
||||
handler='self.importFileSelected(files)',
|
||||
style='display: none;',
|
||||
file-change='->',
|
||||
handler='self.importFileSelected(files)',
|
||||
style='display: none;',
|
||||
type='file'
|
||||
)
|
||||
.sk-label Import Backup
|
||||
span(ng-if='self.isDesktopApplication()')
|
||||
| Backups are automatically created on desktop and can be managed
|
||||
| Backups are automatically created on desktop and can be managed
|
||||
| via the "Backups" top-level menu.
|
||||
#import-password-request(ng-if='self.state.importData.requestPassword')
|
||||
form.sk-panel-form.stretch(ng-submit='self.submitImportPassword()')
|
||||
p Enter the account password associated with the import file.
|
||||
input.sk-input.contrast.mt-5(
|
||||
autofocus='true',
|
||||
ng-model='self.state.importData.password',
|
||||
placeholder='Enter File Account Password',
|
||||
autofocus='true',
|
||||
ng-model='self.state.importData.password',
|
||||
placeholder='Enter File Account Password',
|
||||
type='password'
|
||||
)
|
||||
.sk-button-group.stretch.sk-panel-row.form-submit
|
||||
button.sk-button.info(type='submit')
|
||||
.sk-label Decrypt & Import
|
||||
p
|
||||
| Importing from backup will not overwrite existing data,
|
||||
| Importing from backup will not overwrite existing data,
|
||||
| but instead create a duplicate of any differing data.
|
||||
p
|
||||
| If you'd like to import only a selection of items instead of
|
||||
| If you'd like to import only a selection of items instead of
|
||||
| the whole file, please use the Batch Manager extension.
|
||||
.sk-panel-row
|
||||
.sk-spinner.small.info(ng-if='self.state.importData.loading')
|
||||
@@ -338,9 +338,9 @@
|
||||
)
|
||||
| Cancel
|
||||
a.sk-a.right.danger(
|
||||
ng-click='self.destroyLocalData()',
|
||||
ng-click='self.destroyLocalData()',
|
||||
ng-if=`
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showLogin &&
|
||||
!self.state.formData.showRegister`
|
||||
)
|
||||
| {{ self.state.user ? "Sign out and clear local data" : "Clear all local data" }}
|
||||
| {{ self.state.user ? "Sign out" : "Clear session data" }}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { SNAlertService } from "@node_modules/snjs/dist/@types";
|
||||
import { SNAlertService } from "snjs/dist/@types";
|
||||
export declare class Database {
|
||||
databaseName: string;
|
||||
private alertService;
|
||||
private locked;
|
||||
private alertService?;
|
||||
private db?;
|
||||
constructor(databaseName: string, alertService: SNAlertService);
|
||||
deinit(): void;
|
||||
setAlertService(alertService: SNAlertService): void;
|
||||
/**
|
||||
* Relinquishes the lock and allows db operations to proceed
|
||||
*/
|
||||
|
||||
@@ -18,5 +18,5 @@ export declare class AlertService implements SNAlertService {
|
||||
*/
|
||||
alert(text: string, title?: string, closeButtonText?: string): Promise<void>;
|
||||
confirm(text: string, title?: string, confirmButtonText?: string, confirmButtonType?: ButtonType, cancelButtonText?: string): Promise<boolean>;
|
||||
blockingDialog(text: string): () => void;
|
||||
blockingDialog(text: string, title?: string): () => void;
|
||||
}
|
||||
|
||||
27
dist/@types/app/assets/javascripts/services/autolock_service.d.ts
vendored
Normal file
27
dist/@types/app/assets/javascripts/services/autolock_service.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
export declare class AutolockService {
|
||||
private application;
|
||||
private unsubState;
|
||||
private pollFocusInterval;
|
||||
private lastFocusState?;
|
||||
private lockAfterDate?;
|
||||
private lockTimeout?;
|
||||
constructor(application: WebApplication);
|
||||
observeVisibility(): void;
|
||||
deinit(): void;
|
||||
private lockApplication;
|
||||
setAutoLockInterval(interval: number): Promise<void>;
|
||||
getAutoLockInterval(): Promise<any>;
|
||||
/**
|
||||
* Verify document is in focus every so often as visibilitychange event is
|
||||
* not triggered on a typical window blur event but rather on tab changes.
|
||||
*/
|
||||
beginWebFocusPolling(): void;
|
||||
getAutoLockIntervalOptions(): {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
documentVisibilityChanged(visible: boolean): Promise<void>;
|
||||
beginAutoLockTimer(): Promise<void>;
|
||||
cancelAutoLockTimer(): void;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ export { AlertService } from './alertService';
|
||||
export { ArchiveManager } from './archiveManager';
|
||||
export { DesktopManager } from './desktopManager';
|
||||
export { KeyboardManager } from './keyboardManager';
|
||||
export { LockManager } from './lockManager';
|
||||
export { AutolockService } from './autolock_service';
|
||||
export { NativeExtManager } from './nativeExtManager';
|
||||
export { PreferencesManager } from './preferencesManager';
|
||||
export { StatusManager } from './statusManager';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SNPredicate, ApplicationService } from 'snjs';
|
||||
import { PayloadContent } from '@node_modules/snjs/dist/@types/protocol/payloads/generator';
|
||||
import { PayloadContent } from 'snjs/dist/@types/protocol/payloads/generator';
|
||||
/** A class for handling installation of system extensions */
|
||||
export declare class NativeExtManager extends ApplicationService {
|
||||
extManagerId: string;
|
||||
|
||||
@@ -32,9 +32,10 @@ export declare const STRING_GENERATING_LOGIN_KEYS = "Generating Login 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 function StringImportError(errorCount: number): string;
|
||||
export declare const STRING_ENTER_ACCOUNT_PASSCODE = "Enter your application passcode";
|
||||
export declare const STRING_ENTER_ACCOUNT_PASSCODE = "Enter your application passcode to unlock the application";
|
||||
export declare const STRING_ENTER_ACCOUNT_PASSWORD = "Enter your account password";
|
||||
export declare const STRING_ENTER_PASSCODE_FOR_MIGRATION = "Your application passcode is required to perform an upgrade of your local data storage structure.";
|
||||
export declare const STRING_ENTER_PASSCODE_FOR_LOGIN_REGISTER = "Enter your application passcode before signing in or registering";
|
||||
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.";
|
||||
|
||||
@@ -28,6 +28,9 @@ export interface PermissionsModalScope extends Partial<ng.IScope> {
|
||||
permissionsString: string;
|
||||
callback: (approved: boolean) => void;
|
||||
}
|
||||
export interface AccountSwitcherScope extends Partial<ng.IScope> {
|
||||
application: any;
|
||||
}
|
||||
export declare type PanelPuppet = {
|
||||
onReady?: () => void;
|
||||
ready?: boolean;
|
||||
|
||||
@@ -3,13 +3,15 @@ import { ComponentGroup } from './component_group';
|
||||
import { EditorGroup } from '@/ui_models/editor_group';
|
||||
import { PasswordWizardType } from '@/types';
|
||||
import { SNApplication, Challenge, ProtectedAction } from 'snjs';
|
||||
import { DesktopManager, LockManager, ArchiveManager, NativeExtManager, StatusManager, ThemeManager, PreferencesManager, KeyboardManager } from '@/services';
|
||||
import { WebDeviceInterface } from '@/web_device_interface';
|
||||
import { DesktopManager, AutolockService, ArchiveManager, NativeExtManager, StatusManager, ThemeManager, PreferencesManager, KeyboardManager } from '@/services';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { Bridge } from '@/services/bridge';
|
||||
import { DeinitSource } from 'snjs/dist/@types/types';
|
||||
declare type WebServices = {
|
||||
appState: AppState;
|
||||
desktopService: DesktopManager;
|
||||
lockService: LockManager;
|
||||
autolockService: AutolockService;
|
||||
archiveService: ArchiveManager;
|
||||
nativeExtService: NativeExtManager;
|
||||
statusService: StatusManager;
|
||||
@@ -20,18 +22,17 @@ declare type WebServices = {
|
||||
export declare class WebApplication extends SNApplication {
|
||||
private $compile?;
|
||||
private scope?;
|
||||
private onDeinit?;
|
||||
private webServices;
|
||||
private currentAuthenticationElement?;
|
||||
editorGroup: EditorGroup;
|
||||
componentGroup: ComponentGroup;
|
||||
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void, defaultSyncServerHost: string, bridge: Bridge);
|
||||
constructor(deviceInterface: WebDeviceInterface, identifier: string, $compile: ng.ICompileService, scope: ng.IScope, defaultSyncServerHost: string, bridge: Bridge);
|
||||
/** @override */
|
||||
deinit(): void;
|
||||
deinit(source: DeinitSource): void;
|
||||
setWebServices(services: WebServices): void;
|
||||
getAppState(): AppState;
|
||||
getDesktopService(): DesktopManager;
|
||||
getLockService(): LockManager;
|
||||
getAutolockService(): AutolockService;
|
||||
getArchiveService(): ArchiveManager;
|
||||
getNativeExtService(): NativeExtManager;
|
||||
getStatusService(): StatusManager;
|
||||
@@ -47,5 +48,6 @@ export declare class WebApplication extends SNApplication {
|
||||
authenticationInProgress(): boolean;
|
||||
presentPasswordModal(callback: () => void): void;
|
||||
presentRevisionPreviewModal(uuid: string, content: any): void;
|
||||
openAccountSwitcher(): void;
|
||||
}
|
||||
export {};
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
/// <reference types="angular" />
|
||||
import { WebApplication } from './application';
|
||||
import { SNApplicationGroup } from 'snjs';
|
||||
import { Bridge } from '@/services/bridge';
|
||||
declare type AppManagerChangeCallback = () => void;
|
||||
export declare class ApplicationGroup {
|
||||
export declare class ApplicationGroup extends SNApplicationGroup {
|
||||
private defaultSyncServerHost;
|
||||
private bridge;
|
||||
$compile: ng.ICompileService;
|
||||
$rootScope: ng.IRootScopeService;
|
||||
$timeout: ng.ITimeoutService;
|
||||
applications: WebApplication[];
|
||||
changeObservers: AppManagerChangeCallback[];
|
||||
activeApplication?: WebApplication;
|
||||
constructor($compile: ng.ICompileService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, defaultSyncServerHost: string, bridge: Bridge);
|
||||
private createDefaultApplication;
|
||||
/** @callback */
|
||||
onApplicationDeinit(application: WebApplication): void;
|
||||
private createNewApplication;
|
||||
get application(): WebApplication | undefined;
|
||||
getApplications(): WebApplication[];
|
||||
/**
|
||||
* Notifies observer when the active application has changed.
|
||||
* Any application which is no longer active is destroyed, and
|
||||
* must be removed from the interface.
|
||||
*/
|
||||
addApplicationChangeObserver(callback: AppManagerChangeCallback): () => void;
|
||||
private notifyObserversOfAppChange;
|
||||
initialize(callback?: any): Promise<void>;
|
||||
private createApplication;
|
||||
}
|
||||
export {};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SNComponent, ComponentArea } from 'snjs';
|
||||
import { WebApplication } from './application';
|
||||
import { UuidString } from '@node_modules/snjs/dist/@types/types';
|
||||
import { UuidString } from 'snjs/dist/@types/types';
|
||||
export declare class ComponentGroup {
|
||||
private application;
|
||||
changeObservers: any[];
|
||||
|
||||
4
dist/@types/app/assets/javascripts/views/account_switcher/account_switcher.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/account_switcher/account_switcher.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class AccountSwitcher extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SNNote, SNTag } from 'snjs';
|
||||
import { SNNote } from 'snjs';
|
||||
export declare enum NoteSortKey {
|
||||
CreatedAt = "created_at",
|
||||
UserUpdatedAt = "userModifiedDate",
|
||||
@@ -8,4 +8,4 @@ export declare enum NoteSortKey {
|
||||
/** @legacy Use UserUpdatedAt instead */
|
||||
ClientUpdatedAt = "client_updated_at"
|
||||
}
|
||||
export declare function notePassesFilter(note: SNNote, selectedTag: SNTag, showArchived: boolean, hidePinned: boolean, filterText: string): boolean;
|
||||
export declare function notePassesFilter(note: SNNote, showArchived: boolean, hidePinned: boolean, filterText: string): boolean;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { DeviceInterface, SNApplication } from 'snjs';
|
||||
import { DeviceInterface, SNApplication, ApplicationIdentifier } from 'snjs';
|
||||
import { Bridge } from './services/bridge';
|
||||
export declare class WebDeviceInterface extends DeviceInterface {
|
||||
private bridge;
|
||||
private database;
|
||||
private databases;
|
||||
constructor(timeout: any, bridge: Bridge);
|
||||
setApplication(application: SNApplication): void;
|
||||
private databaseForIdentifier;
|
||||
deinit(): void;
|
||||
getRawStorageValue(key: string): Promise<string | null>;
|
||||
getAllRawStorageKeyValues(): Promise<{
|
||||
@@ -14,19 +15,17 @@ export declare class WebDeviceInterface extends DeviceInterface {
|
||||
setRawStorageValue(key: string, value: any): Promise<void>;
|
||||
removeRawStorageValue(key: string): Promise<void>;
|
||||
removeAllRawStorageValues(): Promise<void>;
|
||||
openDatabase(): Promise<{
|
||||
openDatabase(identifier: ApplicationIdentifier): Promise<{
|
||||
isNewDatabase?: boolean | undefined;
|
||||
} | undefined>;
|
||||
private getDatabaseKeyPrefix;
|
||||
private keyForPayloadId;
|
||||
getAllRawDatabasePayloads(): Promise<any[]>;
|
||||
saveRawDatabasePayload(payload: any): Promise<void>;
|
||||
saveRawDatabasePayloads(payloads: any[]): Promise<void>;
|
||||
removeRawDatabasePayloadWithId(id: string): Promise<void>;
|
||||
removeAllRawDatabasePayloads(): Promise<void>;
|
||||
getNamespacedKeychainValue(): Promise<any>;
|
||||
setNamespacedKeychainValue(value: any): Promise<void>;
|
||||
clearNamespacedKeychainValue(): Promise<void>;
|
||||
getAllRawDatabasePayloads(identifier: ApplicationIdentifier): Promise<any[]>;
|
||||
saveRawDatabasePayload(payload: any, identifier: ApplicationIdentifier): Promise<void>;
|
||||
saveRawDatabasePayloads(payloads: any[], identifier: ApplicationIdentifier): Promise<void>;
|
||||
removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier): Promise<void>;
|
||||
removeAllRawDatabasePayloads(identifier: ApplicationIdentifier): Promise<void>;
|
||||
getNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<any>;
|
||||
setNamespacedKeychainValue(value: any, identifier: ApplicationIdentifier): Promise<void>;
|
||||
clearNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<void>;
|
||||
getRawKeychainValue(): Promise<any>;
|
||||
clearRawKeychainValue(): Promise<void>;
|
||||
openUrl(url: string): void;
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "standard-notes-web",
|
||||
"version": "3.5.0-beta3",
|
||||
"version": "3.5.0-beta2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -10956,8 +10956,8 @@
|
||||
"from": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad"
|
||||
},
|
||||
"snjs": {
|
||||
"version": "github:standardnotes/snjs#a39193f71cdcf1c02a7f0fa0cb96850f07b1717f",
|
||||
"from": "github:standardnotes/snjs#a39193f71cdcf1c02a7f0fa0cb96850f07b1717f"
|
||||
"version": "github:standardnotes/snjs#b029e6f7da367fecc40acab6e378e40ce247505a",
|
||||
"from": "github:standardnotes/snjs#b029e6f7da367fecc40acab6e378e40ce247505a"
|
||||
},
|
||||
"sockjs": {
|
||||
"version": "0.3.20",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "standard-notes-web",
|
||||
"version": "3.5.0-beta3",
|
||||
"version": "3.5.0-beta2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -11,7 +11,6 @@
|
||||
"start": "webpack-dev-server --progress --config webpack.dev.js",
|
||||
"watch": "webpack -w --config webpack.dev.js",
|
||||
"bundle": "webpack --config webpack.prod.js && npm run tsc",
|
||||
"bundle:desktop": "webpack --config webpack.prod.js --env.platform='desktop'",
|
||||
"build": "bundle install && npm ci && bundle exec rails assets:precompile && npm run bundle",
|
||||
"submodules": "git submodule update --init --force",
|
||||
"lint": "eslint --fix app/assets/javascripts/**/*.js",
|
||||
@@ -68,6 +67,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"sncrypto": "github:standardnotes/sncrypto#8794c88daa967eaae493cd5fdec7506d52b257ad",
|
||||
"snjs": "github:standardnotes/snjs#a39193f71cdcf1c02a7f0fa0cb96850f07b1717f"
|
||||
"snjs": "github:standardnotes/snjs#b029e6f7da367fecc40acab6e378e40ce247505a"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user