mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
initial integration of combined dialog
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { TestBed } from "@angular/core/testing";
|
import { TestBed } from "@angular/core/testing";
|
||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
|
import { CollectionAdminService } from "@bitwarden/admin-console/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -9,7 +10,6 @@ import { CipherId } from "@bitwarden/common/types/guid";
|
|||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||||
|
|
||||||
import { CollectionAdminService } from "../../core/collection-admin.service";
|
|
||||||
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
||||||
|
|
||||||
import { AdminConsoleCipherFormConfigService } from "./admin-console-cipher-form-config.service";
|
import { AdminConsoleCipherFormConfigService } from "./admin-console-cipher-form-config.service";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { inject, Injectable } from "@angular/core";
|
import { inject, Injectable } from "@angular/core";
|
||||||
import { combineLatest, defer, filter, firstValueFrom, map, switchMap } from "rxjs";
|
import { combineLatest, defer, filter, firstValueFrom, map, switchMap } from "rxjs";
|
||||||
|
|
||||||
|
import { CollectionAdminService } from "@bitwarden/admin-console/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -18,7 +19,6 @@ import {
|
|||||||
CipherFormConfigService,
|
CipherFormConfigService,
|
||||||
CipherFormMode,
|
CipherFormMode,
|
||||||
} from "../../../../../../../libs/vault/src/cipher-form/abstractions/cipher-form-config.service";
|
} from "../../../../../../../libs/vault/src/cipher-form/abstractions/cipher-form-config.service";
|
||||||
import { CollectionAdminService } from "../../core/collection-admin.service";
|
|
||||||
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
||||||
|
|
||||||
/** Admin Console implementation of the `CipherFormConfigService`. */
|
/** Admin Console implementation of the `CipherFormConfigService`. */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DialogRef } from "@angular/cdk/dialog";
|
||||||
import {
|
import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
@@ -64,6 +65,7 @@ import { CollectionView } from "@bitwarden/common/vault/models/view/collection.v
|
|||||||
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
||||||
import { DialogService, Icons, NoItemsModule, ToastService } from "@bitwarden/components";
|
import { DialogService, Icons, NoItemsModule, ToastService } from "@bitwarden/components";
|
||||||
import {
|
import {
|
||||||
|
CipherFormConfig,
|
||||||
CipherFormConfigService,
|
CipherFormConfigService,
|
||||||
CollectionAssignmentResult,
|
CollectionAssignmentResult,
|
||||||
PasswordRepromptService,
|
PasswordRepromptService,
|
||||||
@@ -80,6 +82,11 @@ import {
|
|||||||
CollectionDialogTabType,
|
CollectionDialogTabType,
|
||||||
openCollectionDialog,
|
openCollectionDialog,
|
||||||
} from "../components/collection-dialog";
|
} from "../components/collection-dialog";
|
||||||
|
import {
|
||||||
|
VaultItemDialogComponent,
|
||||||
|
VaultItemDialogMode,
|
||||||
|
VaultItemDialogResult,
|
||||||
|
} from "../components/vault-item-dialog/vault-item-dialog.component";
|
||||||
import { VaultItemEvent } from "../components/vault-items/vault-item-event";
|
import { VaultItemEvent } from "../components/vault-items/vault-item-event";
|
||||||
import { VaultItemsModule } from "../components/vault-items/vault-items.module";
|
import { VaultItemsModule } from "../components/vault-items/vault-items.module";
|
||||||
import {
|
import {
|
||||||
@@ -184,6 +191,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
protected addAccessStatus$ = new BehaviorSubject<AddAccessStatusType>(0);
|
protected addAccessStatus$ = new BehaviorSubject<AddAccessStatusType>(0);
|
||||||
private extensionRefreshEnabled: boolean;
|
private extensionRefreshEnabled: boolean;
|
||||||
|
private vaultItemDialogRef?: DialogRef<VaultItemDialogResult> | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -481,6 +489,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
firstSetup$
|
firstSetup$
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(() => this.route.queryParams),
|
switchMap(() => this.route.queryParams),
|
||||||
|
// Only process the queryParams if the dialog is not open (only when extension refresh is enabled)
|
||||||
|
filter(() => this.vaultItemDialogRef == undefined || !this.extensionRefreshEnabled),
|
||||||
withLatestFrom(allCipherMap$, allCollections$, organization$),
|
withLatestFrom(allCipherMap$, allCollections$, organization$),
|
||||||
switchMap(async ([qParams, allCiphersMap]) => {
|
switchMap(async ([qParams, allCiphersMap]) => {
|
||||||
const cipherId = getCipherIdFromParams(qParams);
|
const cipherId = getCipherIdFromParams(qParams);
|
||||||
@@ -490,10 +500,15 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
const cipher = allCiphersMap[cipherId];
|
const cipher = allCiphersMap[cipherId];
|
||||||
|
|
||||||
if (cipher) {
|
if (cipher) {
|
||||||
if (qParams.action === "view") {
|
let action = qParams.action;
|
||||||
// Only allow for edit in the admin console via query params,
|
// Default to "view" if extension refresh is enabled
|
||||||
// This prevents multiple modals from stacking on top of each other between view & edit.
|
if (action == null && this.extensionRefreshEnabled) {
|
||||||
// TODO: PM-12398 - combine view/edit actions into a single dialog
|
action = "view";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "view") {
|
||||||
|
await this.viewCipherById(cipherId);
|
||||||
|
} else {
|
||||||
await this.editCipherId(cipherId, false);
|
await this.editCipherId(cipherId, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -877,18 +892,52 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
cipherId,
|
cipherId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const dialogRef = openAddEditCipherDialog(this.dialogService, {
|
await this.openVaultItemDialog("form", cipherFormConfig);
|
||||||
data: cipherFormConfig,
|
}
|
||||||
|
|
||||||
|
/** Opens the view dialog for the given cipher unless password reprompt fails */
|
||||||
|
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.
|
||||||
|
await this.go({ cipherId: null, itemId: null, action: null });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cipherFormConfig = await this.cipherFormConfigService.buildConfig(
|
||||||
|
cipher?.edit ? "edit" : "partial-edit",
|
||||||
|
id as CipherId,
|
||||||
|
cipher?.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.openVaultItemDialog("view", cipherFormConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the combined view / edit dialog for a cipher.
|
||||||
|
*/
|
||||||
|
async openVaultItemDialog(mode: VaultItemDialogMode, formConfig: CipherFormConfig) {
|
||||||
|
this.vaultItemDialogRef = VaultItemDialogComponent.open(this.dialogService, {
|
||||||
|
mode,
|
||||||
|
formConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result: AddEditCipherDialogCloseResult = await firstValueFrom(dialogRef.closed);
|
const result = await lastValueFrom(this.vaultItemDialogRef.closed);
|
||||||
|
this.vaultItemDialogRef = undefined;
|
||||||
|
|
||||||
// When the cipher was edited, refresh the vault view
|
// If the dialog was closed by deleting the cipher, refresh the vault.
|
||||||
if (result?.action === AddEditCipherDialogResult.Edited) {
|
if (result === VaultItemDialogResult.Deleted || result === VaultItemDialogResult.Saved) {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.go({ cipherId: null, itemId: null, action: null });
|
// Clear the query params when the dialog closes
|
||||||
|
await this.go({ cipherId: null, itemId: null, action: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneCipher(cipher: CipherView) {
|
async cloneCipher(cipher: CipherView) {
|
||||||
|
|||||||
Reference in New Issue
Block a user