Add ability to edit client organization name (#9103)

This commit is contained in:
Alex Morask 2024-05-14 09:22:32 -04:00 committed by GitHub
parent 16971be52d
commit 26c08123bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 143 additions and 2 deletions

View File

@ -8186,5 +8186,11 @@
},
"viewAccess": {
"message": "View access"
},
"updateName": {
"message": "Update name"
},
"updatedOrganizationName": {
"message": "Updated organization name"
}
}

View File

@ -12,8 +12,9 @@ import { OssModule } from "@bitwarden/web-vault/app/oss.module";
import { ProviderSubscriptionComponent } from "../../billing/providers";
import {
CreateClientOrganizationComponent,
ManageClientOrganizationSubscriptionComponent,
ManageClientOrganizationsComponent,
ManageClientOrganizationNameComponent,
ManageClientOrganizationSubscriptionComponent,
} from "../../billing/providers/clients";
import { AddOrganizationComponent } from "./clients/add-organization.component";
@ -62,6 +63,7 @@ import { SetupComponent } from "./setup/setup.component";
UserAddEditComponent,
CreateClientOrganizationComponent,
ManageClientOrganizationsComponent,
ManageClientOrganizationNameComponent,
ManageClientOrganizationSubscriptionComponent,
ProviderSubscriptionComponent,
],

View File

@ -1,3 +1,4 @@
export * from "./create-client-organization.component";
export * from "./manage-client-organizations.component";
export * from "./manage-client-organization-name.component";
export * from "./manage-client-organization-subscription.component";

View File

@ -0,0 +1,24 @@
<form [formGroup]="formGroup" [bitSubmit]="submit">
<bit-dialog>
<span bitDialogTitle class="tw-font-semibold">
{{ "updateName" | i18n }}
<small class="tw-text-muted">{{ dialogParams.organization.name }}</small>
</span>
<div bitDialogContent>
<bit-form-field>
<bit-label>
{{ "organizationName" | i18n }}
</bit-label>
<input type="text" bitInput formControlName="name" />
</bit-form-field>
</div>
<ng-container bitDialogFooter>
<button bitButton bitFormButton buttonType="primary" type="submit">
{{ "save" | i18n }}
</button>
<button bitButton buttonType="secondary" type="button" [bitDialogClose]="ResultType.Closed">
{{ "cancel" | i18n }}
</button>
</ng-container>
</bit-dialog>
</form>

View File

@ -0,0 +1,77 @@
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction";
import { UpdateClientOrganizationRequest } from "@bitwarden/common/billing/models/request/update-client-organization.request";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService, ToastService } from "@bitwarden/components";
type ManageClientOrganizationNameParams = {
providerId: string;
organization: {
id: string;
name: string;
seats: number;
};
};
export enum ManageClientOrganizationNameResultType {
Closed = "closed",
Submitted = "submitted",
}
export const openManageClientOrganizationNameDialog = (
dialogService: DialogService,
dialogConfig: DialogConfig<ManageClientOrganizationNameParams>,
) =>
dialogService.open<ManageClientOrganizationNameResultType, ManageClientOrganizationNameParams>(
ManageClientOrganizationNameComponent,
dialogConfig,
);
@Component({
selector: "app-manage-client-organization-name",
templateUrl: "manage-client-organization-name.component.html",
})
export class ManageClientOrganizationNameComponent {
protected ResultType = ManageClientOrganizationNameResultType;
protected formGroup = this.formBuilder.group({
name: [this.dialogParams.organization.name, Validators.required],
});
constructor(
@Inject(DIALOG_DATA) protected dialogParams: ManageClientOrganizationNameParams,
private billingApiService: BillingApiServiceAbstraction,
private dialogRef: DialogRef<ManageClientOrganizationNameResultType>,
private formBuilder: FormBuilder,
private i18nService: I18nService,
private toastService: ToastService,
) {}
submit = async () => {
this.formGroup.markAllAsTouched();
if (this.formGroup.invalid) {
return;
}
const request = new UpdateClientOrganizationRequest();
request.assignedSeats = this.dialogParams.organization.seats;
request.name = this.formGroup.value.name;
await this.billingApiService.updateClientOrganization(
this.dialogParams.providerId,
this.dialogParams.organization.id,
request,
);
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("updatedOrganizationName"),
});
this.dialogRef.close(this.ResultType.Submitted);
};
}

View File

@ -71,6 +71,7 @@ export class ManageClientOrganizationSubscriptionComponent implements OnInit {
const request = new UpdateClientOrganizationRequest();
request.assignedSeats = assignedSeats;
request.name = this.clientName;
await this.billingApiService.updateClientOrganization(
this.providerId,

View File

@ -78,8 +78,12 @@
appA11yTitle="{{ 'options' | i18n }}"
></button>
<bit-menu #rowMenu>
<button type="button" bitMenuItem (click)="manageName(client)">
<i aria-hidden="true" class="bwi bwi-pencil-square"></i>
{{ "updateName" | i18n }}
</button>
<button type="button" bitMenuItem (click)="manageSubscription(client)">
<i aria-hidden="true" class="bwi bwi-question-circle"></i>
<i aria-hidden="true" class="bwi bwi-family"></i>
{{ "manageSubscription" | i18n }}
</button>
<button type="button" bitMenuItem (click)="remove(client)">

View File

@ -24,6 +24,10 @@ import {
CreateClientOrganizationResultType,
openCreateClientOrganizationDialog,
} from "./create-client-organization.component";
import {
ManageClientOrganizationNameResultType,
openManageClientOrganizationNameDialog,
} from "./manage-client-organization-name.component";
import { ManageClientOrganizationSubscriptionComponent } from "./manage-client-organization-subscription.component";
@Component({
@ -106,6 +110,25 @@ export class ManageClientOrganizationsComponent extends BaseClientsComponent {
this.loading = false;
}
async manageName(organization: ProviderOrganizationOrganizationDetailsResponse) {
const dialogRef = openManageClientOrganizationNameDialog(this.dialogService, {
data: {
providerId: this.providerId,
organization: {
id: organization.id,
name: organization.organizationName,
seats: organization.seats,
},
},
});
const result = await firstValueFrom(dialogRef.closed);
if (result === ManageClientOrganizationNameResultType.Submitted) {
await this.load();
}
}
async manageSubscription(organization: ProviderOrganizationOrganizationDetailsResponse) {
if (organization == null) {
return;
@ -135,4 +158,6 @@ export class ManageClientOrganizationsComponent extends BaseClientsComponent {
await this.load();
};
protected readonly openManageClientOrganizationNameDialog =
openManageClientOrganizationNameDialog;
}

View File

@ -1,3 +1,4 @@
export class UpdateClientOrganizationRequest {
assignedSeats: number;
name: string;
}