mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-26363] Add one time setup dialog for auto confirm (#17104)
* add one time setup dialog for auto confirm
* add one time setup dialog for auto confirm
* fix copy, padding, cleanup observable logic
* cleanup
* cleanup
* refactor
* clean up
* more cleanup
* Fix deleted files
This reverts commit 7c18a5e512.
This commit is contained in:
@@ -38,11 +38,11 @@
|
|||||||
<div class="tw-flex tw-flex-col">
|
<div class="tw-flex tw-flex-col">
|
||||||
@let showBadge = firstTimeDialog();
|
@let showBadge = firstTimeDialog();
|
||||||
@if (showBadge) {
|
@if (showBadge) {
|
||||||
<span bitBadge variant="info" class="tw-w-28 tw-my-2"> {{ "availableNow" | i18n }}</span>
|
<span bitBadge variant="info" class="tw-w-[99px] tw-my-2"> {{ "availableNow" | i18n }}</span>
|
||||||
}
|
}
|
||||||
<span>
|
<span>
|
||||||
{{ (firstTimeDialog ? "autoConfirm" : "editPolicy") | i18n }}
|
{{ (showBadge ? "autoConfirm" : "editPolicy") | i18n }}
|
||||||
@if (!firstTimeDialog) {
|
@if (!showBadge) {
|
||||||
<span class="tw-text-muted tw-font-normal tw-text-sm">
|
<span class="tw-text-muted tw-font-normal tw-text-sm">
|
||||||
{{ policy.name | i18n }}
|
{{ policy.name | i18n }}
|
||||||
</span>
|
</span>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
@let autoConfirmEnabled = autoConfirmEnabled$ | async;
|
@let autoConfirmEnabled = autoConfirmEnabled$ | async;
|
||||||
@let managePoliciesOnly = managePolicies$ | async;
|
@let managePoliciesOnly = managePoliciesOnly$ | async;
|
||||||
@if (autoConfirmEnabled || managePoliciesOnly) {
|
@if (autoConfirmEnabled || managePoliciesOnly) {
|
||||||
{{ "save" | i18n }}
|
{{ "save" | i18n }}
|
||||||
} @else {
|
} @else {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
tap,
|
tap,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
|
|
||||||
|
import { AutomaticUserConfirmationService } from "@bitwarden/admin-console/common";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -85,7 +86,10 @@ export class AutoConfirmPolicyDialogComponent
|
|||||||
switchMap((userId) => this.policyService.policies$(userId)),
|
switchMap((userId) => this.policyService.policies$(userId)),
|
||||||
map((policies) => policies.find((p) => p.type === PolicyType.AutoConfirm)?.enabled ?? false),
|
map((policies) => policies.find((p) => p.type === PolicyType.AutoConfirm)?.enabled ?? false),
|
||||||
);
|
);
|
||||||
protected managePolicies$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
// Users with manage policies custom permission should not see the dialog's second step since
|
||||||
|
// they do not have permission to configure the setting. This will only allow them to configure
|
||||||
|
// the policy.
|
||||||
|
protected managePoliciesOnly$: Observable<boolean> = this.accountService.activeAccount$.pipe(
|
||||||
getUserId,
|
getUserId,
|
||||||
switchMap((userId) => this.organizationService.organizations$(userId)),
|
switchMap((userId) => this.organizationService.organizations$(userId)),
|
||||||
getById(this.data.organizationId),
|
getById(this.data.organizationId),
|
||||||
@@ -116,6 +120,7 @@ export class AutoConfirmPolicyDialogComponent
|
|||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private autoConfirmService: AutomaticUserConfirmationService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
data,
|
data,
|
||||||
@@ -161,7 +166,7 @@ export class AutoConfirmPolicyDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildMultiStepSubmit(singleOrgPolicyEnabled: boolean): Observable<MultiStepSubmit[]> {
|
private buildMultiStepSubmit(singleOrgPolicyEnabled: boolean): Observable<MultiStepSubmit[]> {
|
||||||
return this.managePolicies$.pipe(
|
return this.managePoliciesOnly$.pipe(
|
||||||
map((managePoliciesOnly) => {
|
map((managePoliciesOnly) => {
|
||||||
const submitSteps = [
|
const submitSteps = [
|
||||||
{
|
{
|
||||||
@@ -206,6 +211,17 @@ export class AutoConfirmPolicyDialogComponent
|
|||||||
autoConfirmRequest,
|
autoConfirmRequest,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||||
|
|
||||||
|
const currentAutoConfirmState = await firstValueFrom(
|
||||||
|
this.autoConfirmService.configuration$(userId),
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.autoConfirmService.upsert(userId, {
|
||||||
|
...currentAutoConfirmState,
|
||||||
|
showSetupDialog: false,
|
||||||
|
});
|
||||||
|
|
||||||
this.toastService.showToast({
|
this.toastService.showToast({
|
||||||
variant: "success",
|
variant: "success",
|
||||||
message: this.i18nService.t("editedPolicyId", this.i18nService.t(this.data.policy.name)),
|
message: this.i18nService.t("editedPolicyId", this.i18nService.t(this.data.policy.name)),
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ export { PoliciesComponent } from "./policies.component";
|
|||||||
export { ossPolicyEditRegister } from "./policy-edit-register";
|
export { ossPolicyEditRegister } from "./policy-edit-register";
|
||||||
export { BasePolicyEditDefinition, BasePolicyEditComponent } from "./base-policy-edit.component";
|
export { BasePolicyEditDefinition, BasePolicyEditComponent } from "./base-policy-edit.component";
|
||||||
export { POLICY_EDIT_REGISTER } from "./policy-register-token";
|
export { POLICY_EDIT_REGISTER } from "./policy-register-token";
|
||||||
|
export { AutoConfirmPolicyDialogComponent } from "./auto-confirm-edit-policy-dialog.component";
|
||||||
|
export { AutoConfirmPolicy } from "./policy-edit-definitions";
|
||||||
|
export { PolicyEditDialogResult } from "./policy-edit-dialog.component";
|
||||||
|
|||||||
@@ -47,12 +47,12 @@
|
|||||||
<bit-icon class="tw-w-[233px]" [icon]="autoConfirmSvg"></bit-icon>
|
<bit-icon class="tw-w-[233px]" [icon]="autoConfirmSvg"></bit-icon>
|
||||||
</div>
|
</div>
|
||||||
<ol>
|
<ol>
|
||||||
<li>1. {{ "autoConfirmStep1" | i18n }}</li>
|
<li>1. {{ "autoConfirmExtension1" | i18n }}</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
2. {{ "autoConfirmStep2a" | i18n }}
|
2. {{ "autoConfirmExtension2" | i18n }}
|
||||||
<strong>
|
<strong>
|
||||||
{{ "autoConfirmStep2b" | i18n }}
|
{{ "autoConfirmExtension3" | i18n }}
|
||||||
</strong>
|
</strong>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import {
|
|||||||
DefaultCollectionAdminService,
|
DefaultCollectionAdminService,
|
||||||
OrganizationUserApiService,
|
OrganizationUserApiService,
|
||||||
CollectionService,
|
CollectionService,
|
||||||
|
AutomaticUserConfirmationService,
|
||||||
|
DefaultAutomaticUserConfirmationService,
|
||||||
|
OrganizationUserService,
|
||||||
|
DefaultOrganizationUserService,
|
||||||
} from "@bitwarden/admin-console/common";
|
} from "@bitwarden/admin-console/common";
|
||||||
import { DefaultDeviceManagementComponentService } from "@bitwarden/angular/auth/device-management/default-device-management-component.service";
|
import { DefaultDeviceManagementComponentService } from "@bitwarden/angular/auth/device-management/default-device-management-component.service";
|
||||||
import { DeviceManagementComponentServiceAbstraction } from "@bitwarden/angular/auth/device-management/device-management-component.service.abstraction";
|
import { DeviceManagementComponentServiceAbstraction } from "@bitwarden/angular/auth/device-management/device-management-component.service.abstraction";
|
||||||
@@ -44,7 +48,10 @@ import {
|
|||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import {
|
||||||
|
InternalOrganizationServiceAbstraction,
|
||||||
|
OrganizationService,
|
||||||
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import {
|
import {
|
||||||
InternalPolicyService,
|
InternalPolicyService,
|
||||||
@@ -338,6 +345,29 @@ const safeProviders: SafeProvider[] = [
|
|||||||
OrganizationService,
|
OrganizationService,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: OrganizationUserService,
|
||||||
|
useClass: DefaultOrganizationUserService,
|
||||||
|
deps: [
|
||||||
|
KeyServiceAbstraction,
|
||||||
|
EncryptService,
|
||||||
|
OrganizationUserApiService,
|
||||||
|
AccountService,
|
||||||
|
I18nServiceAbstraction,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: AutomaticUserConfirmationService,
|
||||||
|
useClass: DefaultAutomaticUserConfirmationService,
|
||||||
|
deps: [
|
||||||
|
ConfigService,
|
||||||
|
ApiService,
|
||||||
|
OrganizationUserService,
|
||||||
|
StateProvider,
|
||||||
|
InternalOrganizationServiceAbstraction,
|
||||||
|
OrganizationUserApiService,
|
||||||
|
],
|
||||||
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: SdkLoadService,
|
provide: SdkLoadService,
|
||||||
useClass: flagEnabled("sdk") ? WebSdkLoadService : NoopSdkLoadService,
|
useClass: flagEnabled("sdk") ? WebSdkLoadService : NoopSdkLoadService,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
lastValueFrom,
|
lastValueFrom,
|
||||||
Observable,
|
Observable,
|
||||||
Subject,
|
Subject,
|
||||||
|
zip,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import {
|
import {
|
||||||
concatMap,
|
concatMap,
|
||||||
@@ -25,6 +26,7 @@ import {
|
|||||||
} from "rxjs/operators";
|
} from "rxjs/operators";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AutomaticUserConfirmationService,
|
||||||
CollectionData,
|
CollectionData,
|
||||||
CollectionDetailsResponse,
|
CollectionDetailsResponse,
|
||||||
CollectionService,
|
CollectionService,
|
||||||
@@ -54,7 +56,9 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
|||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
@@ -102,6 +106,11 @@ import {
|
|||||||
getNestedCollectionTree,
|
getNestedCollectionTree,
|
||||||
getFlatCollectionTree,
|
getFlatCollectionTree,
|
||||||
} from "../../admin-console/organizations/collections";
|
} from "../../admin-console/organizations/collections";
|
||||||
|
import {
|
||||||
|
AutoConfirmPolicy,
|
||||||
|
AutoConfirmPolicyDialogComponent,
|
||||||
|
PolicyEditDialogResult,
|
||||||
|
} from "../../admin-console/organizations/policies";
|
||||||
import {
|
import {
|
||||||
CollectionDialogAction,
|
CollectionDialogAction,
|
||||||
CollectionDialogTabType,
|
CollectionDialogTabType,
|
||||||
@@ -213,6 +222,8 @@ export class VaultComponent<C extends CipherViewLike> implements OnInit, OnDestr
|
|||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
private vaultItemDialogRef?: DialogRef<VaultItemDialogResult> | undefined;
|
private vaultItemDialogRef?: DialogRef<VaultItemDialogResult> | undefined;
|
||||||
|
private autoConfirmDialogRef?: DialogRef<PolicyEditDialogResult> | undefined;
|
||||||
|
|
||||||
protected showAddCipherBtn: boolean = false;
|
protected showAddCipherBtn: boolean = false;
|
||||||
|
|
||||||
organizations$ = this.accountService.activeAccount$
|
organizations$ = this.accountService.activeAccount$
|
||||||
@@ -328,6 +339,8 @@ export class VaultComponent<C extends CipherViewLike> implements OnInit, OnDestr
|
|||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
private unifiedUpgradePromptService: UnifiedUpgradePromptService,
|
private unifiedUpgradePromptService: UnifiedUpgradePromptService,
|
||||||
private premiumUpgradePromptService: PremiumUpgradePromptService,
|
private premiumUpgradePromptService: PremiumUpgradePromptService,
|
||||||
|
private autoConfirmService: AutomaticUserConfirmationService,
|
||||||
|
private configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -629,6 +642,8 @@ export class VaultComponent<C extends CipherViewLike> implements OnInit, OnDestr
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
void this.unifiedUpgradePromptService.displayUpgradePromptConditionally();
|
void this.unifiedUpgradePromptService.displayUpgradePromptConditionally();
|
||||||
|
|
||||||
|
this.setupAutoConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -1547,6 +1562,72 @@ export class VaultComponent<C extends CipherViewLike> implements OnInit, OnDestr
|
|||||||
const cipherView = await this.cipherService.decrypt(_cipher, activeUserId);
|
const cipherView = await this.cipherService.decrypt(_cipher, activeUserId);
|
||||||
return cipherView.login?.password;
|
return cipherView.login?.password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async openAutoConfirmFeatureDialog(organization: Organization) {
|
||||||
|
if (this.autoConfirmDialogRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autoConfirmDialogRef = AutoConfirmPolicyDialogComponent.open(this.dialogService, {
|
||||||
|
data: {
|
||||||
|
policy: new AutoConfirmPolicy(),
|
||||||
|
organizationId: organization.id,
|
||||||
|
firstTimeDialog: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await lastValueFrom(this.autoConfirmDialogRef.closed);
|
||||||
|
this.autoConfirmDialogRef = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupAutoConfirm() {
|
||||||
|
// if the policy is enabled, then the user may only belong to one organization at most.
|
||||||
|
const organization$ = this.organizations$.pipe(map((organizations) => organizations[0]));
|
||||||
|
|
||||||
|
const featureFlag$ = this.configService.getFeatureFlag$(FeatureFlag.AutoConfirm);
|
||||||
|
|
||||||
|
const autoConfirmState$ = this.userId$.pipe(
|
||||||
|
switchMap((userId) => this.autoConfirmService.configuration$(userId)),
|
||||||
|
);
|
||||||
|
|
||||||
|
const policyEnabled$ = combineLatest([
|
||||||
|
this.userId$.pipe(
|
||||||
|
switchMap((userId) => this.policyService.policies$(userId)),
|
||||||
|
map((policies) => policies.find((p) => p.type === PolicyType.AutoConfirm && p.enabled)),
|
||||||
|
),
|
||||||
|
organization$,
|
||||||
|
]).pipe(
|
||||||
|
map(
|
||||||
|
([policy, organization]) => (policy && policy.organizationId === organization?.id) ?? false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
zip([organization$, featureFlag$, autoConfirmState$, policyEnabled$, this.userId$])
|
||||||
|
.pipe(
|
||||||
|
first(),
|
||||||
|
switchMap(async ([organization, flagEnabled, autoConfirmState, policyEnabled, userId]) => {
|
||||||
|
const showDialog =
|
||||||
|
flagEnabled &&
|
||||||
|
!policyEnabled &&
|
||||||
|
autoConfirmState.showSetupDialog &&
|
||||||
|
!!organization &&
|
||||||
|
(organization.canManageUsers || organization.canManagePolicies);
|
||||||
|
|
||||||
|
if (showDialog) {
|
||||||
|
await this.openAutoConfirmFeatureDialog(organization);
|
||||||
|
|
||||||
|
await this.autoConfirmService.upsert(userId, {
|
||||||
|
...autoConfirmState,
|
||||||
|
showSetupDialog: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
error: (err: unknown) => this.logService.error("Failed to update auto-confirm state", err),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5832,16 +5832,16 @@
|
|||||||
"howToTurnOnAutoConfirm": {
|
"howToTurnOnAutoConfirm": {
|
||||||
"message": "How to turn on automatic user confirmation"
|
"message": "How to turn on automatic user confirmation"
|
||||||
},
|
},
|
||||||
"autoConfirmStep1": {
|
"autoConfirmExtension1": {
|
||||||
"message": "Open your Bitwarden extension."
|
"message": "Open your Bitwarden extension"
|
||||||
},
|
},
|
||||||
"autoConfirmStep2a": {
|
"autoConfirmExtension2": {
|
||||||
"message": "Select",
|
"message": "Select",
|
||||||
"description": "This is a fragment of a larger sencence. The whole sentence will read: 'Select Turn on.'"
|
"description": "This is a fragment of a larger sencence. The whole sentence will read: 'Select Turn on'"
|
||||||
},
|
},
|
||||||
"autoConfirmStep2b": {
|
"autoConfirmExtension3": {
|
||||||
"message": " Turn on.",
|
"message": " Turn on",
|
||||||
"description": "This is a fragment of a larger sencence. The whole sentence will read: 'Select Turn on.'"
|
"description": "This is a fragment of a larger sencence. The whole sentence will read: 'Select Turn on'"
|
||||||
},
|
},
|
||||||
"autoConfirmExtensionOpened": {
|
"autoConfirmExtensionOpened": {
|
||||||
"message": "Successfully opened the Bitwarden browser extension. You can now activate the automatic user confirmation setting."
|
"message": "Successfully opened the Bitwarden browser extension. You can now activate the automatic user confirmation setting."
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ export const AUTO_CONFIRM_STATE = UserKeyDefinition.record<AutoConfirmState>(
|
|||||||
"autoConfirm",
|
"autoConfirm",
|
||||||
{
|
{
|
||||||
deserializer: (autoConfirmState) => autoConfirmState,
|
deserializer: (autoConfirmState) => autoConfirmState,
|
||||||
clearOn: ["logout"],
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -285,6 +285,8 @@ export class DefaultPolicyService implements PolicyService {
|
|||||||
case PolicyType.RemoveUnlockWithPin:
|
case PolicyType.RemoveUnlockWithPin:
|
||||||
// Remove Unlock with PIN policy
|
// Remove Unlock with PIN policy
|
||||||
return false;
|
return false;
|
||||||
|
case PolicyType.AutoConfirm:
|
||||||
|
return false;
|
||||||
case PolicyType.OrganizationDataOwnership:
|
case PolicyType.OrganizationDataOwnership:
|
||||||
// organization data ownership policy applies to everyone except admins and owners
|
// organization data ownership policy applies to everyone except admins and owners
|
||||||
return organization.isAdmin;
|
return organization.isAdmin;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const DELETE_MANAGED_USER_WARNING = new StateDefinition(
|
|||||||
web: "disk-local",
|
web: "disk-local",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
export const AUTO_CONFIRM = new StateDefinition("autoConfirm", "disk");
|
export const AUTO_CONFIRM = new StateDefinition("autoConfirm", "disk", { web: "disk-local" });
|
||||||
|
|
||||||
// Billing
|
// Billing
|
||||||
export const BILLING_DISK = new StateDefinition("billing", "disk");
|
export const BILLING_DISK = new StateDefinition("billing", "disk");
|
||||||
|
|||||||
Reference in New Issue
Block a user