Release/3.6.0 (#527)

* feat: (wip) authorize note access

* fix: remove multiEditorEnabled

* refactor: update SNJS + eslint

* refactor: remove privileges in favor of SNJS protections

* fix: do not close editor when editing an archived note

* chore: remove progress indicator for webpack dev server

* fix: add rel="noreferrer" to bugsnag links

* chore(deps): upgrade snjs

* chore(deps): upgrade snjs

* feat: batch manager protection + react challenge modal + eslint fix

* fix: lint errors

* fix: launch state error

* fix: challenge modal: cancel instead of dismiss when pressing escape

* feat: improve focus styles

* fix: cancel session revoking when pressing escape on confirm dialog

* fix: lint warning

* chore(deps): upgrade minor versions

* feat: make SNWebCrypto a constant

* feat: add random identifier to bugsnag reports

* fix: check onKeyUp instead of onKeyDown

* feat: implement SNJS backup file password retrieval

* chore(deps): upgrade snjs

* feat: display warning banner when using the app with no account

* fix: properly color svg button

* fix: wording

* fix: hide account warning after login + improve key storage wording

* chore(deps): upgrade stylekit

* feat: use stylekit fonts for the editor

* chore(deps): bump nokogiri from 1.10.8 to 1.11.1 (#511)

Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.8 to 1.11.1.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.8...v1.11.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com>

* chore(deps): bump ini from 1.3.5 to 1.3.8 (#504)

Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com>

* fix: rename master branch to main

* fix: add missing placeholders for submodules (#516)

Co-authored-by: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com>

* chore(deps): upgrade snjs, babel, typescript, reach, mobx, preact

* feat: clear protection session

* fix: use correct close icon size

* fix: hide protections paragraph when no account or passcode exist

* chore(deps): remove unused dependencies

* fix: button casing

* feat: implement SNApplication.hasProtectionSources

* chore(version): 3.6.0

* feat: enable sessions management for every build

* feat: make "Protected" flag more subtle

* fix: only match protected note title

* fix: remove inconsistencies between protected note label and date

* feat: show warning when protecting a note with no protection source

* feat: make unprotecting a note a protected action

* chore(deps): upgrade snjs

* chore(version): 3.6.0-beta01

* fix: run docker with root to fix crashing on Linux (undoes 62da387d3a) (#525)

* feat: make encrypted backups protected (#524)

Co-authored-by: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: proletarius101 <54175165+proletarius101@users.noreply.github.com>
Co-authored-by: Darius JJ Chuck <79410894+standarius@users.noreply.github.com>
Co-authored-by: Antonella Sgarlatta <antonella@standardnotes.org>
This commit is contained in:
Baptiste Grob
2021-03-02 15:44:40 +01:00
committed by GitHub
parent 38707cc977
commit bef17ef534
84 changed files with 3410 additions and 2526 deletions

View File

@@ -1,22 +1,22 @@
import { isDesktopApplication, isDev } from '@/utils';
import pull from 'lodash/pull';
import {
ProtectedAction,
ApplicationEvent,
SNTag,
SNNote,
SNUserPrefs,
ContentType,
SNSmartTag,
PayloadSource,
DeinitSource,
UuidString,
SyncOpStatus,
PrefKey,
SNApplication,
} from '@standardnotes/snjs';
import { WebApplication } from '@/ui_models/application';
import { Editor } from '@/ui_models/editor';
import { action, makeObservable, observable } from 'mobx';
import { action, makeObservable, observable, runInAction } from 'mobx';
import { Bridge } from '@/services/bridge';
import { storage, StorageKey } from '@/services/localStorage';
export enum AppStateEvent {
TagChanged,
@@ -29,6 +29,11 @@ export enum AppStateEvent {
WindowDidBlur,
}
export type PanelResizedData = {
panel: string;
collapsed: boolean;
};
export enum EventSource {
UserInteraction,
Script,
@@ -36,8 +41,6 @@ export enum EventSource {
type ObserverCallback = (event: AppStateEvent, data?: any) => Promise<void>;
const SHOW_BETA_WARNING_KEY = 'show_beta_warning';
class ActionsMenuState {
hiddenExtensions: Record<UuidString, boolean> = {};
@@ -45,7 +48,7 @@ class ActionsMenuState {
makeObservable(this, {
hiddenExtensions: observable,
toggleExtensionVisibility: action,
deinit: action,
reset: action,
});
}
@@ -53,7 +56,7 @@ class ActionsMenuState {
this.hiddenExtensions[uuid] = !this.hiddenExtensions[uuid];
}
deinit() {
reset() {
this.hiddenExtensions = {};
}
}
@@ -72,7 +75,7 @@ export class SyncState {
});
}
update(status: SyncOpStatus) {
update(status: SyncOpStatus): void {
this.errorMessage = status.error?.message;
this.inProgress = status.syncInProgress;
const stats = status.getStats();
@@ -92,6 +95,59 @@ export class SyncState {
}
}
class AccountMenuState {
show = false;
constructor() {
makeObservable(this, {
show: observable,
setShow: action,
toggleShow: action,
});
}
setShow(show: boolean) {
this.show = show;
}
toggleShow() {
this.show = !this.show;
}
}
class NoAccountWarningState {
show: boolean;
constructor(application: SNApplication, appObservers: (() => void)[]) {
this.show = application.hasAccount()
? false
: storage.get(StorageKey.ShowNoAccountWarning) ?? true;
appObservers.push(
application.addEventObserver(async () => {
runInAction(() => {
this.show = false;
});
}, ApplicationEvent.SignedIn),
application.addEventObserver(async () => {
if (application.hasAccount()) {
runInAction(() => {
this.show = false;
});
}
}, ApplicationEvent.Started)
);
makeObservable(this, {
show: observable,
hide: action,
});
}
hide() {
this.show = false;
storage.set(StorageKey.ShowNoAccountWarning, false);
}
reset() {
storage.remove(StorageKey.ShowNoAccountWarning);
}
}
export class AppState {
readonly enableUnfinishedFeatures =
isDev || location.host.includes('app-dev.standardnotes.org');
@@ -106,12 +162,15 @@ export class AppState {
rootScopeCleanup2: any;
onVisibilityChange: any;
selectedTag?: SNTag;
multiEditorEnabled = false;
showBetaWarning = false;
showBetaWarning: boolean;
readonly accountMenu = new AccountMenuState();
readonly actionsMenu = new ActionsMenuState();
readonly noAccountWarning: NoAccountWarningState;
readonly sync = new SyncState();
isSessionsModalVisible = false;
private appEventObserverRemovers: (() => void)[] = [];
/* @ngInject */
constructor(
$rootScope: ng.IRootScopeService,
@@ -122,15 +181,10 @@ export class AppState {
this.$timeout = $timeout;
this.$rootScope = $rootScope;
this.application = application;
makeObservable(this, {
showBetaWarning: observable,
isSessionsModalVisible: observable,
enableBetaWarning: action,
disableBetaWarning: action,
openSessionsModal: action,
closeSessionsModal: action,
});
this.noAccountWarning = new NoAccountWarningState(
application,
this.appEventObserverRemovers
);
this.addAppEventObserver();
this.streamNotesAndTags();
this.onVisibilityChange = () => {
@@ -141,17 +195,35 @@ export class AppState {
this.notifyEvent(event);
};
this.registerVisibilityObservers();
this.determineBetaWarningValue();
if (this.bridge.appVersion.includes('-beta')) {
this.showBetaWarning = storage.get(StorageKey.ShowBetaWarning) ?? true;
} else {
this.showBetaWarning = false;
}
makeObservable(this, {
showBetaWarning: observable,
isSessionsModalVisible: observable,
enableBetaWarning: action,
disableBetaWarning: action,
openSessionsModal: action,
closeSessionsModal: action,
});
}
deinit(source: DeinitSource) {
deinit(source: DeinitSource): void {
if (source === DeinitSource.SignOut) {
localStorage.removeItem(SHOW_BETA_WARNING_KEY);
storage.remove(StorageKey.ShowBetaWarning);
this.noAccountWarning.reset();
}
this.actionsMenu.deinit();
this.actionsMenu.reset();
this.unsubApp();
this.unsubApp = undefined;
this.observers.length = 0;
this.appEventObserverRemovers.forEach((remover) => remover());
this.appEventObserverRemovers.length = 0;
if (this.rootScopeCleanup1) {
this.rootScopeCleanup1();
this.rootScopeCleanup2();
@@ -172,30 +244,12 @@ export class AppState {
disableBetaWarning() {
this.showBetaWarning = false;
localStorage.setItem(SHOW_BETA_WARNING_KEY, 'false');
storage.set(StorageKey.ShowBetaWarning, false);
}
enableBetaWarning() {
this.showBetaWarning = true;
localStorage.setItem(SHOW_BETA_WARNING_KEY, 'true');
}
clearBetaWarning() {
localStorage.setItem(SHOW_BETA_WARNING_KEY, 'true');
}
private determineBetaWarningValue() {
if (this.bridge.appVersion.includes('-beta')) {
switch (localStorage.getItem(SHOW_BETA_WARNING_KEY)) {
case 'true':
default:
this.enableBetaWarning();
break;
case 'false':
this.disableBetaWarning();
break;
}
}
storage.set(StorageKey.ShowBetaWarning, true);
}
/**
@@ -210,7 +264,7 @@ export class AppState {
: this.selectedTag.uuid
: undefined;
if (!activeEditor || this.multiEditorEnabled) {
if (!activeEditor) {
this.application.editorGroup.createEditor(
undefined,
title,
@@ -221,35 +275,25 @@ export class AppState {
}
}
async openEditor(noteUuid: string) {
async openEditor(noteUuid: string): Promise<void> {
if (this.getActiveEditor()?.note?.uuid === noteUuid) {
return;
}
const note = this.application.findItem(noteUuid) as SNNote;
if (this.getActiveEditor()?.note?.uuid === noteUuid) return;
const run = async () => {
if (!note) {
console.warn('Tried accessing a non-existant note of UUID ' + noteUuid);
return;
}
if (await this.application.authorizeNoteAccess(note)) {
const activeEditor = this.getActiveEditor();
if (!activeEditor || this.multiEditorEnabled) {
if (!activeEditor) {
this.application.editorGroup.createEditor(noteUuid);
} else {
activeEditor.setNote(note);
}
await this.notifyEvent(AppStateEvent.ActiveEditorChanged);
};
if (
note &&
note.safeContent.protected &&
(await this.application.privilegesService!.actionRequiresPrivilege(
ProtectedAction.ViewProtectedNotes
))
) {
return new Promise((resolve) => {
this.application.presentPrivilegesModal(
ProtectedAction.ViewProtectedNotes,
() => {
run().then(resolve);
}
);
});
} else {
return run();
}
}
@@ -299,7 +343,11 @@ export class AppState {
this.closeEditor(editor);
} else if (note.trashed && !this.selectedTag?.isTrashTag) {
this.closeEditor(editor);
} else if (note.archived && !this.selectedTag?.isArchiveTag) {
} else if (
note.archived &&
!this.selectedTag?.isArchiveTag &&
!this.application.getPreference(PrefKey.NotesShowArchived, false)
) {
this.closeEditor(editor);
}
}
@@ -400,10 +448,11 @@ export class AppState {
}
panelDidResize(name: string, collapsed: boolean) {
this.notifyEvent(AppStateEvent.PanelResized, {
const data: PanelResizedData = {
panel: name,
collapsed: collapsed,
});
};
this.notifyEvent(AppStateEvent.PanelResized, data);
}
editorDidFocus(eventSource: EventSource) {