mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-02 13:23:29 +01:00
[AC-1418] Add initial SM adjustment form
This commit is contained in:
parent
c46d522ac8
commit
55eaff06d6
@ -1 +1,92 @@
|
||||
<p>Secrets Manager Adjust Subscription Component</p>
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-form-field class="tw-w-1/2">
|
||||
<bit-label>{{ "subscriptionSeats" | i18n }}</bit-label>
|
||||
<input bitInput id="smSeatCount" formControlName="seatCount" type="number" step="1" />
|
||||
<bit-hint>
|
||||
<strong>{{ "total" | i18n }}:</strong>
|
||||
{{ formGroup.value.seatCount }} × {{ options.seatPrice | currency }} =
|
||||
{{ seatTotal | currency }} / {{ options.interval | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitSubscription" | i18n }}</bit-label>
|
||||
<input type="checkbox" bitCheckbox id="limitSmSeats" formControlName="limitSeats" />
|
||||
<bit-hint>
|
||||
{{ "limitSmSubscriptionDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-field class="tw-w-1/2" *ngIf="formGroup.value.limitSeats">
|
||||
<bit-label>{{ "maxSeatLimit" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
id="smSeatLimit"
|
||||
formControlName="seatLimit"
|
||||
type="number"
|
||||
step="1"
|
||||
[min]="formGroup.value.seatCount"
|
||||
/>
|
||||
<bit-hint>
|
||||
<strong>{{ "total" | i18n }}:</strong>
|
||||
{{ formGroup.value.seatLimit || 0 }} × {{ options.seatPrice | currency }} =
|
||||
{{ maxSeatTotal | currency }} / {{ options.interval | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-field class="tw-w-1/2">
|
||||
<bit-label>{{ "additionalServiceAccounts" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
id="additionalServiceAccountCount"
|
||||
formControlName="serviceAccountCount"
|
||||
type="number"
|
||||
step="1"
|
||||
min="0"
|
||||
/>
|
||||
<bit-hint>
|
||||
<div>
|
||||
{{
|
||||
"additionalServiceAccountsDesc"
|
||||
| i18n : options.baseServiceAccountCount : (monthlyServiceAccountPrice | currency)
|
||||
}}
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ "total" | i18n }}:</strong>
|
||||
{{ formGroup.value.serviceAccountCount || 0 }} ×
|
||||
{{ options.additionalServiceAccountPrice | currency }} =
|
||||
{{ serviceAccountTotal | currency }} / {{ options.interval | i18n }}
|
||||
</div>
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-control>
|
||||
<bit-label>{{ "limitServiceAccounts" | i18n }}</bit-label>
|
||||
<input
|
||||
type="checkbox"
|
||||
bitCheckbox
|
||||
id="limitServiceAccounts"
|
||||
formControlName="limitServiceAccounts"
|
||||
/>
|
||||
<bit-hint>
|
||||
{{ "limitServiceAccountsDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-field class="tw-w-1/2" *ngIf="formGroup.value.limitServiceAccounts">
|
||||
<bit-label>{{ "serviceAccountLimit" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
id="additionalServiceAccountLimit"
|
||||
formControlName="serviceAccountLimit"
|
||||
type="number"
|
||||
step="1"
|
||||
[min]="formGroup.value.serviceAccountCount"
|
||||
/>
|
||||
<bit-hint>
|
||||
<strong>{{ "total" | i18n }}:</strong>
|
||||
{{ formGroup.value.serviceAccountLimit || 0 }} ×
|
||||
{{ options.additionalServiceAccountPrice | currency }} =
|
||||
{{ maxServiceAccountTotal | currency }} / {{ options.interval | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<button type="submit" bitButton buttonType="primary" bitFormButton>
|
||||
{{ "save" | i18n }}
|
||||
</button>
|
||||
<bit-error-summary [formGroup]="formGroup" class="tw-mt-2"></bit-error-summary>
|
||||
</form>
|
||||
|
@ -1,7 +1,118 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
export interface SecretsManagerSubscriptionOptions {
|
||||
interval: "year" | "month";
|
||||
seatCount: number;
|
||||
seatLimit: number;
|
||||
seatPrice: number;
|
||||
|
||||
/**
|
||||
* The number of service accounts that are included in the base subscription.
|
||||
*/
|
||||
baseServiceAccountCount: number;
|
||||
|
||||
additionalServiceAccountCount: number;
|
||||
additionalServiceAccountLimit: number;
|
||||
additionalServiceAccountPrice: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "app-sm-adjust-subscription",
|
||||
templateUrl: "sm-adjust-subscription.component.html",
|
||||
})
|
||||
export class SecretsManagerAdjustSubscriptionComponent {}
|
||||
export class SecretsManagerAdjustSubscriptionComponent implements OnInit, OnDestroy {
|
||||
@Input() organizationId: string;
|
||||
@Input() options: SecretsManagerSubscriptionOptions;
|
||||
@Output() onAdjusted = new EventEmitter();
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
formGroup = this.formBuilder.group({
|
||||
seatCount: [0, [Validators.required, Validators.min(0)]],
|
||||
limitSeats: [false],
|
||||
seatLimit: [null as number | null],
|
||||
serviceAccountCount: [0, [Validators.required, Validators.min(0)]],
|
||||
limitServiceAccounts: [false],
|
||||
serviceAccountLimit: [null as number | null],
|
||||
});
|
||||
|
||||
get monthlyServiceAccountPrice(): number {
|
||||
return this.options.interval == "month"
|
||||
? this.options.additionalServiceAccountPrice
|
||||
: Math.round((this.options.additionalServiceAccountPrice / 12 + Number.EPSILON) * 100) / 100;
|
||||
}
|
||||
|
||||
get serviceAccountTotal(): number {
|
||||
return Math.abs(
|
||||
this.formGroup.value.serviceAccountCount * this.options.additionalServiceAccountPrice
|
||||
);
|
||||
}
|
||||
|
||||
get seatTotal(): number {
|
||||
return Math.abs(this.formGroup.value.seatCount * this.options.seatPrice);
|
||||
}
|
||||
|
||||
get maxServiceAccountTotal(): number {
|
||||
return Math.abs(
|
||||
(this.formGroup.value.serviceAccountLimit ?? 0) * this.options.additionalServiceAccountPrice
|
||||
);
|
||||
}
|
||||
|
||||
get maxSeatTotal(): number {
|
||||
return Math.abs((this.formGroup.value.seatLimit ?? 0) * this.options.seatPrice);
|
||||
}
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.formGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||
const seatLimitControl = this.formGroup.controls.seatLimit;
|
||||
const serviceAccountLimitControl = this.formGroup.controls.serviceAccountLimit;
|
||||
|
||||
if (value.limitSeats) {
|
||||
seatLimitControl.setValidators([Validators.required, Validators.min(value.seatCount)]);
|
||||
seatLimitControl.enable({ emitEvent: false });
|
||||
} else {
|
||||
seatLimitControl.disable({ emitEvent: false });
|
||||
}
|
||||
|
||||
if (value.limitServiceAccounts) {
|
||||
serviceAccountLimitControl.setValidators([
|
||||
Validators.required,
|
||||
Validators.min(value.serviceAccountCount),
|
||||
]);
|
||||
serviceAccountLimitControl.enable({ emitEvent: false });
|
||||
} else {
|
||||
serviceAccountLimitControl.disable({ emitEvent: false });
|
||||
}
|
||||
});
|
||||
|
||||
this.formGroup.patchValue({
|
||||
seatCount: this.options.seatCount,
|
||||
seatLimit: this.options.seatLimit,
|
||||
serviceAccountCount: this.options.additionalServiceAccountCount,
|
||||
serviceAccountLimit: this.options.additionalServiceAccountLimit,
|
||||
limitSeats: this.options.seatLimit != null,
|
||||
limitServiceAccounts: this.options.additionalServiceAccountLimit != null,
|
||||
});
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
this.formGroup.markAllAsTouched();
|
||||
|
||||
if (this.formGroup.invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Make the request to update the subscription
|
||||
|
||||
this.onAdjusted.emit();
|
||||
};
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
@ -3309,6 +3309,9 @@
|
||||
"limitSubscriptionDesc": {
|
||||
"message": "Set a seat limit for your subscription. Once this limit is reached, you will not be able to invite new members."
|
||||
},
|
||||
"limitSmSubscriptionDesc": {
|
||||
"message": "Set a seat limit for your Secrets Manger subscription. Once this limit is reached, you will not be able to invite new members."
|
||||
},
|
||||
"maxSeatLimit": {
|
||||
"message": "Seat Limit (optional)",
|
||||
"description": "Upper limit of seats to allow through autoscaling"
|
||||
@ -6911,5 +6914,30 @@
|
||||
},
|
||||
"freeOrganization": {
|
||||
"message": "Free Organization"
|
||||
},
|
||||
"additionalServiceAccounts": {
|
||||
"message": "Additional Service Accounts"
|
||||
},
|
||||
"limitServiceAccounts": {
|
||||
"message": "Limit service accounts (optional)"
|
||||
},
|
||||
"limitServiceAccountsDesc": {
|
||||
"message": "Set a limit for your service accounts. Once this limit is reached, you will not be able to create new service accounts."
|
||||
},
|
||||
"serviceAccountLimit": {
|
||||
"message": "Service account limit (optional)"
|
||||
},
|
||||
"additionalServiceAccountsDesc": {
|
||||
"message": "Your plan comes with $COUNT$ service accounts. You can add additional service accounts for $COST$ per month.",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"content": "$1",
|
||||
"example": "50"
|
||||
},
|
||||
"cost": {
|
||||
"content": "$2",
|
||||
"example": "$0.50"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user