mirror of https://github.com/Squidex/squidex.git
32 changed files with 360 additions and 41 deletions
@ -0,0 +1,19 @@ |
|||
<sqx-title message="{app} | Contributors | Settings" parameter="app" value="{{appName() | async}}"></sqx-title> |
|||
|
|||
<div class="panel panel-light"> |
|||
<div class="panel-header"> |
|||
<h3 class="panel-title">History</h3> |
|||
|
|||
<a class="panel-close" routerLink="../"> |
|||
<i class="icon-close"></i> |
|||
</a> |
|||
</div> |
|||
|
|||
<div class="panel-main"> |
|||
<div class="panel-content panel-content-blank"> |
|||
<div *ngFor="let event of events"> |
|||
{{event.message}} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,7 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.panel { |
|||
min-width: 220px; |
|||
max-width: 1220px80px; |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { ActivatedRoute } from '@angular/router'; |
|||
|
|||
import { ImmutableArray, NotificationService } from 'framework'; |
|||
|
|||
import { AppComponentBase } from './../app-component-base'; |
|||
import { AppsStoreService } from './../services/apps-store.service'; |
|||
import { HistoryEventDto, HistoryService } from './../services/history.service'; |
|||
import { UsersProviderService } from './../services/users-provider.service'; |
|||
|
|||
const FALLBACK_NAME = 'my-app'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-history', |
|||
styleUrls: ['./history.component.scss'], |
|||
templateUrl: './history.component.html' |
|||
}) |
|||
export class HistoryComponent extends AppComponentBase implements OnDestroy, OnInit { |
|||
private interval: any; |
|||
|
|||
public events = ImmutableArray.empty(); |
|||
|
|||
constructor(appsStore: AppsStoreService, notifications: NotificationService, usersProvider: UsersProviderService, |
|||
private readonly historyService: HistoryService, |
|||
private readonly route: ActivatedRoute |
|||
) { |
|||
super(appsStore, notifications, usersProvider); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
clearInterval(this.interval); |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.load(); |
|||
|
|||
this.interval = |
|||
setInterval(() => { |
|||
this.load(); |
|||
}, 10000); |
|||
} |
|||
|
|||
public load() { |
|||
const channel = this.route.snapshot.data['channel']; |
|||
|
|||
this.appName() |
|||
.switchMap(app => this.historyService.getHistory(app, channel).retry(2)) |
|||
.subscribe(dtos => { |
|||
this.events = ImmutableArray.of(dtos); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Response, ResponseOptions } from '@angular/http'; |
|||
import { Observable } from 'rxjs'; |
|||
import { Mock, Times } from 'typemoq'; |
|||
|
|||
import { DateTime } from 'framework'; |
|||
|
|||
import { |
|||
ApiUrlConfig, |
|||
AuthService, |
|||
HistoryEventDto, |
|||
HistoryService |
|||
} from './../'; |
|||
|
|||
describe('HistoryService', () => { |
|||
let authService: Mock<AuthService>; |
|||
let languageService: HistoryService; |
|||
|
|||
beforeEach(() => { |
|||
authService = Mock.ofType(AuthService); |
|||
languageService = new HistoryService(authService.object, new ApiUrlConfig('http://service/p/')); |
|||
}); |
|||
|
|||
it('should make get request to get history events', () => { |
|||
authService.setup(x => x.authGet('http://service/p/api/apps/my-app/history?channel=settings.contributors')) |
|||
.returns(() => Observable.of( |
|||
new Response( |
|||
new ResponseOptions({ |
|||
body: [{ |
|||
user: 'User1', |
|||
eventId: '1', |
|||
message: 'Message 1', |
|||
created: '2016-12-12T10:10' |
|||
}, { |
|||
user: 'User2', |
|||
eventId: '2', |
|||
message: 'Message 2', |
|||
created: '2016-12-13T10:10' |
|||
}] |
|||
}) |
|||
) |
|||
)) |
|||
.verifiable(Times.once()); |
|||
|
|||
let events: HistoryEventDto[] = null; |
|||
|
|||
languageService.getHistory('my-app', 'settings.contributors').subscribe(result => { |
|||
events = result; |
|||
}).unsubscribe(); |
|||
|
|||
expect(events).toEqual( |
|||
[ |
|||
new HistoryEventDto('1', 'User1', 'Message 1', DateTime.parseISO_UTC('2016-12-12T10:10')), |
|||
new HistoryEventDto('2', 'User2', 'Message 2', DateTime.parseISO_UTC('2016-12-13T10:10')) |
|||
]); |
|||
|
|||
authService.verifyAll(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,55 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { |
|||
ApiUrlConfig, |
|||
DateTime, |
|||
handleError |
|||
} from 'framework'; |
|||
|
|||
import { AuthService } from './auth.service'; |
|||
|
|||
export class HistoryEventDto { |
|||
constructor( |
|||
public readonly eventId: string, |
|||
public readonly user: string, |
|||
public readonly message: string, |
|||
public readonly created: DateTime |
|||
) { |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class HistoryService { |
|||
constructor( |
|||
private readonly authService: AuthService, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getHistory(appName: string, channel: string): Observable<HistoryEventDto[]> { |
|||
const url = this.apiUrl.buildUrl(`api/apps/${appName}/history?channel=${channel}`); |
|||
|
|||
return this.authService.authGet(url) |
|||
.map(response => response.json()) |
|||
.map(response => { |
|||
const items: any[] = response; |
|||
|
|||
return items.map(item => { |
|||
return new HistoryEventDto( |
|||
item.eventId, |
|||
item.user, |
|||
item.message, |
|||
DateTime.parseISO_UTC(item.created)); |
|||
}); |
|||
}) |
|||
.catch(response => handleError('Failed to load history. Please reload', response)); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue