From 8efb18d45b869968cd34b56ad3f9195b5697c118 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 13:49:25 -0600 Subject: [PATCH 01/16] move `add-edit-folder` component to `angular/vault/components` so it can be consumed by other platforms --- .../new-item-dropdown/new-item-dropdown-v2.component.ts | 2 +- .../src/vault/popup/settings/folders-v2.component.spec.ts | 8 ++++---- .../src/vault/popup/settings/folders-v2.component.ts | 8 ++++---- .../add-edit-folder-dialog.component.html | 0 .../add-edit-folder-dialog.component.spec.ts | 0 .../add-edit-folder-dialog.component.ts | 0 libs/angular/src/vault/components/index.ts | 1 + 7 files changed, 10 insertions(+), 9 deletions(-) rename {apps/browser/src/vault/popup/components/vault-v2 => libs/angular/src/vault/components}/add-edit-folder-dialog/add-edit-folder-dialog.component.html (100%) rename {apps/browser/src/vault/popup/components/vault-v2 => libs/angular/src/vault/components}/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts (100%) rename {apps/browser/src/vault/popup/components/vault-v2 => libs/angular/src/vault/components}/add-edit-folder-dialog/add-edit-folder-dialog.component.ts (100%) create mode 100644 libs/angular/src/vault/components/index.ts diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index f294bb57e8f..155fcfdfd93 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -5,6 +5,7 @@ import { Component, Input, OnInit } from "@angular/core"; import { RouterLink } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums"; @@ -13,7 +14,6 @@ import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitward import { BrowserApi } from "../../../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils"; import { AddEditQueryParams } from "../add-edit/add-edit-v2.component"; -import { AddEditFolderDialogComponent } from "../add-edit-folder-dialog/add-edit-folder-dialog.component"; export interface NewItemInitialValues { folderId?: string; diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts index eecad04613e..def732f5409 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts @@ -4,6 +4,7 @@ import { By } from "@angular/platform-browser"; import { mock } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; +import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -14,7 +15,6 @@ import { DialogService } from "@bitwarden/components"; import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; -import { AddEditFolderDialogComponent } from "../components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component"; import { FoldersV2Component } from "./folders-v2.component"; @@ -24,8 +24,8 @@ import { FoldersV2Component } from "./folders-v2.component"; template: ``, }) class MockPopupHeaderComponent { - @Input() pageTitle: string; - @Input() backAction: () => void; + @Input() pageTitle: string = ""; + @Input() backAction: () => void = () => {}; } @Component({ @@ -34,7 +34,7 @@ class MockPopupHeaderComponent { template: ``, }) class MockPopupFooterComponent { - @Input() pageTitle: string; + @Input() pageTitle: string = ""; } describe("FoldersV2Component", () => { diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.ts index ce196132f88..b288b5f1db2 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.ts @@ -3,6 +3,10 @@ import { Component } from "@angular/core"; import { map, Observable } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { + AddEditFolderDialogComponent, + AddEditFolderDialogData, +} from "@bitwarden/angular/vault/components"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { @@ -19,10 +23,6 @@ import { NoItemsModule } from "../../../../../../libs/components/src/no-items/no import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; -import { - AddEditFolderDialogComponent, - AddEditFolderDialogData, -} from "../components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component"; @Component({ standalone: true, diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.html b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html similarity index 100% rename from apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.html rename to libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts similarity index 100% rename from apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts rename to libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts similarity index 100% rename from apps/browser/src/vault/popup/components/vault-v2/add-edit-folder-dialog/add-edit-folder-dialog.component.ts rename to libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts diff --git a/libs/angular/src/vault/components/index.ts b/libs/angular/src/vault/components/index.ts new file mode 100644 index 00000000000..3afdb79576f --- /dev/null +++ b/libs/angular/src/vault/components/index.ts @@ -0,0 +1 @@ +export * from "./add-edit-folder-dialog/add-edit-folder-dialog.component"; From 91a0fbf9948fb196883bb9a2bbdeebd3ef973098 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 13:57:52 -0600 Subject: [PATCH 02/16] add edit/add folder copy to web app copy --- apps/web/src/locales/en/messages.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index acbb348048c..dc95da26077 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -425,6 +425,15 @@ "editFolder": { "message": "Edit folder" }, + "newFolder": { + "message": "New folder" + }, + "folderName": { + "message": "Folder name" + }, + "folderHintText": { + "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" + }, "baseDomain": { "message": "Base domain", "description": "Domain name. Example: website.com" From 57d85d8410ac51bc70e4c1c29f1b1cefeb98626e Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 13:58:23 -0600 Subject: [PATCH 03/16] add extension refresh folder dialog to individual vault --- apps/web/src/app/vault/individual-vault/vault.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 18a1d8b338a..fe3e6039999 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -42,6 +42,7 @@ import { } from "@bitwarden/admin-console/common"; import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ModalService } from "@bitwarden/angular/services/modal.service"; +import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; @@ -569,8 +570,8 @@ export class VaultComponent implements OnInit, OnDestroy { await this.filterComponent.filters?.organizationFilter?.action(orgNode); } - addFolder = async (): Promise => { - openFolderAddEditDialog(this.dialogService); + addFolder = (): void => { + this.dialogService.open(AddEditFolderDialogComponent); }; editFolder = async (folder: FolderFilter): Promise => { From b4ed747697597e215db46e728b4bd13f2f5eb9ab Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:06:01 -0600 Subject: [PATCH 04/16] adding folder delete message to the web --- apps/web/src/locales/en/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index dc95da26077..3ce250aff25 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -434,6 +434,9 @@ "folderHintText": { "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" }, + "deleteFolderPermanently": { + "message": "Are you sure you want to permanently delete this folder?" + }, "baseDomain": { "message": "Base domain", "description": "Domain name. Example: website.com" From 30024feb99568249538c6253d6de21c1f662f384 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:07:18 -0600 Subject: [PATCH 05/16] add deletion result for add/edit folder dialog --- .../add-edit-folder-dialog.component.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts index 5fbd54d9d78..62835bae76d 100644 --- a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts +++ b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts @@ -35,6 +35,10 @@ import { } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; +export enum AddEditFolderDialogResult { + Deleted = "deleted", +} + export type AddEditFolderDialogData = { /** When provided, dialog will display edit folder variant */ editFolderConfig?: { folder: FolderView }; @@ -79,7 +83,7 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { private i18nService: I18nService, private logService: LogService, private dialogService: DialogService, - private dialogRef: DialogRef, + private dialogRef: DialogRef, @Inject(DIALOG_DATA) private data?: AddEditFolderDialogData, ) {} @@ -154,11 +158,11 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { this.logService.error(e); } - this.close(); + this.close(AddEditFolderDialogResult.Deleted); }; /** Close the dialog */ - private close() { - this.dialogRef.close(); + private close(result?: AddEditFolderDialogResult) { + this.dialogRef.close(result); } } From 9c89ccd13168b4242dba8f360655cb636d0b4b83 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:07:46 -0600 Subject: [PATCH 06/16] allow editing folder from web --- .../vault/individual-vault/vault.component.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index fe3e6039999..79247b4e7ac 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -42,7 +42,11 @@ import { } from "@bitwarden/admin-console/common"; import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; +import { + AddEditFolderDialogComponent, + AddEditFolderDialogData, + AddEditFolderDialogResult, +} from "@bitwarden/angular/vault/components"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; @@ -114,7 +118,6 @@ import { BulkMoveDialogResult, openBulkMoveDialog, } from "./bulk-action-dialogs/bulk-move-dialog/bulk-move-dialog.component"; -import { FolderAddEditDialogResult, openFolderAddEditDialog } from "./folder-add-edit.component"; import { VaultBannersComponent } from "./vault-banners/vault-banners.component"; import { VaultFilterComponent } from "./vault-filter/components/vault-filter.component"; import { VaultFilterService } from "./vault-filter/services/abstractions/vault-filter.service"; @@ -575,15 +578,16 @@ export class VaultComponent implements OnInit, OnDestroy { }; editFolder = async (folder: FolderFilter): Promise => { - const dialog = openFolderAddEditDialog(this.dialogService, { - data: { - folderId: folder.id, + const dialogRef = this.dialogService.open( + AddEditFolderDialogComponent, + { + data: { editFolderConfig: { folder } }, }, - }); + ); - const result = await lastValueFrom(dialog.closed); + const result = await lastValueFrom(dialogRef.closed); - if (result === FolderAddEditDialogResult.Deleted) { + if (result === AddEditFolderDialogResult.Deleted) { await this.router.navigate([], { queryParams: { folderId: null }, queryParamsHandling: "merge", From 14e9c25d229ca2e341de21aac56c0b0be3c39186 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:13:47 -0600 Subject: [PATCH 07/16] fix strict types for changed files --- .../new-item-dropdown-v2.component.ts | 9 +++---- .../add-edit-folder-dialog.component.spec.ts | 2 +- .../add-edit-folder-dialog.component.ts | 25 ++++++++----------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index 155fcfdfd93..c6f224703e1 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; import { RouterLink } from "@angular/router"; @@ -29,12 +27,11 @@ export interface NewItemInitialValues { }) export class NewItemDropdownV2Component implements OnInit { cipherType = CipherType; - private tab?: chrome.tabs.Tab; + private tab: chrome.tabs.Tab | null = null; /** * Optional initial values to pass to the add cipher form */ - @Input() - initialValues: NewItemInitialValues; + @Input() initialValues?: NewItemInitialValues; constructor(private dialogService: DialogService) {} @@ -49,7 +46,7 @@ export class NewItemDropdownV2Component implements OnInit { // When a Login Cipher is created and the extension is not popped out, // pass along the uri and name - if (!poppedOut && type === CipherType.Login && this.tab) { + if (!poppedOut && type === CipherType.Login && this.tab?.url) { loginDetails.uri = this.tab.url; loginDetails.name = Utils.getHostname(this.tab.url); } diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts index 4e222a554f7..8cd103c6b96 100644 --- a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts +++ b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts @@ -161,7 +161,7 @@ describe("AddEditFolderDialogComponent", () => { expect(encrypt).toHaveBeenCalledWith( { - ...dialogData.editFolderConfig.folder, + ...dialogData.editFolderConfig!.folder, name: "Edited Folder", }, "", diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts index 62835bae76d..b257b7cba9c 100644 --- a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts +++ b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog"; import { CommonModule } from "@angular/common"; import { @@ -60,12 +58,12 @@ export type AddEditFolderDialogData = { ], }) export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { - @ViewChild(BitSubmitDirective) private bitSubmit: BitSubmitDirective; - @ViewChild("submitBtn") private submitBtn: ButtonComponent; + @ViewChild(BitSubmitDirective) private bitSubmit?: BitSubmitDirective; + @ViewChild("submitBtn") private submitBtn?: ButtonComponent; - folder: FolderView; + folder: FolderView = new FolderView(); - variant: "add" | "edit"; + variant: "add" | "edit" = "add"; folderForm = this.formBuilder.group({ name: ["", Validators.required], @@ -88,9 +86,8 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { ) {} ngOnInit(): void { - this.variant = this.data?.editFolderConfig ? "edit" : "add"; - - if (this.variant === "edit") { + if (this.data?.editFolderConfig) { + this.variant = "edit"; this.folderForm.controls.name.setValue(this.data.editFolderConfig.folder.name); this.folder = this.data.editFolderConfig.folder; } else { @@ -100,7 +97,7 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { } ngAfterViewInit(): void { - this.bitSubmit.loading$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((loading) => { + this.bitSubmit?.loading$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((loading) => { if (!this.submitBtn) { return; } @@ -115,17 +112,17 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { return; } - this.folder.name = this.folderForm.controls.name.value; + this.folder.name = this.folderForm.controls.name.value ?? ""; try { const activeUserId = await firstValueFrom(this.accountService.activeAccount$); - const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId.id); + const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId!.id); const folder = await this.folderService.encrypt(this.folder, userKey); await this.folderApiService.save(folder); this.toastService.showToast({ variant: "success", - title: null, + title: "", message: this.i18nService.t("editedFolder"), }); @@ -151,7 +148,7 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { await this.folderApiService.delete(this.folder.id); this.toastService.showToast({ variant: "success", - title: null, + title: "", message: this.i18nService.t("deletedFolder"), }); } catch (e) { From 2a840a1b9cb1ff11306c3499e992178e97ae963f Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:21:56 -0600 Subject: [PATCH 08/16] update tests --- .../add-edit-folder-dialog.component.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts index 8cd103c6b96..74b80aa2702 100644 --- a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts +++ b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts @@ -17,6 +17,7 @@ import { KeyService } from "@bitwarden/key-management"; import { AddEditFolderDialogComponent, AddEditFolderDialogData, + AddEditFolderDialogResult, } from "./add-edit-folder-dialog.component"; describe("AddEditFolderDialogComponent", () => { @@ -115,7 +116,7 @@ describe("AddEditFolderDialogComponent", () => { expect(showToast).toHaveBeenCalledWith({ message: "editedFolder", - title: null, + title: "", variant: "success", }); }); @@ -174,9 +175,10 @@ describe("AddEditFolderDialogComponent", () => { expect(deleteFolder).toHaveBeenCalledWith(folderView.id); expect(showToast).toHaveBeenCalledWith({ variant: "success", - title: null, + title: "", message: "deletedFolder", }); + expect(close).toHaveBeenCalledWith(AddEditFolderDialogResult.Deleted); }); }); }); From e41a15ed6f295ab0eded53952e88962049ce7a0c Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:22:12 -0600 Subject: [PATCH 09/16] remove border class so hover state shows --- .../add-edit-folder-dialog.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html index 0e6dbf24427..4869714332c 100644 --- a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html +++ b/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html @@ -31,7 +31,7 @@ *ngIf="variant === 'edit'" type="button" buttonType="danger" - class="tw-border-0 tw-ml-auto" + class="tw-ml-auto" bitIconButton="bwi-trash" [appA11yTitle]="'deleteFolder' | i18n" [bitAction]="deleteFolder" From 2d7b2cc322306d2f590e3357ee61b0873936f15d Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Thu, 19 Dec 2024 14:30:24 -0600 Subject: [PATCH 10/16] revert changes to new-item-dropdown-v2 --- .../new-item-dropdown/new-item-dropdown-v2.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index c6f224703e1..155fcfdfd93 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -1,3 +1,5 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; import { RouterLink } from "@angular/router"; @@ -27,11 +29,12 @@ export interface NewItemInitialValues { }) export class NewItemDropdownV2Component implements OnInit { cipherType = CipherType; - private tab: chrome.tabs.Tab | null = null; + private tab?: chrome.tabs.Tab; /** * Optional initial values to pass to the add cipher form */ - @Input() initialValues?: NewItemInitialValues; + @Input() + initialValues: NewItemInitialValues; constructor(private dialogService: DialogService) {} @@ -46,7 +49,7 @@ export class NewItemDropdownV2Component implements OnInit { // When a Login Cipher is created and the extension is not popped out, // pass along the uri and name - if (!poppedOut && type === CipherType.Login && this.tab?.url) { + if (!poppedOut && type === CipherType.Login && this.tab) { loginDetails.uri = this.tab.url; loginDetails.name = Utils.getHostname(this.tab.url); } From 54ae50e52f7e05aeadf0959871d669f8a7a7fadc Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 20 Dec 2024 09:42:03 -0600 Subject: [PATCH 11/16] migrate `AddEditFolderDialogComponent` to `libs/vault` package --- .../new-item-dropdown-v2.component.ts | 2 +- .../vault/popup/settings/folders-v2.component.spec.ts | 2 +- .../src/vault/popup/settings/folders-v2.component.ts | 10 +++++----- .../src/app/vault/individual-vault/vault.component.ts | 8 +++----- libs/angular/src/vault/components/index.ts | 1 - .../add-edit-folder-dialog.component.html | 0 .../add-edit-folder-dialog.component.spec.ts | 0 .../add-edit-folder-dialog.component.ts | 0 libs/vault/src/index.ts | 1 + 9 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 libs/angular/src/vault/components/index.ts rename libs/{angular/src/vault => vault/src}/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html (100%) rename libs/{angular/src/vault => vault/src}/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts (100%) rename libs/{angular/src/vault => vault/src}/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts (100%) diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index 155fcfdfd93..0fb5c0e6a21 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -5,11 +5,11 @@ import { Component, Input, OnInit } from "@angular/core"; import { RouterLink } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums"; import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components"; +import { AddEditFolderDialogComponent } from "@bitwarden/vault"; import { BrowserApi } from "../../../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils"; diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts index def732f5409..0d1a1740236 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts @@ -4,7 +4,6 @@ import { By } from "@angular/platform-browser"; import { mock } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { AddEditFolderDialogComponent } from "@bitwarden/angular/vault/components"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -12,6 +11,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DialogService } from "@bitwarden/components"; +import { AddEditFolderDialogComponent } from "@bitwarden/vault"; import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.ts index b288b5f1db2..a2d5de8fbc8 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.ts @@ -3,10 +3,6 @@ import { Component } from "@angular/core"; import { map, Observable } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { - AddEditFolderDialogComponent, - AddEditFolderDialogData, -} from "@bitwarden/angular/vault/components"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { @@ -15,7 +11,11 @@ import { DialogService, IconButtonModule, } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; +import { + AddEditFolderDialogComponent, + AddEditFolderDialogData, + VaultIcons, +} from "@bitwarden/vault"; import { ItemGroupComponent } from "../../../../../../libs/components/src/item/item-group.component"; import { ItemModule } from "../../../../../../libs/components/src/item/item.module"; diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 79247b4e7ac..fc56d02c732 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -42,11 +42,6 @@ import { } from "@bitwarden/admin-console/common"; import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { - AddEditFolderDialogComponent, - AddEditFolderDialogData, - AddEditFolderDialogResult, -} from "@bitwarden/angular/vault/components"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; @@ -78,6 +73,9 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { ServiceUtils } from "@bitwarden/common/vault/service-utils"; import { DialogService, Icons, ToastService } from "@bitwarden/components"; import { + AddEditFolderDialogComponent, + AddEditFolderDialogData, + AddEditFolderDialogResult, CipherFormConfig, CollectionAssignmentResult, DefaultCipherFormConfigService, diff --git a/libs/angular/src/vault/components/index.ts b/libs/angular/src/vault/components/index.ts deleted file mode 100644 index 3afdb79576f..00000000000 --- a/libs/angular/src/vault/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./add-edit-folder-dialog/add-edit-folder-dialog.component"; diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html similarity index 100% rename from libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html rename to libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.html diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts similarity index 100% rename from libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts rename to libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts diff --git a/libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts similarity index 100% rename from libs/angular/src/vault/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts rename to libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts diff --git a/libs/vault/src/index.ts b/libs/vault/src/index.ts index 0112de44241..452768c7b6f 100644 --- a/libs/vault/src/index.ts +++ b/libs/vault/src/index.ts @@ -16,5 +16,6 @@ export { DownloadAttachmentComponent } from "./components/download-attachment/do export { PasswordHistoryViewComponent } from "./components/password-history-view/password-history-view.component"; export { NewDeviceVerificationNoticePageOneComponent } from "./components/new-device-verification-notice/new-device-verification-notice-page-one.component"; export { NewDeviceVerificationNoticePageTwoComponent } from "./components/new-device-verification-notice/new-device-verification-notice-page-two.component"; +export * from "./components/add-edit-folder-dialog/add-edit-folder-dialog.component"; export * as VaultIcons from "./icons"; From b20827e52e3b0cdc966c49d83cabb4d54f0b0c96 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 20 Dec 2024 09:45:06 -0600 Subject: [PATCH 12/16] add Created enum type --- .../add-edit-folder-dialog.component.spec.ts | 2 +- .../add-edit-folder-dialog.component.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts index 74b80aa2702..3d2fd38b975 100644 --- a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts +++ b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts @@ -126,7 +126,7 @@ describe("AddEditFolderDialogComponent", () => { await component.submit(); - expect(close).toHaveBeenCalled(); + expect(close).toHaveBeenCalledWith(AddEditFolderDialogResult.Created); }); it("logs error if saving fails", async () => { diff --git a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts index b257b7cba9c..79e6a575e9b 100644 --- a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts +++ b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts @@ -34,6 +34,7 @@ import { import { KeyService } from "@bitwarden/key-management"; export enum AddEditFolderDialogResult { + Created = "created", Deleted = "deleted", } @@ -126,7 +127,7 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { message: this.i18nService.t("editedFolder"), }); - this.close(); + this.close(AddEditFolderDialogResult.Created); } catch (e) { this.logService.error(e); } @@ -159,7 +160,7 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { }; /** Close the dialog */ - private close(result?: AddEditFolderDialogResult) { + private close(result: AddEditFolderDialogResult) { this.dialogRef.close(result); } } From 1b442f691c2aea986e371f17b71862f332f13346 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 20 Dec 2024 09:56:52 -0600 Subject: [PATCH 13/16] add static open method for folder dialog --- .../new-item-dropdown-v2.component.ts | 2 +- .../popup/settings/folders-v2.component.spec.ts | 11 +++++------ .../src/vault/popup/settings/folders-v2.component.ts | 10 ++-------- .../app/vault/individual-vault/vault.component.ts | 12 ++++-------- .../add-edit-folder-dialog.component.ts | 7 +++++++ 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts index 0fb5c0e6a21..d6c341082ee 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/new-item-dropdown/new-item-dropdown-v2.component.ts @@ -64,6 +64,6 @@ export class NewItemDropdownV2Component implements OnInit { } openFolderDialog() { - this.dialogService.open(AddEditFolderDialogComponent); + AddEditFolderDialogComponent.open(this.dialogService); } } diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts index 0d1a1740236..41bbfe3265c 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.spec.ts @@ -41,7 +41,8 @@ describe("FoldersV2Component", () => { let component: FoldersV2Component; let fixture: ComponentFixture; const folderViews$ = new BehaviorSubject([]); - const open = jest.fn(); + const open = jest.spyOn(AddEditFolderDialogComponent, "open"); + const mockDialogService = { open: jest.fn() }; beforeEach(async () => { open.mockClear(); @@ -64,7 +65,7 @@ describe("FoldersV2Component", () => { imports: [MockPopupHeaderComponent, MockPopupFooterComponent], }, }) - .overrideProvider(DialogService, { useValue: { open } }) + .overrideProvider(DialogService, { useValue: mockDialogService }) .compileComponents(); fixture = TestBed.createComponent(FoldersV2Component); @@ -97,9 +98,7 @@ describe("FoldersV2Component", () => { editButton.triggerEventHandler("click"); - expect(open).toHaveBeenCalledWith(AddEditFolderDialogComponent, { - data: { editFolderConfig: { folder } }, - }); + expect(open).toHaveBeenCalledWith(mockDialogService, { editFolderConfig: { folder } }); }); it("opens add dialog for new folder when there are no folders", () => { @@ -110,6 +109,6 @@ describe("FoldersV2Component", () => { addButton.triggerEventHandler("click"); - expect(open).toHaveBeenCalledWith(AddEditFolderDialogComponent, { data: {} }); + expect(open).toHaveBeenCalledWith(mockDialogService, {}); }); }); diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.ts index a2d5de8fbc8..5e899fa171b 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.ts @@ -11,11 +11,7 @@ import { DialogService, IconButtonModule, } from "@bitwarden/components"; -import { - AddEditFolderDialogComponent, - AddEditFolderDialogData, - VaultIcons, -} from "@bitwarden/vault"; +import { AddEditFolderDialogComponent, VaultIcons } from "@bitwarden/vault"; import { ItemGroupComponent } from "../../../../../../libs/components/src/item/item-group.component"; import { ItemModule } from "../../../../../../libs/components/src/item/item.module"; @@ -67,8 +63,6 @@ export class FoldersV2Component { // If a folder is provided, the edit variant should be shown const editFolderConfig = folder ? { folder } : undefined; - this.dialogService.open(AddEditFolderDialogComponent, { - data: { editFolderConfig }, - }); + AddEditFolderDialogComponent.open(this.dialogService, { editFolderConfig }); } } diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index fc56d02c732..d600c204247 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -74,7 +74,6 @@ import { ServiceUtils } from "@bitwarden/common/vault/service-utils"; import { DialogService, Icons, ToastService } from "@bitwarden/components"; import { AddEditFolderDialogComponent, - AddEditFolderDialogData, AddEditFolderDialogResult, CipherFormConfig, CollectionAssignmentResult, @@ -572,16 +571,13 @@ export class VaultComponent implements OnInit, OnDestroy { } addFolder = (): void => { - this.dialogService.open(AddEditFolderDialogComponent); + AddEditFolderDialogComponent.open(this.dialogService); }; editFolder = async (folder: FolderFilter): Promise => { - const dialogRef = this.dialogService.open( - AddEditFolderDialogComponent, - { - data: { editFolderConfig: { folder } }, - }, - ); + const dialogRef = AddEditFolderDialogComponent.open(this.dialogService, { + editFolderConfig: { folder }, + }); const result = await lastValueFrom(dialogRef.closed); diff --git a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts index 79e6a575e9b..dc06bc02484 100644 --- a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts +++ b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.ts @@ -163,4 +163,11 @@ export class AddEditFolderDialogComponent implements AfterViewInit, OnInit { private close(result: AddEditFolderDialogResult) { this.dialogRef.close(result); } + + static open(dialogService: DialogService, data?: AddEditFolderDialogData) { + return dialogService.open( + AddEditFolderDialogComponent, + { data }, + ); + } } From 706c3882ca6cf6585e8e2d0fcc86cc48ab3342b4 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 10 Jan 2025 12:54:18 -0600 Subject: [PATCH 14/16] add fullName to `FolderFilter` type --- .../vault-filter/shared/models/vault-filter.type.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts index 0cd385bd19d..ea4bf748a42 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts @@ -10,5 +10,13 @@ export type CipherTypeFilter = ITreeNodeObject & { type: CipherStatus; icon: str export type CollectionFilter = CollectionAdminView & { icon: string; }; -export type FolderFilter = FolderView & { icon: string }; +export type FolderFilter = FolderView & { + icon: string; + /** + * Full folder name. + * + * Used for when the folder `name` property is be separated into parts. + */ + fullName?: string; +}; export type OrganizationFilter = Organization & { icon: string; hideOptions?: boolean }; From b16fe41ffdc48677687815b097213002e4ccda84 Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 10 Jan 2025 12:55:29 -0600 Subject: [PATCH 15/16] save the full name of a folder before splitting it into parts --- .../vault-filter/services/vault-filter.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts index 97b44132e60..d97067038f4 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts @@ -270,6 +270,7 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { folderCopy.id = f.id; folderCopy.revisionDate = f.revisionDate; folderCopy.icon = "bwi-folder"; + folderCopy.fullName = f.name; // save full folder name before separating it into parts const parts = f.name != null ? f.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, null, NestingDelimiter); }); From 70bd316ab8ddca18276a0d37f96643943e00ddac Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Fri, 10 Jan 2025 12:56:08 -0600 Subject: [PATCH 16/16] use the full name of the folder filter when available --- apps/web/src/app/vault/individual-vault/vault.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index a406dadaa8f..8cb42b884d6 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -607,6 +607,11 @@ export class VaultComponent implements OnInit, OnDestroy { }; editFolder = async (folder: FolderFilter): Promise => { + // If the filter has a fullName populated + if (folder.fullName) { + folder.name = folder.fullName; + } + const dialogRef = AddEditFolderDialogComponent.open(this.dialogService, { editFolderConfig: { folder }, });