diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts b/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
index 7b919cad6c..0e149672e9 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
@@ -54,6 +54,7 @@ import { LoggerWriterService } from "./services/logger-writer-service/logger-wri
import { SidebarService } from "./services/sidebar-service/sidebar.service";
import { ApiKeyInterceptor } from "./shared/interceptors/api-key.interceptor";
import { XSRFInterceptor } from "./shared/interceptors/xsrf.interceptor";
+import { IdentitiesOverviewComponent } from "./components/shared/identities-overview/identities-overview.component";
@NgModule({
declarations: [
@@ -72,7 +73,8 @@ import { XSRFInterceptor } from "./shared/interceptors/xsrf.interceptor";
AssignQuotasDialogComponent,
ConfirmationDialogComponent,
LoginComponent,
- ChangeSecretDialogComponent
+ ChangeSecretDialogComponent,
+ IdentitiesOverviewComponent
],
imports: [
FormsModule,
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.css b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.css
index caaa651c08..cb808b4bdf 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.css
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.css
@@ -79,6 +79,33 @@
color: #fff;
}
+.client-accordion {
+ margin: 0px 0px 0px 5px !important;
+}
+
+.details-expansion-panel-header {
+ background: #17428d !important;
+}
+
+.details-expansion-panel-header:hover {
+ background: #11337a !important;
+}
+.details-expansion-panel-header.mat-expansion-panel-header.mat-expanded {
+ border-radius: 4px 4px 0px 0px;
+}
+
+.details-panel-header-title {
+ color: white !important;
+}
+
+.details-panel-header-desc {
+ color: rgba(255, 255, 255, 0.54) !important;
+}
+
+:host ::ng-deep .details-expansion-panel-header > .mat-expansion-indicator::after {
+ color: white !important;
+}
+
.auto-height {
height: auto;
}
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.html b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.html
index 55a1276361..8859a8d477 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.html
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.html
@@ -78,6 +78,19 @@
+
+
+
+
+
+
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.ts b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.ts
index b623d9f490..4a20bf01f2 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.ts
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/client/client-edit/client-edit.component.ts
@@ -14,8 +14,13 @@ import { PagedHttpResponseEnvelope } from "src/app/utils/paged-http-response-env
export class ClientEditComponent {
public headerEdit: string;
public headerCreate: string;
+
public headerDescriptionEdit: string;
public headerDescriptionCreate: string;
+
+ public headerIdentities: string;
+ public headerIdentitiesDescription: string;
+
public showPassword: boolean;
public clientId?: string;
public editMode: boolean;
@@ -35,6 +40,8 @@ export class ClientEditComponent {
this.headerEdit = "Edit Client";
this.headerDescriptionCreate = "Please fill the form below to create your Client";
this.headerDescriptionEdit = "Perform your desired changes and save to edit your Client";
+ this.headerIdentities = "Identities";
+ this.headerIdentitiesDescription = "View and manage Identities created by this Client.";
this.editMode = false;
this.loading = true;
this.disabled = false;
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.css b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.css
index f54fd74d0b..f672c80a72 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.css
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.css
@@ -1,72 +1,8 @@
-.mat-column-address,
-.mat-column-address-filter,
-.mat-column-clientId,
-.mat-column-publicKey {
- width: 25%;
- word-break: break-all;
-}
-
-.mat-column-createdAt,
-.mat-column-created-at-filter,
-.mat-column-last-login-filter,
-.mat-column-lastLoginAt {
- max-width: 330px;
-}
-
-.mat-column-tier-filter,
-.mat-column-tierName,
-.mat-column-createdWithClient,
-.mat-column-client-filter {
- max-width: 230px;
-}
-
-.mat-column-number-of-devices-filter,
-.mat-column-numberOfDevices,
-.mat-column-identity-version-filter,
-.mat-column-identityVersion,
-.mat-column-datawallet-version-filter,
-.mat-column-datawalletVersion {
- max-width: 200px;
-}
-
.disabled-container {
pointer-events: none;
opacity: 0.4;
}
-.inline-action-buttons ::ng-deep .mat-mdc-form-field-icon-suffix {
- display: inherit;
-}
-
-.mat-column-address {
- width: 26.5em;
-}
-
-.tier-navigation {
- text-decoration: underline;
- color: blue;
-}
-
-.loading {
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 999;
- position: absolute;
- margin-top: -60px;
- width: 100%;
- height: 100%;
-}
-
-.no-data {
- padding: 25px;
-}
-
-.mat-mdc-row:hover {
- background-color: #ddd !important;
- cursor: pointer;
-}
-
.card-header {
border-radius: 3px;
padding: 15px;
@@ -76,11 +12,6 @@
margin: 15px 15px -50px 15px;
}
-.filter-cell {
- display: flex;
- justify-content: space-between;
-}
-
.header-description {
color: #fff;
}
@@ -88,50 +19,3 @@
.header-title {
color: #fff;
}
-
-.action-buttons {
- margin-top: 50px;
- display: flex;
- justify-content: flex-end;
-}
-
-@media screen and (max-width: 960px) {
- .card-header {
- margin: 15px 15px -20px 15px;
- }
-
- .mat-mdc-table .mat-mdc-header-row {
- display: none;
- }
-
- .mat-mdc-table .mat-mdc-row {
- display: flex;
- flex-wrap: wrap;
- height: auto;
- border-bottom: 1px solid #ddd;
- }
-
- .mat-mdc-table .mat-mdc-cell {
- width: 100%;
- border-bottom: 0px solid #ddd;
- font-size: 1em;
- min-height: 30px;
- margin-bottom: 4%;
- word-break: break-all;
- white-space: pre-wrap;
- }
-
- .mat-mdc-table .mat-mdc-cell:before {
- content: attr(data-label) ":";
- float: left;
- font-weight: 500;
- }
-
- .mat-mdc-table .mat-mdc-cell:first-child {
- margin-top: 25px;
- }
-
- .mat-mdc-table .mat-mdc-row:last-child {
- border-bottom: 0px;
- }
-}
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.html b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.html
index 01715ca0bf..624f634cc2 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.html
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.html
@@ -2,186 +2,8 @@
-
+
-
-
-
-
-
-
+
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.ts b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.ts
index 7f942f241a..596782b58d 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.ts
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-list/identity-list.component.ts
@@ -1,14 +1,4 @@
-import { Component, ElementRef, ViewChild } from "@angular/core";
-import { MatPaginator, PageEvent } from "@angular/material/paginator";
-import { MatSnackBar } from "@angular/material/snack-bar";
-import { Router } from "@angular/router";
-import { NGXLogger } from "ngx-logger";
-import { debounceTime, distinctUntilChanged, filter, fromEvent, tap } from "rxjs";
-import { ClientOverview, ClientService } from "src/app/services/client-service/client-service";
-import { IdentityOverview, IdentityOverviewFilter, IdentityService } from "src/app/services/identity-service/identity.service";
-import { TierOverview, TierService } from "src/app/services/tier-service/tier.service";
-import { ODataResponse } from "src/app/utils/odata-response";
-import { PagedHttpResponseEnvelope } from "src/app/utils/paged-http-response-envelope";
+import { Component } from "@angular/core";
@Component({
selector: "app-identity-list",
@@ -16,222 +6,15 @@ import { PagedHttpResponseEnvelope } from "src/app/utils/paged-http-response-env
styleUrls: ["./identity-list.component.css"]
})
export class IdentityListComponent {
- @ViewChild(MatPaginator) public paginator!: MatPaginator;
- @ViewChild("addressFilter", { static: false }) public set addressFilter(input: ElementRef | undefined) {
- this.debounceFilter(input, "address");
- }
- @ViewChild("numberOfDevicesFilter", { static: false }) public set numberOfDevicesFilter(input: ElementRef | undefined) {
- this.debounceFilter(input, "numberOfDevices");
- }
- @ViewChild("datawalletVersionFilter", { static: false }) public set datawalletVersionFilter(input: ElementRef | undefined) {
- this.debounceFilter(input, "datawalletVersion");
- }
- @ViewChild("identityVersionFilter", { static: false }) public set identityVersionFilter(input: ElementRef | undefined) {
- this.debounceFilter(input, "identityVersion");
- }
-
public header: string;
public headerDescription: string;
- public identities: IdentityOverview[];
-
- public totalRecords: number;
- public pageSize: number;
- public pageIndex: number;
-
- public loading = false;
-
- public displayedColumns: string[] = ["address", "tierName", "createdWithClient", "numberOfDevices", "createdAt", "lastLoginAt", "datawalletVersion", "identityVersion"];
- public displayedColumnFilters: string[] = [
- "address-filter",
- "tier-filter",
- "client-filter",
- "number-of-devices-filter",
- "created-at-filter",
- "last-login-filter",
- "datawallet-version-filter",
- "identity-version-filter"
- ];
- public operators: string[] = ["=", "<", ">", ">=", "<="];
+ public loading: boolean;
- public filter: IdentityOverviewFilter;
- public tiers: TierOverview[];
- public clients: ClientOverview[];
-
- public constructor(
- private readonly router: Router,
- private readonly snackBar: MatSnackBar,
- private readonly identityService: IdentityService,
- private readonly tierService: TierService,
- private readonly clientService: ClientService,
- private readonly logger: NGXLogger
- ) {
+ public constructor() {
this.header = "Identities";
this.headerDescription = "A list of existing Identities";
- this.identities = [];
-
- this.totalRecords = 0;
- this.pageSize = 10;
- this.pageIndex = 0;
-
- this.filter = { createdAt: { operator: "=" }, numberOfDevices: { operator: "=" }, identityVersion: { operator: "=" }, lastLoginAt: { operator: "=" }, datawalletVersion: { operator: "=" } };
- this.tiers = [];
- this.clients = [];
-
- this.loading = true;
- }
-
- public ngOnInit(): void {
- this.getIdentities();
- this.getTiers();
- this.getClients();
- }
-
- private debounceFilter(filterElement: ElementRef | undefined, filterName: string): void {
- if (filterElement !== undefined) {
- fromEvent(filterElement.nativeElement, "keyup")
- .pipe(
- filter(Boolean),
- debounceTime(750),
- distinctUntilChanged(),
- tap((_) => {
- this.onFilterChange(filterName);
- })
- )
- .subscribe();
- }
- }
-
- private getTiers(): void {
- this.tierService.getTiers().subscribe({
- next: (data: PagedHttpResponseEnvelope) => {
- this.tiers = data.result;
- },
- complete: () => (this.loading = false),
- error: (err: any) => {
- this.loading = false;
- const errorMessage = err.error?.error?.message ?? err.message;
- this.snackBar.open(errorMessage, "Dismiss", {
- verticalPosition: "top",
- horizontalPosition: "center"
- });
- }
- });
- }
-
- private getClients(): void {
- this.clientService.getClients().subscribe({
- next: (data: PagedHttpResponseEnvelope) => {
- this.clients = data.result;
- },
- complete: () => (this.loading = false),
- error: (err: any) => {
- this.loading = false;
- const errorMessage = err.error?.error?.message ?? err.message;
- this.snackBar.open(errorMessage, "Dismiss", {
- verticalPosition: "top",
- horizontalPosition: "center"
- });
- }
- });
- }
-
- private getIdentities(): void {
- this.loading = true;
- this.identityService.getIdentities(this.filter, this.pageIndex, this.pageSize).subscribe({
- next: (data: ODataResponse) => {
- this.identities = data.value;
- this.totalRecords = data.value.length;
- },
- complete: () => (this.loading = false),
- error: (err: any) => {
- this.loading = false;
- const errorMessage = err.error?.error?.message ?? err.message;
- this.snackBar.open(errorMessage, "Dismiss", {
- verticalPosition: "top",
- horizontalPosition: "center"
- });
- }
- });
- }
-
- public pageChangeEvent(event: PageEvent): void {
- this.pageIndex = event.pageIndex;
- this.pageSize = event.pageSize;
- this.getIdentities();
- }
-
- public async editIdentity(identityAddress: string): Promise {
- await this.router.navigate([`/identities/${identityAddress}`]);
- }
-
- public async goToTier(tierId: string): Promise {
- await this.router.navigate([`/tiers/${tierId}`]);
- }
-
- public onFilterChange(filter: string): void {
- switch (filter) {
- case "address":
- if (this.filter.address!.length > 2) this.getIdentities();
- break;
- case "tiers":
- case "clients":
- this.getIdentities();
- break;
- case "numberOfDevices":
- if (
- (this.filter.numberOfDevices.operator !== undefined && this.filter.numberOfDevices.value !== undefined) ||
- (this.filter.numberOfDevices.operator !== undefined && this.filter.numberOfDevices.value === undefined)
- ) {
- this.getIdentities();
- }
- break;
- case "createdAt":
- if (this.filter.createdAt.operator !== undefined && this.filter.createdAt.operator !== "" && this.filter.createdAt.value !== undefined) this.getIdentities();
- break;
- case "lastLoginAt":
- if (this.filter.lastLoginAt.operator !== undefined && this.filter.lastLoginAt.operator !== "" && this.filter.lastLoginAt.value !== undefined) this.getIdentities();
- break;
- case "datawalletVersion":
- if (
- (this.filter.datawalletVersion.operator !== undefined && this.filter.datawalletVersion.value !== undefined) ||
- (this.filter.datawalletVersion.operator !== undefined && this.filter.datawalletVersion.value === undefined)
- ) {
- this.getIdentities();
- }
- break;
- case "identityVersion":
- if (
- (this.filter.identityVersion.operator !== undefined && this.filter.identityVersion.value !== undefined) ||
- (this.filter.identityVersion.operator !== undefined && this.filter.identityVersion.value === undefined)
- ) {
- this.getIdentities();
- }
- break;
- default:
- this.logger.error(`OnFilterChange: Invalid filter name: ${filter}`);
- break;
- }
- }
-
- public clearFilter(filter: string): void {
- switch (filter) {
- case "address":
- this.filter.address = "";
- this.getIdentities();
- break;
- case "createdAt":
- this.filter.createdAt.value = undefined;
- if (this.filter.createdAt.operator !== undefined) this.getIdentities();
- break;
- case "lastLoginAt":
- this.filter.lastLoginAt.value = undefined;
- if (this.filter.lastLoginAt.operator !== undefined) this.getIdentities();
- break;
- default:
- this.logger.error(`ClearFilter: Invalid filter name: ${filter}`);
- break;
- }
+ this.loading = false;
}
}
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.css b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.css
new file mode 100644
index 0000000000..9461619e64
--- /dev/null
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.css
@@ -0,0 +1,144 @@
+.mat-column-address,
+.mat-column-address-filter,
+.mat-column-clientId,
+.mat-column-publicKey {
+ width: 25%;
+ word-break: break-all;
+}
+
+.mat-column-createdAt,
+.mat-column-created-at-filter,
+.mat-column-last-login-filter,
+.mat-column-lastLoginAt {
+ max-width: 330px;
+}
+
+.mat-column-tier-filter,
+.mat-column-tierName,
+.mat-column-createdWithClient,
+.mat-column-client-filter {
+ max-width: 230px;
+}
+
+.mat-column-number-of-devices-filter,
+.mat-column-numberOfDevices,
+.mat-column-identity-version-filter,
+.mat-column-identityVersion,
+.mat-column-datawallet-version-filter,
+.mat-column-datawalletVersion {
+ max-width: 200px;
+}
+
+.disabled-container {
+ pointer-events: none;
+ opacity: 0.4;
+}
+
+.inline-action-buttons ::ng-deep .mat-mdc-form-field-icon-suffix {
+ display: inherit;
+}
+
+.mat-column-address {
+ width: 26.5em;
+}
+
+.tier-navigation {
+ text-decoration: underline;
+ color: blue;
+}
+
+.loading {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+ position: absolute;
+ margin-top: -60px;
+ width: 100%;
+ height: 100%;
+}
+
+.no-data {
+ padding: 25px;
+}
+
+.mat-mdc-row:hover {
+ background-color: #ddd !important;
+ cursor: pointer;
+}
+
+.card-header {
+ border-radius: 3px;
+ padding: 15px;
+ background-color: #17428d;
+ position: relative;
+ z-index: 1;
+ margin: 15px 15px -50px 15px;
+}
+
+.filter-cell {
+ display: flex;
+ justify-content: space-between;
+}
+
+.header-description {
+ color: #fff;
+}
+
+.header-title {
+ color: #fff;
+}
+
+.action-buttons {
+ margin-top: 50px;
+ display: flex;
+ justify-content: flex-end;
+}
+
+@media screen and (max-width: 960px) {
+ .card-header {
+ margin: 15px 15px -20px 15px;
+ }
+
+ .mat-mdc-table .mat-mdc-header-row {
+ display: none;
+ }
+
+ .mat-mdc-table .mat-mdc-row {
+ display: flex;
+ flex-wrap: wrap;
+ height: auto;
+ border-bottom: 1px solid #ddd;
+ }
+
+ .mat-mdc-table .mat-mdc-cell {
+ width: 100%;
+ border-bottom: 0px solid #ddd;
+ font-size: 1em;
+ min-height: 30px;
+ margin-bottom: 4%;
+ word-break: break-all;
+ white-space: pre-wrap;
+ }
+
+ .mat-mdc-table .mat-mdc-cell:before {
+ content: attr(data-label) ":";
+ float: left;
+ font-weight: 500;
+ }
+
+ .mat-mdc-table .mat-mdc-cell:first-child {
+ margin-top: 25px;
+ }
+
+ .mat-mdc-table .mat-mdc-row:last-child {
+ border-bottom: 0px;
+ }
+}
+
+@media screen and (min-width: 960px) {
+ .mat-mdc-header-cell,
+ .mat-mdc-cell {
+ text-align: center;
+ }
+}
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.html b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.html
new file mode 100644
index 0000000000..3819c49c2a
--- /dev/null
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.html
@@ -0,0 +1,181 @@
+
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.spec.ts b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.spec.ts
new file mode 100644
index 0000000000..987bf345e8
--- /dev/null
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+
+import { IdentitiesOverviewComponent } from "./identities-overview.component";
+
+describe("IdentitiesOverviewComponent", function () {
+ let component: IdentitiesOverviewComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(function () {
+ TestBed.configureTestingModule({
+ declarations: [IdentitiesOverviewComponent]
+ });
+ fixture = TestBed.createComponent(IdentitiesOverviewComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it("should create", async function () {
+ await expect(component).toBeTruthy();
+ });
+});
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.ts b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.ts
new file mode 100644
index 0000000000..72d1e742a8
--- /dev/null
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/shared/identities-overview/identities-overview.component.ts
@@ -0,0 +1,244 @@
+import { Component, ElementRef, Input, ViewChild } from "@angular/core";
+import { MatPaginator, PageEvent } from "@angular/material/paginator";
+import { MatSnackBar } from "@angular/material/snack-bar";
+import { Router } from "@angular/router";
+import { NGXLogger } from "ngx-logger";
+import { fromEvent, filter, debounceTime, distinctUntilChanged, tap } from "rxjs";
+import { ClientOverview, ClientService } from "src/app/services/client-service/client-service";
+import { IdentityOverview, IdentityOverviewFilter, IdentityService } from "src/app/services/identity-service/identity.service";
+import { TierOverview, TierService } from "src/app/services/tier-service/tier.service";
+import { ODataResponse } from "src/app/utils/odata-response";
+import { PagedHttpResponseEnvelope } from "src/app/utils/paged-http-response-envelope";
+
+@Component({
+ selector: "app-identities-overview",
+ templateUrl: "./identities-overview.component.html",
+ styleUrls: ["./identities-overview.component.css"]
+})
+export class IdentitiesOverviewComponent {
+ @Input() public clientId?: string;
+
+ @ViewChild(MatPaginator) public paginator!: MatPaginator;
+ @ViewChild("addressFilter", { static: false }) public set addressFilter(input: ElementRef | undefined) {
+ this.debounceFilter(input, "address");
+ }
+ @ViewChild("numberOfDevicesFilter", { static: false }) public set numberOfDevicesFilter(input: ElementRef | undefined) {
+ this.debounceFilter(input, "numberOfDevices");
+ }
+ @ViewChild("datawalletVersionFilter", { static: false }) public set datawalletVersionFilter(input: ElementRef | undefined) {
+ this.debounceFilter(input, "datawalletVersion");
+ }
+ @ViewChild("identityVersionFilter", { static: false }) public set identityVersionFilter(input: ElementRef | undefined) {
+ this.debounceFilter(input, "identityVersion");
+ }
+
+ public identities: IdentityOverview[];
+
+ public totalRecords: number;
+ public pageSize: number;
+ public pageIndex: number;
+
+ public loading = false;
+
+ public displayedColumns: string[] = ["address", "tierName", "createdWithClient", "numberOfDevices", "createdAt", "lastLoginAt", "datawalletVersion", "identityVersion"];
+ public displayedColumnFilters: string[] = [
+ "address-filter",
+ "tier-filter",
+ "client-filter",
+ "number-of-devices-filter",
+ "created-at-filter",
+ "last-login-filter",
+ "datawallet-version-filter",
+ "identity-version-filter"
+ ];
+ public operators: string[] = ["=", "<", ">", ">=", "<="];
+
+ public filter: IdentityOverviewFilter;
+ public tiers: TierOverview[];
+ public clients: ClientOverview[];
+
+ public constructor(
+ private readonly router: Router,
+ private readonly snackBar: MatSnackBar,
+ private readonly identityService: IdentityService,
+ private readonly tierService: TierService,
+ private readonly clientService: ClientService,
+ private readonly logger: NGXLogger
+ ) {
+ this.identities = [];
+
+ this.totalRecords = 0;
+ this.pageSize = 10;
+ this.pageIndex = 0;
+
+ this.filter = { createdAt: { operator: "=" }, numberOfDevices: { operator: "=" }, identityVersion: { operator: "=" }, lastLoginAt: { operator: "=" }, datawalletVersion: { operator: "=" } };
+ this.tiers = [];
+ this.clients = [];
+
+ this.loading = true;
+ }
+
+ public ngOnInit(): void {
+ if (this.clientId) {
+ this.setClientFilter();
+ } else {
+ this.getClients();
+ }
+
+ this.getIdentities();
+ this.getTiers();
+ }
+
+ private debounceFilter(filterElement: ElementRef | undefined, filterName: string): void {
+ if (filterElement !== undefined) {
+ fromEvent(filterElement.nativeElement, "keyup")
+ .pipe(
+ filter(Boolean),
+ debounceTime(750),
+ distinctUntilChanged(),
+ tap((_) => {
+ this.onFilterChange(filterName);
+ })
+ )
+ .subscribe();
+ }
+ }
+
+ private getTiers(): void {
+ this.tierService.getTiers().subscribe({
+ next: (data: PagedHttpResponseEnvelope) => {
+ this.tiers = data.result;
+ },
+ complete: () => (this.loading = false),
+ error: (err: any) => {
+ this.loading = false;
+ const errorMessage = err.error?.error?.message ?? err.message;
+ this.snackBar.open(errorMessage, "Dismiss", {
+ verticalPosition: "top",
+ horizontalPosition: "center"
+ });
+ }
+ });
+ }
+
+ private setClientFilter(): void {
+ this.filter.clients = [this.clientId!];
+ this.displayedColumns = this.displayedColumns.filter((dc) => dc !== "createdWithClient");
+ this.displayedColumnFilters = this.displayedColumnFilters.filter((dcf) => dcf !== "client-filter");
+ }
+
+ private getClients(): void {
+ this.clientService.getClients().subscribe({
+ next: (data: PagedHttpResponseEnvelope) => {
+ this.clients = data.result;
+ },
+ complete: () => (this.loading = false),
+ error: (err: any) => {
+ this.loading = false;
+ const errorMessage = err.error?.error?.message ?? err.message;
+ this.snackBar.open(errorMessage, "Dismiss", {
+ verticalPosition: "top",
+ horizontalPosition: "center"
+ });
+ }
+ });
+ }
+
+ private getIdentities(): void {
+ this.loading = true;
+ this.identityService.getIdentities(this.filter, this.pageIndex, this.pageSize).subscribe({
+ next: (data: ODataResponse) => {
+ this.identities = data.value;
+ this.totalRecords = data.value.length;
+ },
+ complete: () => (this.loading = false),
+ error: (err: any) => {
+ this.loading = false;
+ const errorMessage = err.error?.error?.message ?? err.message;
+ this.snackBar.open(errorMessage, "Dismiss", {
+ verticalPosition: "top",
+ horizontalPosition: "center"
+ });
+ }
+ });
+ }
+
+ public pageChangeEvent(event: PageEvent): void {
+ this.pageIndex = event.pageIndex;
+ this.pageSize = event.pageSize;
+ this.getIdentities();
+ }
+
+ public async editIdentity(identityAddress: string): Promise {
+ await this.router.navigate([`/identities/${identityAddress}`]);
+ }
+
+ public async goToTier(tierId: string): Promise {
+ await this.router.navigate([`/tiers/${tierId}`]);
+ }
+
+ public onFilterChange(filter: string): void {
+ switch (filter) {
+ case "address":
+ if (this.filter.address!.length > 2) this.getIdentities();
+ break;
+ case "tiers":
+ case "clients":
+ this.getIdentities();
+ break;
+ case "numberOfDevices":
+ if (
+ (this.filter.numberOfDevices.operator !== undefined && this.filter.numberOfDevices.value !== undefined) ||
+ (this.filter.numberOfDevices.operator !== undefined && this.filter.numberOfDevices.value === undefined)
+ ) {
+ this.getIdentities();
+ }
+ break;
+ case "createdAt":
+ if (this.filter.createdAt.operator !== undefined && this.filter.createdAt.operator !== "" && this.filter.createdAt.value !== undefined) this.getIdentities();
+ break;
+ case "lastLoginAt":
+ if (this.filter.lastLoginAt.operator !== undefined && this.filter.lastLoginAt.operator !== "" && this.filter.lastLoginAt.value !== undefined) this.getIdentities();
+ break;
+ case "datawalletVersion":
+ if (
+ (this.filter.datawalletVersion.operator !== undefined && this.filter.datawalletVersion.value !== undefined) ||
+ (this.filter.datawalletVersion.operator !== undefined && this.filter.datawalletVersion.value === undefined)
+ ) {
+ this.getIdentities();
+ }
+ break;
+ case "identityVersion":
+ if (
+ (this.filter.identityVersion.operator !== undefined && this.filter.identityVersion.value !== undefined) ||
+ (this.filter.identityVersion.operator !== undefined && this.filter.identityVersion.value === undefined)
+ ) {
+ this.getIdentities();
+ }
+ break;
+ default:
+ this.logger.error(`OnFilterChange: Invalid filter name: ${filter}`);
+ break;
+ }
+ }
+
+ public clearFilter(filter: string): void {
+ switch (filter) {
+ case "address":
+ this.filter.address = "";
+ this.getIdentities();
+ break;
+ case "createdAt":
+ this.filter.createdAt.value = undefined;
+ if (this.filter.createdAt.operator !== undefined) this.getIdentities();
+ break;
+ case "lastLoginAt":
+ this.filter.lastLoginAt.value = undefined;
+ if (this.filter.lastLoginAt.operator !== undefined) this.getIdentities();
+ break;
+ default:
+ this.logger.error(`ClearFilter: Invalid filter name: ${filter}`);
+ break;
+ }
+ }
+}