mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 11:13:46 +00:00
[AC-2027] Update Flexible Collections logic to use organization property (#7445)
* Remove unused feature flag * Replace feature flag ref with org flag * Remove deprecated feature flag to discourage use * Add check to org.canCreateNewCollections * Adjust init logic of components to avoid race conditions * Make canCreateNewCollections logic more explicit * Resolve merge conflicts with vault changes * Update comments * Remove uses of old feature flag * Remove last of old feature flag * Clean up feature flag * Fix linting * Fix linting
This commit is contained in:
@@ -2,7 +2,6 @@ import { Injectable } from "@angular/core";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
|
||||
@@ -22,23 +21,6 @@ export class GroupService {
|
||||
protected configService: ConfigServiceAbstraction,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* TODO: This should be replaced with `GroupView.fromResponse` when `FeatureFlag.FlexibleCollections` is removed.
|
||||
**/
|
||||
protected async groupViewFromResponse(response: GroupResponse): Promise<GroupView> {
|
||||
const view = GroupView.fromResponse(response);
|
||||
|
||||
const hasFlexibleCollections = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
if (hasFlexibleCollections) {
|
||||
view.accessAll = false;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
async get(orgId: string, groupId: string): Promise<GroupView> {
|
||||
const r = await this.apiService.send(
|
||||
"GET",
|
||||
@@ -48,7 +30,7 @@ export class GroupService {
|
||||
true,
|
||||
);
|
||||
|
||||
return this.groupViewFromResponse(new GroupDetailsResponse(r));
|
||||
return GroupView.fromResponse(new GroupDetailsResponse(r));
|
||||
}
|
||||
|
||||
async getAll(orgId: string): Promise<GroupView[]> {
|
||||
@@ -62,7 +44,7 @@ export class GroupService {
|
||||
|
||||
const listResponse = new ListResponse(r, GroupDetailsResponse);
|
||||
|
||||
return Promise.all(listResponse.data?.map((gr) => this.groupViewFromResponse(gr))) ?? [];
|
||||
return Promise.all(listResponse.data?.map((gr) => GroupView.fromResponse(gr))) ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +101,7 @@ export class InternalGroupService extends GroupService {
|
||||
true,
|
||||
true,
|
||||
);
|
||||
return this.groupViewFromResponse(new GroupResponse(r));
|
||||
return GroupView.fromResponse(new GroupResponse(r));
|
||||
}
|
||||
|
||||
private async putGroup(
|
||||
@@ -134,6 +116,6 @@ export class InternalGroupService extends GroupService {
|
||||
true,
|
||||
true,
|
||||
);
|
||||
return this.groupViewFromResponse(new GroupResponse(r));
|
||||
return GroupView.fromResponse(new GroupResponse(r));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export class GroupResponse extends BaseResponse {
|
||||
name: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* To be removed alongside `FeatureFlag.FlexibleCollections`.
|
||||
* To be removed after Flexible Collections.
|
||||
**/
|
||||
accessAll: boolean;
|
||||
externalId: string;
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
OrganizationUserUpdateRequest,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
||||
import { OrganizationUserDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
|
||||
import { CoreOrganizationModule } from "../core-organization.module";
|
||||
@@ -78,12 +77,7 @@ export class UserAdminService {
|
||||
view.type = u.type;
|
||||
view.status = u.status;
|
||||
view.externalId = u.externalId;
|
||||
view.accessAll = (await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
))
|
||||
? false
|
||||
: u.accessAll;
|
||||
view.accessAll = u.accessAll;
|
||||
view.permissions = u.permissions;
|
||||
view.resetPasswordEnrolled = u.resetPasswordEnrolled;
|
||||
view.collections = u.collections.map((c) => ({
|
||||
|
||||
@@ -10,7 +10,7 @@ export class GroupView implements View {
|
||||
name: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* To be removed alongside `FeatureFlag.FlexibleCollections`.
|
||||
* To be removed after Flexible Collections.
|
||||
* This will always return `false` if Flexible Collections is enabled.
|
||||
**/
|
||||
accessAll: boolean;
|
||||
|
||||
@@ -15,7 +15,7 @@ export class OrganizationUserAdminView {
|
||||
externalId: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* To be removed alongside `FeatureFlag.FlexibleCollections`.
|
||||
* To be removed after Flexible Collections.
|
||||
* This will always return `false` if Flexible Collections is enabled.
|
||||
**/
|
||||
accessAll: boolean;
|
||||
|
||||
@@ -14,8 +14,7 @@ export class OrganizationUserView {
|
||||
status: OrganizationUserStatusType;
|
||||
/**
|
||||
* @deprecated
|
||||
* To be removed alongside `FeatureFlag.FlexibleCollections`.
|
||||
*
|
||||
* To be removed after Flexible Collections.
|
||||
* This will always return `false` if Flexible Collections is enabled.
|
||||
**/
|
||||
accessAll: boolean;
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
></app-organization-switcher>
|
||||
<bit-tab-nav-bar class="-tw-mb-px">
|
||||
<bit-tab-link
|
||||
*ngIf="
|
||||
canShowVaultTab(organization) && (flexibleCollectionsEnabled$ | async);
|
||||
else vaultTab
|
||||
"
|
||||
*ngIf="canShowVaultTab(organization) && organization.flexibleCollections; else vaultTab"
|
||||
route="vault"
|
||||
>{{ "collections" | i18n }}</bit-tab-link
|
||||
>
|
||||
|
||||
@@ -13,8 +13,6 @@ import {
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
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({
|
||||
selector: "app-organization-layout",
|
||||
@@ -25,15 +23,9 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
||||
|
||||
private _destroy = new Subject<void>();
|
||||
|
||||
protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private configService: ConfigServiceAbstraction,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
@@ -4,10 +4,9 @@ import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { catchError, combineLatest, from, map, of, Subject, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -80,10 +79,9 @@ export const openGroupAddEditDialog = (
|
||||
templateUrl: "group-add-edit.component.html",
|
||||
})
|
||||
export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
protected flexibleCollectionsEnabled$ = this.organizationService
|
||||
.get$(this.organizationId)
|
||||
.pipe(map((o) => o?.flexibleCollections));
|
||||
|
||||
protected PermissionMode = PermissionMode;
|
||||
protected ResultType = GroupAddEditDialogResultType;
|
||||
@@ -189,7 +187,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
private formBuilder: FormBuilder,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private dialogService: DialogService,
|
||||
private configService: ConfigServiceAbstraction,
|
||||
private organizationService: OrganizationService,
|
||||
) {
|
||||
this.tabIndex = params.initialTab ?? GroupAddEditTabType.Info;
|
||||
}
|
||||
|
||||
@@ -60,10 +60,7 @@
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="!(flexibleCollectionsEnabled$ | async)"
|
||||
class="tw-mb-2 tw-flex tw-items-baseline"
|
||||
>
|
||||
<div *ngIf="!flexibleCollectionsEnabled" class="tw-mb-2 tw-flex tw-items-baseline">
|
||||
<input
|
||||
type="radio"
|
||||
id="userTypeManager"
|
||||
@@ -141,7 +138,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
<ng-container *ngIf="customUserTypeSelected">
|
||||
<ng-container *ngIf="!(flexibleCollectionsEnabled$ | async); else customPermissionsFC">
|
||||
<ng-container *ngIf="!flexibleCollectionsEnabled; else customPermissionsFC">
|
||||
<h3 class="mt-4 d-flex tw-font-semibold">
|
||||
{{ "permissions" | i18n }}
|
||||
</h3>
|
||||
@@ -404,14 +401,14 @@
|
||||
[columnHeader]="'groups' | i18n"
|
||||
[selectorLabelText]="'selectGroups' | i18n"
|
||||
[emptySelectionText]="'noGroupsAdded' | i18n"
|
||||
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
|
||||
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled"
|
||||
></bit-access-selector>
|
||||
</bit-tab>
|
||||
<bit-tab [label]="'collections' | i18n">
|
||||
<div *ngIf="organization.useGroups" class="tw-mb-6">
|
||||
{{ "userPermissionOverrideHelper" | i18n }}
|
||||
</div>
|
||||
<div *ngIf="!(flexibleCollectionsEnabled$ | async)" class="tw-mb-6">
|
||||
<div *ngIf="!flexibleCollectionsEnabled" class="tw-mb-6">
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox formControlName="accessAllCollections" />
|
||||
<bit-label>
|
||||
@@ -437,7 +434,7 @@
|
||||
[columnHeader]="'collection' | i18n"
|
||||
[selectorLabelText]="'selectCollections' | i18n"
|
||||
[emptySelectionText]="'noCollectionsAdded' | i18n"
|
||||
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
|
||||
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled"
|
||||
></bit-access-selector
|
||||
></bit-tab>
|
||||
</bit-tab-group>
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
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";
|
||||
@@ -68,11 +67,6 @@ export enum MemberDialogResult {
|
||||
templateUrl: "member-dialog.component.html",
|
||||
})
|
||||
export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
|
||||
loading = true;
|
||||
editMode = false;
|
||||
isRevoked = false;
|
||||
@@ -521,6 +515,10 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
protected get flexibleCollectionsEnabled() {
|
||||
return this.organization?.flexibleCollections;
|
||||
}
|
||||
|
||||
protected readonly ProductType = ProductType;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,7 @@ import {
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { ProductType } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -126,7 +124,6 @@ export class PeopleComponent
|
||||
private router: Router,
|
||||
private groupService: GroupService,
|
||||
private collectionService: CollectionService,
|
||||
private configService: ConfigServiceAbstraction,
|
||||
) {
|
||||
super(
|
||||
apiService,
|
||||
@@ -244,18 +241,9 @@ export class PeopleComponent
|
||||
collectionsPromise,
|
||||
]);
|
||||
|
||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
|
||||
return usersResponse.data?.map<OrganizationUserView>((r) => {
|
||||
const userView = OrganizationUserView.fromResponse(r);
|
||||
|
||||
if (flexibleCollectionsEnabled) {
|
||||
userView.accessAll = false;
|
||||
}
|
||||
|
||||
userView.groupNames = userView.groups
|
||||
.map((g) => groupNamesMap.get(g))
|
||||
.sort(this.i18nService.collator?.compare);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
<form
|
||||
*ngIf="org && !loading && (flexibleCollectionsEnabled$ | async)"
|
||||
*ngIf="org && !loading && org.flexibleCollections"
|
||||
[bitSubmit]="submitCollectionManagement"
|
||||
[formGroup]="collectionManagementFormGroup"
|
||||
>
|
||||
|
||||
@@ -41,10 +41,6 @@ export class AccountComponent {
|
||||
canUseApi = false;
|
||||
org: OrganizationResponse;
|
||||
taxFormPromise: Promise<unknown>;
|
||||
flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollections,
|
||||
false,
|
||||
);
|
||||
flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.FlexibleCollectionsV1,
|
||||
false,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { map, switchMap } from "rxjs";
|
||||
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -36,7 +36,6 @@ export class OrganizationVaultExportComponent extends ExportComponent {
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogService,
|
||||
organizationService: OrganizationService,
|
||||
configService: ConfigServiceAbstraction,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -50,7 +49,6 @@ export class OrganizationVaultExportComponent extends ExportComponent {
|
||||
fileDownloadService,
|
||||
dialogService,
|
||||
organizationService,
|
||||
configService,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,6 +61,12 @@ export class OrganizationVaultExportComponent extends ExportComponent {
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
});
|
||||
|
||||
this.flexibleCollectionsEnabled$ = this.route.parent.parent.params.pipe(
|
||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
map((organization) => organization.flexibleCollections),
|
||||
);
|
||||
|
||||
await super.ngOnInit();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user