diff --git a/app/assets/javascripts/directives/views/accountMenu.ts b/app/assets/javascripts/directives/views/accountMenu.ts index 82fc6cdca..6012d5fbe 100644 --- a/app/assets/javascripts/directives/views/accountMenu.ts +++ b/app/assets/javascripts/directives/views/accountMenu.ts @@ -148,9 +148,7 @@ class AccountMenuCtrl extends PureViewCtrl { async $onInit() { super.$onInit(); this.setState({ - showSessions: - this.appState.enableUnfinishedFeatures && - (await this.application.userCanManageSessions()), + showSessions: await this.application.userCanManageSessions() }); const sync = this.appState.sync; diff --git a/app/assets/javascripts/strings.ts b/app/assets/javascripts/strings.ts index c8782ae29..25232bc9c 100644 --- a/app/assets/javascripts/strings.ts +++ b/app/assets/javascripts/strings.ts @@ -124,4 +124,6 @@ export const Strings = { : 'password manager'; return `Your keys are currently stored in your operating system's ${keychainName}. Adding a passcode prevents even your operating system from reading them.`; }, + protectingNoteWithoutProtectionSources: 'Access to this note will not be restricted until you set up a passcode or account.', + openAccountMenu: 'Open Account Menu' }; diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index c0f67f836..f5ed13f1a 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -1,4 +1,4 @@ -import { STRING_ARCHIVE_LOCKED_ATTEMPT, STRING_SAVING_WHILE_DOCUMENT_HIDDEN, STRING_UNARCHIVE_LOCKED_ATTEMPT } from './../../strings'; +import { Strings, STRING_ARCHIVE_LOCKED_ATTEMPT, STRING_SAVING_WHILE_DOCUMENT_HIDDEN, STRING_UNARCHIVE_LOCKED_ATTEMPT } from './../../strings'; import { Editor } from '@/ui_models/editor'; import { WebApplication } from '@/ui_models/application'; import { PanelPuppet, WebDirective } from '@/types'; @@ -713,15 +713,21 @@ class EditorViewCtrl extends PureViewCtrl { ); } - toggleProtectNote() { - this.saveNote( - true, - false, - true, - (mutator) => { - mutator.protected = !this.note.protected; + async toggleProtectNote() { + if (this.note.protected) { + void this.application.unprotectNote(this.note); + } else { + const note = await this.application.protectNote(this.note); + if (note?.protected && !this.application.hasProtectionSources()) { + if (await confirmDialog({ + text: Strings.protectingNoteWithoutProtectionSources, + confirmButtonText: Strings.openAccountMenu, + confirmButtonStyle: 'info', + })) { + this.appState.accountMenu.setShow(true); + } } - ); + } } toggleNotePreview() { diff --git a/app/assets/javascripts/views/notes/note_utils.ts b/app/assets/javascripts/views/notes/note_utils.ts index 7ddb91a73..6f8265982 100644 --- a/app/assets/javascripts/views/notes/note_utils.ts +++ b/app/assets/javascripts/views/notes/note_utils.ts @@ -5,44 +5,54 @@ export function notePassesFilter( showArchived: boolean, hidePinned: boolean, filterText: string -) { - +): boolean { const canShowArchived = showArchived; const canShowPinned = !hidePinned; - if ( - (note.archived && !canShowArchived) || - (note.pinned && !canShowPinned) - ) { + if ((note.archived && !canShowArchived) || (note.pinned && !canShowPinned)) { return false; } - return noteMatchesQuery(note, filterText); + if (note.protected) { + const match = noteMatchesQuery(note, filterText); + /** Only match title to prevent leaking protected note text */ + return match === Match.Title || match === Match.TitleAndText; + } else { + return noteMatchesQuery(note, filterText) !== Match.None; + } } -function noteMatchesQuery( - note: SNNote, - query: string -) { +enum Match { + None = 0, + Title = 1, + Text = 2, + TitleAndText = Title + Text, + Uuid = 5, +} + +function noteMatchesQuery(note: SNNote, query: string): Match { if (query.length === 0) { - return true; + return Match.TitleAndText; } const title = note.safeTitle().toLowerCase(); const text = note.safeText().toLowerCase(); const lowercaseText = query.toLowerCase(); + const words = lowercaseText.split(' '); const quotedText = stringBetweenQuotes(lowercaseText); if (quotedText) { - return title.includes(quotedText) || text.includes(quotedText); + return ( + (title.includes(quotedText) ? Match.Title : Match.None) + + (text.includes(quotedText) ? Match.Text : Match.None) + ); } if (stringIsUuid(lowercaseText)) { - return note.uuid === lowercaseText; + return note.uuid === lowercaseText ? Match.Uuid : Match.None; } - const words = lowercaseText.split(" "); const matchesTitle = words.every((word) => { return title.indexOf(word) >= 0; }); const matchesBody = words.every((word) => { return text.indexOf(word) >= 0; }); - return matchesTitle || matchesBody; + return (matchesTitle ? Match.Title : 0) + (matchesBody ? Match.Text : 0); } function stringBetweenQuotes(text: string) { diff --git a/app/assets/javascripts/views/notes/notes-view.pug b/app/assets/javascripts/views/notes/notes-view.pug index 6271ce2b8..a42e16bc1 100644 --- a/app/assets/javascripts/views/notes/notes-view.pug +++ b/app/assets/javascripts/views/notes/notes-view.pug @@ -143,10 +143,12 @@ .default-preview( ng-show='!note.preview_html && !note.preview_plain' ) {{note.text}} - .date.faded(ng-show='!self.state.hideDate') - span(ng-show="self.state.sortBy == 'userModifiedDate'") + .bottom-info.faded(ng-show='!self.state.hideDate || note.protected') + span(ng-if="note.protected") + | Protected{{self.state.hideDate ? '' : ' • '}} + span(ng-show="!self.state.hideDate && self.state.sortBy == 'userModifiedDate'") | Modified {{note.updatedAtString || 'Now'}} - span(ng-show="self.state.sortBy != 'userModifiedDate'") + span(ng-show="!self.state.hideDate && self.state.sortBy != 'userModifiedDate'") | {{note.createdAtString || 'Now'}} .tags-string(ng-if='!self.state.hideTags && self.state.renderedNotesTags[$index]') .faded {{self.state.renderedNotesTags[$index]}} diff --git a/app/assets/javascripts/views/notes/notes_view.ts b/app/assets/javascripts/views/notes/notes_view.ts index 154a5f7f6..3bd631cf6 100644 --- a/app/assets/javascripts/views/notes/notes_view.ts +++ b/app/assets/javascripts/views/notes/notes_view.ts @@ -576,12 +576,6 @@ class NotesViewCtrl extends PureViewCtrl { class: 'warning' }); } - if (note.protected) { - flags.push({ - text: "Protected", - class: 'success' - }); - } if (note.locked) { flags.push({ text: "Locked", diff --git a/app/assets/stylesheets/_notes.scss b/app/assets/stylesheets/_notes.scss index 794255703..fa7d78c10 100644 --- a/app/assets/stylesheets/_notes.scss +++ b/app/assets/stylesheets/_notes.scss @@ -126,7 +126,7 @@ text-overflow: ellipsis; } - > .date { + > .bottom-info { font-size: 12px; margin-top: 4px; } diff --git a/app/assets/templates/directives/account-menu.pug b/app/assets/templates/directives/account-menu.pug index f5dbf61e2..e56af6939 100644 --- a/app/assets/templates/directives/account-menu.pug +++ b/app/assets/templates/directives/account-menu.pug @@ -156,7 +156,6 @@ ) Change Password a.sk-a.info.sk-panel-row.condensed( ng-click="self.openSessionsModal()" - ng-if="self.state.showSessions" ) Manage Sessions .sk-panel-section .sk-panel-section-title Encryption diff --git a/package.json b/package.json index ffa7e9b3e..6f6057cb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.5.19", + "version": "3.6.0-beta01", "license": "AGPL-3.0-or-later", "repository": { "type": "git",