1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-25 12:15:18 +01:00

[AC-2647] Remove Flexible Collections MVP code (#9518)

* chore: organization.ts, remove refs to flexibleCollections and isManager, refs AC-2647

* chore: clean up callers of removed methods from organization.ts, refs AC-2647

* chore: access-selector, remove fc input and update permissionList param, refs AC-2647

* chore: update permissionList caller, update group-add-edit fc refs, and remove accessAll, refs AC-2647

* chore: update member-dialog fc callers, refs AC-2647

* chore: update bulk-collections-dialog fc callers, refs AC-2647

* chore: update collection-dialog fc callers, refs AC-2647

* chore: update simple fc caller to misc files, refs AC-2647

* chore: update member-dialog fc callers, refs AC-2647

* chore: remove accessAll references and update callers, refs AC-2647

* chore: update comment to specify v1 usage, refs AC-2647

* chore: remove unused message keys and code calls to use those messages, refs AC-2647

* chore: remove readonly false from access-selector model map function, refs AC-2647
This commit is contained in:
Vincent Salucci 2024-06-10 11:59:20 -05:00 committed by GitHub
parent 19f2d2aefc
commit b169207b74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 106 additions and 453 deletions

View File

@ -80,7 +80,6 @@ export class InternalGroupService extends GroupService {
async save(group: GroupView): Promise<GroupView> { async save(group: GroupView): Promise<GroupView> {
const request = new GroupRequest(); const request = new GroupRequest();
request.name = group.name; request.name = group.name;
request.accessAll = group.accessAll;
request.users = group.members; request.users = group.members;
request.collections = group.collections.map( request.collections = group.collections.map(
(c) => new SelectionReadOnlyRequest(c.id, c.readOnly, c.hidePasswords, c.manage), (c) => new SelectionReadOnlyRequest(c.id, c.readOnly, c.hidePasswords, c.manage),

View File

@ -2,7 +2,6 @@ import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models
export class GroupRequest { export class GroupRequest {
name: string; name: string;
accessAll: boolean;
collections: SelectionReadOnlyRequest[] = []; collections: SelectionReadOnlyRequest[] = [];
users: string[] = []; users: string[] = [];
} }

View File

@ -5,11 +5,6 @@ export class GroupResponse extends BaseResponse {
id: string; id: string;
organizationId: string; organizationId: string;
name: string; name: string;
/**
* @deprecated
* To be removed after Flexible Collections.
**/
accessAll: boolean;
externalId: string; externalId: string;
constructor(response: any) { constructor(response: any) {
@ -17,7 +12,6 @@ export class GroupResponse extends BaseResponse {
this.id = this.getResponseProperty("Id"); this.id = this.getResponseProperty("Id");
this.organizationId = this.getResponseProperty("OrganizationId"); this.organizationId = this.getResponseProperty("OrganizationId");
this.name = this.getResponseProperty("Name"); this.name = this.getResponseProperty("Name");
this.accessAll = this.getResponseProperty("AccessAll");
this.externalId = this.getResponseProperty("ExternalId"); this.externalId = this.getResponseProperty("ExternalId");
} }
} }

View File

@ -41,7 +41,6 @@ export class UserAdminService {
async save(user: OrganizationUserAdminView): Promise<void> { async save(user: OrganizationUserAdminView): Promise<void> {
const request = new OrganizationUserUpdateRequest(); const request = new OrganizationUserUpdateRequest();
request.accessAll = user.accessAll;
request.permissions = user.permissions; request.permissions = user.permissions;
request.type = user.type; request.type = user.type;
request.collections = user.collections; request.collections = user.collections;
@ -54,7 +53,6 @@ export class UserAdminService {
async invite(emails: string[], user: OrganizationUserAdminView): Promise<void> { async invite(emails: string[], user: OrganizationUserAdminView): Promise<void> {
const request = new OrganizationUserInviteRequest(); const request = new OrganizationUserInviteRequest();
request.emails = emails; request.emails = emails;
request.accessAll = user.accessAll;
request.permissions = user.permissions; request.permissions = user.permissions;
request.type = user.type; request.type = user.type;
request.collections = user.collections; request.collections = user.collections;
@ -77,7 +75,6 @@ export class UserAdminService {
view.type = u.type; view.type = u.type;
view.status = u.status; view.status = u.status;
view.externalId = u.externalId; view.externalId = u.externalId;
view.accessAll = u.accessAll;
view.permissions = u.permissions; view.permissions = u.permissions;
view.resetPasswordEnrolled = u.resetPasswordEnrolled; view.resetPasswordEnrolled = u.resetPasswordEnrolled;
view.collections = u.collections.map((c) => ({ view.collections = u.collections.map((c) => ({

View File

@ -8,12 +8,6 @@ export class GroupView implements View {
id: string; id: string;
organizationId: string; organizationId: string;
name: string; name: string;
/**
* @deprecated
* To be removed after Flexible Collections.
* This will always return `false` if Flexible Collections is enabled.
**/
accessAll: boolean;
externalId: string; externalId: string;
collections: CollectionAccessSelectionView[] = []; collections: CollectionAccessSelectionView[] = [];
members: string[] = []; members: string[] = [];

View File

@ -13,12 +13,6 @@ export class OrganizationUserAdminView {
type: OrganizationUserType; type: OrganizationUserType;
status: OrganizationUserStatusType; status: OrganizationUserStatusType;
externalId: string; externalId: string;
/**
* @deprecated
* To be removed after Flexible Collections.
* This will always return `false` if Flexible Collections is enabled.
**/
accessAll: boolean;
permissions: PermissionsApi; permissions: PermissionsApi;
resetPasswordEnrolled: boolean; resetPasswordEnrolled: boolean;
hasMasterPassword: boolean; hasMasterPassword: boolean;

View File

@ -12,12 +12,6 @@ export class OrganizationUserView {
userId: string; userId: string;
type: OrganizationUserType; type: OrganizationUserType;
status: OrganizationUserStatusType; status: OrganizationUserStatusType;
/**
* @deprecated
* To be removed after Flexible Collections.
* This will always return `false` if Flexible Collections is enabled.
**/
accessAll: boolean;
permissions: PermissionsApi; permissions: PermissionsApi;
resetPasswordEnrolled: boolean; resetPasswordEnrolled: boolean;
name: string; name: string;

View File

@ -11,7 +11,7 @@
<bit-nav-item <bit-nav-item
icon="bwi-collection" icon="bwi-collection"
[text]="(organization.flexibleCollections ? 'collections' : 'vault') | i18n" [text]="'collections' | i18n"
route="vault" route="vault"
*ngIf="canShowVaultTab(organization)" *ngIf="canShowVaultTab(organization)"
> >

View File

@ -45,7 +45,6 @@
[columnHeader]="'member' | i18n" [columnHeader]="'member' | i18n"
[selectorLabelText]="'selectMembers' | i18n" [selectorLabelText]="'selectMembers' | i18n"
[emptySelectionText]="'noMembersAdded' | i18n" [emptySelectionText]="'noMembersAdded' | i18n"
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
></bit-access-selector> ></bit-access-selector>
</bit-tab> </bit-tab>
@ -56,24 +55,14 @@
{{ "restrictedCollectionAssignmentDesc" | i18n }} {{ "restrictedCollectionAssignmentDesc" | i18n }}
</span> </span>
</p> </p>
<div *ngIf="!(flexibleCollectionsEnabled$ | async)" class="tw-my-3"> <bit-access-selector
<input type="checkbox" formControlName="accessAll" id="accessAll" /> formControlName="collections"
<label class="tw-mb-0 tw-text-lg" for="accessAll">{{ [items]="collections"
"accessAllCollectionsDesc" | i18n [permissionMode]="PermissionMode.Edit"
}}</label> [columnHeader]="'collection' | i18n"
<p class="tw-my-0 tw-text-muted">{{ "accessAllCollectionsHelp" | i18n }}</p> [selectorLabelText]="'selectCollections' | i18n"
</div> [emptySelectionText]="'noCollectionsAdded' | i18n"
<ng-container *ngIf="!groupForm.value.accessAll"> ></bit-access-selector>
<bit-access-selector
formControlName="collections"
[items]="collections"
[permissionMode]="PermissionMode.Edit"
[columnHeader]="'collection' | i18n"
[selectorLabelText]="'selectCollections' | i18n"
[emptySelectionText]="'noCollectionsAdded' | i18n"
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
></bit-access-selector>
</ng-container>
</bit-tab> </bit-tab>
</bit-tab-group> </bit-tab-group>
</div> </div>

View File

@ -96,9 +96,6 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
private organization$ = this.organizationService private organization$ = this.organizationService
.get$(this.organizationId) .get$(this.organizationId)
.pipe(shareReplay({ refCount: true })); .pipe(shareReplay({ refCount: true }));
protected flexibleCollectionsEnabled$ = this.organization$.pipe(
map((o) => o?.flexibleCollections),
);
private flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$( private flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$(
FeatureFlag.FlexibleCollectionsV1, FeatureFlag.FlexibleCollectionsV1,
); );
@ -114,7 +111,6 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
group: GroupView; group: GroupView;
groupForm = this.formBuilder.group({ groupForm = this.formBuilder.group({
accessAll: [false],
name: ["", [Validators.required, Validators.maxLength(100)]], name: ["", [Validators.required, Validators.maxLength(100)]],
externalId: this.formBuilder.control({ value: "", disabled: true }), externalId: this.formBuilder.control({ value: "", disabled: true }),
members: [[] as AccessItemValue[]], members: [[] as AccessItemValue[]],
@ -188,7 +184,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
this.flexibleCollectionsV1Enabled$, this.flexibleCollectionsV1Enabled$,
]).pipe( ]).pipe(
map(([organization, flexibleCollectionsV1Enabled]) => { map(([organization, flexibleCollectionsV1Enabled]) => {
if (!flexibleCollectionsV1Enabled || !organization.flexibleCollections) { if (!flexibleCollectionsV1Enabled) {
return true; return true;
} }
@ -276,7 +272,6 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
this.groupForm.patchValue({ this.groupForm.patchValue({
name: this.group.name, name: this.group.name,
externalId: this.group.externalId, externalId: this.group.externalId,
accessAll: this.group.accessAll,
members: this.group.members.map((m) => ({ members: this.group.members.map((m) => ({
id: m, id: m,
type: AccessItemType.Member, type: AccessItemType.Member,
@ -328,12 +323,8 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
const formValue = this.groupForm.value; const formValue = this.groupForm.value;
groupView.name = formValue.name; groupView.name = formValue.name;
groupView.accessAll = formValue.accessAll;
groupView.members = formValue.members?.map((m) => m.id) ?? []; groupView.members = formValue.members?.map((m) => m.id) ?? [];
groupView.collections = formValue.collections.map((c) => convertToSelectionView(c));
if (!groupView.accessAll) {
groupView.collections = formValue.collections.map((c) => convertToSelectionView(c));
}
await this.groupService.save(groupView); await this.groupService.save(groupView);

View File

@ -74,12 +74,10 @@
</td> </td>
<td bitCell (click)="edit(g, ModalTabType.Collections)" class="tw-cursor-pointer"> <td bitCell (click)="edit(g, ModalTabType.Collections)" class="tw-cursor-pointer">
<bit-badge-list <bit-badge-list
*ngIf="!g.details.accessAll"
[items]="g.collectionNames" [items]="g.collectionNames"
[maxItems]="3" [maxItems]="3"
variant="secondary" variant="secondary"
></bit-badge-list> ></bit-badge-list>
<span *ngIf="g.details.accessAll">{{ "all" | i18n }}</span>
</td> </td>
<td bitCell> <td bitCell>
<button <button

View File

@ -49,14 +49,6 @@
<bit-label>{{ "user" | i18n }}</bit-label> <bit-label>{{ "user" | i18n }}</bit-label>
<bit-hint>{{ "userDesc" | i18n }}</bit-hint> <bit-hint>{{ "userDesc" | i18n }}</bit-hint>
</bit-radio-button> </bit-radio-button>
<bit-radio-button
*ngIf="!organization.flexibleCollections"
id="userTypeManager"
[value]="organizationUserType.Manager"
>
<bit-label>{{ "manager" | i18n }}</bit-label>
<bit-hint>{{ "managerDesc" | i18n }}</bit-hint>
</bit-radio-button>
<bit-radio-button id="userTypeAdmin" [value]="organizationUserType.Admin"> <bit-radio-button id="userTypeAdmin" [value]="organizationUserType.Admin">
<bit-label>{{ "admin" | i18n }}</bit-label> <bit-label>{{ "admin" | i18n }}</bit-label>
<bit-hint>{{ "adminDesc" | i18n }}</bit-hint> <bit-hint>{{ "adminDesc" | i18n }}</bit-hint>
@ -91,140 +83,64 @@
</bit-radio-button> </bit-radio-button>
</bit-radio-group> </bit-radio-group>
<ng-container *ngIf="customUserTypeSelected"> <ng-container *ngIf="customUserTypeSelected">
<ng-container *ngIf="!organization.flexibleCollections; else customPermissionsFC"> <div class="tw-grid tw-grid-cols-12 tw-gap-4" [formGroup]="permissionsGroup">
<h3 bitTypography="h3"> <div class="tw-col-span-4">
{{ "permissions" | i18n }} <bit-form-control>
</h3> <input type="checkbox" bitCheckbox formControlName="accessEventLogs" />
<div class="tw-grid tw-grid-cols-12 tw-gap-4" [formGroup]="permissionsGroup"> <bit-label>{{ "accessEventLogs" | i18n }}</bit-label>
<div class="tw-col-span-6"> </bit-form-control>
<div class="tw-mb-3"> <bit-form-control>
<bit-label class="tw-font-semibold">{{ <input type="checkbox" bitCheckbox formControlName="accessImportExport" />
"managerPermissions" | i18n <bit-label>{{ "accessImportExport" | i18n }}</bit-label>
}}</bit-label> </bit-form-control>
<hr class="tw-mb-2 tw-mr-2 tw-mt-0" /> <bit-form-control>
<app-nested-checkbox <input type="checkbox" bitCheckbox formControlName="accessReports" />
parentId="manageAssignedCollections" <bit-label>{{ "accessReports" | i18n }}</bit-label>
[checkboxes]="permissionsGroup.controls.manageAssignedCollectionsGroup" </bit-form-control>
> </div>
</app-nested-checkbox> <div class="tw-col-span-4">
</div> <app-nested-checkbox
</div> parentId="manageAllCollections"
<div class="tw-col-span-6"> [checkboxes]="permissionsGroup.controls.manageAllCollectionsGroup"
<div class="tw-mb-3"> >
<bit-label class="tw-font-semibold">{{ "adminPermissions" | i18n }}</bit-label> </app-nested-checkbox>
<hr class="tw-mb-2 tw-mr-2 tw-mt-0" /> </div>
<bit-form-control> <div class="tw-col-span-4">
<input type="checkbox" bitCheckbox formControlName="accessEventLogs" /> <div class="tw-mb-3">
<bit-label>{{ "accessEventLogs" | i18n }}</bit-label> <bit-form-control>
</bit-form-control> <input type="checkbox" bitCheckbox formControlName="manageGroups" />
<bit-form-control> <bit-label>{{ "manageGroups" | i18n }}</bit-label>
<input type="checkbox" bitCheckbox formControlName="accessImportExport" /> </bit-form-control>
<bit-label>{{ "accessImportExport" | i18n }}</bit-label> <bit-form-control>
</bit-form-control> <input type="checkbox" bitCheckbox formControlName="manageSso" />
<bit-form-control> <bit-label>{{ "manageSso" | i18n }}</bit-label>
<input type="checkbox" bitCheckbox formControlName="accessReports" /> </bit-form-control>
<bit-label>{{ "accessReports" | i18n }}</bit-label> <bit-form-control>
</bit-form-control> <input type="checkbox" bitCheckbox formControlName="managePolicies" />
<app-nested-checkbox <bit-label>{{ "managePolicies" | i18n }}</bit-label>
parentId="manageAllCollections" </bit-form-control>
[checkboxes]="permissionsGroup.controls.manageAllCollectionsGroup" <bit-form-control>
> <input
</app-nested-checkbox> id="manageUsers"
<bit-form-control> type="checkbox"
<input type="checkbox" bitCheckbox formControlName="manageGroups" /> bitCheckbox
<bit-label>{{ "manageGroups" | i18n }}</bit-label> formControlName="manageUsers"
</bit-form-control> (change)="handleDependentPermissions()"
<bit-form-control> />
<input type="checkbox" bitCheckbox formControlName="manageSso" /> <bit-label>{{ "manageUsers" | i18n }}</bit-label>
<bit-label>{{ "manageSso" | i18n }}</bit-label> </bit-form-control>
</bit-form-control> <bit-form-control>
<bit-form-control> <input
<input type="checkbox" bitCheckbox formControlName="managePolicies" /> type="checkbox"
<bit-label>{{ "managePolicies" | i18n }}</bit-label> bitCheckbox
</bit-form-control> formControlName="manageResetPassword"
<bit-form-control> (change)="handleDependentPermissions()"
<input />
id="manageUsers" <bit-label>{{ "manageAccountRecovery" | i18n }}</bit-label>
type="checkbox" </bit-form-control>
bitCheckbox
formControlName="manageUsers"
(change)="handleDependentPermissions()"
/>
<bit-label>{{ "manageUsers" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input
type="checkbox"
bitCheckbox
formControlName="manageResetPassword"
(change)="handleDependentPermissions()"
/>
<bit-label>{{ "manageAccountRecovery" | i18n }}</bit-label>
</bit-form-control>
</div>
</div> </div>
</div> </div>
</ng-container> </div>
<ng-template #customPermissionsFC>
<div class="tw-grid tw-grid-cols-12 tw-gap-4" [formGroup]="permissionsGroup">
<div class="tw-col-span-4">
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="accessEventLogs" />
<bit-label>{{ "accessEventLogs" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="accessImportExport" />
<bit-label>{{ "accessImportExport" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="accessReports" />
<bit-label>{{ "accessReports" | i18n }}</bit-label>
</bit-form-control>
</div>
<div class="tw-col-span-4">
<app-nested-checkbox
parentId="manageAllCollections"
[checkboxes]="permissionsGroup.controls.manageAllCollectionsGroup"
>
</app-nested-checkbox>
</div>
<div class="tw-col-span-4">
<div class="tw-mb-3">
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="manageGroups" />
<bit-label>{{ "manageGroups" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="manageSso" />
<bit-label>{{ "manageSso" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="managePolicies" />
<bit-label>{{ "managePolicies" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input
id="manageUsers"
type="checkbox"
bitCheckbox
formControlName="manageUsers"
(change)="handleDependentPermissions()"
/>
<bit-label>{{ "manageUsers" | i18n }}</bit-label>
</bit-form-control>
<bit-form-control>
<input
type="checkbox"
bitCheckbox
formControlName="manageResetPassword"
(change)="handleDependentPermissions()"
/>
<bit-label>{{ "manageAccountRecovery" | i18n }}</bit-label>
</bit-form-control>
</div>
</div>
</div>
</ng-template>
</ng-container> </ng-container>
<ng-container *ngIf="organization.useSecretsManager"> <ng-container *ngIf="organization.useSecretsManager">
<h3 class="tw-mt-4"> <h3 class="tw-mt-4">
@ -272,7 +188,6 @@
[columnHeader]="'groups' | i18n" [columnHeader]="'groups' | i18n"
[selectorLabelText]="'selectGroups' | i18n" [selectorLabelText]="'selectGroups' | i18n"
[emptySelectionText]="'noGroupsAdded' | i18n" [emptySelectionText]="'noGroupsAdded' | i18n"
[flexibleCollectionsEnabled]="organization.flexibleCollections"
[hideMultiSelect]="restrictEditingSelf$ | async" [hideMultiSelect]="restrictEditingSelf$ | async"
></bit-access-selector> ></bit-access-selector>
</bit-tab> </bit-tab>
@ -294,26 +209,7 @@
{{ "restrictedCollectionAssignmentDesc" | i18n }} {{ "restrictedCollectionAssignmentDesc" | i18n }}
</span> </span>
</div> </div>
<div *ngIf="!organization.flexibleCollections" class="tw-mb-6">
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="accessAllCollections" />
<bit-label>
{{ "accessAllCollectionsDesc" | i18n }}
<a
bitLink
target="_blank"
rel="noreferrer"
appA11yTitle="{{ 'learnMore' | i18n }}"
href="https://bitwarden.com/help/user-types-access-control/#access-control"
>
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
</a>
</bit-label>
<bit-hint>{{ "accessAllCollectionsHelp" | i18n }}</bit-hint>
</bit-form-control>
</div>
<bit-access-selector <bit-access-selector
*ngIf="!accessAllCollections"
[permissionMode]="PermissionMode.Edit" [permissionMode]="PermissionMode.Edit"
formControlName="access" formControlName="access"
[showGroupColumn]="organization.useGroups" [showGroupColumn]="organization.useGroups"
@ -321,7 +217,6 @@
[columnHeader]="'collection' | i18n" [columnHeader]="'collection' | i18n"
[selectorLabelText]="'selectCollections' | i18n" [selectorLabelText]="'selectCollections' | i18n"
[emptySelectionText]="'noCollectionsAdded' | i18n" [emptySelectionText]="'noCollectionsAdded' | i18n"
[flexibleCollectionsEnabled]="organization.flexibleCollections"
[hideMultiSelect]="restrictEditingSelf$ | async" [hideMultiSelect]="restrictEditingSelf$ | async"
></bit-access-selector ></bit-access-selector
></bit-tab> ></bit-tab>

View File

@ -99,7 +99,6 @@ export class MemberDialogComponent implements OnDestroy {
emails: [""], emails: [""],
type: OrganizationUserType.User, type: OrganizationUserType.User,
externalId: this.formBuilder.control({ value: "", disabled: true }), externalId: this.formBuilder.control({ value: "", disabled: true }),
accessAllCollections: false,
accessSecretsManager: false, accessSecretsManager: false,
access: [[] as AccessItemValue[]], access: [[] as AccessItemValue[]],
groups: [[] as AccessItemValue[]], groups: [[] as AccessItemValue[]],
@ -110,11 +109,6 @@ export class MemberDialogComponent implements OnDestroy {
protected canAssignAccessToAnyCollection$: Observable<boolean>; protected canAssignAccessToAnyCollection$: Observable<boolean>;
protected permissionsGroup = this.formBuilder.group({ protected permissionsGroup = this.formBuilder.group({
manageAssignedCollectionsGroup: this.formBuilder.group<Record<string, boolean>>({
manageAssignedCollections: false,
editAssignedCollections: false,
deleteAssignedCollections: false,
}),
manageAllCollectionsGroup: this.formBuilder.group<Record<string, boolean>>({ manageAllCollectionsGroup: this.formBuilder.group<Record<string, boolean>>({
manageAllCollections: false, manageAllCollections: false,
createNewCollections: false, createNewCollections: false,
@ -137,10 +131,6 @@ export class MemberDialogComponent implements OnDestroy {
return this.formGroup.value.type === OrganizationUserType.Custom; return this.formGroup.value.type === OrganizationUserType.Custom;
} }
get accessAllCollections(): boolean {
return this.formGroup.value.accessAllCollections;
}
constructor( constructor(
@Inject(DIALOG_DATA) protected params: MemberDialogParams, @Inject(DIALOG_DATA) protected params: MemberDialogParams,
private dialogRef: DialogRef<MemberDialogResult>, private dialogRef: DialogRef<MemberDialogResult>,
@ -189,7 +179,7 @@ export class MemberDialogComponent implements OnDestroy {
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1), this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1),
]).pipe( ]).pipe(
map(([organization, flexibleCollectionsV1Enabled]) => { map(([organization, flexibleCollectionsV1Enabled]) => {
if (!flexibleCollectionsV1Enabled || !organization.flexibleCollections) { if (!flexibleCollectionsV1Enabled) {
return true; return true;
} }
@ -316,13 +306,6 @@ export class MemberDialogComponent implements OnDestroy {
this.showNoMasterPasswordWarning = this.showNoMasterPasswordWarning =
userDetails.status > OrganizationUserStatusType.Invited && userDetails.status > OrganizationUserStatusType.Invited &&
userDetails.hasMasterPassword === false; userDetails.hasMasterPassword === false;
const assignedCollectionsPermissions = {
editAssignedCollections: userDetails.permissions.editAssignedCollections,
deleteAssignedCollections: userDetails.permissions.deleteAssignedCollections,
manageAssignedCollections:
userDetails.permissions.editAssignedCollections &&
userDetails.permissions.deleteAssignedCollections,
};
const allCollectionsPermissions = { const allCollectionsPermissions = {
createNewCollections: userDetails.permissions.createNewCollections, createNewCollections: userDetails.permissions.createNewCollections,
editAnyCollection: userDetails.permissions.editAnyCollection, editAnyCollection: userDetails.permissions.editAnyCollection,
@ -342,7 +325,6 @@ export class MemberDialogComponent implements OnDestroy {
managePolicies: userDetails.permissions.managePolicies, managePolicies: userDetails.permissions.managePolicies,
manageUsers: userDetails.permissions.manageUsers, manageUsers: userDetails.permissions.manageUsers,
manageResetPassword: userDetails.permissions.manageResetPassword, manageResetPassword: userDetails.permissions.manageResetPassword,
manageAssignedCollectionsGroup: assignedCollectionsPermissions,
manageAllCollectionsGroup: allCollectionsPermissions, manageAllCollectionsGroup: allCollectionsPermissions,
}); });
} }
@ -378,7 +360,6 @@ export class MemberDialogComponent implements OnDestroy {
this.formGroup.patchValue({ this.formGroup.patchValue({
type: userDetails.type, type: userDetails.type,
externalId: userDetails.externalId, externalId: userDetails.externalId,
accessAllCollections: userDetails.accessAll,
access: accessSelections, access: accessSelections,
accessSecretsManager: userDetails.accessSecretsManager, accessSecretsManager: userDetails.accessSecretsManager,
groups: groupAccessSelections, groups: groupAccessSelections,
@ -414,10 +395,6 @@ export class MemberDialogComponent implements OnDestroy {
editAnyCollection: this.permissionsGroup.value.manageAllCollectionsGroup.editAnyCollection, editAnyCollection: this.permissionsGroup.value.manageAllCollectionsGroup.editAnyCollection,
deleteAnyCollection: deleteAnyCollection:
this.permissionsGroup.value.manageAllCollectionsGroup.deleteAnyCollection, this.permissionsGroup.value.manageAllCollectionsGroup.deleteAnyCollection,
editAssignedCollections:
this.permissionsGroup.value.manageAssignedCollectionsGroup.editAssignedCollections,
deleteAssignedCollections:
this.permissionsGroup.value.manageAssignedCollectionsGroup.deleteAssignedCollections,
}; };
return Object.assign(p, partialPermissions); return Object.assign(p, partialPermissions);
@ -467,7 +444,6 @@ export class MemberDialogComponent implements OnDestroy {
const userView = new OrganizationUserAdminView(); const userView = new OrganizationUserAdminView();
userView.id = this.params.organizationUserId; userView.id = this.params.organizationUserId;
userView.organizationId = this.params.organizationId; userView.organizationId = this.params.organizationId;
userView.accessAll = this.accessAllCollections;
userView.type = this.formGroup.value.type; userView.type = this.formGroup.value.type;
userView.permissions = this.setRequestPermissions( userView.permissions = this.setRequestPermissions(
userView.permissions ?? new PermissionsApi(), userView.permissions ?? new PermissionsApi(),

View File

@ -190,12 +190,10 @@
class="tw-cursor-pointer" class="tw-cursor-pointer"
> >
<bit-badge-list <bit-badge-list
*ngIf="organization.useGroups || !u.accessAll"
[items]="organization.useGroups ? u.groupNames : u.collectionNames" [items]="organization.useGroups ? u.groupNames : u.collectionNames"
[maxItems]="3" [maxItems]="3"
variant="secondary" variant="secondary"
></bit-badge-list> ></bit-badge-list>
<span *ngIf="!organization.useGroups && u.accessAll">{{ "all" | i18n }}</span>
</td> </td>
<td <td

View File

@ -51,7 +51,7 @@
</button> </button>
</ng-container> </ng-container>
<form <form
*ngIf="org && !loading && org.flexibleCollections" *ngIf="org && !loading"
[bitSubmit]="submitCollectionManagement" [bitSubmit]="submitCollectionManagement"
[formGroup]="collectionManagementFormGroup" [formGroup]="collectionManagementFormGroup"
> >

View File

@ -110,15 +110,6 @@
</ng-container> </ng-container>
<ng-template #readOnlyPerm> <ng-template #readOnlyPerm>
<div
*ngIf="item.accessAllItems"
class="tw-max-w-40 tw-overflow-hidden tw-overflow-ellipsis tw-whitespace-nowrap tw-border tw-border-solid tw-border-transparent tw-font-bold tw-text-muted"
[appA11yTitle]="accessAllLabelId(item) | i18n"
>
{{ "canEdit" | i18n }}
<i class="bwi bwi-filter tw-ml-1" aria-hidden="true"></i>
</div>
<div <div
*ngIf="item.readonly || disabled" *ngIf="item.readonly || disabled"
class="tw-max-w-40 tw-overflow-hidden tw-overflow-ellipsis tw-whitespace-nowrap tw-font-bold tw-text-muted" class="tw-max-w-40 tw-overflow-hidden tw-overflow-ellipsis tw-whitespace-nowrap tw-font-bold tw-text-muted"

View File

@ -75,7 +75,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
// The enable() above also enables the permission control, so we need to disable it again // The enable() above also enables the permission control, so we need to disable it again
// Disable permission control if accessAllItems is enabled or not in Edit mode // Disable permission control if accessAllItems is enabled or not in Edit mode
if (item.accessAllItems || this.permissionMode != PermissionMode.Edit) { if (this.permissionMode != PermissionMode.Edit) {
controlRow.controls.permission.disable(); controlRow.controls.permission.disable();
} }
} }
@ -196,21 +196,11 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
*/ */
@Input() showGroupColumn: boolean; @Input() showGroupColumn: boolean;
/**
* Enable Flexible Collections changes (feature flag)
*/
@Input() set flexibleCollectionsEnabled(value: boolean) {
this._flexibleCollectionsEnabled = value;
this.permissionList = getPermissionList(value);
}
/** /**
* Hide the multi-select so that new items cannot be added * Hide the multi-select so that new items cannot be added
*/ */
@Input() hideMultiSelect = false; @Input() hideMultiSelect = false;
private _flexibleCollectionsEnabled: boolean;
constructor( constructor(
private readonly formBuilder: FormBuilder, private readonly formBuilder: FormBuilder,
private readonly i18nService: I18nService, private readonly i18nService: I18nService,
@ -275,7 +265,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
} }
async ngOnInit() { async ngOnInit() {
this.permissionList = getPermissionList(this._flexibleCollectionsEnabled); this.permissionList = getPermissionList();
// 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) {
@ -328,12 +318,8 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On
return this.permissionList.find((p) => p.perm == perm)?.labelId; return this.permissionList.find((p) => p.perm == perm)?.labelId;
} }
protected accessAllLabelId(item: AccessItemView) {
return item.type == AccessItemType.Group ? "groupAccessAll" : "memberAccessAll";
}
protected canEditItemPermission(item: AccessItemView) { protected canEditItemPermission(item: AccessItemView) {
return this.permissionMode == PermissionMode.Edit && !item.readonly && !item.accessAllItems; return this.permissionMode == PermissionMode.Edit && !item.readonly;
} }
private _itemComparator(a: AccessItemView, b: AccessItemView) { private _itemComparator(a: AccessItemView, b: AccessItemView) {

View File

@ -34,12 +34,6 @@ export enum AccessItemType {
* *
*/ */
export type AccessItemView = SelectItemView & { export type AccessItemView = SelectItemView & {
/**
* Flag that this group/member can access all items.
* This will disable the permission editor for this item.
*/
accessAllItems?: boolean;
/** /**
* Flag that this item cannot be modified. * Flag that this item cannot be modified.
* This will disable the permission editor and will keep * This will disable the permission editor and will keep
@ -82,16 +76,14 @@ export type Permission = {
labelId: string; labelId: string;
}; };
export const getPermissionList = (flexibleCollectionsEnabled: boolean): Permission[] => { export const getPermissionList = (): Permission[] => {
const permissions = [ const permissions = [
{ perm: CollectionPermission.View, labelId: "canView" }, { perm: CollectionPermission.View, labelId: "canView" },
{ perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" }, { perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" },
{ perm: CollectionPermission.Edit, labelId: "canEdit" }, { perm: CollectionPermission.Edit, labelId: "canEdit" },
{ perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" }, { perm: CollectionPermission.EditExceptPass, labelId: "canEditExceptPass" },
{ perm: CollectionPermission.Manage, labelId: "canManage" },
]; ];
if (flexibleCollectionsEnabled) {
permissions.push({ perm: CollectionPermission.Manage, labelId: "canManage" });
}
return permissions; return permissions;
}; };
@ -142,8 +134,6 @@ export function mapGroupToAccessItemView(group: GroupView): AccessItemView {
type: AccessItemType.Group, type: AccessItemType.Group,
listName: group.name, listName: group.name,
labelName: group.name, labelName: group.name,
accessAllItems: group.accessAll,
readonly: group.accessAll,
}; };
} }
@ -157,7 +147,5 @@ export function mapUserToAccessItemView(user: OrganizationUserUserDetailsRespons
listName: user.name?.length > 0 ? `${user.name} (${user.email})` : user.email, listName: user.name?.length > 0 ? `${user.name} (${user.email})` : user.email,
labelName: user.name ?? user.email, labelName: user.name ?? user.email,
status: user.status, status: user.status,
accessAllItems: user.accessAll,
readonly: user.accessAll,
}; };
} }

View File

@ -253,7 +253,6 @@ MemberGroupAccess.args = {
type: AccessItemType.Group, type: AccessItemType.Group,
listName: "Admin Group", listName: "Admin Group",
labelName: "Admin Group", labelName: "Admin Group",
accessAllItems: true,
}, },
]), ]),
}; };
@ -309,7 +308,6 @@ CollectionAccess.args = {
type: AccessItemType.Group, type: AccessItemType.Group,
listName: "Admin Group", listName: "Admin Group",
labelName: "Admin Group", labelName: "Admin Group",
accessAllItems: true,
readonly: true, readonly: true,
}, },
{ {
@ -320,7 +318,6 @@ CollectionAccess.args = {
status: OrganizationUserStatusType.Confirmed, status: OrganizationUserStatusType.Confirmed,
role: OrganizationUserType.Admin, role: OrganizationUserType.Admin,
email: "admin@email.com", email: "admin@email.com",
accessAllItems: true,
readonly: true, readonly: true,
}, },
]), ]),

View File

@ -20,8 +20,6 @@ export class UserTypePipe implements PipeTransform {
return this.i18nService.t("admin"); return this.i18nService.t("admin");
case OrganizationUserType.User: case OrganizationUserType.User:
return this.i18nService.t("user"); return this.i18nService.t("user");
case OrganizationUserType.Manager:
return this.i18nService.t("manager");
case OrganizationUserType.Custom: case OrganizationUserType.Custom:
return this.i18nService.t("custom"); return this.i18nService.t("custom");
} }

View File

@ -64,7 +64,7 @@
</bit-form-field> </bit-form-field>
</bit-tab> </bit-tab>
<bit-tab label="{{ 'access' | i18n }}"> <bit-tab label="{{ 'access' | i18n }}">
<div class="tw-mb-3" *ngIf="organization.flexibleCollections"> <div class="tw-mb-3">
<ng-container *ngIf="dialogReadonly"> <ng-container *ngIf="dialogReadonly">
<span>{{ "readOnlyCollectionAccess" | i18n }}</span> <span>{{ "readOnlyCollectionAccess" | i18n }}</span>
</ng-container> </ng-container>
@ -107,7 +107,6 @@
[selectorLabelText]="'selectGroupsAndMembers' | i18n" [selectorLabelText]="'selectGroupsAndMembers' | i18n"
[selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n" [selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n"
[emptySelectionText]="'noMembersOrGroupsAdded' | i18n" [emptySelectionText]="'noMembersOrGroupsAdded' | i18n"
[flexibleCollectionsEnabled]="organization.flexibleCollections"
></bit-access-selector> ></bit-access-selector>
<bit-access-selector <bit-access-selector
*ngIf="!organization.useGroups" *ngIf="!organization.useGroups"
@ -117,7 +116,6 @@
[columnHeader]="'memberColumnHeader' | i18n" [columnHeader]="'memberColumnHeader' | i18n"
[selectorLabelText]="'selectMembers' | i18n" [selectorLabelText]="'selectMembers' | i18n"
[emptySelectionText]="'noMembersAdded' | i18n" [emptySelectionText]="'noMembersAdded' | i18n"
[flexibleCollectionsEnabled]="organization.flexibleCollections"
></bit-access-selector> ></bit-access-selector>
</bit-tab> </bit-tab>
</bit-tab-group> </bit-tab-group>

View File

@ -223,7 +223,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
(u) => u.userId === this.organization?.userId, (u) => u.userId === this.organization?.userId,
)?.id; )?.id;
const initialSelection: AccessItemValue[] = const initialSelection: AccessItemValue[] =
currentOrgUserId !== undefined && organization.flexibleCollections currentOrgUserId !== undefined
? [ ? [
{ {
id: currentOrgUserId, id: currentOrgUserId,
@ -239,11 +239,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
}); });
} }
if ( if (flexibleCollectionsV1 && !organization.allowAdminAccessToAllCollectionItems) {
organization.flexibleCollections &&
flexibleCollectionsV1 &&
!organization.allowAdminAccessToAllCollectionItems
) {
this.formGroup.controls.access.addValidators(validateCanManagePermission); this.formGroup.controls.access.addValidators(validateCanManagePermission);
} else { } else {
this.formGroup.controls.access.removeValidators(validateCanManagePermission); this.formGroup.controls.access.removeValidators(validateCanManagePermission);
@ -444,8 +440,7 @@ function mapGroupToAccessItemView(group: GroupView, collectionId: string): Acces
type: AccessItemType.Group, type: AccessItemType.Group,
listName: group.name, listName: group.name,
labelName: group.name, labelName: group.name,
accessAllItems: group.accessAll, readonly: false,
readonly: group.accessAll,
readonlyPermission: readonlyPermission:
collectionId != null collectionId != null
? convertToPermission(group.collections.find((gc) => gc.id == collectionId)) ? convertToPermission(group.collections.find((gc) => gc.id == collectionId))
@ -471,8 +466,7 @@ function mapUserToAccessItemView(
listName: user.name?.length > 0 ? `${user.name} (${user.email})` : user.email, listName: user.name?.length > 0 ? `${user.name} (${user.email})` : user.email,
labelName: user.name ?? user.email, labelName: user.name ?? user.email,
status: user.status, status: user.status,
accessAllItems: user.accessAll, readonly: false,
readonly: user.accessAll,
readonlyPermission: readonlyPermission:
collectionId != null collectionId != null
? convertToPermission( ? convertToPermission(

View File

@ -86,7 +86,7 @@ export class VaultCollectionRowComponent {
return this.i18nService.t("canEdit"); return this.i18nService.t("canEdit");
} }
if ((this.collection as CollectionAdminView).assigned) { if ((this.collection as CollectionAdminView).assigned) {
const permissionList = getPermissionList(this.organization?.flexibleCollections); const permissionList = getPermissionList();
return this.i18nService.t( return this.i18nService.t(
permissionList.find((p) => p.perm === convertToPermission(this.collection))?.labelId, permissionList.find((p) => p.perm === convertToPermission(this.collection))?.labelId,
); );

View File

@ -15,7 +15,6 @@ import { VaultFilter } from "../models/vault-filter.model";
}) })
export class VaultFilterSectionComponent implements OnInit, OnDestroy { export class VaultFilterSectionComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
protected flexibleCollectionsEnabled: boolean;
@Input() activeFilter: VaultFilter; @Input() activeFilter: VaultFilter;
@Input() section: VaultFilterSection; @Input() section: VaultFilterSection;
@ -40,12 +39,6 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy {
this.section?.data$?.pipe(takeUntil(this.destroy$)).subscribe((data) => { this.section?.data$?.pipe(takeUntil(this.destroy$)).subscribe((data) => {
this.data = data; this.data = data;
}); });
this.vaultFilterService
.getOrganizationFilter()
.pipe(takeUntil(this.destroy$))
.subscribe((org) => {
this.flexibleCollectionsEnabled = org != null ? org.flexibleCollections : false;
});
} }
ngOnDestroy() { ngOnDestroy() {
@ -77,10 +70,9 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy {
const { organizationId, cipherTypeId, folderId, collectionId, isCollectionSelected } = const { organizationId, cipherTypeId, folderId, collectionId, isCollectionSelected } =
this.activeFilter; this.activeFilter;
const collectionStatus = this.flexibleCollectionsEnabled const collectionStatus =
? filterNode?.node.id === "AllCollections" && filterNode?.node.id === "AllCollections" &&
(isCollectionSelected || collectionId === "AllCollections") (isCollectionSelected || collectionId === "AllCollections");
: collectionId === filterNode?.node.id;
return ( return (
organizationId === filterNode?.node.id || organizationId === filterNode?.node.id ||

View File

@ -17,7 +17,6 @@
[selectorLabelText]="'selectGroupsAndMembers' | i18n" [selectorLabelText]="'selectGroupsAndMembers' | i18n"
[selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n" [selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n"
[emptySelectionText]="'noMembersOrGroupsAdded' | i18n" [emptySelectionText]="'noMembersOrGroupsAdded' | i18n"
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
></bit-access-selector> ></bit-access-selector>
<bit-access-selector <bit-access-selector
*ngIf="!organization?.useGroups" *ngIf="!organization?.useGroups"
@ -27,7 +26,6 @@
[columnHeader]="'memberColumnHeader' | i18n" [columnHeader]="'memberColumnHeader' | i18n"
[selectorLabelText]="'selectMembers' | i18n" [selectorLabelText]="'selectMembers' | i18n"
[emptySelectionText]="'noMembersAdded' | i18n" [emptySelectionText]="'noMembersAdded' | i18n"
[flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async"
></bit-access-selector> ></bit-access-selector>
</div> </div>

View File

@ -1,7 +1,7 @@
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
import { Component, Inject, OnDestroy } from "@angular/core"; import { Component, Inject, OnDestroy } from "@angular/core";
import { FormBuilder } from "@angular/forms"; import { FormBuilder } from "@angular/forms";
import { combineLatest, map, of, Subject, switchMap, takeUntil } from "rxjs"; import { combineLatest, of, Subject, switchMap, takeUntil } from "rxjs";
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 { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
@ -42,10 +42,6 @@ export enum BulkCollectionsDialogResult {
standalone: true, standalone: true,
}) })
export class BulkCollectionsDialogComponent implements OnDestroy { export class BulkCollectionsDialogComponent implements OnDestroy {
protected flexibleCollectionsEnabled$ = this.organizationService
.get$(this.params.organizationId)
.pipe(map((o) => o?.flexibleCollections));
protected readonly PermissionMode = PermissionMode; protected readonly PermissionMode = PermissionMode;
protected formGroup = this.formBuilder.group({ protected formGroup = this.formBuilder.group({

View File

@ -103,11 +103,7 @@ export class VaultFilterComponent extends BaseVaultFilterComponent implements On
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"]);
if (this._organization?.flexibleCollections) { builderFilter.collectionFilter = await this.addCollectionFilter();
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;
} }

View File

@ -6,10 +6,7 @@
queryParamsHandling="merge" queryParamsHandling="merge"
> >
{{ organization.name }} {{ organization.name }}
<span *ngIf="!organization.flexibleCollections"> <span>
{{ "vault" | i18n | lowercase }}
</span>
<span *ngIf="organization.flexibleCollections">
{{ "collections" | i18n | lowercase }} {{ "collections" | i18n | lowercase }}
</span> </span>
</bit-breadcrumb> </bit-breadcrumb>

View File

@ -89,9 +89,7 @@ export class VaultHeaderComponent implements OnInit {
} }
get title() { get title() {
const headerType = this.organization?.flexibleCollections const headerType = this.i18nService.t("collections").toLowerCase();
? this.i18nService.t("collections").toLowerCase()
: this.i18nService.t("vault").toLowerCase();
if (this.collection != null) { if (this.collection != null) {
return this.collection.node.name; return this.collection.node.name;

View File

@ -65,8 +65,8 @@
[useEvents]="organization?.canAccessEventLogs" [useEvents]="organization?.canAccessEventLogs"
[showAdminActions]="true" [showAdminActions]="true"
(onEvent)="onVaultItemsEvent($event)" (onEvent)="onVaultItemsEvent($event)"
[showBulkEditCollectionAccess]="organization?.flexibleCollections" [showBulkEditCollectionAccess]="true"
[showBulkAddToCollections]="organization?.flexibleCollections" [showBulkAddToCollections]="true"
[viewingOrgVault]="true" [viewingOrgVault]="true"
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled" [flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled"
[addAccessStatus]="addAccessStatus$ | async" [addAccessStatus]="addAccessStatus$ | async"

View File

@ -156,7 +156,7 @@ export class VaultComponent implements OnInit, OnDestroy {
private _flexibleCollectionsV1FlagEnabled: boolean; private _flexibleCollectionsV1FlagEnabled: boolean;
protected get flexibleCollectionsV1Enabled(): boolean { protected get flexibleCollectionsV1Enabled(): boolean {
return this._flexibleCollectionsV1FlagEnabled && this.organization?.flexibleCollections; return this._flexibleCollectionsV1FlagEnabled;
} }
protected orgRevokedUsers: OrganizationUserUserDetailsResponse[]; protected orgRevokedUsers: OrganizationUserUserDetailsResponse[];

View File

@ -2794,12 +2794,6 @@
"userDesc": { "userDesc": {
"message": "Access and add items to assigned collections" "message": "Access and add items to assigned collections"
}, },
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Create, delete, and manage access in assigned collections"
},
"all": { "all": {
"message": "All" "message": "All"
}, },
@ -4576,12 +4570,6 @@
"permission": { "permission": {
"message": "Permission" "message": "Permission"
}, },
"managerPermissions": {
"message": "Manager Permissions"
},
"adminPermissions": {
"message": "Admin Permissions"
},
"accessEventLogs": { "accessEventLogs": {
"message": "Access event logs" "message": "Access event logs"
}, },
@ -4606,9 +4594,6 @@
"deleteAnyCollection": { "deleteAnyCollection": {
"message": "Delete any collection" "message": "Delete any collection"
}, },
"manageAssignedCollections": {
"message": "Manage assigned collections"
},
"editAssignedCollections": { "editAssignedCollections": {
"message": "Edit assigned collections" "message": "Edit assigned collections"
}, },
@ -6669,12 +6654,6 @@
"restrictedCollectionAssignmentDesc": { "restrictedCollectionAssignmentDesc": {
"message": "You can only assign collections you manage." "message": "You can only assign collections you manage."
}, },
"accessAllCollectionsDesc": {
"message": "Grant access to all current and future collections."
},
"accessAllCollectionsHelp": {
"message": "If checked, this will replace all other collection permissions."
},
"selectMembers": { "selectMembers": {
"message": "Select members" "message": "Select members"
}, },
@ -6717,12 +6696,6 @@
"group": { "group": {
"message": "Group" "message": "Group"
}, },
"groupAccessAll": {
"message": "This group can access and modify all items."
},
"memberAccessAll": {
"message": "This member can access and modify all items."
},
"domainVerification": { "domainVerification": {
"message": "Domain verification" "message": "Domain verification"
}, },

View File

@ -20,8 +20,6 @@ export class UserTypePipe implements PipeTransform {
return this.i18nService.t("admin"); return this.i18nService.t("admin");
case OrganizationUserType.User: case OrganizationUserType.User:
return this.i18nService.t("user"); return this.i18nService.t("user");
case OrganizationUserType.Manager:
return this.i18nService.t("manager");
case OrganizationUserType.Custom: case OrganizationUserType.Custom:
return this.i18nService.t("custom"); return this.i18nService.t("custom");
} }

View File

@ -5,7 +5,6 @@ import { SelectionReadOnlyRequest } from "../../../models/request/selection-read
export class OrganizationUserInviteRequest { export class OrganizationUserInviteRequest {
emails: string[] = []; emails: string[] = [];
type: OrganizationUserType; type: OrganizationUserType;
accessAll: boolean;
accessSecretsManager: boolean; accessSecretsManager: boolean;
collections: SelectionReadOnlyRequest[] = []; collections: SelectionReadOnlyRequest[] = [];
groups: string[]; groups: string[];

View File

@ -4,7 +4,6 @@ import { SelectionReadOnlyRequest } from "../../../models/request/selection-read
export class OrganizationUserUpdateRequest { export class OrganizationUserUpdateRequest {
type: OrganizationUserType; type: OrganizationUserType;
accessAll: boolean;
accessSecretsManager: boolean; accessSecretsManager: boolean;
collections: SelectionReadOnlyRequest[] = []; collections: SelectionReadOnlyRequest[] = [];
groups: string[] = []; groups: string[] = [];

View File

@ -10,11 +10,6 @@ export class OrganizationUserResponse extends BaseResponse {
type: OrganizationUserType; type: OrganizationUserType;
status: OrganizationUserStatusType; status: OrganizationUserStatusType;
externalId: string; externalId: string;
/**
* @deprecated
* To be removed after Flexible Collections.
**/
accessAll: boolean;
accessSecretsManager: boolean; accessSecretsManager: boolean;
permissions: PermissionsApi; permissions: PermissionsApi;
resetPasswordEnrolled: boolean; resetPasswordEnrolled: boolean;
@ -30,7 +25,6 @@ export class OrganizationUserResponse extends BaseResponse {
this.status = this.getResponseProperty("Status"); this.status = this.getResponseProperty("Status");
this.permissions = new PermissionsApi(this.getResponseProperty("Permissions")); this.permissions = new PermissionsApi(this.getResponseProperty("Permissions"));
this.externalId = this.getResponseProperty("ExternalId"); this.externalId = this.getResponseProperty("ExternalId");
this.accessAll = this.getResponseProperty("AccessAll");
this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager"); this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager");
this.resetPasswordEnrolled = this.getResponseProperty("ResetPasswordEnrolled"); this.resetPasswordEnrolled = this.getResponseProperty("ResetPasswordEnrolled");
this.hasMasterPassword = this.getResponseProperty("HasMasterPassword"); this.hasMasterPassword = this.getResponseProperty("HasMasterPassword");

View File

@ -7,7 +7,7 @@ import { OrganizationData } from "../../models/data/organization.data";
import { Organization } from "../../models/domain/organization"; import { Organization } from "../../models/domain/organization";
export function canAccessVaultTab(org: Organization): boolean { export function canAccessVaultTab(org: Organization): boolean {
return org.canViewAssignedCollections || org.canViewAllCollections; return org.canViewAllCollections;
} }
export function canAccessSettingsTab(org: Organization): boolean { export function canAccessSettingsTab(org: Organization): boolean {
@ -77,10 +77,7 @@ export function canAccessImportExport(i18nService: I18nService) {
export function canAccessImport(i18nService: I18nService) { export function canAccessImport(i18nService: I18nService) {
return map<Organization[], Organization[]>((orgs) => return map<Organization[], Organization[]>((orgs) =>
orgs orgs
.filter( .filter((org) => org.canAccessImportExport || org.canCreateNewCollections)
(org) =>
org.canAccessImportExport || (org.canCreateNewCollections && org.flexibleCollections),
)
.sort(Utils.getSortFunction(i18nService, "name")), .sort(Utils.getSortFunction(i18nService, "name")),
); );
} }

View File

@ -142,16 +142,6 @@ export class Organization {
return this.enabled && this.status === OrganizationUserStatusType.Confirmed; return this.enabled && this.status === OrganizationUserStatusType.Confirmed;
} }
/**
* Whether a user has Manager permissions or greater
*
* @deprecated
* This is deprecated with the introduction of Flexible Collections.
*/
get isManager() {
return this.type === OrganizationUserType.Manager || this.isAdmin;
}
/** /**
* Whether a user has Admin permissions or greater * Whether a user has Admin permissions or greater
*/ */
@ -179,19 +169,13 @@ export class Organization {
} }
get canCreateNewCollections() { get canCreateNewCollections() {
if (this.flexibleCollections) { return (
return ( !this.limitCollectionCreationDeletion || this.isAdmin || this.permissions.createNewCollections
!this.limitCollectionCreationDeletion || );
this.isAdmin ||
this.permissions.createNewCollections
);
}
return this.isManager || this.permissions.createNewCollections;
} }
canEditAnyCollection(flexibleCollectionsV1Enabled: boolean) { canEditAnyCollection(flexibleCollectionsV1Enabled: boolean) {
if (!this.flexibleCollections || !flexibleCollectionsV1Enabled) { if (!flexibleCollectionsV1Enabled) {
// Pre-Flexible Collections v1 logic // Pre-Flexible Collections v1 logic
return this.isAdmin || this.permissions.editAnyCollection; return this.isAdmin || this.permissions.editAnyCollection;
} }
@ -221,8 +205,8 @@ export class Organization {
flexibleCollectionsV1Enabled: boolean, flexibleCollectionsV1Enabled: boolean,
restrictProviderAccessFlagEnabled: boolean, restrictProviderAccessFlagEnabled: boolean,
) { ) {
// Before Flexible Collections, any admin or anyone with editAnyCollection permission could edit all ciphers // Before Flexible Collections V1, any admin or anyone with editAnyCollection permission could edit all ciphers
if (!this.flexibleCollections || !flexibleCollectionsV1Enabled || !this.flexibleCollections) { if (!flexibleCollectionsV1Enabled) {
return this.isAdmin || this.permissions.editAnyCollection; return this.isAdmin || this.permissions.editAnyCollection;
} }
@ -269,33 +253,6 @@ export class Organization {
); );
} }
/**
* @deprecated
* This is deprecated with the introduction of Flexible Collections.
* This will always return false if FlexibleCollections flag is on.
*/
get canEditAssignedCollections() {
return this.isManager || this.permissions.editAssignedCollections;
}
/**
* @deprecated
* This is deprecated with the introduction of Flexible Collections.
* This will always return false if FlexibleCollections flag is on.
*/
get canDeleteAssignedCollections() {
return this.isManager || this.permissions.deleteAssignedCollections;
}
/**
* @deprecated
* This is deprecated with the introduction of Flexible Collections.
* This will always return false if FlexibleCollections flag is on.
*/
get canViewAssignedCollections() {
return this.canDeleteAssignedCollections || this.canEditAssignedCollections;
}
get canManageGroups() { get canManageGroups() {
return (this.isAdmin || this.permissions.manageGroups) && this.useGroups; return (this.isAdmin || this.permissions.manageGroups) && this.useGroups;
} }

View File

@ -49,15 +49,11 @@ export class CollectionView implements View, ITreeNodeObject {
); );
} }
if (org?.flexibleCollections) { return (
return ( org?.canEditAllCiphers(v1FlexibleCollections, restrictProviderAccess) ||
org?.canEditAllCiphers(v1FlexibleCollections, restrictProviderAccess) || this.manage ||
this.manage || (this.assigned && !this.readOnly)
(this.assigned && !this.readOnly) );
);
}
return org?.canEditAnyCollection(false) || (org?.canEditAssignedCollections && this.assigned);
} }
/** /**

View File

@ -256,17 +256,14 @@ export class ImportComponent implements OnInit, OnDestroy {
if (!this._importBlockedByPolicy) { if (!this._importBlockedByPolicy) {
this.formGroup.controls.targetSelector.enable(); this.formGroup.controls.targetSelector.enable();
} }
const flexCollectionEnabled =
organizations.find((x) => x.id == this.organizationId)?.flexibleCollections ?? false;
if (value) { if (value) {
this.collections$ = Utils.asyncToObservable(() => this.collections$ = Utils.asyncToObservable(() =>
this.collectionService this.collectionService
.getAllDecrypted() .getAllDecrypted()
.then((decryptedCollections) => .then((decryptedCollections) =>
decryptedCollections decryptedCollections
.filter( .filter((c2) => c2.organizationId === value && c2.manage)
(c2) => c2.organizationId === value && (!flexCollectionEnabled || c2.manage),
)
.sort(Utils.getSortFunction(this.i18nService, "name")), .sort(Utils.getSortFunction(this.i18nService, "name")),
), ),
); );

View File

@ -167,11 +167,7 @@ export class ExportComponent implements OnInit, OnDestroy {
} }
this.organizations$ = this.organizationService.memberOrganizations$.pipe( this.organizations$ = this.organizationService.memberOrganizations$.pipe(
map((orgs) => map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))),
orgs
.filter((org) => org.flexibleCollections)
.sort(Utils.getSortFunction(this.i18nService, "name")),
),
); );
this.exportForm.controls.vaultSelector.valueChanges this.exportForm.controls.vaultSelector.valueChanges