mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[AC-1139] Fix canDelete logic in
collection-dialog.component.ts and bulk-delete-dialog.component.ts
This commit is contained in:
@@ -72,7 +72,7 @@ export enum CollectionDialogAction {
|
||||
export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
@@ -107,7 +107,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
private organizationUserService: OrganizationUserService,
|
||||
private dialogService: DialogService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private configService: ConfigServiceAbstraction
|
||||
private configService: ConfigServiceAbstraction,
|
||||
) {
|
||||
this.tabIndex = params.initialTab ?? CollectionDialogTabType.Info;
|
||||
}
|
||||
@@ -123,8 +123,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
map((orgs) =>
|
||||
orgs
|
||||
.filter((o) => o.canCreateNewCollections && !o.isProviderUser)
|
||||
.sort(Utils.getSortFunction(this.i18nService, "name"))
|
||||
)
|
||||
.sort(Utils.getSortFunction(this.i18nService, "name")),
|
||||
),
|
||||
);
|
||||
// patchValue will trigger a call to loadOrg() in this case, so no need to call it again here
|
||||
this.formGroup.patchValue({ selectedOrg: this.params.organizationId });
|
||||
@@ -141,7 +141,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
async loadOrg(orgId: string, collectionIds: string[]) {
|
||||
const organization$ = of(this.organizationService.get(orgId)).pipe(
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
const groups$ = organization$.pipe(
|
||||
switchMap((organization) => {
|
||||
@@ -150,7 +150,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
return this.groupService.getAll(orgId);
|
||||
})
|
||||
}),
|
||||
);
|
||||
combineLatest({
|
||||
organization: organization$,
|
||||
@@ -168,7 +168,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.organization = organization;
|
||||
this.accessItems = [].concat(
|
||||
groups.map(mapGroupToAccessItemView),
|
||||
users.data.map(mapUserToAccessItemView)
|
||||
users.data.map(mapUserToAccessItemView),
|
||||
);
|
||||
|
||||
// Force change detection to update the access selector's items
|
||||
@@ -201,9 +201,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
this.nestOptions = collections;
|
||||
const parent = collections.find((c) => c.id === this.params.parentCollectionId);
|
||||
const currentOrgUserId = users.data.find(
|
||||
(u) => u.userId === this.organization?.userId
|
||||
)?.id;
|
||||
const currentOrgUserId = users.data.find((u) => u.userId === this.organization?.userId)
|
||||
?.id;
|
||||
const initialSelection: AccessItemValue[] =
|
||||
currentOrgUserId !== undefined
|
||||
? [
|
||||
@@ -224,7 +223,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -250,13 +249,13 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
null,
|
||||
this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("collectionInfo"))
|
||||
this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("collectionInfo")),
|
||||
);
|
||||
} else if (this.tabIndex === CollectionDialogTabType.Info && accessTabError) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
null,
|
||||
this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("access"))
|
||||
this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("access")),
|
||||
);
|
||||
}
|
||||
return;
|
||||
@@ -287,8 +286,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
null,
|
||||
this.i18nService.t(
|
||||
this.editMode ? "editedCollectionId" : "createdCollectionId",
|
||||
collectionView.name
|
||||
)
|
||||
collectionView.name,
|
||||
),
|
||||
);
|
||||
|
||||
this.close(CollectionDialogAction.Saved, savedCollection);
|
||||
@@ -310,18 +309,17 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("deletedCollectionId", this.collection?.name)
|
||||
this.i18nService.t("deletedCollectionId", this.collection?.name),
|
||||
);
|
||||
|
||||
this.close(CollectionDialogAction.Deleted, this.collection);
|
||||
};
|
||||
|
||||
protected canDelete$ = this.flexibleCollectionsEnabled$.pipe(
|
||||
switchMap(async (flexibleCollectionsEnabled) => {
|
||||
return (
|
||||
this.editMode && this.collection.canDelete(this.organization, flexibleCollectionsEnabled)
|
||||
);
|
||||
})
|
||||
map(
|
||||
(flexibleCollectionsEnabled) =>
|
||||
this.editMode && this.collection.canDelete(this.organization, flexibleCollectionsEnabled),
|
||||
),
|
||||
);
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@@ -356,7 +354,7 @@ function mapToAccessSelections(collectionDetails: CollectionAdminView): AccessIt
|
||||
id: selection.id,
|
||||
type: AccessItemType.Member,
|
||||
permission: convertToPermission(selection),
|
||||
}))
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,10 +375,10 @@ function validateCanManagePermission(control: AbstractControl) {
|
||||
*/
|
||||
export function openCollectionDialog(
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<CollectionDialogParams>
|
||||
config: DialogConfig<CollectionDialogParams>,
|
||||
) {
|
||||
return dialogService.open<CollectionDialogResult, CollectionDialogParams>(
|
||||
CollectionDialogComponent,
|
||||
config
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ export enum BulkDeleteDialogResult {
|
||||
*/
|
||||
export const openBulkDeleteDialog = (
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<BulkDeleteDialogParams>
|
||||
config: DialogConfig<BulkDeleteDialogParams>,
|
||||
) => {
|
||||
return dialogService.open<BulkDeleteDialogResult, BulkDeleteDialogParams>(
|
||||
BulkDeleteDialogComponent,
|
||||
config
|
||||
config,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ export class BulkDeleteDialogComponent {
|
||||
private i18nService: I18nService,
|
||||
private apiService: ApiService,
|
||||
private collectionService: CollectionService,
|
||||
private configService: ConfigServiceAbstraction
|
||||
private configService: ConfigServiceAbstraction,
|
||||
) {
|
||||
this.cipherIds = params.cipherIds ?? [];
|
||||
this.collectionIds = params.collectionIds ?? [];
|
||||
@@ -95,7 +95,7 @@ export class BulkDeleteDialogComponent {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.permanent ? "permanentlyDeletedItems" : "deletedItems")
|
||||
this.i18nService.t(this.permanent ? "permanentlyDeletedItems" : "deletedItems"),
|
||||
);
|
||||
}
|
||||
if (this.collectionIds.length) {
|
||||
@@ -103,7 +103,7 @@ export class BulkDeleteDialogComponent {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("deletedCollections")
|
||||
this.i18nService.t("deletedCollections"),
|
||||
);
|
||||
}
|
||||
this.close(BulkDeleteDialogResult.Deleted);
|
||||
@@ -130,20 +130,17 @@ export class BulkDeleteDialogComponent {
|
||||
private async deleteCollections(): Promise<any> {
|
||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false
|
||||
false,
|
||||
);
|
||||
// From org vault
|
||||
if (this.organization) {
|
||||
if (
|
||||
(flexibleCollectionsEnabled
|
||||
? this.collections.some((c) => !c.canDelete)
|
||||
: !this.organization.canDeleteAssignedCollections) &&
|
||||
!this.organization.canDeleteAnyCollection
|
||||
this.collections.some((c) => !c.canDelete(this.organization, flexibleCollectionsEnabled))
|
||||
) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("missingPermissions")
|
||||
this.i18nService.t("missingPermissions"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -152,16 +149,11 @@ export class BulkDeleteDialogComponent {
|
||||
} else if (this.organizations && this.collections) {
|
||||
const deletePromises: Promise<any>[] = [];
|
||||
for (const organization of this.organizations) {
|
||||
if (
|
||||
(flexibleCollectionsEnabled
|
||||
? this.collections.some((c) => !c.canDelete)
|
||||
: !this.organization.canDeleteAssignedCollections) &&
|
||||
!organization.canDeleteAnyCollection
|
||||
) {
|
||||
if (this.collections.some((c) => !c.canDelete(organization, flexibleCollectionsEnabled))) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("missingPermissions")
|
||||
this.i18nService.t("missingPermissions"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +161,7 @@ export class BulkDeleteDialogComponent {
|
||||
.filter((o) => o.organizationId === organization.id)
|
||||
.map((c) => c.id);
|
||||
deletePromises.push(
|
||||
this.apiService.deleteManyCollections(this.organization.id, orgCollections)
|
||||
this.apiService.deleteManyCollections(this.organization.id, orgCollections),
|
||||
);
|
||||
}
|
||||
return await Promise.all(deletePromises);
|
||||
|
||||
@@ -147,7 +147,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected currentSearchText$: Observable<string>;
|
||||
protected showBulkCollectionAccess$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.BulkCollectionAccess,
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
private searchText$ = new Subject<string>();
|
||||
@@ -183,7 +183,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
private searchPipe: SearchPipe,
|
||||
private configService: ConfigServiceAbstraction,
|
||||
private apiService: ApiService,
|
||||
private userVerificationService: UserVerificationService
|
||||
private userVerificationService: UserVerificationService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -191,7 +191,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.trashCleanupWarning = this.i18nService.t(
|
||||
this.platformUtilsService.isSelfHost()
|
||||
? "trashCleanupWarningSelfHosted"
|
||||
: "trashCleanupWarning"
|
||||
: "trashCleanupWarning",
|
||||
);
|
||||
|
||||
const firstSetup$ = this.route.queryParams.pipe(
|
||||
@@ -219,7 +219,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
await this.editCipher(cipherView);
|
||||
}
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
@@ -243,11 +243,11 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
const filter$ = this.routedVaultFilterService.filter$;
|
||||
const canAccessPremium$ = Utils.asyncToObservable(() =>
|
||||
this.stateService.getCanAccessPremium()
|
||||
this.stateService.getCanAccessPremium(),
|
||||
).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
const allCollections$ = Utils.asyncToObservable(() => this.collectionService.getAllDecrypted());
|
||||
const nestedCollections$ = allCollections$.pipe(
|
||||
map((collections) => getNestedCollectionTree(collections))
|
||||
map((collections) => getNestedCollectionTree(collections)),
|
||||
);
|
||||
|
||||
this.searchText$
|
||||
@@ -257,7 +257,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
queryParams: { search: Utils.isNullOrEmpty(searchText) ? null : searchText },
|
||||
queryParamsHandling: "merge",
|
||||
replaceUrl: true,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||
@@ -277,7 +277,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
return ciphers.filter(filterFunction);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const collections$ = combineLatest([nestedCollections$, filter$, this.currentSearchText$]).pipe(
|
||||
@@ -297,7 +297,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
const selectedCollection = ServiceUtils.getTreeNodeObjectFromList(
|
||||
collections,
|
||||
filter.collectionId
|
||||
filter.collectionId,
|
||||
);
|
||||
collectionsToReturn = selectedCollection?.children.map((c) => c.node) ?? [];
|
||||
}
|
||||
@@ -307,13 +307,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
collectionsToReturn,
|
||||
searchText,
|
||||
(collection) => collection.name,
|
||||
(collection) => collection.id
|
||||
(collection) => collection.id,
|
||||
);
|
||||
}
|
||||
|
||||
return collectionsToReturn;
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const selectedCollection$ = combineLatest([nestedCollections$, filter$]).pipe(
|
||||
@@ -329,7 +329,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
return ServiceUtils.getTreeNodeObjectFromList(collections, filter.collectionId);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
firstSetup$
|
||||
@@ -344,7 +344,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("unknownCipher")
|
||||
this.i18nService.t("unknownCipher"),
|
||||
);
|
||||
this.router.navigate([], {
|
||||
queryParams: { itemId: null, cipherId: null },
|
||||
@@ -353,7 +353,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
@@ -370,9 +370,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
ciphers$,
|
||||
collections$,
|
||||
selectedCollection$,
|
||||
])
|
||||
]),
|
||||
),
|
||||
takeUntil(this.destroy$)
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe(
|
||||
([
|
||||
@@ -393,7 +393,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.selectedCollection = selectedCollection;
|
||||
|
||||
this.canCreateCollections = allOrganizations?.some(
|
||||
(o) => o.canCreateNewCollections && !o.isProviderUser
|
||||
(o) => o.canCreateNewCollections && !o.isProviderUser,
|
||||
);
|
||||
|
||||
this.showBulkMove =
|
||||
@@ -407,7 +407,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.performingInitialLoad = false;
|
||||
this.refreshing = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
comp.onReuploadedAttachment
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => (madeAttachmentChanges = true));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
modal.onClosed.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||
@@ -559,7 +559,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
modal.close();
|
||||
this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -573,7 +573,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
modal.close();
|
||||
this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
const selectedColId = this.activeFilter.collectionId;
|
||||
if (selectedColId !== "AllCollections") {
|
||||
component.organizationId = component.collections.find(
|
||||
(collection) => collection.id === selectedColId
|
||||
(collection) => collection.id === selectedColId,
|
||||
)?.organizationId;
|
||||
component.collectionIds = [selectedColId];
|
||||
}
|
||||
@@ -635,7 +635,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
modal.close();
|
||||
this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
modal.onClosedPromise().then(() => {
|
||||
@@ -690,16 +690,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
const organization = this.organizationService.get(collection.organizationId);
|
||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false
|
||||
false,
|
||||
);
|
||||
if (
|
||||
(flexibleCollectionsEnabled || !organization.canDeleteAssignedCollections) &&
|
||||
!organization.canDeleteAnyCollection
|
||||
) {
|
||||
if (collection.canDelete(organization, flexibleCollectionsEnabled)) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("missingPermissions")
|
||||
this.i18nService.t("missingPermissions"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -717,7 +714,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("deletedCollectionId", collection.name)
|
||||
this.i18nService.t("deletedCollectionId", collection.name),
|
||||
);
|
||||
// Navigate away if we deleted the collection we were viewing
|
||||
if (this.selectedCollection?.node.id === collection.id) {
|
||||
@@ -778,7 +775,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -801,8 +798,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
.map((i) => i.collection.organizationId);
|
||||
const orgs = await firstValueFrom(
|
||||
this.organizationService.organizations$.pipe(
|
||||
map((orgs) => orgs.filter((o) => orgIds.includes(o.id)))
|
||||
)
|
||||
map((orgs) => orgs.filter((o) => orgIds.includes(o.id))),
|
||||
),
|
||||
);
|
||||
await this.bulkDelete(ciphers, collections, orgs);
|
||||
}
|
||||
@@ -830,7 +827,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(permanent ? "permanentlyDeletedItem" : "deletedItem")
|
||||
this.i18nService.t(permanent ? "permanentlyDeletedItem" : "deletedItem"),
|
||||
);
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
@@ -841,7 +838,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async bulkDelete(
|
||||
ciphers: CipherView[],
|
||||
collections: CollectionView[],
|
||||
organizations: Organization[]
|
||||
organizations: Organization[],
|
||||
) {
|
||||
if (!(await this.repromptCipher(ciphers))) {
|
||||
return;
|
||||
@@ -851,7 +848,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -881,7 +878,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -933,7 +930,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"info",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey))
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
);
|
||||
|
||||
if (field === "password") {
|
||||
@@ -952,7 +949,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected currentSearchText$: Observable<string>;
|
||||
protected showBulkEditCollectionAccess$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.BulkCollectionAccess,
|
||||
false
|
||||
false,
|
||||
);
|
||||
protected flexibleCollectionsEnabled: boolean;
|
||||
|
||||
@@ -164,27 +164,27 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private totpService: TotpService,
|
||||
private apiService: ApiService,
|
||||
protected configService: ConfigServiceAbstraction
|
||||
protected configService: ConfigServiceAbstraction,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.trashCleanupWarning = this.i18nService.t(
|
||||
this.platformUtilsService.isSelfHost()
|
||||
? "trashCleanupWarningSelfHosted"
|
||||
: "trashCleanupWarning"
|
||||
: "trashCleanupWarning",
|
||||
);
|
||||
|
||||
const filter$ = this.routedVaultFilterService.filter$;
|
||||
const organizationId$ = filter$.pipe(
|
||||
map((filter) => filter.organizationId),
|
||||
filter((filter) => filter !== undefined),
|
||||
distinctUntilChanged()
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
|
||||
const organization$ = organizationId$.pipe(
|
||||
switchMap((organizationId) => this.organizationService.get$(organizationId)),
|
||||
takeUntil(this.destroy$),
|
||||
shareReplay({ refCount: false, bufferSize: 1 })
|
||||
shareReplay({ refCount: false, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const firstSetup$ = combineLatest([organization$, this.route.queryParams]).pipe(
|
||||
@@ -198,7 +198,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
return undefined;
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
@@ -227,14 +227,14 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
queryParams: { search: Utils.isNullOrEmpty(searchText) ? null : searchText },
|
||||
queryParamsHandling: "merge",
|
||||
replaceUrl: true,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||
|
||||
const allCollectionsWithoutUnassigned$ = organizationId$.pipe(
|
||||
switchMap((orgId) => this.collectionAdminService.getAll(orgId)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const allCollections$ = combineLatest([organizationId$, allCollectionsWithoutUnassigned$]).pipe(
|
||||
@@ -244,12 +244,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
noneCollection.id = Unassigned;
|
||||
noneCollection.organizationId = organizationId;
|
||||
return allCollections.concat(noneCollection);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const allGroups$ = organizationId$.pipe(
|
||||
switchMap((organizationId) => this.groupService.getAll(organizationId)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const allCiphers$ = organization$.pipe(
|
||||
@@ -259,12 +259,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
ciphers = await this.cipherService.getAllFromApiForOrganization(organization.id);
|
||||
} else {
|
||||
ciphers = (await this.cipherService.getAllDecrypted()).filter(
|
||||
(c) => c.organizationId === organization.id
|
||||
(c) => c.organizationId === organization.id,
|
||||
);
|
||||
}
|
||||
await this.searchService.indexCiphers(ciphers, organization.id);
|
||||
return ciphers;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const ciphers$ = combineLatest([allCiphers$, filter$, this.currentSearchText$]).pipe(
|
||||
@@ -282,12 +282,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
return ciphers.filter(filterFunction);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const nestedCollections$ = allCollections$.pipe(
|
||||
map((collections) => getNestedCollectionTree(collections)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const collections$ = combineLatest([nestedCollections$, filter$, this.currentSearchText$]).pipe(
|
||||
@@ -306,7 +306,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
} else {
|
||||
const selectedCollection = ServiceUtils.getTreeNodeObjectFromList(
|
||||
collections,
|
||||
filter.collectionId
|
||||
filter.collectionId,
|
||||
);
|
||||
collectionsToReturn = selectedCollection?.children.map((c) => c.node) ?? [];
|
||||
}
|
||||
@@ -316,14 +316,14 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
collectionsToReturn,
|
||||
searchText,
|
||||
(collection) => collection.name,
|
||||
(collection) => collection.id
|
||||
(collection) => collection.id,
|
||||
);
|
||||
}
|
||||
|
||||
return collectionsToReturn;
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const selectedCollection$ = combineLatest([nestedCollections$, filter$]).pipe(
|
||||
@@ -339,7 +339,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
return ServiceUtils.getTreeNodeObjectFromList(collections, filter.collectionId);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
const showMissingCollectionPermissionMessage$ = combineLatest([
|
||||
@@ -357,7 +357,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
!organization.canUseAdminCollections)
|
||||
);
|
||||
}),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
firstSetup$
|
||||
@@ -378,7 +378,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("unknownCipher")
|
||||
this.i18nService.t("unknownCipher"),
|
||||
);
|
||||
this.router.navigate([], {
|
||||
queryParams: { cipherId: null, itemId: null },
|
||||
@@ -386,7 +386,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
@@ -405,7 +405,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("unknownCipher")
|
||||
this.i18nService.t("unknownCipher"),
|
||||
);
|
||||
this.router.navigate([], {
|
||||
queryParams: { viewEvents: null },
|
||||
@@ -413,7 +413,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
@@ -431,9 +431,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
collections$,
|
||||
selectedCollection$,
|
||||
showMissingCollectionPermissionMessage$,
|
||||
])
|
||||
]),
|
||||
),
|
||||
takeUntil(this.destroy$)
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe(
|
||||
([
|
||||
@@ -463,7 +463,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.refreshing = false;
|
||||
this.performingInitialLoad = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
comp.onDeletedAttachment
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => (madeAttachmentChanges = true));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
modal.onClosed.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||
@@ -575,13 +575,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
modal.close();
|
||||
this.refresh();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async addCipher() {
|
||||
const collections = (await firstValueFrom(this.vaultFilterService.filteredCollections$)).filter(
|
||||
(c) => !c.readOnly && c.id != Unassigned
|
||||
(c) => !c.readOnly && c.id != Unassigned,
|
||||
);
|
||||
|
||||
await this.editCipher(null, (comp) => {
|
||||
@@ -599,14 +599,14 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
async editCipher(
|
||||
cipher: CipherView,
|
||||
additionalComponentParameters?: (comp: AddEditComponent) => void
|
||||
additionalComponentParameters?: (comp: AddEditComponent) => void,
|
||||
) {
|
||||
return this.editCipherId(cipher?.id, additionalComponentParameters);
|
||||
}
|
||||
|
||||
async editCipherId(
|
||||
cipherId: string,
|
||||
additionalComponentParameters?: (comp: AddEditComponent) => void
|
||||
additionalComponentParameters?: (comp: AddEditComponent) => void,
|
||||
) {
|
||||
const cipher = await this.cipherService.get(cipherId);
|
||||
// if cipher exists (cipher is null when new) and MP reprompt
|
||||
@@ -647,7 +647,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
: (comp) => {
|
||||
defaultComponentParameters(comp);
|
||||
additionalComponentParameters(comp);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
modal.onClosedPromise().then(() => {
|
||||
@@ -671,7 +671,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
const collections = (await firstValueFrom(this.vaultFilterService.filteredCollections$)).filter(
|
||||
(c) => !c.readOnly && c.id != Unassigned
|
||||
(c) => !c.readOnly && c.id != Unassigned,
|
||||
);
|
||||
|
||||
await this.editCipher(cipher, (comp) => {
|
||||
@@ -710,7 +710,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -742,7 +742,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(permanent ? "permanentlyDeletedItem" : "deletedItem")
|
||||
this.i18nService.t(permanent ? "permanentlyDeletedItem" : "deletedItem"),
|
||||
);
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
@@ -753,16 +753,13 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async deleteCollection(collection: CollectionView): Promise<void> {
|
||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false
|
||||
false,
|
||||
);
|
||||
if (
|
||||
(flexibleCollectionsEnabled || !this.organization.canDeleteAssignedCollections) &&
|
||||
!this.organization.canDeleteAnyCollection
|
||||
) {
|
||||
if (collection.canDelete(this.organization, flexibleCollectionsEnabled)) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("missingPermissions")
|
||||
this.i18nService.t("missingPermissions"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -780,7 +777,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("deletedCollectionId", collection.name)
|
||||
this.i18nService.t("deletedCollectionId", collection.name),
|
||||
);
|
||||
|
||||
// Navigate away if we deleted the colletion we were viewing
|
||||
@@ -801,7 +798,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
async bulkDelete(
|
||||
ciphers: CipherView[],
|
||||
collections: CollectionView[],
|
||||
organization: Organization
|
||||
organization: Organization,
|
||||
) {
|
||||
if (!(await this.repromptCipher(ciphers))) {
|
||||
return;
|
||||
@@ -811,7 +808,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -867,7 +864,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"info",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey))
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
);
|
||||
|
||||
if (field === "password") {
|
||||
@@ -913,7 +910,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nothingSelected")
|
||||
this.i18nService.t("nothingSelected"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user