feat: add protect option to menu
This commit is contained in:
@@ -9,6 +9,7 @@ import HashtagIcon from '../../icons/ic-hashtag.svg';
|
||||
import ChevronRightIcon from '../../icons/ic-chevron-right.svg';
|
||||
import RestoreIcon from '../../icons/ic-restore.svg';
|
||||
import CloseIcon from '../../icons/ic-close.svg';
|
||||
import PasswordIcon from '../../icons/ic-textbox-password.svg';
|
||||
import { toDirective } from './utils';
|
||||
|
||||
const ICONS = {
|
||||
@@ -23,6 +24,7 @@ const ICONS = {
|
||||
'chevron-right': ChevronRightIcon,
|
||||
'restore': RestoreIcon,
|
||||
'close': CloseIcon,
|
||||
'password': PasswordIcon,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -35,6 +35,7 @@ export const NotesOptions = observer(
|
||||
const notes = Object.values(appState.notes.selectedNotes);
|
||||
const hidePreviews = toggleOn(note => note.hidePreview);
|
||||
const locked = toggleOn(note => note.locked);
|
||||
const protect = toggleOn(note => note.protected);
|
||||
const archived = notes.some((note) => note.archived);
|
||||
const unarchived = notes.some((note) => !note.archived);
|
||||
const trashed = notes.some((note) => note.trashed);
|
||||
@@ -84,6 +85,19 @@ export const NotesOptions = observer(
|
||||
Show preview
|
||||
</span>
|
||||
</Switch>
|
||||
<Switch
|
||||
onBlur={closeOnBlur}
|
||||
className="px-3 py-1.5"
|
||||
checked={protect}
|
||||
onChange={() => {
|
||||
appState.notes.setProtectSelectedNotes(!protect);
|
||||
}}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<Icon type="password" className={iconClass} />
|
||||
Protect
|
||||
</span>
|
||||
</Switch>
|
||||
<div className="h-1px my-2 bg-border"></div>
|
||||
{appState.tags.tagsCount > 0 && (
|
||||
<Disclosure
|
||||
|
||||
@@ -26,6 +26,7 @@ export class NotesState {
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
showProtectedWarning = false;
|
||||
|
||||
constructor(
|
||||
private application: WebApplication,
|
||||
@@ -36,6 +37,7 @@ export class NotesState {
|
||||
selectedNotes: observable,
|
||||
contextMenuOpen: observable,
|
||||
contextMenuPosition: observable,
|
||||
showProtectedWarning: observable,
|
||||
|
||||
selectedNotesCount: computed,
|
||||
|
||||
@@ -52,6 +54,7 @@ export class NotesState {
|
||||
addTagToSelectedNotes: action,
|
||||
removeTagFromSelectedNotes: action,
|
||||
isTagInSelectedNotes: action,
|
||||
setShowProtectedWarning: action,
|
||||
});
|
||||
|
||||
appEventListeners.push(
|
||||
@@ -75,6 +78,23 @@ export class NotesState {
|
||||
return Object.keys(this.selectedNotes).length;
|
||||
}
|
||||
|
||||
async runProtectedAction(action: (note: SNNote) => void, notes: SNNote[]): Promise<void> {
|
||||
let protectedNotesAccessRequest: Promise<boolean>;
|
||||
await Promise.all(
|
||||
notes.map(async (note) => {
|
||||
if (note.protected) {
|
||||
if (!protectedNotesAccessRequest) {
|
||||
protectedNotesAccessRequest =
|
||||
this.application.authorizeNoteAccess(note);
|
||||
}
|
||||
}
|
||||
if (!note.protected || await protectedNotesAccessRequest) {
|
||||
action(note);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async selectNotesRange(selectedNote: SNNote): Promise<void> {
|
||||
const notes = this.application.getDisplayableItems(
|
||||
ContentType.Note
|
||||
@@ -85,32 +105,18 @@ export class NotesState {
|
||||
const selectedNoteIndex = notes.findIndex(
|
||||
(note) => note.uuid == selectedNote.uuid
|
||||
);
|
||||
let protectedNotesAccessRequest: Promise<boolean>;
|
||||
let notesToSelect = [];
|
||||
|
||||
let notesToSelect = [];
|
||||
if (selectedNoteIndex > lastSelectedNoteIndex) {
|
||||
notesToSelect = notes.slice(lastSelectedNoteIndex, selectedNoteIndex + 1);
|
||||
} else {
|
||||
notesToSelect = notes.slice(selectedNoteIndex, lastSelectedNoteIndex + 1);
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
notesToSelect.map(async (note) => {
|
||||
const requestAccess =
|
||||
note.protected && this.application.hasProtectionSources();
|
||||
if (requestAccess) {
|
||||
if (!protectedNotesAccessRequest) {
|
||||
protectedNotesAccessRequest =
|
||||
this.application.authorizeNoteAccess(note);
|
||||
}
|
||||
}
|
||||
if (!requestAccess || (await protectedNotesAccessRequest)) {
|
||||
this.selectedNotes[note.uuid] = note;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.lastSelectedNote = selectedNote;
|
||||
this.runProtectedAction((note) => {
|
||||
this.selectedNotes[note.uuid] = note;
|
||||
this.lastSelectedNote = selectedNote;
|
||||
}, notesToSelect);
|
||||
}
|
||||
|
||||
async selectNote(note: SNNote): Promise<void> {
|
||||
@@ -211,7 +217,7 @@ export class NotesState {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.changeSelectedNotes((mutator) => {
|
||||
await this.changeSelectedNotes((mutator) => {
|
||||
mutator.trashed = trashed;
|
||||
});
|
||||
this.unselectNotes();
|
||||
@@ -258,7 +264,7 @@ export class NotesState {
|
||||
await this.application.deleteItem(note);
|
||||
}
|
||||
} else {
|
||||
this.changeSelectedNotes((mutator) => {
|
||||
await this.changeSelectedNotes((mutator) => {
|
||||
mutator.trashed = true;
|
||||
});
|
||||
}
|
||||
@@ -282,7 +288,7 @@ export class NotesState {
|
||||
return;
|
||||
}
|
||||
|
||||
this.changeSelectedNotes((mutator) => {
|
||||
await this.changeSelectedNotes((mutator) => {
|
||||
mutator.archived = archived;
|
||||
});
|
||||
|
||||
@@ -292,6 +298,25 @@ export class NotesState {
|
||||
});
|
||||
}
|
||||
|
||||
async setProtectSelectedNotes(protect: boolean): Promise<void> {
|
||||
if (protect) {
|
||||
await this.changeSelectedNotes((mutator) => {
|
||||
mutator.protected = protect;
|
||||
});
|
||||
if (!this.application.hasProtectionSources()) {
|
||||
this.setShowProtectedWarning(true);
|
||||
}
|
||||
} else {
|
||||
const selectedNotes = Object.values(this.selectedNotes);
|
||||
this.runProtectedAction(async (note) => {
|
||||
await this.application.changeItem(note.uuid, (mutator) => {
|
||||
mutator.protected = protect;
|
||||
});
|
||||
}, selectedNotes);
|
||||
this.setShowProtectedWarning(false);
|
||||
}
|
||||
}
|
||||
|
||||
unselectNotes(): void {
|
||||
this.selectedNotes = {};
|
||||
}
|
||||
@@ -326,6 +351,10 @@ export class NotesState {
|
||||
);
|
||||
}
|
||||
|
||||
setShowProtectedWarning(show: boolean): void {
|
||||
this.showProtectedWarning = show;
|
||||
}
|
||||
|
||||
private get io() {
|
||||
return this.application.io;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#editor-column.section.editor.sn-component(aria-label='Note')
|
||||
protected-note-panel.h-full.flex.justify-center.items-center(
|
||||
ng-if='self.state.showProtectedWarning'
|
||||
ng-if='self.appState.notes.showProtectedWarning'
|
||||
app-state='self.appState'
|
||||
on-view-note='self.dismissProtectedWarning()'
|
||||
)
|
||||
.flex-grow.flex.flex-col(
|
||||
ng-if='!self.state.showProtectedWarning'
|
||||
ng-if='!self.appState.notes.showProtectedWarning'
|
||||
)
|
||||
.sn-component
|
||||
.sk-app-bar.no-edges(
|
||||
|
||||
@@ -85,7 +85,6 @@ type EditorState = {
|
||||
textareaUnloading: boolean;
|
||||
/** Fields that can be directly mutated by the template */
|
||||
mutable: any;
|
||||
showProtectedWarning: boolean;
|
||||
};
|
||||
|
||||
type EditorValues = {
|
||||
@@ -241,7 +240,6 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
mutable: {
|
||||
tagsString: '',
|
||||
},
|
||||
showProtectedWarning: false,
|
||||
} as EditorState;
|
||||
}
|
||||
|
||||
@@ -291,8 +289,8 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
async handleEditorNoteChange() {
|
||||
this.cancelPendingSetStatus();
|
||||
const note = this.editor.note;
|
||||
const showProtectedWarning =
|
||||
note.protected && !this.application.hasProtectionSources();
|
||||
const showProtectedWarning = note.protected && !this.application.hasProtectionSources();
|
||||
this.setShowProtectedWarning(showProtectedWarning);
|
||||
await this.setState({
|
||||
showActionsMenu: false,
|
||||
showOptionsMenu: false,
|
||||
@@ -300,7 +298,6 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
showHistoryMenu: false,
|
||||
altKeyDown: false,
|
||||
noteStatus: undefined,
|
||||
showProtectedWarning,
|
||||
});
|
||||
this.editorValues.title = note.title;
|
||||
this.editorValues.text = note.text;
|
||||
@@ -318,9 +315,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
}
|
||||
|
||||
async dismissProtectedWarning() {
|
||||
await this.setState({
|
||||
showProtectedWarning: false,
|
||||
});
|
||||
this.setShowProtectedWarning(false);
|
||||
this.focusTitle();
|
||||
}
|
||||
|
||||
@@ -658,6 +653,10 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
}
|
||||
}
|
||||
|
||||
setShowProtectedWarning(show: boolean) {
|
||||
this.application.getAppState().notes.setShowProtectedWarning(show);
|
||||
}
|
||||
|
||||
async deleteNote(permanently: boolean) {
|
||||
if (this.editor.isTemplateNote) {
|
||||
this.application.alertService!.alert(STRING_DELETE_PLACEHOLDER_ATTEMPT);
|
||||
@@ -767,9 +766,7 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
} else {
|
||||
const note = await this.application.protectNote(this.note);
|
||||
if (note?.protected && !this.application.hasProtectionSources()) {
|
||||
this.setState({
|
||||
showProtectedWarning: true,
|
||||
});
|
||||
this.setShowProtectedWarning(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user