feat: handle unprotected session expiration (#779)
* feat: hide note contents if the protection expires when the protected note is open and wasn't edited for a while * feat: handle session expiration for opened protected note for both plain advanced editors * fix: if after canceling session expiry modal only one unprotected note stays selected, show its contents in the editor * refactor: handle session expiration for opened protected note (move the logic to web client) * feat: handle the case of selecting "Don't remember" option in session expiry dialog * test (WIP): add unit tests for protecting opened note after the session has expired * test: add remaining unit tests * refactor: move the opened note protection logic to "editor_view" * refactor: reviewer comments - don't rely on user signed-in/out status to require authentication for protected note - remove unnecessary async/awaits - better wording on ui * refactor: reviewer's comments: - use snjs method to check if "Don't remember" option is selected in authentication modal - move the constant to snjs - fix eslint error * refactor: avoid `any` type for `appEvent` payload * test: add unit tests * chore: update function name * refactor: use simpler protection session event types * refactor: protected access terminology * refactor: start counting idle timer after every edit (instead of counting by interval in spite of edits) * test: unit tests * style: don't give extra brightness to the "View Note"/"Authenticate" button on hover/focus * chore: bump snjs version * chore: put snjs "beta" version * fix: run protection timeout when the note is marked as protected * chore: snjs version bump * refactor: immediately lock the note if it's marked as "Protected" * refactor: rename component, directive and some props * refactor: remove extra check * refactor: rename the method * chore: update snjs version Co-authored-by: Mo Bitar <me@bitar.io>
This commit is contained in:
@@ -28,7 +28,7 @@ export class NotesState {
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
contextMenuClickLocation: { x: number, y: number } = { x: 0, y: 0 };
|
||||
contextMenuClickLocation: { x: number; y: number } = { x: 0, y: 0 };
|
||||
contextMenuMaxHeight: number | 'auto' = 'auto';
|
||||
showProtectedWarning = false;
|
||||
|
||||
@@ -185,7 +185,7 @@ export class NotesState {
|
||||
this.contextMenuOpen = open;
|
||||
}
|
||||
|
||||
setContextMenuClickLocation(location: { x: number, y: number }): void {
|
||||
setContextMenuClickLocation(location: { x: number; y: number }): void {
|
||||
this.contextMenuClickLocation = location;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,8 @@ export class NotesState {
|
||||
// Open up-bottom is default behavior
|
||||
let openUpBottom = true;
|
||||
|
||||
const bottomSpace = clientHeight - footerHeight - this.contextMenuClickLocation.y;
|
||||
const bottomSpace =
|
||||
clientHeight - footerHeight - this.contextMenuClickLocation.y;
|
||||
const upSpace = this.contextMenuClickLocation.y;
|
||||
|
||||
// If not enough space to open up-bottom
|
||||
@@ -220,26 +221,18 @@ export class NotesState {
|
||||
// If there's enough space, open bottom-up
|
||||
if (upSpace > maxContextMenuHeight) {
|
||||
openUpBottom = false;
|
||||
this.setContextMenuMaxHeight(
|
||||
'auto'
|
||||
);
|
||||
// Else, reduce max height (menu will be scrollable) and open in whichever direction there's more space
|
||||
this.setContextMenuMaxHeight('auto');
|
||||
// Else, reduce max height (menu will be scrollable) and open in whichever direction there's more space
|
||||
} else {
|
||||
if (upSpace > bottomSpace) {
|
||||
this.setContextMenuMaxHeight(
|
||||
upSpace - 2
|
||||
);
|
||||
this.setContextMenuMaxHeight(upSpace - 2);
|
||||
openUpBottom = false;
|
||||
} else {
|
||||
this.setContextMenuMaxHeight(
|
||||
bottomSpace - 2
|
||||
);
|
||||
this.setContextMenuMaxHeight(bottomSpace - 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setContextMenuMaxHeight(
|
||||
'auto'
|
||||
);
|
||||
this.setContextMenuMaxHeight('auto');
|
||||
}
|
||||
|
||||
if (openUpBottom) {
|
||||
@@ -375,9 +368,7 @@ export class NotesState {
|
||||
const selectedNotes = Object.values(this.selectedNotes);
|
||||
if (protect) {
|
||||
await this.application.protectNotes(selectedNotes);
|
||||
if (!this.application.hasProtectionSources()) {
|
||||
this.setShowProtectedWarning(true);
|
||||
}
|
||||
this.setShowProtectedWarning(true);
|
||||
} else {
|
||||
await this.application.unprotectNotes(selectedNotes);
|
||||
this.setShowProtectedWarning(false);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ApplicationEvent } from "@standardnotes/snjs";
|
||||
import { makeObservable, observable, action, runInAction } from "mobx";
|
||||
import { WebApplication } from "../application";
|
||||
import { ApplicationEvent } from '@standardnotes/snjs';
|
||||
import { makeObservable, observable, action, runInAction } from 'mobx';
|
||||
import { WebApplication } from '../application';
|
||||
|
||||
export class SearchOptionsState {
|
||||
includeProtectedContents = false;
|
||||
@@ -25,7 +25,10 @@ export class SearchOptionsState {
|
||||
appObservers.push(
|
||||
this.application.addEventObserver(async () => {
|
||||
this.refreshIncludeProtectedContents();
|
||||
}, ApplicationEvent.ProtectionSessionExpiryDateChanged)
|
||||
}, ApplicationEvent.UnprotectedSessionBegan),
|
||||
this.application.addEventObserver(async () => {
|
||||
this.refreshIncludeProtectedContents();
|
||||
}, ApplicationEvent.UnprotectedSessionExpired)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,21 +41,17 @@ export class SearchOptionsState {
|
||||
};
|
||||
|
||||
refreshIncludeProtectedContents = (): void => {
|
||||
if (
|
||||
this.includeProtectedContents &&
|
||||
this.application.areProtectionsEnabled()
|
||||
) {
|
||||
this.includeProtectedContents = false;
|
||||
}
|
||||
this.includeProtectedContents =
|
||||
this.application.hasUnprotectedAccessSession();
|
||||
};
|
||||
|
||||
toggleIncludeProtectedContents = async (): Promise<void> => {
|
||||
if (this.includeProtectedContents) {
|
||||
this.includeProtectedContents = false;
|
||||
} else {
|
||||
const authorized = await this.application.authorizeSearchingProtectedNotesText();
|
||||
await this.application.authorizeSearchingProtectedNotesText();
|
||||
runInAction(() => {
|
||||
this.includeProtectedContents = authorized;
|
||||
this.refreshIncludeProtectedContents();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user