From 411630296536340c4db998b1dd96faacc619e59e Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 10:26:11 -0400 Subject: [PATCH 1/7] [Soft Delete] - Trash bin in browser extension --- src/_locales/en/messages.json | 25 +++++++++++++++++++++ src/popup/vault/ciphers.component.ts | 9 +++++++- src/popup/vault/groupings.component.html | 17 ++++++++++++++ src/popup/vault/groupings.component.ts | 19 ++++++++++++++-- src/popup/vault/view.component.html | 28 ++++++++++++++++++++---- src/popup/vault/view.component.ts | 25 +++++++++++++++++++++ 6 files changed, 116 insertions(+), 7 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 4bdb0c6edd..669bb879c1 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1257,5 +1257,30 @@ "lock": { "message": "Lock", "description": "Verb form: to make secure or inaccesible by" + }, + "trash": { + "message": "Trash", + "description": "Noun: a special folder to hold deleted items" + }, + "searchTrash": { + "message": "Search trash" + }, + "permanentlyDeleteItem": { + "message": "Permanently Delete Item" + }, + "permanentlyDeleteItemConfirmation": { + "message": "Are you sure you want to permanently delete this item?" + }, + "permanentlyDeletedItem": { + "message": "Permanently Deleted item" + }, + "restoreItem": { + "message": "Restore Item" + }, + "restoreItemConfirmation": { + "message": "Are you sure you want to restore this item?" + }, + "restoredItem": { + "message": "Restored Item" } } diff --git a/src/popup/vault/ciphers.component.ts b/src/popup/vault/ciphers.component.ts index b64ea9ba61..cdeb6fe90a 100644 --- a/src/popup/vault/ciphers.component.ts +++ b/src/popup/vault/ciphers.component.ts @@ -79,7 +79,11 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On } } - if (params.type) { + if (params.deleted) { + this.groupingTitle = this.i18nService.t('trash'); + this.searchPlaceholder = this.i18nService.t('searchTrash'); + await this.load(null, true); + } else if (params.type) { this.searchPlaceholder = this.i18nService.t('searchType'); this.type = parseInt(params.type, null); switch (this.type) { @@ -198,6 +202,9 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On } addCipher() { + if (this.deleted) { + return false; + } super.addCipher(); this.router.navigate(['/add-cipher'], { queryParams: { diff --git a/src/popup/vault/groupings.component.html b/src/popup/vault/groupings.component.html index 68ab75c880..d576d19e87 100644 --- a/src/popup/vault/groupings.component.html +++ b/src/popup/vault/groupings.component.html @@ -121,6 +121,23 @@ (onSelected)="selectCipher($event)" (onDoubleSelected)="launchCipher($event)"> +
+
+ {{'trash' | i18n}} + {{deletedCount}} +
+
+ +
+
+ {{'trash' | i18n}} +
+ {{deletedCount}} + +
+
+
diff --git a/src/popup/vault/groupings.component.ts b/src/popup/vault/groupings.component.ts index ba54e9c106..009695af95 100644 --- a/src/popup/vault/groupings.component.ts +++ b/src/popup/vault/groupings.component.ts @@ -57,6 +57,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit showLeftHeader = true; searchPending = false; searchTypeSearch = false; + deletedCount: number = 0; private loadedTimeout: number; private selectedTimeout: number; @@ -167,6 +168,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit if (!this.hasLoadedAllCiphers) { this.hasLoadedAllCiphers = !this.searchService.isSearchable(this.searchText); } + this.deletedCount = this.allCiphers.filter((c) => c.isDeleted).length; await this.search(null); let favoriteCiphers: CipherView[] = null; let noFolderCiphers: CipherView[] = null; @@ -175,6 +177,9 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit const typeCounts = new Map(); this.ciphers.forEach((c) => { + if (c.isDeleted) { + return; + } if (c.favorite) { if (favoriteCiphers == null) { favoriteCiphers = []; @@ -224,9 +229,10 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit if (this.searchTimeout != null) { clearTimeout(this.searchTimeout); } + const filterDeleted = (c: CipherView) => !c.isDeleted; if (timeout == null) { this.hasSearched = this.searchService.isSearchable(this.searchText); - this.ciphers = await this.searchService.searchCiphers(this.searchText, null, this.allCiphers); + this.ciphers = await this.searchService.searchCiphers(this.searchText, filterDeleted, this.allCiphers); return; } this.searchPending = true; @@ -235,7 +241,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit if (!this.hasLoadedAllCiphers && !this.hasSearched) { await this.loadCiphers(); } else { - this.ciphers = await this.searchService.searchCiphers(this.searchText, null, this.allCiphers); + this.ciphers = await this.searchService.searchCiphers(this.searchText, filterDeleted, this.allCiphers); } this.searchPending = false; }, timeout); @@ -256,6 +262,11 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit this.router.navigate(['/ciphers'], { queryParams: { collectionId: collection.id } }); } + async selectTrash() { + super.selectTrash(); + this.router.navigate(['/ciphers'], { queryParams: { deleted: true } }); + } + async selectCipher(cipher: CipherView) { this.selectedTimeout = window.setTimeout(() => { if (!this.preventSelected) { @@ -305,6 +316,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit typeCounts: this.typeCounts, folders: this.folders, collections: this.collections, + deletedCount: this.deletedCount, }; await this.stateService.save(ScopeStateId, this.scopeState); } @@ -339,6 +351,9 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit if (this.scopeState.collections != null) { this.collections = this.scopeState.collections; } + if (this.scopeState.deletedCiphers != null) { + this.deletedCount = this.scopeState.deletedCount; + } return true; } diff --git a/src/popup/vault/view.component.html b/src/popup/vault/view.component.html index c7b0779b52..6de6725658 100644 --- a/src/popup/vault/view.component.html +++ b/src/popup/vault/view.component.html @@ -6,7 +6,7 @@ {{'viewItem' | i18n}}
- +
@@ -259,8 +259,8 @@ -
-
+ - \ No newline at end of file + diff --git a/src/popup/vault/view.component.ts b/src/popup/vault/view.component.ts index 83e83dfe8a..f74ed34fe0 100644 --- a/src/popup/vault/view.component.ts +++ b/src/popup/vault/view.component.ts @@ -60,11 +60,17 @@ export class ViewComponent extends BaseViewComponent { } edit() { + if (this.cipher.isDeleted) { + return false; + } super.edit(); this.router.navigate(['/edit-cipher'], { queryParams: { cipherId: this.cipher.id } }); } clone() { + if (this.cipher.isDeleted) { + return false; + } super.clone(); this.router.navigate(['/clone-cipher'], { queryParams: { @@ -74,6 +80,25 @@ export class ViewComponent extends BaseViewComponent { }); } + async restore() { + if (!this.cipher.isDeleted) { + return false; + } + if (await super.restore()) { + this.close(); + return true; + } + return false; + } + + async delete() { + if (await super.delete()) { + this.close(); + return true; + } + return false; + } + close() { this.location.back(); } From a473dc958ede3f35e92be1a968a028eb7bb0fee7 Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 10:32:45 -0400 Subject: [PATCH 2/7] Lint errors --- .../browserPlatformUtils.service.spec.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/services/browserPlatformUtils.service.spec.ts b/src/services/browserPlatformUtils.service.spec.ts index 8a33f811d0..813c82f7e5 100644 --- a/src/services/browserPlatformUtils.service.spec.ts +++ b/src/services/browserPlatformUtils.service.spec.ts @@ -24,7 +24,8 @@ describe('Browser Utils Service', () => { it('should detect chrome', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome / 62.0.3202.94 Safari/ 537.36', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -34,7 +35,7 @@ describe('Browser Utils Service', () => { it('should detect firefox', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0' + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -44,12 +45,13 @@ describe('Browser Utils Service', () => { it('should detect opera', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3175.3 Safari/537.36 OPR/49.0.2695.0 (Edition developer)' + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome / 62.0.3175.3 Safari/ 537.36 OPR / 49.0.2695.0(Edition developer)', }); Object.defineProperty(window, 'opr', { configurable: true, - value: {} + value: {}, }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -59,7 +61,8 @@ describe('Browser Utils Service', () => { it('should detect edge', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063' + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 9) AppleWebKit/537.36 (KHTML, like Gecko)' + + 'Chrome / 52.0.2743.116 Safari/ 537.36 Edge / 15.15063', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -69,7 +72,8 @@ describe('Browser Utils Service', () => { it('should detect safari', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8' + value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) ' + + 'Version / 10.0.3 Safari / 602.4.8', }); Object.defineProperty(window, 'safariAppExtension', { @@ -89,7 +93,8 @@ describe('Browser Utils Service', () => { it('should detect vivaldi', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.97 Safari/537.36 Vivaldi/1.94.1008.40' + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome / 62.0.3202.97 Safari/ 537.36 Vivaldi / 1.94.1008.40', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); From 7a458ba356586d44d13539afe70fad148a829b4a Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 11:03:33 -0400 Subject: [PATCH 3/7] [Soft delete] - Update jslib submodule version ref --- jslib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jslib b/jslib index 72e3893f8e..e9db844285 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 72e3893f8eee79f1e3678839aa194f1096c343ea +Subproject commit e9db844285e21525f5152e782063f04e02543553 From 7f49ceead2df9d99bdc349cd34e865a9639cff24 Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 11:14:21 -0400 Subject: [PATCH 4/7] lint change revert, failed unit test fix --- src/services/browserPlatformUtils.service.spec.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/services/browserPlatformUtils.service.spec.ts b/src/services/browserPlatformUtils.service.spec.ts index 813c82f7e5..01cbbb219b 100644 --- a/src/services/browserPlatformUtils.service.spec.ts +++ b/src/services/browserPlatformUtils.service.spec.ts @@ -24,8 +24,7 @@ describe('Browser Utils Service', () => { it('should detect chrome', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + - 'Chrome / 62.0.3202.94 Safari/ 537.36', + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -45,8 +44,7 @@ describe('Browser Utils Service', () => { it('should detect opera', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + - 'Chrome / 62.0.3175.3 Safari/ 537.36 OPR / 49.0.2695.0(Edition developer)', + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3175.3 Safari/537.36 OPR/49.0.2695.0 (Edition developer)', }); Object.defineProperty(window, 'opr', { @@ -61,8 +59,7 @@ describe('Browser Utils Service', () => { it('should detect edge', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 9) AppleWebKit/537.36 (KHTML, like Gecko)' + - 'Chrome / 52.0.2743.116 Safari/ 537.36 Edge / 15.15063', + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); @@ -72,8 +69,7 @@ describe('Browser Utils Service', () => { it('should detect safari', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) ' + - 'Version / 10.0.3 Safari / 602.4.8', + value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8', }); Object.defineProperty(window, 'safariAppExtension', { @@ -93,8 +89,7 @@ describe('Browser Utils Service', () => { it('should detect vivaldi', () => { Object.defineProperty(navigator, 'userAgent', { configurable: true, - value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + - 'Chrome / 62.0.3202.97 Safari/ 537.36 Vivaldi / 1.94.1008.40', + value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.97 Safari/537.36 Vivaldi/1.94.1008.40', }); const browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null); From 2644afca935e13219fe9273c597b36a646fa4ba7 Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 11:32:56 -0400 Subject: [PATCH 5/7] [Soft delete] - remove uselss type definition --- src/popup/vault/groupings.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popup/vault/groupings.component.ts b/src/popup/vault/groupings.component.ts index 009695af95..ec4053beb2 100644 --- a/src/popup/vault/groupings.component.ts +++ b/src/popup/vault/groupings.component.ts @@ -57,7 +57,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit showLeftHeader = true; searchPending = false; searchTypeSearch = false; - deletedCount: number = 0; + deletedCount = 0; private loadedTimeout: number; private selectedTimeout: number; From 35235a9c3062b55b246d4972d3e0fab2412c3f58 Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Mon, 13 Apr 2020 11:56:37 -0400 Subject: [PATCH 6/7] [Soft delete] - fixed borders, spacing for buttons --- src/popup/vault/view.component.html | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/popup/vault/view.component.html b/src/popup/vault/view.component.html index 6de6725658..8b989c4c6a 100644 --- a/src/popup/vault/view.component.html +++ b/src/popup/vault/view.component.html @@ -260,8 +260,9 @@