Browse Source

API calls in UI

pull/65/head
Sebastian Stehle 9 years ago
parent
commit
d2be2ef4c5
  1. 4
      src/Squidex/Controllers/Api/Apps/AppUsageController.cs
  2. 2
      src/Squidex/app/features/dashboard/module.ts
  3. 16
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.html
  4. 11
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.scss
  5. 43
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts
  6. 1
      src/Squidex/app/shared/declarations-base.ts
  7. 2
      src/Squidex/app/shared/module.ts
  8. 62
      src/Squidex/app/shared/services/usages.service.spec.ts
  9. 50
      src/Squidex/app/shared/services/usages.service.ts
  10. 1
      src/Squidex/package.json
  11. 4
      tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

4
src/Squidex/Controllers/Api/Apps/AppUsageController.cs

@ -58,11 +58,11 @@ namespace Squidex.Controllers.Api.Apps
return BadRequest();
}
var entities = await usageTracker.FindAsync(App.Id.ToString(), fromDate, toDate);
var entities = await usageTracker.FindAsync(App.Id.ToString(), fromDate.Date, toDate.Date);
var models = entities.Select(x =>
{
var averageMs = x.TotalElapsedMs / x.TotalCount;
var averageMs = x.TotalCount == 0 ? 0 : x.TotalElapsedMs / x.TotalCount;
return new UsageDto { Date = x.Date, Count = x.TotalCount, AverageMs = averageMs };
}).ToList();

2
src/Squidex/app/features/dashboard/module.ts

@ -7,6 +7,7 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ChartModule } from 'angular2-chartjs';
import { SqxFrameworkModule } from 'shared';
@ -23,6 +24,7 @@ const routes: Routes = [
@NgModule({
imports: [
ChartModule,
SqxFrameworkModule,
RouterModule.forChild(routes)
],

16
src/Squidex/app/features/dashboard/pages/dashboard-page.component.html

@ -9,7 +9,7 @@
</div>
</div>
<div>
<div class="clearfix">
<a class="card" [routerLink]="['schemas', { showDialog: true }]">
<div class="card-block">
<div class="card-image">
@ -51,4 +51,18 @@
</div>
</a>
</div>
<div>
<div class="card card-big">
<div class="card-block">
<chart type="bar" [data]="chartCount" [options]="chartOptions"></chart>
</div>
</div>
<div class="card card-big">
<div class="card-block">
<chart type="bar" [data]="chartPerformance" [options]="chartOptions"></chart>
</div>
</div>
</div>
</div>

11
src/Squidex/app/features/dashboard/pages/dashboard-page.component.scss

@ -21,9 +21,14 @@ h1 {
color: $color-title;
}
a {
&.card {
cursor: pointer;
}
}
.card {
& {
cursor: pointer;
margin-right: 1rem;
margin-bottom: 1rem;
width: 16rem;
@ -43,6 +48,10 @@ h1 {
color: $color-title;
}
&-big {
width: 33rem;
}
&-block {
min-height: 14.5rem;
}

43
src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts

@ -12,8 +12,10 @@ import {
AppComponentBase,
AppsStoreService,
AuthService,
DateTime,
fadeAnimation,
NotificationService
NotificationService,
UsagesService
} from 'shared';
declare var _urq: any;
@ -31,8 +33,13 @@ export class DashboardPageComponent extends AppComponentBase implements OnInit,
public profileDisplayName = '';
public chartCount: any;
public chartPerformance: any;
public chartOptions = { };
constructor(apps: AppsStoreService, notifications: NotificationService,
private readonly auth: AuthService
private readonly auth: AuthService,
private readonly usagesService: UsagesService
) {
super(notifications, apps);
}
@ -42,6 +49,38 @@ export class DashboardPageComponent extends AppComponentBase implements OnInit,
}
public ngOnInit() {
this.appName()
.switchMap(app => this.usagesService.getUsages(app, DateTime.today().addDays(-30), DateTime.today()))
.subscribe(dtos => {
const usages: any[] = dtos.map(x => { return { date: x.date.toStringFormat('L'), count: x.count, averageMs: x.averageMs }; });
this.chartCount = {
labels: usages.map(x => x.date),
datasets: [
{
label: 'Number of API Calls',
backgroundColor: 'rgba(61, 135, 213, 0.6)',
borderColor: 'rgba(61, 135, 213, 1)',
borderWidth: 1,
data: usages.map(x => x.count)
}
]
};
this.chartPerformance = {
labels: usages.map(x => x.date),
datasets: [
{
label: 'API Performance (Milliseconds)',
backgroundColor: 'rgba(61, 135, 213, 0.6)',
borderColor: 'rgba(61, 135, 213, 1)',
borderWidth: 1,
data: usages.map(x => x.averageMs)
}
]
};
});
this.authenticationSubscription =
this.auth.isAuthenticated.subscribe(() => {
const user = this.auth.user;

1
src/Squidex/app/shared/declarations-base.ts

@ -26,6 +26,7 @@ export * from './services/help.service';
export * from './services/history.service';
export * from './services/languages.service';
export * from './services/schemas.service';
export * from './services/usages.service';
export * from './services/users-provider.service';
export * from './services/users.service';

2
src/Squidex/app/shared/module.ts

@ -40,6 +40,7 @@ import {
ResolvePublishedSchemaGuard,
ResolveSchemaGuard,
SchemasService,
UsagesService,
UserEmailPipe,
UserEmailRefPipe,
UserNamePipe,
@ -113,6 +114,7 @@ export class SqxSharedModule {
ResolvePublishedSchemaGuard,
ResolveSchemaGuard,
SchemasService,
UsagesService,
UserManagementService,
UsersProviderService,
UsersService

62
src/Squidex/app/shared/services/usages.service.spec.ts

@ -0,0 +1,62 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs';
import { IMock, Mock, Times } from 'typemoq';
import {
ApiUrlConfig,
AuthService,
DateTime,
UsageDto,
UsagesService
} from './../';
describe('UsagesService', () => {
let authService: IMock<AuthService>;
let usagesService: UsagesService;
beforeEach(() => {
authService = Mock.ofType(AuthService);
usagesService = new UsagesService(authService.object, new ApiUrlConfig('http://service/p/'));
});
it('should make get request to get usages', () => {
authService.setup(x => x.authGet('http://service/p/api/apps/my-app/usages/2017-10-12/2017-10-13'))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: [{
date: '2017-10-12',
count: 1,
averageMs: 130
}, {
date: '2017-10-13',
count: 13,
averageMs: 170
}]
})
)
))
.verifiable(Times.once());
let usages: UsageDto[] | null = null;
usagesService.getUsages('my-app', DateTime.parseISO_UTC('2017-10-12'), DateTime.parseISO_UTC('2017-10-13')).subscribe(result => {
usages = result;
}).unsubscribe();
expect(usages).toEqual(
[
new UsageDto(DateTime.parseISO_UTC('2017-10-12'), 1, 130),
new UsageDto(DateTime.parseISO_UTC('2017-10-13'), 13, 170)
]);
authService.verifyAll();
});
});

50
src/Squidex/app/shared/services/usages.service.ts

@ -0,0 +1,50 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig, DateTime } from 'framework';
import { AuthService } from './auth.service';
export class UsageDto {
constructor(
public readonly date: DateTime,
public readonly count: number,
public readonly averageMs: number
) {
}
}
@Injectable()
export class UsagesService {
constructor(
private readonly authService: AuthService,
private readonly apiUrl: ApiUrlConfig
) {
}
public getUsages(app: string, fromDate: DateTime, toDate: DateTime): Observable<UsageDto[]> {
const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/${fromDate.toStringFormat('YYYY-MM-DD')}/${toDate.toStringFormat('YYYY-MM-DD')}`);
return this.authService.authGet(url)
.map(response => response.json())
.map(response => {
const items: any[] = response;
return items.map(item => {
return new UsageDto(
DateTime.parseISO_UTC(item.date),
item.count,
item.averageMs);
});
})
.catchError('Failed to load usage. Please reload.');
}
}

1
src/Squidex/package.json

@ -46,6 +46,7 @@
"@types/jasmine": "2.5.43",
"@types/mousetrap": "1.5.33",
"@types/node": "7.0.5",
"angular2-chartjs": "^0.2.0",
"angular2-router-loader": "0.3.5",
"angular2-template-loader": "0.6.2",
"awesome-typescript-loader": "3.1.3",

4
tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

@ -53,7 +53,7 @@ namespace Squidex.Infrastructure.UsageTracking
new StoredUsage(dateFrom.AddDays(1), 10, 15),
new StoredUsage(dateFrom.AddDays(3), 13, 18),
new StoredUsage(dateFrom.AddDays(5), 15, 20),
new StoredUsage(dateFrom.AddDays(7), 17, 22),
new StoredUsage(dateFrom.AddDays(7), 17, 22)
};
usageStore.Setup(x => x.FindAsync("key", dateFrom, dateTo)).Returns(Task.FromResult(originalDate));
@ -69,7 +69,7 @@ namespace Squidex.Infrastructure.UsageTracking
new StoredUsage(dateFrom.AddDays(4), 00, 00),
new StoredUsage(dateFrom.AddDays(5), 15, 20),
new StoredUsage(dateFrom.AddDays(6), 00, 00),
new StoredUsage(dateFrom.AddDays(7), 17, 22),
new StoredUsage(dateFrom.AddDays(7), 17, 22)
});
}

Loading…
Cancel
Save