1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-14 10:26:19 +01:00

[PM-14183] Show success toast on copy history value (#11911)

* Remove unnecessary copy icon

* Fix styling of copy success toast
- Use CopyClick directive instead of manually copying and showing the toast
- Adjust tests

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
Daniel James Smith 2024-11-08 00:28:32 +01:00 committed by GitHub
parent e8dac0cc12
commit b23d62a280
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 8 additions and 49 deletions

View File

@ -15,10 +15,10 @@
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
[appA11yTitle]="'copyPassword' | i18n" [appA11yTitle]="'copyPassword' | i18n"
appStopClick appStopClick
(click)="copy(h.password)" [appCopyClick]="h.password"
> [valueLabel]="'password' | i18n"
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> showToast
</button> ></button>
</bit-item-action> </bit-item-action>
</ng-container> </ng-container>
</bit-item> </bit-item>

View File

@ -3,14 +3,13 @@ import { By } from "@angular/platform-browser";
import { BehaviorSubject } from "rxjs"; import { BehaviorSubject } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { ColorPasswordModule, ItemModule, ToastService } from "@bitwarden/components"; import { ColorPasswordModule, ItemModule } from "@bitwarden/components";
import { ColorPasswordComponent } from "@bitwarden/components/src/color-password/color-password.component"; import { ColorPasswordComponent } from "@bitwarden/components/src/color-password/color-password.component";
import { PasswordHistoryViewComponent } from "./password-history-view.component"; import { PasswordHistoryViewComponent } from "./password-history-view.component";
@ -25,8 +24,6 @@ describe("PasswordHistoryViewComponent", () => {
organizationId: "222-444-555", organizationId: "222-444-555",
} as CipherView; } as CipherView;
const copyToClipboard = jest.fn();
const showToast = jest.fn();
const activeAccount$ = new BehaviorSubject<{ id: string }>({ id: "666-444-444" }); const activeAccount$ = new BehaviorSubject<{ id: string }>({ id: "666-444-444" });
const mockCipherService = { const mockCipherService = {
get: jest.fn().mockResolvedValue({ decrypt: jest.fn().mockResolvedValue(mockCipher) }), get: jest.fn().mockResolvedValue({ decrypt: jest.fn().mockResolvedValue(mockCipher) }),
@ -36,17 +33,13 @@ describe("PasswordHistoryViewComponent", () => {
beforeEach(async () => { beforeEach(async () => {
mockCipherService.get.mockClear(); mockCipherService.get.mockClear();
mockCipherService.getKeyForCipherKeyDecryption.mockClear(); mockCipherService.getKeyForCipherKeyDecryption.mockClear();
copyToClipboard.mockClear();
showToast.mockClear();
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [ItemModule, ColorPasswordModule, JslibModule], imports: [ItemModule, ColorPasswordModule, JslibModule],
providers: [ providers: [
{ provide: WINDOW, useValue: window },
{ provide: CipherService, useValue: mockCipherService }, { provide: CipherService, useValue: mockCipherService },
{ provide: PlatformUtilsService, useValue: { copyToClipboard } }, { provide: PlatformUtilsService },
{ provide: AccountService, useValue: { activeAccount$ } }, { provide: AccountService, useValue: { activeAccount$ } },
{ provide: ToastService, useValue: { showToast } },
{ provide: I18nService, useValue: { t: (key: string) => key } }, { provide: I18nService, useValue: { t: (key: string) => key } },
], ],
}).compileComponents(); }).compileComponents();
@ -80,18 +73,5 @@ describe("PasswordHistoryViewComponent", () => {
"bad-password-2", "bad-password-2",
]); ]);
}); });
it("copies a password", () => {
const copyButton = fixture.debugElement.query(By.css("button"));
copyButton.nativeElement.click();
expect(copyToClipboard).toHaveBeenCalledWith("bad-password-1", { window: window });
expect(showToast).toHaveBeenCalledWith({
message: "passwordCopied",
title: "",
variant: "info",
});
});
}); });
}); });

View File

@ -1,21 +1,14 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { OnInit, Inject, Component, Input } from "@angular/core"; import { OnInit, Component, Input } from "@angular/core";
import { firstValueFrom, map } from "rxjs"; import { firstValueFrom, map } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { CipherId, UserId } from "@bitwarden/common/types/guid"; import { CipherId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { PasswordHistoryView } from "@bitwarden/common/vault/models/view/password-history.view"; import { PasswordHistoryView } from "@bitwarden/common/vault/models/view/password-history.view";
import { import { ItemModule, ColorPasswordModule, IconButtonModule } from "@bitwarden/components";
ToastService,
ItemModule,
ColorPasswordModule,
IconButtonModule,
} from "@bitwarden/components";
@Component({ @Component({
selector: "vault-password-history-view", selector: "vault-password-history-view",
@ -33,29 +26,15 @@ export class PasswordHistoryViewComponent implements OnInit {
history: PasswordHistoryView[] = []; history: PasswordHistoryView[] = [];
constructor( constructor(
@Inject(WINDOW) private win: Window,
protected cipherService: CipherService, protected cipherService: CipherService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService, protected i18nService: I18nService,
protected accountService: AccountService, protected accountService: AccountService,
protected toastService: ToastService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
await this.init(); await this.init();
} }
/** Copies a password to the clipboard. */
copy(password: string) {
const copyOptions = this.win != null ? { window: this.win } : undefined;
this.platformUtilsService.copyToClipboard(password, copyOptions);
this.toastService.showToast({
variant: "info",
title: "",
message: this.i18nService.t("passwordCopied"),
});
}
/** Retrieve the password history for the given cipher */ /** Retrieve the password history for the given cipher */
protected async init() { protected async init() {
const cipher = await this.cipherService.get(this.cipherId); const cipher = await this.cipherService.get(this.cipherId);