mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 05:13:29 +00:00
remove unused view component (#16582)
This commit is contained in:
@@ -2,7 +2,6 @@ import { NgModule } from "@angular/core";
|
||||
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
import { OrganizationBadgeModule } from "../../../vault/individual-vault/organization-badge/organization-badge.module";
|
||||
import { ViewComponent } from "../../../vault/individual-vault/view.component";
|
||||
import { CollectionDialogComponent } from "../shared/components/collection-dialog";
|
||||
|
||||
import { CollectionNameBadgeComponent } from "./collection-badge";
|
||||
@@ -19,7 +18,6 @@ import { VaultComponent } from "./vault.component";
|
||||
OrganizationBadgeModule,
|
||||
CollectionDialogComponent,
|
||||
VaultComponent,
|
||||
ViewComponent,
|
||||
],
|
||||
})
|
||||
export class VaultModule {}
|
||||
|
||||
@@ -10,7 +10,6 @@ import { OrganizationBadgeModule } from "./organization-badge/organization-badge
|
||||
import { PipesModule } from "./pipes/pipes.module";
|
||||
import { VaultRoutingModule } from "./vault-routing.module";
|
||||
import { VaultComponent } from "./vault.component";
|
||||
import { ViewComponent } from "./view.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -23,7 +22,6 @@ import { ViewComponent } from "./view.component";
|
||||
BulkDialogsModule,
|
||||
CollectionDialogComponent,
|
||||
VaultComponent,
|
||||
ViewComponent,
|
||||
],
|
||||
})
|
||||
export class VaultModule {}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<bit-dialog dialogSize="large" background="alt">
|
||||
<span bitDialogTitle>
|
||||
{{ cipherTypeString }}
|
||||
</span>
|
||||
<ng-container bitDialogContent>
|
||||
<app-cipher-view [cipher]="cipher" [collections]="collections"></app-cipher-view>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button
|
||||
bitButton
|
||||
(click)="edit()"
|
||||
buttonType="primary"
|
||||
type="button"
|
||||
[disabled]="params.disableEdit"
|
||||
>
|
||||
{{ "edit" | i18n }}
|
||||
</button>
|
||||
<div class="tw-ml-auto">
|
||||
<button
|
||||
bitButton
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
[appA11yTitle]="'delete' | i18n"
|
||||
[bitAction]="delete"
|
||||
[disabled]="!(canDeleteCipher$ | async)"
|
||||
>
|
||||
<i class="bwi bwi-trash bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
@@ -1,148 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
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";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||
import { TaskService } from "@bitwarden/common/vault/tasks";
|
||||
import { DIALOG_DATA, DialogRef, DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { ChangeLoginPasswordService } from "@bitwarden/vault";
|
||||
|
||||
import { ViewCipherDialogParams, ViewCipherDialogResult, ViewComponent } from "./view.component";
|
||||
|
||||
describe("ViewComponent", () => {
|
||||
let component: ViewComponent;
|
||||
let fixture: ComponentFixture<ViewComponent>;
|
||||
|
||||
const mockCipher: CipherView = {
|
||||
id: "cipher-id",
|
||||
type: 1,
|
||||
organizationId: "org-id",
|
||||
isDeleted: false,
|
||||
} as CipherView;
|
||||
|
||||
const mockOrganization: Organization = {
|
||||
id: "org-id",
|
||||
name: "Test Organization",
|
||||
} as Organization;
|
||||
|
||||
const mockParams: ViewCipherDialogParams = {
|
||||
cipher: mockCipher,
|
||||
};
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ViewComponent],
|
||||
providers: [
|
||||
{ provide: DIALOG_DATA, useValue: mockParams },
|
||||
{ provide: DialogRef, useValue: mock<DialogRef>() },
|
||||
{ provide: I18nService, useValue: { t: jest.fn().mockReturnValue("login") } },
|
||||
{ provide: DialogService, useValue: mock<DialogService>() },
|
||||
{ provide: CipherService, useValue: mock<CipherService>() },
|
||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||
{ provide: MessagingService, useValue: mock<MessagingService>() },
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{ provide: LogService, useValue: mock<LogService>() },
|
||||
{
|
||||
provide: OrganizationService,
|
||||
useValue: { organizations$: jest.fn().mockReturnValue(of([mockOrganization])) },
|
||||
},
|
||||
{ provide: CollectionService, useValue: mock<CollectionService>() },
|
||||
{ provide: FolderService, useValue: mock<FolderService>() },
|
||||
{ provide: KeyService, useValue: mock<KeyService>() },
|
||||
{
|
||||
provide: BillingAccountProfileStateService,
|
||||
useValue: mock<BillingAccountProfileStateService>(),
|
||||
},
|
||||
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
||||
{ provide: AccountService, useValue: mockAccountServiceWith("UserId" as UserId) },
|
||||
{
|
||||
provide: CipherAuthorizationService,
|
||||
useValue: {
|
||||
canDeleteCipher$: jest.fn().mockReturnValue(true),
|
||||
},
|
||||
},
|
||||
{ provide: TaskService, useValue: mock<TaskService>() },
|
||||
],
|
||||
})
|
||||
.overrideComponent(ViewComponent, {
|
||||
remove: {
|
||||
providers: [
|
||||
{ provide: PlatformUtilsService, useValue: PlatformUtilsService },
|
||||
{
|
||||
provide: ChangeLoginPasswordService,
|
||||
useValue: ChangeLoginPasswordService,
|
||||
},
|
||||
],
|
||||
},
|
||||
add: {
|
||||
providers: [
|
||||
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||
{
|
||||
provide: ChangeLoginPasswordService,
|
||||
useValue: mock<ChangeLoginPasswordService>(),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ViewComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.params = mockParams;
|
||||
component.cipher = mockCipher;
|
||||
});
|
||||
|
||||
describe("ngOnInit", () => {
|
||||
it("initializes the component with cipher and organization", async () => {
|
||||
await component.ngOnInit();
|
||||
|
||||
expect(component.cipher).toEqual(mockCipher);
|
||||
expect(component.organization).toEqual(mockOrganization);
|
||||
});
|
||||
});
|
||||
|
||||
describe("edit", () => {
|
||||
it("closes the dialog with the proper arguments", async () => {
|
||||
const dialogRefCloseSpy = jest.spyOn(component["dialogRef"], "close");
|
||||
|
||||
await component.edit();
|
||||
|
||||
expect(dialogRefCloseSpy).toHaveBeenCalledWith({ action: ViewCipherDialogResult.Edited });
|
||||
});
|
||||
});
|
||||
|
||||
describe("delete", () => {
|
||||
it("calls the delete method on delete and closes the dialog with the proper arguments", async () => {
|
||||
const deleteSpy = jest.spyOn(component, "delete");
|
||||
const dialogRefCloseSpy = jest.spyOn(component["dialogRef"], "close");
|
||||
jest.spyOn(component["dialogService"], "openSimpleDialog").mockResolvedValue(true);
|
||||
|
||||
await component.delete();
|
||||
|
||||
expect(deleteSpy).toHaveBeenCalled();
|
||||
expect(dialogRefCloseSpy).toHaveBeenCalledWith({ action: ViewCipherDialogResult.Deleted });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,218 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, EventEmitter, Inject, OnInit } from "@angular/core";
|
||||
import { firstValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { VaultViewPasswordHistoryService } from "@bitwarden/angular/services/view-password-history.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CollectionId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||
import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
|
||||
import {
|
||||
DIALOG_DATA,
|
||||
DialogRef,
|
||||
DialogConfig,
|
||||
AsyncActionsModule,
|
||||
DialogModule,
|
||||
DialogService,
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
import { CipherViewComponent } from "@bitwarden/vault";
|
||||
|
||||
import { SharedModule } from "../../shared/shared.module";
|
||||
|
||||
export interface ViewCipherDialogParams {
|
||||
cipher: CipherView;
|
||||
|
||||
/**
|
||||
* Optional list of collections the cipher is assigned to. If none are provided, they will be loaded using the
|
||||
* `CipherService` and the `collectionIds` property of the cipher.
|
||||
*/
|
||||
collections?: CollectionView[];
|
||||
|
||||
/**
|
||||
* Optional collection ID used to know the collection filter selected.
|
||||
*/
|
||||
activeCollectionId?: CollectionId;
|
||||
|
||||
/**
|
||||
* If true, the edit button will be disabled in the dialog.
|
||||
*/
|
||||
disableEdit?: boolean;
|
||||
}
|
||||
|
||||
export const ViewCipherDialogResult = {
|
||||
Edited: "edited",
|
||||
Deleted: "deleted",
|
||||
PremiumUpgrade: "premiumUpgrade",
|
||||
} as const;
|
||||
|
||||
type ViewCipherDialogResult = UnionOfValues<typeof ViewCipherDialogResult>;
|
||||
|
||||
export interface ViewCipherDialogCloseResult {
|
||||
action: ViewCipherDialogResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component for viewing a cipher, presented in a dialog.
|
||||
* @deprecated Use the VaultItemDialogComponent instead.
|
||||
*/
|
||||
@Component({
|
||||
selector: "app-vault-view",
|
||||
templateUrl: "view.component.html",
|
||||
imports: [CipherViewComponent, CommonModule, AsyncActionsModule, DialogModule, SharedModule],
|
||||
providers: [{ provide: ViewPasswordHistoryService, useClass: VaultViewPasswordHistoryService }],
|
||||
})
|
||||
export class ViewComponent implements OnInit {
|
||||
cipher: CipherView;
|
||||
collections?: CollectionView[];
|
||||
onDeletedCipher = new EventEmitter<CipherView>();
|
||||
cipherTypeString: string;
|
||||
organization: Organization;
|
||||
|
||||
canDeleteCipher$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) public params: ViewCipherDialogParams,
|
||||
private dialogRef: DialogRef<ViewCipherDialogCloseResult>,
|
||||
private i18nService: I18nService,
|
||||
private dialogService: DialogService,
|
||||
private messagingService: MessagingService,
|
||||
private logService: LogService,
|
||||
private cipherService: CipherService,
|
||||
private toastService: ToastService,
|
||||
private organizationService: OrganizationService,
|
||||
private cipherAuthorizationService: CipherAuthorizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Lifecycle hook for component initialization.
|
||||
*/
|
||||
async ngOnInit() {
|
||||
this.cipher = this.params.cipher;
|
||||
this.collections = this.params.collections;
|
||||
this.cipherTypeString = this.getCipherViewTypeString();
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (this.cipher.organizationId) {
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) => organizations.find((o) => o.id === this.cipher.organizationId)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(this.cipher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle cipher deletion. Called when a user clicks the delete button.
|
||||
*/
|
||||
delete = async () => {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "deleteItem" },
|
||||
content: {
|
||||
key: this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation",
|
||||
},
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.deleteCipher();
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: this.i18nService.t("success"),
|
||||
message: this.i18nService.t(
|
||||
this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem",
|
||||
),
|
||||
});
|
||||
this.onDeletedCipher.emit(this.cipher);
|
||||
this.messagingService.send(
|
||||
this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher",
|
||||
);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
this.dialogRef.close({ action: ViewCipherDialogResult.Deleted });
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method to delete cipher.
|
||||
*/
|
||||
protected async deleteCipher(): Promise<void> {
|
||||
const asAdmin = this.organization?.canEditAllCiphers;
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (this.cipher.isDeleted) {
|
||||
await this.cipherService.deleteWithServer(this.cipher.id, userId, asAdmin);
|
||||
} else {
|
||||
await this.cipherService.softDeleteWithServer(this.cipher.id, userId, asAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle cipher editing. Called when a user clicks the edit button.
|
||||
*/
|
||||
async edit(): Promise<void> {
|
||||
this.dialogRef.close({ action: ViewCipherDialogResult.Edited });
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get cipher view type string, used for the dialog title.
|
||||
* E.g. "View login" or "View note".
|
||||
* @returns The localized string for the cipher type
|
||||
*/
|
||||
getCipherViewTypeString(): string {
|
||||
if (!this.cipher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (this.cipher.type) {
|
||||
case CipherType.Login:
|
||||
return this.i18nService.t("viewItemHeaderLogin");
|
||||
case CipherType.SecureNote:
|
||||
return this.i18nService.t("viewItemHeaderCard");
|
||||
case CipherType.Card:
|
||||
return this.i18nService.t("viewItemHeaderIdentity");
|
||||
case CipherType.Identity:
|
||||
return this.i18nService.t("viewItemHeaderNote");
|
||||
case CipherType.SshKey:
|
||||
return this.i18nService.t("viewItemHeaderSshKey");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strongly typed helper to open a cipher view dialog
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param config Configuration for the dialog
|
||||
* @returns A reference to the opened dialog
|
||||
*/
|
||||
export function openViewCipherDialog(
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<ViewCipherDialogParams>,
|
||||
): DialogRef<ViewCipherDialogCloseResult> {
|
||||
return dialogService.open(ViewComponent, config);
|
||||
}
|
||||
Reference in New Issue
Block a user