mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-28 12:45:45 +01:00
AC-1115 Modify AC Vault/Collections (#6789)
* Permissions Column added to Org Vault. Other updates to filter section and Can Manage Permission added and put behind feature flag --------- Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com>
This commit is contained in:
parent
c67fd9b584
commit
48d161009d
@ -7,9 +7,19 @@
|
|||||||
[activeOrganization]="organization"
|
[activeOrganization]="organization"
|
||||||
></app-organization-switcher>
|
></app-organization-switcher>
|
||||||
<bit-tab-nav-bar class="-tw-mb-px">
|
<bit-tab-nav-bar class="-tw-mb-px">
|
||||||
<bit-tab-link *ngIf="canShowVaultTab(organization)" route="vault">{{
|
<bit-tab-link
|
||||||
"vault" | i18n
|
*ngIf="
|
||||||
}}</bit-tab-link>
|
canShowVaultTab(organization) && (flexibleCollectionsEnabled$ | async);
|
||||||
|
else vaultTab
|
||||||
|
"
|
||||||
|
route="vault"
|
||||||
|
>{{ "collections" | i18n }}</bit-tab-link
|
||||||
|
>
|
||||||
|
<ng-template #vaultTab>
|
||||||
|
<bit-tab-link *ngIf="canShowVaultTab(organization)" route="vault">{{
|
||||||
|
"vault" | i18n
|
||||||
|
}}</bit-tab-link>
|
||||||
|
</ng-template>
|
||||||
<bit-tab-link *ngIf="canShowMembersTab(organization)" route="members">{{
|
<bit-tab-link *ngIf="canShowMembersTab(organization)" route="members">{{
|
||||||
"members" | i18n
|
"members" | i18n
|
||||||
}}</bit-tab-link>
|
}}</bit-tab-link>
|
||||||
|
@ -13,6 +13,8 @@ import {
|
|||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-organization-layout",
|
selector: "app-organization-layout",
|
||||||
@ -23,12 +25,18 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private _destroy = new Subject<void>();
|
private _destroy = new Subject<void>();
|
||||||
|
|
||||||
|
protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||||
|
FeatureFlag.FlexibleCollections,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
|
private configService: ConfigServiceAbstraction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
async ngOnInit() {
|
||||||
document.body.classList.remove("layout_frontend");
|
document.body.classList.remove("layout_frontend");
|
||||||
|
|
||||||
this.organization$ = this.route.params
|
this.organization$ = this.route.params
|
||||||
|
@ -18,6 +18,8 @@ import {
|
|||||||
AccessItemValue,
|
AccessItemValue,
|
||||||
AccessItemView,
|
AccessItemView,
|
||||||
CollectionPermission,
|
CollectionPermission,
|
||||||
|
getPermissionList,
|
||||||
|
Permission,
|
||||||
} from "./access-selector.models";
|
} from "./access-selector.models";
|
||||||
|
|
||||||
export enum PermissionMode {
|
export enum PermissionMode {
|
||||||
@ -116,16 +118,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
|
|||||||
});
|
});
|
||||||
|
|
||||||
protected itemType = AccessItemType;
|
protected itemType = AccessItemType;
|
||||||
protected permissionList = [
|
protected permissionList: Permission[];
|
||||||
{ perm: CollectionPermission.View, labelId: "canView" },
|
|
||||||
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
|
|
||||||
{ perm: CollectionPermission.Edit, labelId: "canEdit" },
|
|
||||||
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
|
|
||||||
];
|
|
||||||
private canManagePermissionListItem = {
|
|
||||||
perm: CollectionPermission.Manage,
|
|
||||||
labelId: "canManage",
|
|
||||||
};
|
|
||||||
protected initialPermission = CollectionPermission.View;
|
protected initialPermission = CollectionPermission.View;
|
||||||
|
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@ -264,6 +257,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
this.permissionList = getPermissionList(this.flexibleCollectionsEnabled);
|
||||||
// Watch the internal formArray for changes and propagate them
|
// Watch the internal formArray for changes and propagate them
|
||||||
this.selectionList.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((v) => {
|
this.selectionList.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((v) => {
|
||||||
if (!this.notifyOnChange || this.pauseChangeNotification) {
|
if (!this.notifyOnChange || this.pauseChangeNotification) {
|
||||||
@ -277,10 +271,6 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
|
|||||||
}
|
}
|
||||||
this.notifyOnChange(v);
|
this.notifyOnChange(v);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.flexibleCollectionsEnabled) {
|
|
||||||
this.permissionList.push(this.canManagePermissionListItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
@ -77,6 +77,25 @@ export type AccessItemValue = {
|
|||||||
type: AccessItemType;
|
type: AccessItemType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Permission = {
|
||||||
|
perm: CollectionPermission;
|
||||||
|
labelId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPermissionList = (flexibleCollectionsEnabled: boolean): Permission[] => {
|
||||||
|
const permissions = [
|
||||||
|
{ perm: CollectionPermission.View, labelId: "canView" },
|
||||||
|
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
|
||||||
|
{ perm: CollectionPermission.Edit, labelId: "canEdit" },
|
||||||
|
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
|
||||||
|
];
|
||||||
|
if (flexibleCollectionsEnabled) {
|
||||||
|
permissions.push({ perm: CollectionPermission.Manage, labelId: "canManage" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the CollectionAccessSelectionView interface to one of the new CollectionPermission values
|
* Converts the CollectionAccessSelectionView interface to one of the new CollectionPermission values
|
||||||
* for the dropdown in the AccessSelectorComponent
|
* for the dropdown in the AccessSelectorComponent
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
></app-collection-badge>
|
></app-collection-badge>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell [ngClass]="RowHeightClass" *ngIf="showGroups"></td>
|
<td bitCell [ngClass]="RowHeightClass" *ngIf="showGroups"></td>
|
||||||
|
<td bitCell [ngClass]="RowHeightClass" *ngIf="!showCollections"></td>
|
||||||
<td bitCell [ngClass]="RowHeightClass" class="tw-text-right">
|
<td bitCell [ngClass]="RowHeightClass" class="tw-text-right">
|
||||||
<button
|
<button
|
||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
|
@ -47,6 +47,11 @@
|
|||||||
[allGroups]="groups"
|
[allGroups]="groups"
|
||||||
></app-group-badge>
|
></app-group-badge>
|
||||||
</td>
|
</td>
|
||||||
|
<td bitCell [ngClass]="RowHeightClass" *ngIf="showPermissionsColumn">
|
||||||
|
<p class="tw-mb-0 tw-text-muted">
|
||||||
|
{{ permissionText }}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
<td bitCell [ngClass]="RowHeightClass" class="tw-text-right">
|
<td bitCell [ngClass]="RowHeightClass" class="tw-text-right">
|
||||||
<button
|
<button
|
||||||
*ngIf="canEditCollection || canDeleteCollection"
|
*ngIf="canEditCollection || canDeleteCollection"
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
import { Component, EventEmitter, HostBinding, HostListener, Input, Output } from "@angular/core";
|
import {
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
HostBinding,
|
||||||
|
HostListener,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
} from "@angular/core";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||||
|
|
||||||
import { GroupView } from "../../../admin-console/organizations/core";
|
import { GroupView } from "../../../admin-console/organizations/core";
|
||||||
import { CollectionAdminView } from "../../core/views/collection-admin.view";
|
import { CollectionAdminView } from "../../core/views/collection-admin.view";
|
||||||
|
|
||||||
|
import {
|
||||||
|
convertToPermission,
|
||||||
|
getPermissionList,
|
||||||
|
Permission,
|
||||||
|
} from "./../../../admin-console/organizations/shared/components/access-selector/access-selector.models";
|
||||||
import { VaultItemEvent } from "./vault-item-event";
|
import { VaultItemEvent } from "./vault-item-event";
|
||||||
import { RowHeightClass } from "./vault-items.component";
|
import { RowHeightClass } from "./vault-items.component";
|
||||||
|
|
||||||
@ -14,7 +28,7 @@ import { RowHeightClass } from "./vault-items.component";
|
|||||||
selector: "tr[appVaultCollectionRow]",
|
selector: "tr[appVaultCollectionRow]",
|
||||||
templateUrl: "vault-collection-row.component.html",
|
templateUrl: "vault-collection-row.component.html",
|
||||||
})
|
})
|
||||||
export class VaultCollectionRowComponent {
|
export class VaultCollectionRowComponent implements OnInit {
|
||||||
protected RowHeightClass = RowHeightClass;
|
protected RowHeightClass = RowHeightClass;
|
||||||
|
|
||||||
@Input() disabled: boolean;
|
@Input() disabled: boolean;
|
||||||
@ -26,17 +40,25 @@ export class VaultCollectionRowComponent {
|
|||||||
@Input() canDeleteCollection: boolean;
|
@Input() canDeleteCollection: boolean;
|
||||||
@Input() organizations: Organization[];
|
@Input() organizations: Organization[];
|
||||||
@Input() groups: GroupView[];
|
@Input() groups: GroupView[];
|
||||||
|
@Input() showPermissionsColumn: boolean;
|
||||||
|
@Input() flexibleCollectionsEnabled: boolean;
|
||||||
|
|
||||||
@Output() onEvent = new EventEmitter<VaultItemEvent>();
|
@Output() onEvent = new EventEmitter<VaultItemEvent>();
|
||||||
|
|
||||||
@Input() checked: boolean;
|
@Input() checked: boolean;
|
||||||
@Output() checkedToggled = new EventEmitter<void>();
|
@Output() checkedToggled = new EventEmitter<void>();
|
||||||
|
|
||||||
|
private permissionList: Permission[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private activatedRoute: ActivatedRoute,
|
private i18nService: I18nService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.permissionList = getPermissionList(this.flexibleCollectionsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
@HostBinding("class")
|
@HostBinding("class")
|
||||||
get classes() {
|
get classes() {
|
||||||
return [].concat(this.disabled ? [] : ["tw-cursor-pointer"]);
|
return [].concat(this.disabled ? [] : ["tw-cursor-pointer"]);
|
||||||
@ -54,6 +76,16 @@ export class VaultCollectionRowComponent {
|
|||||||
return this.organizations.find((o) => o.id === this.collection.organizationId);
|
return this.organizations.find((o) => o.id === this.collection.organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get permissionText() {
|
||||||
|
if (!(this.collection as CollectionAdminView).assigned) {
|
||||||
|
return "-";
|
||||||
|
} else {
|
||||||
|
return this.i18nService.t(
|
||||||
|
this.permissionList.find((p) => p.perm === convertToPermission(this.collection))?.labelId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener("click")
|
@HostListener("click")
|
||||||
protected click() {
|
protected click() {
|
||||||
this.router.navigate([], {
|
this.router.navigate([], {
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
<th bitCell class="tw-w-2/5" *ngIf="showOwner">{{ "owner" | i18n }}</th>
|
<th bitCell class="tw-w-2/5" *ngIf="showOwner">{{ "owner" | i18n }}</th>
|
||||||
<th bitCell class="tw-w-2/5" *ngIf="showCollections">{{ "collections" | i18n }}</th>
|
<th bitCell class="tw-w-2/5" *ngIf="showCollections">{{ "collections" | i18n }}</th>
|
||||||
<th bitCell class="tw-w-2/5" *ngIf="showGroups">{{ "groups" | i18n }}</th>
|
<th bitCell class="tw-w-2/5" *ngIf="showGroups">{{ "groups" | i18n }}</th>
|
||||||
|
<th bitCell class="tw-w-2/5" *ngIf="showPermissionsColumn">
|
||||||
|
{{ "permission" | i18n }}
|
||||||
|
</th>
|
||||||
<th bitCell class="tw-w-12 tw-text-right">
|
<th bitCell class="tw-w-12 tw-text-right">
|
||||||
<button
|
<button
|
||||||
[disabled]="disabled || isEmpty"
|
[disabled]="disabled || isEmpty"
|
||||||
@ -79,10 +82,12 @@
|
|||||||
[showCollections]="showCollections"
|
[showCollections]="showCollections"
|
||||||
[showGroups]="showGroups"
|
[showGroups]="showGroups"
|
||||||
[organizations]="allOrganizations"
|
[organizations]="allOrganizations"
|
||||||
|
[showPermissionsColumn]="showPermissionsColumn"
|
||||||
[groups]="allGroups"
|
[groups]="allGroups"
|
||||||
[canDeleteCollection]="canDeleteCollection(item.collection)"
|
[canDeleteCollection]="canDeleteCollection(item.collection)"
|
||||||
[canEditCollection]="canEditCollection(item.collection)"
|
[canEditCollection]="canEditCollection(item.collection)"
|
||||||
[checked]="selection.isSelected(item)"
|
[checked]="selection.isSelected(item)"
|
||||||
|
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled"
|
||||||
(checkedToggled)="selection.toggle(item)"
|
(checkedToggled)="selection.toggle(item)"
|
||||||
(onEvent)="event($event)"
|
(onEvent)="event($event)"
|
||||||
></tr>
|
></tr>
|
||||||
|
@ -29,7 +29,7 @@ const MaxSelectionCount = 500;
|
|||||||
export class VaultItemsComponent {
|
export class VaultItemsComponent {
|
||||||
protected RowHeight = RowHeight;
|
protected RowHeight = RowHeight;
|
||||||
|
|
||||||
private flexibleCollectionsEnabled: boolean;
|
protected flexibleCollectionsEnabled: boolean;
|
||||||
|
|
||||||
@Input() disabled: boolean;
|
@Input() disabled: boolean;
|
||||||
@Input() showOwner: boolean;
|
@Input() showOwner: boolean;
|
||||||
@ -46,6 +46,7 @@ export class VaultItemsComponent {
|
|||||||
@Input() allCollections: CollectionView[] = [];
|
@Input() allCollections: CollectionView[] = [];
|
||||||
@Input() allGroups: GroupView[] = [];
|
@Input() allGroups: GroupView[] = [];
|
||||||
@Input() showBulkEditCollectionAccess = false;
|
@Input() showBulkEditCollectionAccess = false;
|
||||||
|
@Input() showPermissionsColumn = false;
|
||||||
|
|
||||||
private _ciphers?: CipherView[] = [];
|
private _ciphers?: CipherView[] = [];
|
||||||
@Input() get ciphers(): CipherView[] {
|
@Input() get ciphers(): CipherView[] {
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
import { Component, Input, OnDestroy, OnInit } from "@angular/core";
|
import { Component, Input, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { firstValueFrom, Subject } from "rxjs";
|
import { firstValueFrom, Subject } from "rxjs";
|
||||||
|
|
||||||
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||||
|
|
||||||
import { VaultFilterComponent as BaseVaultFilterComponent } from "../../individual-vault/vault-filter/components/vault-filter.component"; //../../vault/vault-filter/components/vault-filter.component";
|
import { VaultFilterComponent as BaseVaultFilterComponent } from "../../individual-vault/vault-filter/components/vault-filter.component"; //../../vault/vault-filter/components/vault-filter.component";
|
||||||
|
import { VaultFilterService } from "../../individual-vault/vault-filter/services/abstractions/vault-filter.service";
|
||||||
import {
|
import {
|
||||||
VaultFilterList,
|
VaultFilterList,
|
||||||
VaultFilterType,
|
VaultFilterType,
|
||||||
|
VaultFilterSection,
|
||||||
} from "../../individual-vault/vault-filter/shared/models/vault-filter-section.type";
|
} from "../../individual-vault/vault-filter/shared/models/vault-filter-section.type";
|
||||||
import { CollectionFilter } from "../../individual-vault/vault-filter/shared/models/vault-filter.type";
|
import { CollectionFilter } from "../../individual-vault/vault-filter/shared/models/vault-filter.type";
|
||||||
|
|
||||||
@ -25,7 +32,22 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On
|
|||||||
_organization: Organization;
|
_organization: Organization;
|
||||||
protected destroy$: Subject<void>;
|
protected destroy$: Subject<void>;
|
||||||
|
|
||||||
|
private flexibleCollectionsEnabled: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected vaultFilterService: VaultFilterService,
|
||||||
|
protected policyService: PolicyService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected configService: ConfigServiceAbstraction,
|
||||||
|
) {
|
||||||
|
super(vaultFilterService, policyService, i18nService, platformUtilsService);
|
||||||
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
this.flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
||||||
|
FeatureFlag.FlexibleCollections,
|
||||||
|
);
|
||||||
this.filters = await this.buildAllFilters();
|
this.filters = await this.buildAllFilters();
|
||||||
if (!this.activeFilter.selectedCipherTypeNode) {
|
if (!this.activeFilter.selectedCipherTypeNode) {
|
||||||
this.activeFilter.resetFilter();
|
this.activeFilter.resetFilter();
|
||||||
@ -40,10 +62,52 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On
|
|||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async removeCollapsibleCollection() {
|
||||||
|
const collapsedNodes = await firstValueFrom(this.vaultFilterService.collapsedFilterNodes$);
|
||||||
|
|
||||||
|
collapsedNodes.delete("AllCollections");
|
||||||
|
|
||||||
|
await this.vaultFilterService.setCollapsedFilterNodes(collapsedNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async addCollectionFilter(): Promise<VaultFilterSection> {
|
||||||
|
// Ensure the Collections filter is never collapsed for the org vault
|
||||||
|
this.removeCollapsibleCollection();
|
||||||
|
|
||||||
|
const collectionFilterSection: VaultFilterSection = {
|
||||||
|
data$: this.vaultFilterService.buildTypeTree(
|
||||||
|
{
|
||||||
|
id: "AllCollections",
|
||||||
|
name: "collections",
|
||||||
|
type: "all",
|
||||||
|
icon: "bwi-collection",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: "AllCollections",
|
||||||
|
name: "Collections",
|
||||||
|
type: "all",
|
||||||
|
icon: "bwi-collection",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
header: {
|
||||||
|
showHeader: false,
|
||||||
|
isSelectable: true,
|
||||||
|
},
|
||||||
|
action: this.applyCollectionFilter,
|
||||||
|
};
|
||||||
|
return collectionFilterSection;
|
||||||
|
}
|
||||||
|
|
||||||
async buildAllFilters(): Promise<VaultFilterList> {
|
async buildAllFilters(): Promise<VaultFilterList> {
|
||||||
const builderFilter = {} as VaultFilterList;
|
const builderFilter = {} as VaultFilterList;
|
||||||
builderFilter.typeFilter = await this.addTypeFilter(["favorites"]);
|
builderFilter.typeFilter = await this.addTypeFilter(["favorites"]);
|
||||||
builderFilter.collectionFilter = await this.addCollectionFilter();
|
if (this.flexibleCollectionsEnabled) {
|
||||||
|
builderFilter.collectionFilter = await this.addCollectionFilter();
|
||||||
|
} else {
|
||||||
|
builderFilter.collectionFilter = await super.addCollectionFilter();
|
||||||
|
}
|
||||||
builderFilter.trashFilter = await this.addTrashFilter();
|
builderFilter.trashFilter = await this.addTrashFilter();
|
||||||
return builderFilter;
|
return builderFilter;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,10 @@ export class VaultHeaderComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
|
const headerType = this.flexibleCollectionsEnabled
|
||||||
|
? this.i18nService.t("collections").toLowerCase()
|
||||||
|
: this.i18nService.t("vault").toLowerCase();
|
||||||
|
|
||||||
if (this.collection !== undefined) {
|
if (this.collection !== undefined) {
|
||||||
return this.collection.node.name;
|
return this.collection.node.name;
|
||||||
}
|
}
|
||||||
@ -84,7 +88,7 @@ export class VaultHeaderComponent {
|
|||||||
return this.i18nService.t("unassigned");
|
return this.i18nService.t("unassigned");
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${this.organization.name} ${this.i18nService.t("vault").toLowerCase()}`;
|
return `${this.organization.name} ${headerType}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get showBreadcrumbs() {
|
protected get showBreadcrumbs() {
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
[allGroups]="allGroups"
|
[allGroups]="allGroups"
|
||||||
[disabled]="loading"
|
[disabled]="loading"
|
||||||
[showOwner]="false"
|
[showOwner]="false"
|
||||||
|
[showPermissionsColumn]="true"
|
||||||
[showCollections]="filter.type !== undefined"
|
[showCollections]="filter.type !== undefined"
|
||||||
[showGroups]="
|
[showGroups]="
|
||||||
organization?.useGroups &&
|
organization?.useGroups &&
|
||||||
|
@ -46,6 +46,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
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 { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||||
@ -164,6 +165,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
private eventCollectionService: EventCollectionService,
|
private eventCollectionService: EventCollectionService,
|
||||||
private totpService: TotpService,
|
private totpService: TotpService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
private collectionService: CollectionService,
|
||||||
protected configService: ConfigServiceAbstraction,
|
protected configService: ConfigServiceAbstraction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -232,8 +234,26 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||||
|
|
||||||
const allCollectionsWithoutUnassigned$ = organizationId$.pipe(
|
const allCollectionsWithoutUnassigned$ = combineLatest([
|
||||||
switchMap((orgId) => this.collectionAdminService.getAll(orgId)),
|
organizationId$.pipe(switchMap((orgId) => this.collectionAdminService.getAll(orgId))),
|
||||||
|
this.collectionService.getAllDecrypted(),
|
||||||
|
]).pipe(
|
||||||
|
map(([adminCollections, syncCollections]) => {
|
||||||
|
const syncCollectionDict = Object.fromEntries(syncCollections.map((c) => [c.id, c]));
|
||||||
|
|
||||||
|
return adminCollections.map((collection) => {
|
||||||
|
const currentId: any = collection.id;
|
||||||
|
|
||||||
|
const match = syncCollectionDict[currentId];
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
collection.manage = match.manage;
|
||||||
|
collection.readOnly = match.readOnly;
|
||||||
|
collection.hidePasswords = match.hidePasswords;
|
||||||
|
}
|
||||||
|
return collection;
|
||||||
|
});
|
||||||
|
}),
|
||||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -454,7 +474,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
this.collections = collections;
|
this.collections = collections;
|
||||||
this.selectedCollection = selectedCollection;
|
this.selectedCollection = selectedCollection;
|
||||||
this.showMissingCollectionPermissionMessage = showMissingCollectionPermissionMessage;
|
this.showMissingCollectionPermissionMessage = showMissingCollectionPermissionMessage;
|
||||||
|
|
||||||
this.isEmpty = collections?.length === 0 && ciphers?.length === 0;
|
this.isEmpty = collections?.length === 0 && ciphers?.length === 0;
|
||||||
|
|
||||||
// This is a temporary fix to avoid double fetching collections.
|
// This is a temporary fix to avoid double fetching collections.
|
||||||
|
Loading…
Reference in New Issue
Block a user