From 8302733a49c66c4056bfc96fbb86300a6ba9ef49 Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 11 May 2021 17:09:23 -0300 Subject: [PATCH] feat: add protect option to menu --- app/assets/icons/ic-textbox-password.svg | 3 + app/assets/javascripts/components/Icon.tsx | 2 + .../javascripts/components/NotesOptions.tsx | 14 ++++ .../ui_models/app_state/notes_state.ts | 73 +++++++++++++------ .../javascripts/views/editor/editor-view.pug | 4 +- .../javascripts/views/editor/editor_view.ts | 19 ++--- 6 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 app/assets/icons/ic-textbox-password.svg diff --git a/app/assets/icons/ic-textbox-password.svg b/app/assets/icons/ic-textbox-password.svg new file mode 100644 index 00000000000..a5edc4e3834 --- /dev/null +++ b/app/assets/icons/ic-textbox-password.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index 45a6431ff7c..39e893d2b82 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -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 = { diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx index 11a928da650..4fd6d5f89c5 100644 --- a/app/assets/javascripts/components/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions.tsx @@ -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 + { + appState.notes.setProtectSelectedNotes(!protect); + }} + > + + + Protect + +
{appState.tags.tagsCount > 0 && ( void, notes: SNNote[]): Promise { + let protectedNotesAccessRequest: Promise; + 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 { 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; - 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 { @@ -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 { + 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; } diff --git a/app/assets/javascripts/views/editor/editor-view.pug b/app/assets/javascripts/views/editor/editor-view.pug index 273a96e1091..75c75f6abbd 100644 --- a/app/assets/javascripts/views/editor/editor-view.pug +++ b/app/assets/javascripts/views/editor/editor-view.pug @@ -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( diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index 2092e990e13..8f66ccb9646 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -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 { mutable: { tagsString: '', }, - showProtectedWarning: false, } as EditorState; } @@ -291,8 +289,8 @@ class EditorViewCtrl extends PureViewCtrl { 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 { 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 { } async dismissProtectedWarning() { - await this.setState({ - showProtectedWarning: false, - }); + this.setShowProtectedWarning(false); this.focusTitle(); } @@ -658,6 +653,10 @@ class EditorViewCtrl extends PureViewCtrl { } } + 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 { } else { const note = await this.application.protectNote(this.note); if (note?.protected && !this.application.hasProtectionSources()) { - this.setState({ - showProtectedWarning: true, - }); + this.setShowProtectedWarning(true); } } }