1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-06 10:33:57 +00:00

PM-9665: implement view item view (#10416)

* Add initial view cipher dialog.

* Add working view cipher modal dialog markup.

* Cleanup dialog markup and allow edit from dialog.

* Cleanup unused imports.

* Begin adding org-vault view-cipher functionality.

* Refactor to remove loose-components usage and use DialogService.

* Add edit and delete button functionality.

* Add delete functionality.

* Remove addition to loose components.

* Remove unused modal-dialog artifacts.

* Ensure dialog closes and URL updates properly on edit or close.

* Disable edit/delete buttons instead of hiding them.

* Add simple tests for view.component.ts.

* Adjust import order.

* Remove now unnecessary ng-template.

* Decrypt cipher to cipher view.

* Add cleanup function and additional delete test.

* Remove boolean return from delete promise.

* Remove fake timers.

* Remove unnecessary TestBed.inject calls.

* Add code comments.

* Hide new view cipher dialog behind feature flag.

* Keep "else if" statement intact.

* Simplify getting cipherTypeString.

* Add comments to vault.component.ts files.

* Change button type to "danger"

Update apps/web/src/app/vault/individual-vault/view.component.html

Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com>

* Add a11y title to delete button.

* Simplify OrganizationService testing.

* Update comment to better reflect function.

* Use large dialog to better match designs.

* Add aria-haspopup to cipher row button.

* Add deleteCipher to messages.json.

* Remove extra argument from canEditAllCiphers.

* Use 'delete' instead of 'delete cipher' for a11y title.

* Remove 'bitFormButton' from non-form buttons.

* Rework view cipher view delete functionality.

* Add translations for cipher types.

* Remove unecesarry test.

* Add additional test coverage to ensure dialogs close.

* Add back delete functionality in view.component.ts.

* Update "secure note" to "note".

---------

Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com>
This commit is contained in:
Alec Rippberger
2024-08-19 16:32:17 -05:00
committed by GitHub
parent d62bdd6e6c
commit 3a31eb2f10
10 changed files with 505 additions and 9 deletions

View File

@@ -89,6 +89,12 @@ import {
RoutedVaultFilterModel,
Unassigned,
} from "../individual-vault/vault-filter/shared/models/routed-vault-filter.model";
import {
openViewCipherDialog,
ViewCipherDialogCloseResult,
ViewCipherDialogResult,
ViewComponent,
} from "../individual-vault/view.component";
import { VaultHeaderComponent } from "../org-vault/vault-header/vault-header.component";
import { getNestedCollectionTree } from "../utils/collection-utils";
@@ -121,6 +127,7 @@ enum AddAccessStatusType {
VaultItemsModule,
SharedModule,
NoItemsModule,
ViewComponent,
],
providers: [RoutedVaultFilterService, RoutedVaultFilterBridgeService],
})
@@ -517,7 +524,11 @@ export class VaultComponent implements OnInit, OnDestroy {
(await firstValueFrom(allCipherMap$))[cipherId] != undefined;
if (canEditCipher) {
await this.editCipherId(cipherId);
if (qParams.action === "view") {
await this.viewCipherById(cipherId);
} else {
await this.editCipherId(cipherId);
}
} else {
this.toastService.showToast({
variant: "error",
@@ -848,12 +859,64 @@ export class VaultComponent implements OnInit, OnDestroy {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
modal.onClosedPromise().then(() => {
this.go({ cipherId: null, itemId: null });
this.go({ cipherId: null, itemId: null, action: null });
});
return childComponent;
}
/**
* Takes a CipherView and opens a dialog where it can be viewed (wraps viewCipherById).
* @param cipher - CipherView
* @returns Promise<void>
*/
viewCipher(cipher: CipherView) {
return this.viewCipherById(cipher.id);
}
/**
* Takes a cipher id and opens a dialog where it can be viewed.
* @param id - string
* @returns Promise<void>
*/
async viewCipherById(id: string) {
const cipher = await this.cipherService.get(id);
// if cipher exists (cipher is null when new) and MP reprompt
// is on for this cipher, then show password reprompt.
if (
cipher &&
cipher.reprompt !== 0 &&
!(await this.passwordRepromptService.showPasswordPrompt())
) {
// didn't pass password prompt, so don't open add / edit modal.
this.go({ cipherId: null, itemId: null });
return;
}
// Decrypt the cipher.
const cipherView = await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher),
);
// Open the dialog.
const dialogRef = openViewCipherDialog(this.dialogService, {
data: { cipher: cipherView },
});
// Wait for the dialog to close.
const result: ViewCipherDialogCloseResult = await lastValueFrom(dialogRef.closed);
// If the dialog was closed by deleting the cipher, refresh the vault.
if (result.action === ViewCipherDialogResult.deleted) {
this.refresh();
}
// If the dialog was closed by any other action (close button, escape key, etc), navigate back to the vault.
if (!result.action) {
this.go({ cipherId: null, itemId: null, action: null });
}
}
async cloneCipher(cipher: CipherView) {
if (cipher.login?.hasFido2Credentials) {
const confirmed = await this.dialogService.openSimpleDialog({