[AC-2420] Hide SM checkbox on member invite when org is on SM Standalone (#8644)
* Refactoring * Hide SM toggle on member invite and default to true for SM standalone org * changed from hide sm checkbox to default and disable * Removed errant addition from conflict resolution
This commit is contained in:
parent
a45706cde7
commit
adb1ee3d38
|
@ -385,7 +385,12 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p class="tw-text-muted">{{ "secretsManagerAccessDescription" | i18n }}</p>
|
<p class="tw-text-muted">{{ "secretsManagerAccessDescription" | i18n }}</p>
|
||||||
<bit-form-control>
|
<bit-form-control>
|
||||||
<input type="checkbox" bitCheckbox formControlName="accessSecretsManager" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
[disabled]="isOnSecretsManagerStandalone"
|
||||||
|
bitCheckbox
|
||||||
|
formControlName="accessSecretsManager"
|
||||||
|
/>
|
||||||
<bit-label>
|
<bit-label>
|
||||||
{{ "userAccessSecretsManagerGA" | i18n }}
|
{{ "userAccessSecretsManagerGA" | i18n }}
|
||||||
</bit-label>
|
</bit-label>
|
||||||
|
|
|
@ -63,6 +63,7 @@ export interface MemberDialogParams {
|
||||||
organizationUserId: string;
|
organizationUserId: string;
|
||||||
allOrganizationUserEmails: string[];
|
allOrganizationUserEmails: string[];
|
||||||
usesKeyConnector: boolean;
|
usesKeyConnector: boolean;
|
||||||
|
isOnSecretsManagerStandalone: boolean;
|
||||||
initialTab?: MemberDialogTab;
|
initialTab?: MemberDialogTab;
|
||||||
numConfirmedMembers: number;
|
numConfirmedMembers: number;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +89,7 @@ export class MemberDialogComponent implements OnDestroy {
|
||||||
organizationUserType = OrganizationUserType;
|
organizationUserType = OrganizationUserType;
|
||||||
PermissionMode = PermissionMode;
|
PermissionMode = PermissionMode;
|
||||||
showNoMasterPasswordWarning = false;
|
showNoMasterPasswordWarning = false;
|
||||||
|
isOnSecretsManagerStandalone: boolean;
|
||||||
|
|
||||||
protected organization$: Observable<Organization>;
|
protected organization$: Observable<Organization>;
|
||||||
protected collectionAccessItems: AccessItemView[] = [];
|
protected collectionAccessItems: AccessItemView[] = [];
|
||||||
|
@ -160,6 +162,13 @@ export class MemberDialogComponent implements OnDestroy {
|
||||||
this.editMode = this.params.organizationUserId != null;
|
this.editMode = this.params.organizationUserId != null;
|
||||||
this.tabIndex = this.params.initialTab ?? MemberDialogTab.Role;
|
this.tabIndex = this.params.initialTab ?? MemberDialogTab.Role;
|
||||||
this.title = this.i18nService.t(this.editMode ? "editMember" : "inviteMember");
|
this.title = this.i18nService.t(this.editMode ? "editMember" : "inviteMember");
|
||||||
|
this.isOnSecretsManagerStandalone = this.params.isOnSecretsManagerStandalone;
|
||||||
|
|
||||||
|
if (this.isOnSecretsManagerStandalone) {
|
||||||
|
this.formGroup.patchValue({
|
||||||
|
accessSecretsManager: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const groups$ = this.organization$.pipe(
|
const groups$ = this.organization$.pipe(
|
||||||
switchMap((organization) =>
|
switchMap((organization) =>
|
||||||
|
|
|
@ -37,6 +37,7 @@ import {
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||||
|
import { OrganizationBillingServiceAbstraction as OrganizationBillingService } from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
||||||
import { ProductType } from "@bitwarden/common/enums";
|
import { ProductType } from "@bitwarden/common/enums";
|
||||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
|
@ -93,6 +94,7 @@ export class PeopleComponent extends BasePeopleComponent<OrganizationUserView> {
|
||||||
organization: Organization;
|
organization: Organization;
|
||||||
status: OrganizationUserStatusType = null;
|
status: OrganizationUserStatusType = null;
|
||||||
orgResetPasswordPolicyEnabled = false;
|
orgResetPasswordPolicyEnabled = false;
|
||||||
|
orgIsOnSecretsManagerStandalone = false;
|
||||||
|
|
||||||
protected canUseSecretsManager$: Observable<boolean>;
|
protected canUseSecretsManager$: Observable<boolean>;
|
||||||
|
|
||||||
|
@ -119,6 +121,7 @@ export class PeopleComponent extends BasePeopleComponent<OrganizationUserView> {
|
||||||
private groupService: GroupService,
|
private groupService: GroupService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
organizationManagementPreferencesService: OrganizationManagementPreferencesService,
|
||||||
|
private organizationBillingService: OrganizationBillingService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
apiService,
|
apiService,
|
||||||
|
@ -187,6 +190,11 @@ export class PeopleComponent extends BasePeopleComponent<OrganizationUserView> {
|
||||||
.find((p) => p.organizationId === this.organization.id);
|
.find((p) => p.organizationId === this.organization.id);
|
||||||
this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
|
this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
|
||||||
|
|
||||||
|
this.orgIsOnSecretsManagerStandalone =
|
||||||
|
await this.organizationBillingService.isOnSecretsManagerStandalone(
|
||||||
|
this.organization.id,
|
||||||
|
);
|
||||||
|
|
||||||
await this.load();
|
await this.load();
|
||||||
|
|
||||||
this.searchText = qParams.search;
|
this.searchText = qParams.search;
|
||||||
|
@ -446,6 +454,7 @@ export class PeopleComponent extends BasePeopleComponent<OrganizationUserView> {
|
||||||
organizationUserId: user != null ? user.id : null,
|
organizationUserId: user != null ? user.id : null,
|
||||||
allOrganizationUserEmails: this.allUsers?.map((user) => user.email) ?? [],
|
allOrganizationUserEmails: this.allUsers?.map((user) => user.email) ?? [],
|
||||||
usesKeyConnector: user?.usesKeyConnector,
|
usesKeyConnector: user?.usesKeyConnector,
|
||||||
|
isOnSecretsManagerStandalone: this.orgIsOnSecretsManagerStandalone,
|
||||||
initialTab: initialTab,
|
initialTab: initialTab,
|
||||||
numConfirmedMembers: this.confirmedCount,
|
numConfirmedMembers: this.confirmedCount,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1052,6 +1052,7 @@ const safeProviders: SafeProvider[] = [
|
||||||
useClass: OrganizationBillingService,
|
useClass: OrganizationBillingService,
|
||||||
deps: [
|
deps: [
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
|
BillingApiServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
EncryptService,
|
EncryptService,
|
||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request";
|
import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request";
|
||||||
import { OrganizationBillingStatusResponse } from "../../billing/models/response/organization-billing-status.response";
|
import { OrganizationBillingStatusResponse } from "../../billing/models/response/organization-billing-status.response";
|
||||||
|
import { OrganizationSubscriptionResponse } from "../../billing/models/response/organization-subscription.response";
|
||||||
import { PlanResponse } from "../../billing/models/response/plan.response";
|
import { PlanResponse } from "../../billing/models/response/plan.response";
|
||||||
import { ListResponse } from "../../models/response/list.response";
|
import { ListResponse } from "../../models/response/list.response";
|
||||||
import { CreateClientOrganizationRequest } from "../models/request/create-client-organization.request";
|
import { CreateClientOrganizationRequest } from "../models/request/create-client-organization.request";
|
||||||
|
@ -11,12 +12,16 @@ export abstract class BillingApiServiceAbstraction {
|
||||||
organizationId: string,
|
organizationId: string,
|
||||||
request: SubscriptionCancellationRequest,
|
request: SubscriptionCancellationRequest,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
cancelPremiumUserSubscription: (request: SubscriptionCancellationRequest) => Promise<void>;
|
cancelPremiumUserSubscription: (request: SubscriptionCancellationRequest) => Promise<void>;
|
||||||
createClientOrganization: (
|
createClientOrganization: (
|
||||||
providerId: string,
|
providerId: string,
|
||||||
request: CreateClientOrganizationRequest,
|
request: CreateClientOrganizationRequest,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getBillingStatus: (id: string) => Promise<OrganizationBillingStatusResponse>;
|
getBillingStatus: (id: string) => Promise<OrganizationBillingStatusResponse>;
|
||||||
|
getOrganizationSubscription: (
|
||||||
|
organizationId: string,
|
||||||
|
) => Promise<OrganizationSubscriptionResponse>;
|
||||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
||||||
getProviderSubscription: (providerId: string) => Promise<ProviderSubscriptionResponse>;
|
getProviderSubscription: (providerId: string) => Promise<ProviderSubscriptionResponse>;
|
||||||
updateClientOrganization: (
|
updateClientOrganization: (
|
||||||
|
|
|
@ -41,6 +41,8 @@ export type SubscriptionInformation = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class OrganizationBillingServiceAbstraction {
|
export abstract class OrganizationBillingServiceAbstraction {
|
||||||
|
isOnSecretsManagerStandalone: (organizationId: string) => Promise<boolean>;
|
||||||
|
|
||||||
purchaseSubscription: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
|
purchaseSubscription: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
|
||||||
|
|
||||||
startFree: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
|
startFree: (subscription: SubscriptionInformation) => Promise<OrganizationResponse>;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { ApiService } from "../../abstractions/api.service";
|
||||||
import { BillingApiServiceAbstraction } from "../../billing/abstractions/billilng-api.service.abstraction";
|
import { BillingApiServiceAbstraction } from "../../billing/abstractions/billilng-api.service.abstraction";
|
||||||
import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request";
|
import { SubscriptionCancellationRequest } from "../../billing/models/request/subscription-cancellation.request";
|
||||||
import { OrganizationBillingStatusResponse } from "../../billing/models/response/organization-billing-status.response";
|
import { OrganizationBillingStatusResponse } from "../../billing/models/response/organization-billing-status.response";
|
||||||
|
import { OrganizationSubscriptionResponse } from "../../billing/models/response/organization-subscription.response";
|
||||||
import { PlanResponse } from "../../billing/models/response/plan.response";
|
import { PlanResponse } from "../../billing/models/response/plan.response";
|
||||||
import { ListResponse } from "../../models/response/list.response";
|
import { ListResponse } from "../../models/response/list.response";
|
||||||
import { CreateClientOrganizationRequest } from "../models/request/create-client-organization.request";
|
import { CreateClientOrganizationRequest } from "../models/request/create-client-organization.request";
|
||||||
|
@ -49,10 +50,22 @@ export class BillingApiService implements BillingApiServiceAbstraction {
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return new OrganizationBillingStatusResponse(r);
|
return new OrganizationBillingStatusResponse(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getOrganizationSubscription(
|
||||||
|
organizationId: string,
|
||||||
|
): Promise<OrganizationSubscriptionResponse> {
|
||||||
|
const r = await this.apiService.send(
|
||||||
|
"GET",
|
||||||
|
"/organizations/" + organizationId + "/subscription",
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
return new OrganizationSubscriptionResponse(r);
|
||||||
|
}
|
||||||
|
|
||||||
async getPlans(): Promise<ListResponse<PlanResponse>> {
|
async getPlans(): Promise<ListResponse<PlanResponse>> {
|
||||||
const r = await this.apiService.send("GET", "/plans", null, false, true);
|
const r = await this.apiService.send("GET", "/plans", null, false, true);
|
||||||
return new ListResponse(r, PlanResponse);
|
return new ListResponse(r, PlanResponse);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { I18nService } from "../../platform/abstractions/i18n.service";
|
||||||
import { EncString } from "../../platform/models/domain/enc-string";
|
import { EncString } from "../../platform/models/domain/enc-string";
|
||||||
import { OrgKey } from "../../types/key";
|
import { OrgKey } from "../../types/key";
|
||||||
import { SyncService } from "../../vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "../../vault/abstractions/sync/sync.service.abstraction";
|
||||||
|
import { BillingApiServiceAbstraction as BillingApiService } from "../abstractions/billilng-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
OrganizationBillingServiceAbstraction,
|
OrganizationBillingServiceAbstraction,
|
||||||
OrganizationInformation,
|
OrganizationInformation,
|
||||||
|
@ -28,6 +29,7 @@ interface OrganizationKeys {
|
||||||
export class OrganizationBillingService implements OrganizationBillingServiceAbstraction {
|
export class OrganizationBillingService implements OrganizationBillingServiceAbstraction {
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
private billingApiService: BillingApiService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private encryptService: EncryptService,
|
private encryptService: EncryptService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
|
@ -35,6 +37,19 @@ export class OrganizationBillingService implements OrganizationBillingServiceAbs
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
async isOnSecretsManagerStandalone(organizationId: string): Promise<boolean> {
|
||||||
|
const response = await this.billingApiService.getOrganizationSubscription(organizationId);
|
||||||
|
if (response.customerDiscount?.id === "sm-standalone") {
|
||||||
|
const productIds = response.subscription.items.map((item) => item.productId);
|
||||||
|
return (
|
||||||
|
response.customerDiscount?.appliesTo.filter((appliesToProductId) =>
|
||||||
|
productIds.includes(appliesToProductId),
|
||||||
|
).length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async purchaseSubscription(subscription: SubscriptionInformation): Promise<OrganizationResponse> {
|
async purchaseSubscription(subscription: SubscriptionInformation): Promise<OrganizationResponse> {
|
||||||
const request = new OrganizationCreateRequest();
|
const request = new OrganizationCreateRequest();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue