diff --git a/apps/web/src/app/organizations/manage/groups.component.html b/apps/web/src/app/organizations/manage/groups.component.html
index b8954de648c..0e420bd928b 100644
--- a/apps/web/src/app/organizations/manage/groups.component.html
+++ b/apps/web/src/app/organizations/manage/groups.component.html
@@ -77,7 +77,7 @@
|
@@ -129,5 +129,4 @@
-
diff --git a/apps/web/src/app/organizations/manage/groups.component.ts b/apps/web/src/app/organizations/manage/groups.component.ts
index 44d44732bfc..3b1a57ba30b 100644
--- a/apps/web/src/app/organizations/manage/groups.component.ts
+++ b/apps/web/src/app/organizations/manage/groups.component.ts
@@ -29,18 +29,22 @@ import {
CollectionDetailsResponse,
CollectionResponse,
} from "@bitwarden/common/models/response/collectionResponse";
-import { IGroupDetailsResponse } from "@bitwarden/common/models/response/groupResponse";
+import { GroupDetailsResponse } from "@bitwarden/common/models/response/groupResponse";
import { ListResponse } from "@bitwarden/common/models/response/listResponse";
import { CollectionView } from "@bitwarden/common/models/view/collectionView";
-import { EntityUsersComponent } from "./entity-users.component";
import { GroupAddEditComponent } from "./group-add-edit.component";
type CollectionViewMap = {
[id: string]: CollectionView;
};
-interface IGroupDetailsRow extends IGroupDetailsResponse {
+type GroupDetailsRow = {
+ /**
+ * Details used for displaying group information
+ */
+ details: GroupDetailsResponse;
+
/**
* True if the group is selected in the table
*/
@@ -50,7 +54,7 @@ interface IGroupDetailsRow extends IGroupDetailsResponse {
* A list of collection names the group has access to
*/
collectionNames?: string[];
-}
+};
@Component({
selector: "app-org-groups",
@@ -63,16 +67,15 @@ export class GroupsComponent implements OnInit, OnDestroy {
loading = true;
organizationId: string;
- groups: IGroupDetailsRow[];
- collectionMap: CollectionViewMap = {};
+ groups: GroupDetailsRow[];
protected didScroll = false;
protected pageSize = 100;
protected maxCollections = 2;
private pagedGroupsCount = 0;
- private pagedGroups: IGroupDetailsRow[];
- private searchedGroups: IGroupDetailsRow[];
+ private pagedGroups: GroupDetailsRow[];
+ private searchedGroups: GroupDetailsRow[];
private _searchText: string;
private destroy$ = new Subject();
private refreshGroups$ = new BehaviorSubject(null);
@@ -92,7 +95,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
* we need a reference to the currently visible groups for
* the Select All checkbox
*/
- get visibleGroups(): IGroupDetailsRow[] {
+ get visibleGroups(): GroupDetailsRow[] {
if (this.isPaging()) {
return this.pagedGroups;
}
@@ -136,8 +139,8 @@ export class GroupsComponent implements OnInit, OnDestroy {
map(([collectionMap, groups]) => {
return groups
.sort(Utils.getSortFunction(this.i18nService, "name"))
- .map((g) => ({
- ...g,
+ .map((g) => ({
+ details: g,
checked: false,
collectionNames: g.collections
.map((c) => collectionMap[c.id]?.name)
@@ -169,26 +172,6 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.destroy$.complete();
}
- async toCollectionMap(response: ListResponse) {
- const collections = response.data.map(
- (r) => new Collection(new CollectionData(r as CollectionDetailsResponse))
- );
- const decryptedCollections = await this.collectionService.decryptMany(collections);
-
- // Convert to an object using collection Ids as keys for faster name lookups
- const collectionMap: CollectionViewMap = {};
- decryptedCollections.forEach((c) => (collectionMap[c.id] = c));
-
- return collectionMap;
- }
-
- private updateSearchedGroups() {
- if (this.searchService.isSearchable(this.searchText)) {
- // Making use of the pipe in the component as we need know which groups where filtered
- this.searchedGroups = this.searchPipe.transform(this.groups, this.searchText, "name", "id");
- }
- }
-
loadMore() {
if (!this.groups || this.groups.length <= this.pageSize) {
return;
@@ -207,20 +190,20 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.didScroll = this.pagedGroups.length > this.pageSize;
}
- async edit(group: IGroupDetailsRow) {
+ async edit(groupRow: GroupDetailsRow) {
const [modal] = await this.modalService.openViewRef(
GroupAddEditComponent,
this.addEditModalRef,
(comp) => {
comp.organizationId = this.organizationId;
- comp.groupId = group != null ? group.id : null;
+ comp.groupId = groupRow != null ? groupRow.details.id : null;
comp.onSavedGroup.pipe(takeUntil(this.destroy$)).subscribe(() => {
modal.close();
this.refreshGroups$.next();
});
comp.onDeletedGroup.pipe(takeUntil(this.destroy$)).subscribe(() => {
modal.close();
- this.removeGroup(group.id);
+ this.removeGroup(groupRow.details.id);
});
}
);
@@ -230,10 +213,10 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.edit(null);
}
- async delete(group: IGroupDetailsRow) {
+ async delete(groupRow: GroupDetailsRow) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("deleteGroupConfirmation"),
- group.name,
+ groupRow.details.name,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
@@ -243,13 +226,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
try {
- await this.apiService.deleteGroup(this.organizationId, group.id);
+ await this.apiService.deleteGroup(this.organizationId, groupRow.details.id);
this.platformUtilsService.showToast(
"success",
null,
- this.i18nService.t("deletedGroupId", group.name)
+ this.i18nService.t("deletedGroupId", groupRow.details.name)
);
- this.removeGroup(group.id);
+ this.removeGroup(groupRow.details.id);
} catch (e) {
this.logService.error(e);
}
@@ -262,7 +245,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
return;
}
- const deleteMessage = groupsToDelete.map((g) => g.name).join(", ");
+ const deleteMessage = groupsToDelete.map((g) => g.details.name).join(", ");
const confirmed = await this.platformUtilsService.showDialog(
deleteMessage,
this.i18nService.t("deleteMultipleGroupsConfirmation", groupsToDelete.length.toString()),
@@ -277,7 +260,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
try {
const result = await this.apiService.deleteManyGroups(
this.organizationId,
- new OrganizationGroupBulkRequest(groupsToDelete.map((g) => g.id))
+ new OrganizationGroupBulkRequest(groupsToDelete.map((g) => g.details.id))
);
this.platformUtilsService.showToast(
"success",
@@ -285,29 +268,12 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.i18nService.t("deletedManyGroups", result.data.length.toString())
);
- groupsToDelete.forEach((g) => this.removeGroup(g.id));
+ groupsToDelete.forEach((g) => this.removeGroup(g.details.id));
} catch (e) {
this.logService.error(e);
}
}
- async users(group: IGroupDetailsRow) {
- const [modal] = await this.modalService.openViewRef(
- EntityUsersComponent,
- this.usersModalRef,
- (comp) => {
- comp.organizationId = this.organizationId;
- comp.entity = "group";
- comp.entityId = group.id;
- comp.entityName = group.name;
-
- comp.onEditedUsers.pipe(takeUntil(this.destroy$)).subscribe(() => {
- modal.close();
- });
- }
- );
- }
-
resetPaging() {
this.pagedGroups = [];
this.loadMore();
@@ -317,8 +283,8 @@ export class GroupsComponent implements OnInit, OnDestroy {
return this.searchService.isSearchable(this.searchText);
}
- check(group: IGroupDetailsRow) {
- group.checked = !group.checked;
+ check(groupRow: GroupDetailsRow) {
+ groupRow.checked = !groupRow.checked;
}
toggleAllVisible(event: Event) {
@@ -334,11 +300,31 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
private removeGroup(id: string) {
- const index = this.groups.findIndex((g) => g.id === id);
+ const index = this.groups.findIndex((g) => g.details.id === id);
if (index > -1) {
this.groups.splice(index, 1);
this.resetPaging();
this.updateSearchedGroups();
}
}
+
+ private async toCollectionMap(response: ListResponse) {
+ const collections = response.data.map(
+ (r) => new Collection(new CollectionData(r as CollectionDetailsResponse))
+ );
+ const decryptedCollections = await this.collectionService.decryptMany(collections);
+
+ // Convert to an object using collection Ids as keys for faster name lookups
+ const collectionMap: CollectionViewMap = {};
+ decryptedCollections.forEach((c) => (collectionMap[c.id] = c));
+
+ return collectionMap;
+ }
+
+ private updateSearchedGroups() {
+ if (this.searchService.isSearchable(this.searchText)) {
+ // Making use of the pipe in the component as we need know which groups where filtered
+ this.searchedGroups = this.searchPipe.transform(this.groups, this.searchText, "name", "id");
+ }
+ }
}
diff --git a/libs/common/src/models/response/groupResponse.ts b/libs/common/src/models/response/groupResponse.ts
index 6704f7b0fcd..ab4b58b7b55 100644
--- a/libs/common/src/models/response/groupResponse.ts
+++ b/libs/common/src/models/response/groupResponse.ts
@@ -1,15 +1,7 @@
import { BaseResponse } from "./baseResponse";
import { SelectionReadOnlyResponse } from "./selectionReadOnlyResponse";
-export interface IGroupResponse {
- id: string;
- organizationId: string;
- name: string;
- accessAll: boolean;
- externalId: string;
-}
-
-export class GroupResponse extends BaseResponse implements IGroupResponse {
+export class GroupResponse extends BaseResponse {
id: string;
organizationId: string;
name: string;
@@ -26,11 +18,7 @@ export class GroupResponse extends BaseResponse implements IGroupResponse {
}
}
-export interface IGroupDetailsResponse extends IGroupResponse {
- collections: SelectionReadOnlyResponse[];
-}
-
-export class GroupDetailsResponse extends GroupResponse implements IGroupDetailsResponse {
+export class GroupDetailsResponse extends GroupResponse {
collections: SelectionReadOnlyResponse[] = [];
constructor(response: any) {
|