Merge branch 'main' into ps/extension-layout-component

This commit is contained in:
Victoria League 2024-04-25 16:12:44 -04:00 committed by GitHub
commit 3984fe6204
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 287 additions and 283 deletions

View File

@ -0,0 +1,130 @@
import { SelectionModel } from "@angular/cdk/collections";
import { Directive, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { BehaviorSubject, from, Subject, switchMap } from "rxjs";
import { first, takeUntil } from "rxjs/operators";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { DialogService, TableDataSource, ToastService } from "@bitwarden/components";
import { WebProviderService } from "../services/web-provider.service";
@Directive()
export abstract class BaseClientsComponent implements OnInit, OnDestroy {
protected destroy$ = new Subject<void>();
private searchText$ = new BehaviorSubject<string>("");
get searchText() {
return this.searchText$.value;
}
set searchText(value: string) {
this.searchText$.next(value);
this.selection.clear();
this.dataSource.filter = value;
}
private searching = false;
protected scrolled = false;
protected pageSize = 100;
private pagedClientsCount = 0;
protected selection = new SelectionModel<string>(true, []);
protected clients: ProviderOrganizationOrganizationDetailsResponse[];
protected pagedClients: ProviderOrganizationOrganizationDetailsResponse[];
protected dataSource = new TableDataSource<ProviderOrganizationOrganizationDetailsResponse>();
abstract providerId: string;
protected constructor(
protected activatedRoute: ActivatedRoute,
protected dialogService: DialogService,
private i18nService: I18nService,
private searchService: SearchService,
private toastService: ToastService,
private validationService: ValidationService,
private webProviderService: WebProviderService,
) {}
abstract load(): Promise<void>;
ngOnInit() {
this.activatedRoute.queryParams
.pipe(first(), takeUntil(this.destroy$))
.subscribe((queryParams) => {
this.searchText = queryParams.search;
});
this.searchText$
.pipe(
switchMap((searchText) => from(this.searchService.isSearchable(searchText))),
takeUntil(this.destroy$),
)
.subscribe((isSearchable) => {
this.searching = isSearchable;
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
isPaging() {
if (this.searching && this.scrolled) {
this.resetPaging();
}
return !this.searching && this.clients && this.clients.length > this.pageSize;
}
resetPaging() {
this.pagedClients = [];
this.loadMore();
}
loadMore() {
if (!this.clients || this.clients.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedClients.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedClientsCount > this.pageSize) {
pagedSize = this.pagedClientsCount;
}
if (this.clients.length > pagedLength) {
this.pagedClients = this.pagedClients.concat(
this.clients.slice(pagedLength, pagedLength + pagedSize),
);
}
this.pagedClientsCount = this.pagedClients.length;
this.scrolled = this.pagedClients.length > this.pageSize;
}
async remove(organization: ProviderOrganizationOrganizationDetailsResponse) {
const confirmed = await this.dialogService.openSimpleDialog({
title: organization.organizationName,
content: { key: "detachOrganizationConfirmation" },
type: "warning",
});
if (!confirmed) {
return;
}
try {
await this.webProviderService.detachOrganization(this.providerId, organization.id);
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("detachedOrganization", organization.organizationName),
});
await this.load();
} catch (e) {
this.validationService.showError(e);
}
}
}

View File

@ -1,29 +1,26 @@
import { Component, OnInit } from "@angular/core";
import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { BehaviorSubject, Subject, firstValueFrom, from } from "rxjs";
import { first, switchMap, takeUntil } from "rxjs/operators";
import { combineLatest, firstValueFrom, from } from "rxjs";
import { concatMap, switchMap, takeUntil } from "rxjs/operators";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
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 { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { ProviderUserType } from "@bitwarden/common/admin-console/enums";
import { ProviderStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response";
import { PlanType } from "@bitwarden/common/billing/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { DialogService } from "@bitwarden/components";
import { DialogService, ToastService } from "@bitwarden/components";
import { WebProviderService } from "../services/web-provider.service";
import { AddOrganizationComponent } from "./add-organization.component";
import { BaseClientsComponent } from "./base-clients.component";
const DisallowedPlanTypes = [
PlanType.Free,
@ -36,90 +33,76 @@ const DisallowedPlanTypes = [
@Component({
templateUrl: "clients.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ClientsComponent implements OnInit {
export class ClientsComponent extends BaseClientsComponent {
providerId: string;
addableOrganizations: Organization[];
loading = true;
manageOrganizations = false;
showAddExisting = false;
clients: ProviderOrganizationOrganizationDetailsResponse[];
pagedClients: ProviderOrganizationOrganizationDetailsResponse[];
protected didScroll = false;
protected pageSize = 100;
protected actionPromise: Promise<unknown>;
private pagedClientsCount = 0;
protected enableConsolidatedBilling$ = this.configService.getFeatureFlag$(
protected consolidatedBillingEnabled$ = this.configService.getFeatureFlag$(
FeatureFlag.EnableConsolidatedBilling,
false,
);
private destroy$ = new Subject<void>();
private _searchText$ = new BehaviorSubject<string>("");
private isSearching: boolean = false;
get searchText() {
return this._searchText$.value;
}
set searchText(value: string) {
this._searchText$.next(value);
}
constructor(
private route: ActivatedRoute,
private router: Router,
private providerService: ProviderService,
private apiService: ApiService,
private searchService: SearchService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private validationService: ValidationService,
private webProviderService: WebProviderService,
private logService: LogService,
private modalService: ModalService,
private organizationService: OrganizationService,
private organizationApiService: OrganizationApiServiceAbstraction,
private dialogService: DialogService,
private configService: ConfigService,
) {}
activatedRoute: ActivatedRoute,
dialogService: DialogService,
i18nService: I18nService,
searchService: SearchService,
toastService: ToastService,
validationService: ValidationService,
webProviderService: WebProviderService,
) {
super(
activatedRoute,
dialogService,
i18nService,
searchService,
toastService,
validationService,
webProviderService,
);
}
async ngOnInit() {
const enableConsolidatedBilling = await firstValueFrom(this.enableConsolidatedBilling$);
if (enableConsolidatedBilling) {
await this.router.navigate(["../manage-client-organizations"], { relativeTo: this.route });
} else {
this.route.parent.params
.pipe(
switchMap((params) => {
this.providerId = params.providerId;
return from(this.load());
}),
takeUntil(this.destroy$),
)
.subscribe();
this.route.queryParams.pipe(first(), takeUntil(this.destroy$)).subscribe((qParams) => {
this.searchText = qParams.search;
});
this._searchText$
.pipe(
switchMap((searchText) => from(this.searchService.isSearchable(searchText))),
takeUntil(this.destroy$),
)
.subscribe((isSearchable) => {
this.isSearching = isSearchable;
});
}
ngOnInit() {
this.activatedRoute.parent.params
.pipe(
switchMap((params) => {
this.providerId = params.providerId;
return combineLatest([
this.providerService.get(this.providerId),
this.consolidatedBillingEnabled$,
]).pipe(
concatMap(([provider, consolidatedBillingEnabled]) => {
if (
consolidatedBillingEnabled &&
provider.providerStatus === ProviderStatusType.Billable
) {
return from(
this.router.navigate(["../manage-client-organizations"], {
relativeTo: this.activatedRoute,
}),
);
} else {
return from(this.load());
}
}),
);
}),
takeUntil(this.destroy$),
)
.subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
super.ngOnDestroy();
}
async load() {
@ -141,37 +124,6 @@ export class ClientsComponent implements OnInit {
this.loading = false;
}
isPaging() {
const searching = this.isSearching;
if (searching && this.didScroll) {
this.resetPaging();
}
return !searching && this.clients && this.clients.length > this.pageSize;
}
resetPaging() {
this.pagedClients = [];
this.loadMore();
}
loadMore() {
if (!this.clients || this.clients.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedClients.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedClientsCount > this.pageSize) {
pagedSize = this.pagedClientsCount;
}
if (this.clients.length > pagedLength) {
this.pagedClients = this.pagedClients.concat(
this.clients.slice(pagedLength, pagedLength + pagedSize),
);
}
this.pagedClientsCount = this.pagedClients.length;
this.didScroll = this.pagedClients.length > this.pageSize;
}
async addExistingOrganization() {
const dialogRef = AddOrganizationComponent.open(this.dialogService, {
providerId: this.providerId,
@ -182,33 +134,4 @@ export class ClientsComponent implements OnInit {
await this.load();
}
}
async remove(organization: ProviderOrganizationOrganizationDetailsResponse) {
const confirmed = await this.dialogService.openSimpleDialog({
title: organization.organizationName,
content: { key: "detachOrganizationConfirmation" },
type: "warning",
});
if (!confirmed) {
return false;
}
this.actionPromise = this.webProviderService.detachOrganization(
this.providerId,
organization.id,
);
try {
await this.actionPromise;
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("detachedOrganization", organization.organizationName),
);
await this.load();
} catch (e) {
this.validationService.showError(e);
}
this.actionPromise = null;
}
}

View File

@ -7,7 +7,12 @@
<bit-nav-item
icon="bwi-bank"
[text]="'clients' | i18n"
[route]="(enableConsolidatedBilling$ | async) ? 'manage-client-organizations' : 'clients'"
[route]="
(enableConsolidatedBilling$ | async) &&
provider.providerStatus === ProviderStatusType.Billable
? 'manage-client-organizations'
: 'clients'
"
></bit-nav-item>
<bit-nav-group icon="bwi-sliders" [text]="'manage' | i18n" route="manage" *ngIf="showManageTab">
<bit-nav-item

View File

@ -4,6 +4,7 @@ import { ActivatedRoute, RouterModule } from "@angular/router";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { ProviderStatusType } from "@bitwarden/common/admin-console/enums";
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
@ -83,4 +84,6 @@ export class ProvidersLayoutComponent {
return "manage/events";
}
}
protected readonly ProviderStatusType = ProviderStatusType;
}

View File

@ -11,14 +11,7 @@
<bit-label>
{{ "assignedSeats" | i18n }}
</bit-label>
<input
id="assignedSeats"
type="number"
appAutoFocus
bitInput
required
[(ngModel)]="assignedSeats"
/>
<input id="assignedSeats" type="number" bitInput required [(ngModel)]="assignedSeats" />
</bit-form-field>
<ng-container *ngIf="remainingOpenSeats > 0">
<p>

View File

@ -1,21 +1,23 @@
import { SelectionModel } from "@angular/cdk/collections";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { BehaviorSubject, firstValueFrom, from, lastValueFrom, Subject } from "rxjs";
import { first, switchMap, takeUntil } from "rxjs/operators";
import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { combineLatest, firstValueFrom, from, lastValueFrom } from "rxjs";
import { concatMap, switchMap, takeUntil } from "rxjs/operators";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { ProviderUserType } from "@bitwarden/common/admin-console/enums";
import { ProviderStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums";
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
import { ProviderOrganizationOrganizationDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-organization.response";
import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction";
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { DialogService, TableDataSource } from "@bitwarden/components";
import { DialogService, ToastService } from "@bitwarden/components";
import { BaseClientsComponent } from "../../../admin-console/providers/clients/base-clients.component";
import { WebProviderService } from "../../../admin-console/providers/services/web-provider.service";
import {
@ -27,127 +29,91 @@ import { ManageClientOrganizationSubscriptionComponent } from "./manage-client-o
@Component({
templateUrl: "manage-client-organizations.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ManageClientOrganizationsComponent implements OnInit, OnDestroy {
export class ManageClientOrganizationsComponent extends BaseClientsComponent {
providerId: string;
provider: Provider;
loading = true;
manageOrganizations = false;
private destroy$ = new Subject<void>();
private _searchText$ = new BehaviorSubject<string>("");
private isSearching: boolean = false;
private consolidatedBillingEnabled$ = this.configService.getFeatureFlag$(
FeatureFlag.EnableConsolidatedBilling,
false,
);
get searchText() {
return this._searchText$.value;
}
set searchText(search: string) {
this._searchText$.value;
this.selection.clear();
this.dataSource.filter = search;
}
clients: ProviderOrganizationOrganizationDetailsResponse[];
pagedClients: ProviderOrganizationOrganizationDetailsResponse[];
protected didScroll = false;
protected pageSize = 100;
protected actionPromise: Promise<unknown>;
private pagedClientsCount = 0;
selection = new SelectionModel<string>(true, []);
protected dataSource = new TableDataSource<ProviderOrganizationOrganizationDetailsResponse>();
protected plans: PlanResponse[];
constructor(
private route: ActivatedRoute,
private providerService: ProviderService,
private apiService: ApiService,
private searchService: SearchService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private validationService: ValidationService,
private webProviderService: WebProviderService,
private dialogService: DialogService,
private billingApiService: BillingApiService,
) {}
async ngOnInit() {
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.params.subscribe(async (params) => {
this.providerId = params.providerId;
await this.load();
/* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
this.searchText = qParams.search;
});
});
this._searchText$
.pipe(
switchMap((searchText) => from(this.searchService.isSearchable(searchText))),
takeUntil(this.destroy$),
)
.subscribe((isSearchable) => {
this.isSearching = isSearchable;
});
private configService: ConfigService,
private providerService: ProviderService,
private router: Router,
activatedRoute: ActivatedRoute,
dialogService: DialogService,
i18nService: I18nService,
searchService: SearchService,
toastService: ToastService,
validationService: ValidationService,
webProviderService: WebProviderService,
) {
super(
activatedRoute,
dialogService,
i18nService,
searchService,
toastService,
validationService,
webProviderService,
);
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
ngOnInit() {
this.activatedRoute.parent.params
.pipe(
switchMap((params) => {
this.providerId = params.providerId;
return combineLatest([
this.providerService.get(this.providerId),
this.consolidatedBillingEnabled$,
]).pipe(
concatMap(([provider, consolidatedBillingEnabled]) => {
if (
!consolidatedBillingEnabled ||
provider.providerStatus !== ProviderStatusType.Billable
) {
return from(
this.router.navigate(["../clients"], {
relativeTo: this.activatedRoute,
}),
);
} else {
this.provider = provider;
this.manageOrganizations = this.provider.type === ProviderUserType.ProviderAdmin;
return from(this.load());
}
}),
);
}),
takeUntil(this.destroy$),
)
.subscribe();
}
ngOnDestroy() {
super.ngOnDestroy();
}
async load() {
const clientsResponse = await this.apiService.getProviderClients(this.providerId);
this.clients =
clientsResponse.data != null && clientsResponse.data.length > 0 ? clientsResponse.data : [];
this.dataSource.data = this.clients;
this.manageOrganizations =
(await this.providerService.get(this.providerId)).type === ProviderUserType.ProviderAdmin;
this.clients = (await this.apiService.getProviderClients(this.providerId)).data;
const plansResponse = await this.billingApiService.getPlans();
this.plans = plansResponse.data;
this.dataSource.data = this.clients;
this.plans = (await this.billingApiService.getPlans()).data;
this.loading = false;
}
isPaging() {
const searching = this.isSearching;
if (searching && this.didScroll) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.resetPaging();
}
return !searching && this.clients && this.clients.length > this.pageSize;
}
async resetPaging() {
this.pagedClients = [];
this.loadMore();
}
loadMore() {
if (!this.clients || this.clients.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedClients.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedClientsCount > this.pageSize) {
pagedSize = this.pagedClientsCount;
}
if (this.clients.length > pagedLength) {
this.pagedClients = this.pagedClients.concat(
this.clients.slice(pagedLength, pagedLength + pagedSize),
);
}
this.pagedClientsCount = this.pagedClients.length;
this.didScroll = this.pagedClients.length > this.pageSize;
}
async manageSubscription(organization: ProviderOrganizationOrganizationDetailsResponse) {
if (organization == null) {
return;
@ -161,35 +127,6 @@ export class ManageClientOrganizationsComponent implements OnInit, OnDestroy {
await this.load();
}
async remove(organization: ProviderOrganizationOrganizationDetailsResponse) {
const confirmed = await this.dialogService.openSimpleDialog({
title: organization.organizationName,
content: { key: "detachOrganizationConfirmation" },
type: "warning",
});
if (!confirmed) {
return false;
}
this.actionPromise = this.webProviderService.detachOrganization(
this.providerId,
organization.id,
);
try {
await this.actionPromise;
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("detachedOrganization", organization.organizationName),
);
await this.load();
} catch (e) {
this.validationService.showError(e);
}
this.actionPromise = null;
}
createClientOrganization = async () => {
const reference = openCreateClientOrganizationDialog(this.dialogService, {
data: {

View File

@ -7,3 +7,4 @@ export * from "./provider-type.enum";
export * from "./provider-user-status-type.enum";
export * from "./provider-user-type.enum";
export * from "./scim-provider-type.enum";
export * from "./provider-status-type.enum";

View File

@ -0,0 +1,5 @@
export enum ProviderStatusType {
Pending = 0,
Created = 1,
Billable = 2,
}

View File

@ -1,4 +1,4 @@
import { ProviderUserStatusType, ProviderUserType } from "../../enums";
import { ProviderStatusType, ProviderUserStatusType, ProviderUserType } from "../../enums";
import { ProfileProviderResponse } from "../response/profile-provider.response";
export class ProviderData {
@ -9,6 +9,7 @@ export class ProviderData {
enabled: boolean;
userId: string;
useEvents: boolean;
providerStatus: ProviderStatusType;
constructor(response: ProfileProviderResponse) {
this.id = response.id;
@ -18,5 +19,6 @@ export class ProviderData {
this.enabled = response.enabled;
this.userId = response.userId;
this.useEvents = response.useEvents;
this.providerStatus = response.providerStatus;
}
}

View File

@ -1,4 +1,4 @@
import { ProviderUserStatusType, ProviderUserType } from "../../enums";
import { ProviderStatusType, ProviderUserStatusType, ProviderUserType } from "../../enums";
import { ProviderData } from "../data/provider.data";
export class Provider {
@ -9,6 +9,7 @@ export class Provider {
enabled: boolean;
userId: string;
useEvents: boolean;
providerStatus: ProviderStatusType;
constructor(obj?: ProviderData) {
if (obj == null) {
@ -22,6 +23,7 @@ export class Provider {
this.enabled = obj.enabled;
this.userId = obj.userId;
this.useEvents = obj.useEvents;
this.providerStatus = obj.providerStatus;
}
get canAccess() {

View File

@ -1,5 +1,5 @@
import { BaseResponse } from "../../../models/response/base.response";
import { ProviderUserStatusType, ProviderUserType } from "../../enums";
import { ProviderStatusType, ProviderUserStatusType, ProviderUserType } from "../../enums";
import { PermissionsApi } from "../api/permissions.api";
export class ProfileProviderResponse extends BaseResponse {
@ -12,6 +12,7 @@ export class ProfileProviderResponse extends BaseResponse {
permissions: PermissionsApi;
userId: string;
useEvents: boolean;
providerStatus: ProviderStatusType;
constructor(response: any) {
super(response);
@ -24,5 +25,6 @@ export class ProfileProviderResponse extends BaseResponse {
this.permissions = new PermissionsApi(this.getResponseProperty("permissions"));
this.userId = this.getResponseProperty("UserId");
this.useEvents = this.getResponseProperty("UseEvents");
this.providerStatus = this.getResponseProperty("ProviderStatus");
}
}

View File

@ -2,7 +2,7 @@ import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from ".
import { FakeActiveUserState, FakeSingleUserState } from "../../../spec/fake-state";
import { Utils } from "../../platform/misc/utils";
import { UserId } from "../../types/guid";
import { ProviderUserStatusType, ProviderUserType } from "../enums";
import { ProviderStatusType, ProviderUserStatusType, ProviderUserType } from "../enums";
import { ProviderData } from "../models/data/provider.data";
import { Provider } from "../models/domain/provider";
@ -64,6 +64,7 @@ describe("PROVIDERS key definition", () => {
enabled: true,
userId: "string",
useEvents: true,
providerStatus: ProviderStatusType.Pending,
},
};
const result = sut.deserializer(JSON.parse(JSON.stringify(expectedResult)));