diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts b/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
index 0e149672e9..bd469b4fca 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/app.module.ts
@@ -23,6 +23,7 @@ import { MatIconModule } from "@angular/material/icon";
import { MatInputModule } from "@angular/material/input";
import { MatListModule } from "@angular/material/list";
import { MatPaginatorModule } from "@angular/material/paginator";
+import { MatProgressBarModule } from "@angular/material/progress-bar";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatSelectModule } from "@angular/material/select";
import { MatSidenavModule } from "@angular/material/sidenav";
@@ -46,6 +47,7 @@ import { IdentityListComponent } from "./components/quotas/identity/identity-lis
import { TierEditComponent } from "./components/quotas/tier/tier-edit/tier-edit.component";
import { TierListComponent } from "./components/quotas/tier/tier-list/tier-list.component";
import { ConfirmationDialogComponent } from "./components/shared/confirmation-dialog/confirmation-dialog.component";
+import { IdentitiesOverviewComponent } from "./components/shared/identities-overview/identities-overview.component";
import { LoginComponent } from "./components/shared/login/login.component";
import { SidebarComponent } from "./components/sidebar/sidebar.component";
import { TopbarComponent } from "./components/topbar/topbar.component";
@@ -54,7 +56,6 @@ 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: [
@@ -125,7 +126,8 @@ import { IdentitiesOverviewComponent } from "./components/shared/identities-over
LayoutModule,
MatDialogModule,
MatSelectModule,
- MatChipsModule
+ MatChipsModule,
+ MatProgressBarModule
],
providers: [
SidebarService,
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.css b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.css
index 1a0517f917..4580a65f9a 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.css
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.css
@@ -154,3 +154,12 @@
.auto-height {
height: auto;
}
+
+.progressWrapper {
+ display: flex;
+ align-items: center;
+}
+
+.progressWrapper > span {
+ min-width: 2.5rem;
+}
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.html b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.html
index 32fb78195e..859c1b7b87 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.html
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/components/quotas/identity/identity-edit/identity-edit.component.html
@@ -93,9 +93,12 @@
- Max |
-
- {{ Quota.max }}
+ | Used/Max |
+
+
+ {{ Quota.usage }}/{{ Quota.max }}
+
+
|
diff --git a/AdminUi/src/AdminUi/ClientApp/src/app/services/quotas-service/quotas.service.ts b/AdminUi/src/AdminUi/ClientApp/src/app/services/quotas-service/quotas.service.ts
index 0a6055ccc0..33861a0064 100644
--- a/AdminUi/src/AdminUi/ClientApp/src/app/services/quotas-service/quotas.service.ts
+++ b/AdminUi/src/AdminUi/ClientApp/src/app/services/quotas-service/quotas.service.ts
@@ -63,6 +63,7 @@ export interface Quota {
source: "Tier" | "Individual";
metric: Metric;
max: number;
+ usage: number;
period: string;
disabled: boolean;
deleteable: boolean;
diff --git a/Modules/Quotas/src/Quotas.Application/DTOs/QuotaDTO.cs b/Modules/Quotas/src/Quotas.Application/DTOs/QuotaDTO.cs
index f3fd00eb5a..ba6718d9f6 100644
--- a/Modules/Quotas/src/Quotas.Application/DTOs/QuotaDTO.cs
+++ b/Modules/Quotas/src/Quotas.Application/DTOs/QuotaDTO.cs
@@ -3,18 +3,20 @@
namespace Backbone.Modules.Quotas.Application.DTOs;
public class QuotaDTO
{
- public QuotaDTO(string id, QuotaSource source, MetricDTO metric, int max, string period)
+ public QuotaDTO(Quota quota, MetricDTO metric, uint usage)
{
- Id = id;
- Source = source;
+ Id = quota.Id;
+ Source = quota is TierQuota ? QuotaSource.Tier : QuotaSource.Individual;
Metric = metric;
- Max = max;
- Period = period;
+ Max = quota.Max;
+ Period = quota.Period.ToString();
+ Usage = usage;
}
public string Id { get; set; }
public QuotaSource Source { get; set; }
public MetricDTO Metric { get; set; }
public int Max { get; set; }
+ public uint Usage { get; set; }
public string Period { get; set; }
}
diff --git a/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/GetIdentityResponse.cs b/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/GetIdentityResponse.cs
index b069ec738f..b545c932d5 100644
--- a/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/GetIdentityResponse.cs
+++ b/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/GetIdentityResponse.cs
@@ -1,36 +1,40 @@
using Backbone.Modules.Quotas.Application.DTOs;
using Backbone.Modules.Quotas.Domain.Aggregates.Identities;
using Backbone.Modules.Quotas.Domain.Aggregates.Metrics;
+using Backbone.Modules.Quotas.Domain.Metrics;
namespace Backbone.Modules.Quotas.Application.Identities.Queries.GetIdentity;
public class GetIdentityResponse
{
- public GetIdentityResponse(string identityAddress, IEnumerable tierQuotas, IEnumerable individualQuotas, IEnumerable metrics)
+ public string Address { get; set; }
+ public IEnumerable Quotas { get; set; }
+
+ public static async Task Create(MetricCalculatorFactory metricCalculatorFactory, string identityAddress, IEnumerable tierQuotas, IEnumerable individualQuotas, IEnumerable metrics, CancellationToken cancellationToken)
{
var quotasList = new List();
- quotasList.AddRange(individualQuotas.Select(q =>
- new QuotaDTO(
- q.Id,
- QuotaSource.Individual,
- new MetricDTO(metrics.First(m => m.Key == q.MetricKey)),
- q.Max,
- q.Period.ToString()
- )
- ));
- quotasList.AddRange(tierQuotas.Select(q =>
- new QuotaDTO(
- q.Id,
- QuotaSource.Tier,
- new MetricDTO(metrics.First(m => m.Key == q.MetricKey)),
- q.Max,
- q.Period.ToString()
- )
- ));
- Address = identityAddress;
- Quotas = quotasList;
+ var allQuotas = (individualQuotas as IEnumerable).Union(tierQuotas);
+
+ foreach (var quota in allQuotas)
+ {
+ var usage = await CalculateUsage(metricCalculatorFactory, quota, identityAddress, cancellationToken);
+ quotasList.Add(new QuotaDTO(
+ quota,
+ new MetricDTO(metrics.First(m => m.Key == quota.MetricKey)),
+ usage
+ ));
+ }
+
+ return new GetIdentityResponse()
+ {
+ Address = identityAddress,
+ Quotas = quotasList
+ };
}
- public string Address { get; set; }
- public IEnumerable Quotas { get; set; }
+ private static async Task CalculateUsage(MetricCalculatorFactory metricCalculatorFactory, Quota quota, string identityAddress, CancellationToken cancellationToken)
+ {
+ var calculator = metricCalculatorFactory.CreateFor(quota.MetricKey);
+ return await calculator.CalculateUsage(quota.Period.CalculateBegin(), quota.Period.CalculateEnd(), identityAddress, cancellationToken);
+ }
}
diff --git a/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/Handler.cs b/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/Handler.cs
index 62b98dee11..d890777b81 100644
--- a/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/Handler.cs
+++ b/Modules/Quotas/src/Quotas.Application/Identities/Queries/GetIdentity/Handler.cs
@@ -1,6 +1,7 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.Modules.Quotas.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Quotas.Domain.Aggregates.Identities;
+using Backbone.Modules.Quotas.Domain.Metrics;
using MediatR;
namespace Backbone.Modules.Quotas.Application.Identities.Queries.GetIdentity;
@@ -8,11 +9,13 @@ public class Handler : IRequestHandler
{
private readonly IIdentitiesRepository _identitiesRepository;
private readonly IMetricsRepository _metricsRepository;
+ private readonly MetricCalculatorFactory _metricCalculatorFactory;
- public Handler(IIdentitiesRepository identitiesRepository, IMetricsRepository metricsRepository)
+ public Handler(IIdentitiesRepository identitiesRepository, IMetricsRepository metricsRepository, MetricCalculatorFactory metricCalculatorFactory)
{
_identitiesRepository = identitiesRepository;
_metricsRepository = metricsRepository;
+ _metricCalculatorFactory = metricCalculatorFactory;
}
public async Task Handle(GetIdentityQuery request, CancellationToken cancellationToken)
@@ -21,7 +24,6 @@ public async Task Handle(GetIdentityQuery request, Cancella
var metricsKeys = identity.TierQuotas.Select(q => q.MetricKey).Union(identity.IndividualQuotas.Select(q => q.MetricKey));
var metrics = await _metricsRepository.FindAllWithKeys(metricsKeys, cancellationToken);
-
- return new GetIdentityResponse(identity.Address, identity.TierQuotas, identity.IndividualQuotas, metrics);
+ return await GetIdentityResponse.Create(_metricCalculatorFactory, identity.Address, identity.TierQuotas, identity.IndividualQuotas, metrics, cancellationToken);
}
}
diff --git a/Modules/Quotas/test/Quotas.Application.Tests/Tests/Identities/GetIdentity/HandlerTests.cs b/Modules/Quotas/test/Quotas.Application.Tests/Tests/Identities/GetIdentity/HandlerTests.cs
index f6db89e0cd..9adfab9233 100644
--- a/Modules/Quotas/test/Quotas.Application.Tests/Tests/Identities/GetIdentity/HandlerTests.cs
+++ b/Modules/Quotas/test/Quotas.Application.Tests/Tests/Identities/GetIdentity/HandlerTests.cs
@@ -5,6 +5,7 @@
using Backbone.Modules.Quotas.Domain.Aggregates.Identities;
using Backbone.Modules.Quotas.Domain.Aggregates.Metrics;
using Backbone.Modules.Quotas.Domain.Aggregates.Tiers;
+using Backbone.Modules.Quotas.Domain.Metrics;
using Backbone.UnitTestTools.Extensions;
using FakeItEasy;
using FluentAssertions;
@@ -29,10 +30,10 @@ public async void Gets_identity_quotas_by_address()
var stubMetricsRepository = new FindAllWithKeysMetricsStubRepository(new List { metric });
- var identitiesRepository = A.Fake();
- A.CallTo(() => identitiesRepository.Find(A._, A._, A._)).Returns(identity);
+ var stubIdentitiesRepository = A.Fake();
+ A.CallTo(() => stubIdentitiesRepository.Find(A._, A._, A._)).Returns(identity);
- var handler = CreateHandler(identitiesRepository, stubMetricsRepository);
+ var handler = CreateHandler(stubIdentitiesRepository, stubMetricsRepository);
// Act
var result = await handler.Handle(new GetIdentityQuery(identity.Address), CancellationToken.None);
@@ -58,11 +59,10 @@ public async void Gets_identity_quotas_by_address()
public void Fails_when_no_identity_found()
{
// Arrange
- var metricsRepository = A.Fake();
- var identitiesRepository = A.Fake();
- A.CallTo(() => identitiesRepository.Find(A._, A._, A._)).Returns((Identity)null);
+ var stubIdentitiesRepository = A.Fake();
+ A.CallTo(() => stubIdentitiesRepository.Find(A._, A._, A._)).Returns((Identity)null);
- var handler = CreateHandler(identitiesRepository, metricsRepository);
+ var handler = CreateHandler(stubIdentitiesRepository);
// Act
Func acting = async () => await handler.Handle(new GetIdentityQuery("some-inexistent-identity-address"), CancellationToken.None);
@@ -73,8 +73,15 @@ public void Fails_when_no_identity_found()
exception.Code.Should().Be("error.platform.recordNotFound");
}
- private Handler CreateHandler(IIdentitiesRepository identitiesRepository, IMetricsRepository metricsRepository)
+ private static Handler CreateHandler(IIdentitiesRepository identitiesRepository)
{
- return new Handler(identitiesRepository, metricsRepository);
+ var dummyMetricsRepository = A.Dummy();
+ return CreateHandler(identitiesRepository, dummyMetricsRepository);
+ }
+
+ private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, IMetricsRepository metricsRepository)
+ {
+ var dummyMetricCalculatorFactory = A.Dummy();
+ return new Handler(identitiesRepository, metricsRepository, dummyMetricCalculatorFactory);
}
}