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(); 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 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 }; return new UsageDto { Date = x.Date, Count = x.TotalCount, AverageMs = averageMs };
}).ToList(); }).ToList();

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

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

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

@ -9,7 +9,7 @@
</div> </div>
</div> </div>
<div> <div class="clearfix">
<a class="card" [routerLink]="['schemas', { showDialog: true }]"> <a class="card" [routerLink]="['schemas', { showDialog: true }]">
<div class="card-block"> <div class="card-block">
<div class="card-image"> <div class="card-image">
@ -51,4 +51,18 @@
</div> </div>
</a> </a>
</div> </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> </div>

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

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

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

@ -12,8 +12,10 @@ import {
AppComponentBase, AppComponentBase,
AppsStoreService, AppsStoreService,
AuthService, AuthService,
DateTime,
fadeAnimation, fadeAnimation,
NotificationService NotificationService,
UsagesService
} from 'shared'; } from 'shared';
declare var _urq: any; declare var _urq: any;
@ -31,8 +33,13 @@ export class DashboardPageComponent extends AppComponentBase implements OnInit,
public profileDisplayName = ''; public profileDisplayName = '';
public chartCount: any;
public chartPerformance: any;
public chartOptions = { };
constructor(apps: AppsStoreService, notifications: NotificationService, constructor(apps: AppsStoreService, notifications: NotificationService,
private readonly auth: AuthService private readonly auth: AuthService,
private readonly usagesService: UsagesService
) { ) {
super(notifications, apps); super(notifications, apps);
} }
@ -42,6 +49,38 @@ export class DashboardPageComponent extends AppComponentBase implements OnInit,
} }
public ngOnInit() { 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.authenticationSubscription =
this.auth.isAuthenticated.subscribe(() => { this.auth.isAuthenticated.subscribe(() => {
const user = this.auth.user; 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/history.service';
export * from './services/languages.service'; export * from './services/languages.service';
export * from './services/schemas.service'; export * from './services/schemas.service';
export * from './services/usages.service';
export * from './services/users-provider.service'; export * from './services/users-provider.service';
export * from './services/users.service'; export * from './services/users.service';

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

@ -40,6 +40,7 @@ import {
ResolvePublishedSchemaGuard, ResolvePublishedSchemaGuard,
ResolveSchemaGuard, ResolveSchemaGuard,
SchemasService, SchemasService,
UsagesService,
UserEmailPipe, UserEmailPipe,
UserEmailRefPipe, UserEmailRefPipe,
UserNamePipe, UserNamePipe,
@ -113,6 +114,7 @@ export class SqxSharedModule {
ResolvePublishedSchemaGuard, ResolvePublishedSchemaGuard,
ResolveSchemaGuard, ResolveSchemaGuard,
SchemasService, SchemasService,
UsagesService,
UserManagementService, UserManagementService,
UsersProviderService, UsersProviderService,
UsersService 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/jasmine": "2.5.43",
"@types/mousetrap": "1.5.33", "@types/mousetrap": "1.5.33",
"@types/node": "7.0.5", "@types/node": "7.0.5",
"angular2-chartjs": "^0.2.0",
"angular2-router-loader": "0.3.5", "angular2-router-loader": "0.3.5",
"angular2-template-loader": "0.6.2", "angular2-template-loader": "0.6.2",
"awesome-typescript-loader": "3.1.3", "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(1), 10, 15),
new StoredUsage(dateFrom.AddDays(3), 13, 18), new StoredUsage(dateFrom.AddDays(3), 13, 18),
new StoredUsage(dateFrom.AddDays(5), 15, 20), 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)); 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(4), 00, 00),
new StoredUsage(dateFrom.AddDays(5), 15, 20), new StoredUsage(dateFrom.AddDays(5), 15, 20),
new StoredUsage(dateFrom.AddDays(6), 00, 00), new StoredUsage(dateFrom.AddDays(6), 00, 00),
new StoredUsage(dateFrom.AddDays(7), 17, 22), new StoredUsage(dateFrom.AddDays(7), 17, 22)
}); });
} }

Loading…
Cancel
Save