1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 13:23:34 +00:00

remove unused view component (#16582)

This commit is contained in:
Nick Krantz
2025-10-06 11:42:21 -05:00
committed by GitHub
parent 8cf379d997
commit 6d98360b04
5 changed files with 0 additions and 401 deletions

View File

@@ -2,7 +2,6 @@ import { NgModule } from "@angular/core";
import { SharedModule } from "../../../shared/shared.module"; import { SharedModule } from "../../../shared/shared.module";
import { OrganizationBadgeModule } from "../../../vault/individual-vault/organization-badge/organization-badge.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 { CollectionDialogComponent } from "../shared/components/collection-dialog";
import { CollectionNameBadgeComponent } from "./collection-badge"; import { CollectionNameBadgeComponent } from "./collection-badge";
@@ -19,7 +18,6 @@ import { VaultComponent } from "./vault.component";
OrganizationBadgeModule, OrganizationBadgeModule,
CollectionDialogComponent, CollectionDialogComponent,
VaultComponent, VaultComponent,
ViewComponent,
], ],
}) })
export class VaultModule {} export class VaultModule {}

View File

@@ -10,7 +10,6 @@ import { OrganizationBadgeModule } from "./organization-badge/organization-badge
import { PipesModule } from "./pipes/pipes.module"; import { PipesModule } from "./pipes/pipes.module";
import { VaultRoutingModule } from "./vault-routing.module"; import { VaultRoutingModule } from "./vault-routing.module";
import { VaultComponent } from "./vault.component"; import { VaultComponent } from "./vault.component";
import { ViewComponent } from "./view.component";
@NgModule({ @NgModule({
imports: [ imports: [
@@ -23,7 +22,6 @@ import { ViewComponent } from "./view.component";
BulkDialogsModule, BulkDialogsModule,
CollectionDialogComponent, CollectionDialogComponent,
VaultComponent, VaultComponent,
ViewComponent,
], ],
}) })
export class VaultModule {} export class VaultModule {}

View File

@@ -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>

View File

@@ -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 });
});
});
});

View File

@@ -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);
}