mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 01:33:33 +00:00
[AC-1011] Admin Console / Billing code ownership (#4973)
* refactor: move SCIM component to admin-console, refs EC-1011 * refactor: move scimProviderType to admin-console, refs EC-1011 * refactor: move scim-config.api to admin-console, refs EC-1011 * refactor: create models folder and nest existing api contents, refs EC-1011 * refactor: move scim-config to admin-console models, refs EC-1011 * refactor: move billing.component to billing, refs EC-1011 * refactor: remove nested app folder from new billing structure, refs EC-1011 * refactor: move organizations/billing to billing, refs EC-1011 * refactor: move add-credit and adjust-payment to billing/settings, refs EC-1011 * refactor: billing history/sync to billing, refs EC-1011 * refactor: move org plans, payment/method to billing/settings, refs EC-1011 * fix: update legacy file paths for payment-method and tax-info, refs EC-1011 * fix: update imports for scim component, refs EC-1011 * refactor: move subscription and tax-info into billing, refs EC-1011 * refactor: move user-subscription to billing, refs EC-1011 * refactor: move images/cards to billing and update base path, refs EC-1011 * refactor: move payment-method, plan subscription, and plan to billing, refs EC-1011 * refactor: move transaction-type to billing, refs EC-1011 * refactor: move billing-sync-config to billing, refs EC-1011 * refactor: move billing-sync and bit-pay-invoice request to billing, refs EC-1011 * refactor: move org subscription and tax info update requests to billing, refs EC-1011 * fix: broken paths to billing, refs EC-1011 * refactor: move payment request to billing, refs EC-1011 * fix: update remaining imports for payment-request, refs EC-1011 * refactor: move tax-info-update to billing, refs EC-1011 * refactor: move billing-payment, billing-history, and billing responses to billing, refs EC-1011 * refactor: move organization-subscription-responset to billing, refs EC-1011 * refactor: move payment and plan responses to billing, refs EC-1011 * refactor: move subscription response to billing ,refs EC-1011 * refactor: move tax info and rate responses to billing, refs EC-1011 * fix: update remaining path to base response for tax-rate response, refs EC-1011 * refactor: (browser) move organization-service to admin-console, refs EC-1011 * refactor: (browser) move organizaiton-service to admin-console, refs EC-1011 * refactor: (cli) move share command to admin-console, refs EC-1011 * refactor: move organization-collect request model to admin-console, refs EC-1011 * refactor: (web) move organization, collection/user responses to admin-console, refs EC-1011 * refactor: (cli) move selection-read-only to admin-console, refs EC-1011 * refactor: (desktop) move organization-filter to admin-console, refs EC-1011 * refactor: (web) move organization-switcher to admin-console, refs EC-1011 * refactor: (web) move access-selector to admin-console, refs EC-1011 * refactor: (web) move create folder to admin-console, refs EC-1011 * refactor: (web) move org guards folder to admin-console, refs EC-1011 * refactor: (web) move org layout to admin-console, refs EC-1011 * refactor: move manage collections to admin console, refs EC-1011 * refactor: (web) move collection-dialog to admin-console, refs EC-1011 * refactor: (web) move entity users/events and events component to admin-console, refs EC-1011 * refactor: (web) move groups/group-add-edit to admin-console, refs EC-1011 * refactor: (web) move manage, org-manage module, and user-confirm to admin-console, refs EC-1011 * refactor: (web) move people to admin-console, refs EC-1011 * refactor: (web) move reset-password to admin-console, refs EC-1011 * refactor: (web) move organization-routing and module to admin-console, refs EC-1011 * refactor: move admin-console and billing within app scope, refs EC-1011 * fix: update leftover merge conflicts, refs EC-1011 * refactor: (web) member-dialog to admin-console, refs EC-1011 * refactor: (web) move policies to admin-console, refs EC-1011 * refactor: (web) move reporting to admin-console, refs EC-1011 * refactor: (web) move settings to admin-console, refs EC-1011 * refactor: (web) move sponsorships to admin-console, refs EC-1011 * refactor: (web) move tools to admin-console, refs EC-1011 * refactor: (web) move users to admin-console, refs EC-1011 * refactor: (web) move collections to admin-console, refs EC-1011 * refactor: (web) move create-organization to admin-console, refs EC-1011 * refactor: (web) move licensed components to admin-console, refs EC-1011 * refactor: (web) move bit organization modules to admin-console, refs EC-1011 * fix: update leftover import statements for organizations.module, refs EC-1011 * refactor: (web) move personal vault and max timeout to admin-console, refs EC-1011 * refactor: (web) move providers to admin-console, refs EC-1011 * refactor: (libs) move organization service to admin-console, refs EC-1011 * refactor: (libs) move profile org/provider responses and other misc org responses to admin-console, refs EC-1011 * refactor: (libs) move provider request and selectionion-read-only request to admin-console, refs EC-1011 * fix: update missed import path for provider-user-update request, refs EC-1011 * refactor: (libs) move abstractions to admin-console, refs EC-1011 * refactor: (libs) move org/provider enums to admin-console, refs EC-1011 * fix: update downstream import statements from libs changes, refs EC-1011 * refactor: (libs) move data files to admin-console, refs EC-1011 * refactor: (libs) move domain to admin-console, refs EC-1011 * refactor: (libs) move request objects to admin-console, refs EC-1011 * fix: update downstream import changes from libs, refs EC-1011 * refactor: move leftover provider files to admin-console, refs EC-1011 * refactor: (browser) move group policy environment to admin-console, refs EC-1011 * fix: (browser) update downstream import statements, refs EC-1011 * fix: (desktop) update downstream libs moves, refs EC-1011 * fix: (cli) update downstream import changes from libs, refs EC-1011 * refactor: move org-auth related files to admin-console, refs EC-1011 * refactor: (libs) move request objects to admin-console, refs EC-1011 * refactor: move persmissions to admin-console, refs EC-1011 * refactor: move sponsored families to admin-console and fix libs changes, refs EC-1011 * refactor: move collections to admin-console, refs EC-1011 * refactor: move spec file back to spec scope, refs EC-1011 * fix: update downstream imports due to libs changes, refs EC-1011 * fix: udpate downstream import changes due to libs, refs EC-1011 * fix: update downstream imports due to libs changes, refs EC-1011 * fix: update downstream imports from libs changes, refs EC-1011 * fix: update path malformation in jslib-services.module, refs EC-1011 * fix: lint errors from improper casing, refs AC-1011 * fix: update downstream filename changes, refs AC-1011 * fix: (cli) update downstream filename changes, refs AC-1011 * fix: (desktop) update downstream filename changes, refs AC-1011 * fix: (browser) update downstream filename changes, refs AC-1011 * fix: lint errors, refs AC-1011 * fix: prettier, refs AC-1011 * fix: lint fixes for import order, refs AC-1011 * fix: update import path for provider user type, refs AC-1011 * fix: update new codes import paths for admin console structure, refs AC-1011 * fix: lint/prettier, refs AC-1011 * fix: update layout stories path, refs AC-1011 * fix: update comoponents card icons base variable in styles, refs AC-1011 * fix: update provider service path in permissions guard spec, refs AC-1011 * fix: update provider permission guard path, refs AC-1011 * fix: remove unecessary TODO for shared index export statement, refs AC-1011 * refactor: move browser-organization service and cli organization-user response out of admin-console, refs AC-1011 * refactor: move web/browser/desktop collections component to vault domain, refs AC-1011 * refactor: move organization.module out of admin-console scope, refs AC-1011 * fix: prettier, refs AC-1011 * refactor: move organizations-api-key.request out of admin-console scope, refs AC-1011
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
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 { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
|
||||
import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data";
|
||||
import { Collection } from "@bitwarden/common/admin-console/models/domain/collection";
|
||||
import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { GroupService, GroupView } from "../../../organizations/core";
|
||||
import {
|
||||
AccessItemType,
|
||||
AccessItemValue,
|
||||
AccessItemView,
|
||||
convertToPermission,
|
||||
convertToSelectionView,
|
||||
PermissionMode,
|
||||
} from "../shared/components/access-selector";
|
||||
|
||||
/**
|
||||
* Indices for the available tabs in the dialog
|
||||
*/
|
||||
export enum GroupAddEditTabType {
|
||||
Info = 0,
|
||||
Members = 1,
|
||||
Collections = 2,
|
||||
}
|
||||
|
||||
export interface GroupAddEditDialogParams {
|
||||
/**
|
||||
* ID of the organization the group belongs to
|
||||
*/
|
||||
organizationId: string;
|
||||
|
||||
/**
|
||||
* Optional ID of the group being modified
|
||||
*/
|
||||
groupId?: string;
|
||||
|
||||
/**
|
||||
* Tab to open when the dialog is open.
|
||||
* Defaults to Group Info
|
||||
*/
|
||||
initialTab?: GroupAddEditTabType;
|
||||
}
|
||||
|
||||
export enum GroupAddEditDialogResultType {
|
||||
Saved = "saved",
|
||||
Canceled = "canceled",
|
||||
Deleted = "deleted",
|
||||
}
|
||||
|
||||
/**
|
||||
* Strongly typed helper to open a groupAddEditDialog
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param config Configuration for the dialog
|
||||
*/
|
||||
export const openGroupAddEditDialog = (
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<GroupAddEditDialogParams>
|
||||
) => {
|
||||
return dialogService.open<GroupAddEditDialogResultType, GroupAddEditDialogParams>(
|
||||
GroupAddEditComponent,
|
||||
config
|
||||
);
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-group-add-edit",
|
||||
templateUrl: "group-add-edit.component.html",
|
||||
})
|
||||
export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
protected PermissionMode = PermissionMode;
|
||||
protected ResultType = GroupAddEditDialogResultType;
|
||||
|
||||
tabIndex: GroupAddEditTabType;
|
||||
loading = true;
|
||||
editMode = false;
|
||||
title: string;
|
||||
collections: AccessItemView[] = [];
|
||||
members: AccessItemView[] = [];
|
||||
group: GroupView;
|
||||
|
||||
groupForm = this.formBuilder.group({
|
||||
accessAll: [false],
|
||||
name: ["", [Validators.required, Validators.maxLength(100)]],
|
||||
externalId: this.formBuilder.control({ value: "", disabled: true }),
|
||||
members: [[] as AccessItemValue[]],
|
||||
collections: [[] as AccessItemValue[]],
|
||||
});
|
||||
|
||||
get groupId(): string | undefined {
|
||||
return this.params.groupId;
|
||||
}
|
||||
|
||||
get organizationId(): string {
|
||||
return this.params.organizationId;
|
||||
}
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
private get orgCollections$() {
|
||||
return from(this.apiService.getCollections(this.organizationId)).pipe(
|
||||
switchMap((response) => {
|
||||
return from(
|
||||
this.collectionService.decryptMany(
|
||||
response.data.map(
|
||||
(r) => new Collection(new CollectionData(r as CollectionDetailsResponse))
|
||||
)
|
||||
)
|
||||
);
|
||||
}),
|
||||
map((collections) =>
|
||||
collections.map<AccessItemView>((c) => ({
|
||||
id: c.id,
|
||||
type: AccessItemType.Collection,
|
||||
labelName: c.name,
|
||||
listName: c.name,
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private get orgMembers$() {
|
||||
return from(this.organizationUserService.getAllUsers(this.organizationId)).pipe(
|
||||
map((response) =>
|
||||
response.data.map((m) => ({
|
||||
id: m.id,
|
||||
type: AccessItemType.Member,
|
||||
email: m.email,
|
||||
role: m.type,
|
||||
listName: m.name?.length > 0 ? `${m.name} (${m.email})` : m.email,
|
||||
labelName: m.name || m.email,
|
||||
status: m.status,
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private get groupDetails$() {
|
||||
if (!this.editMode) {
|
||||
return of(undefined);
|
||||
}
|
||||
|
||||
return combineLatest([
|
||||
this.groupService.get(this.organizationId, this.groupId),
|
||||
this.apiService.getGroupUsers(this.organizationId, this.groupId),
|
||||
]).pipe(
|
||||
map(([groupView, users]) => {
|
||||
groupView.members = users;
|
||||
return groupView;
|
||||
}),
|
||||
catchError((e: unknown) => {
|
||||
if (e instanceof ErrorResponse) {
|
||||
this.logService.error(e.message);
|
||||
} else {
|
||||
this.logService.error(e.toString());
|
||||
}
|
||||
return of(undefined);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) private params: GroupAddEditDialogParams,
|
||||
private dialogRef: DialogRef<GroupAddEditDialogResultType>,
|
||||
private apiService: ApiService,
|
||||
private organizationUserService: OrganizationUserService,
|
||||
private groupService: GroupService,
|
||||
private i18nService: I18nService,
|
||||
private collectionService: CollectionService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private logService: LogService,
|
||||
private formBuilder: FormBuilder,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
this.tabIndex = params.initialTab ?? GroupAddEditTabType.Info;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.editMode = this.loading = this.groupId != null;
|
||||
this.title = this.i18nService.t(this.editMode ? "editGroup" : "newGroup");
|
||||
|
||||
combineLatest([this.orgCollections$, this.orgMembers$, this.groupDetails$])
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(([collections, members, group]) => {
|
||||
this.collections = collections;
|
||||
this.members = members;
|
||||
this.group = group;
|
||||
|
||||
if (this.group != undefined) {
|
||||
// Must detect changes so that AccessSelector @Inputs() are aware of the latest
|
||||
// collections/members set above, otherwise no selected values will be patched below
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
this.groupForm.patchValue({
|
||||
name: this.group.name,
|
||||
externalId: this.group.externalId,
|
||||
accessAll: this.group.accessAll,
|
||||
members: this.group.members.map((m) => ({
|
||||
id: m,
|
||||
type: AccessItemType.Member,
|
||||
})),
|
||||
collections: this.group.collections.map((gc) => ({
|
||||
id: gc.id,
|
||||
type: AccessItemType.Collection,
|
||||
permission: convertToPermission(gc),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
this.groupForm.markAllAsTouched();
|
||||
|
||||
if (this.groupForm.invalid) {
|
||||
if (this.tabIndex !== GroupAddEditTabType.Info) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
null,
|
||||
this.i18nService.t("fieldOnTabRequiresAttention", this.i18nService.t("groupInfo"))
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const groupView = new GroupView();
|
||||
groupView.id = this.groupId;
|
||||
groupView.organizationId = this.organizationId;
|
||||
|
||||
const formValue = this.groupForm.value;
|
||||
groupView.name = formValue.name;
|
||||
groupView.accessAll = formValue.accessAll;
|
||||
groupView.members = formValue.members?.map((m) => m.id) ?? [];
|
||||
|
||||
if (!groupView.accessAll) {
|
||||
groupView.collections = formValue.collections.map((c) => convertToSelectionView(c));
|
||||
}
|
||||
|
||||
await this.groupService.save(groupView);
|
||||
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.editMode ? "editedGroupId" : "createdGroupId", formValue.name)
|
||||
);
|
||||
|
||||
this.dialogRef.close(GroupAddEditDialogResultType.Saved);
|
||||
};
|
||||
|
||||
delete = async () => {
|
||||
if (!this.editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("deleteGroupConfirmation"),
|
||||
this.group.name,
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("no"),
|
||||
"warning",
|
||||
false,
|
||||
"app-group-add-edit .modal-content"
|
||||
);
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.groupService.delete(this.organizationId, this.groupId);
|
||||
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("deletedGroupId", this.group.name)
|
||||
);
|
||||
this.dialogRef.close(GroupAddEditDialogResultType.Deleted);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user