Browse Source

History in dashboard.

pull/248/head
Sebastian Stehle 8 years ago
parent
commit
b4a6970d75
  1. 17
      src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs
  2. 4
      src/Squidex/app/features/content/pages/content/content-history.component.html
  3. 2
      src/Squidex/app/features/content/pages/content/content-history.component.scss
  4. 38
      src/Squidex/app/features/content/pages/content/content-history.component.ts
  5. 3
      src/Squidex/app/features/dashboard/module.ts
  6. 19
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.html
  7. 50
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.scss
  8. 23
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts
  9. 4
      src/Squidex/app/shared/components/history.component.html
  10. 38
      src/Squidex/app/shared/components/history.component.ts
  11. 2
      src/Squidex/app/shared/components/pipes.ts
  12. 43
      src/Squidex/app/shared/services/history.service.ts
  13. 2
      src/Squidex/app/shared/services/users-provider.service.ts

17
src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs

@ -66,9 +66,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.History
public async Task<IReadOnlyList<IHistoryEventEntity>> QueryByChannelAsync(Guid appId, string channelPrefix, int count)
{
var historyEventEntities =
await Collection.Find(x => x.AppId == appId && x.Channel == channelPrefix).SortByDescending(x => x.Created).ThenByDescending(x => x.Version).Limit(count)
.ToListAsync();
List<MongoHistoryEventEntity> historyEventEntities;
if (!string.IsNullOrWhiteSpace(channelPrefix))
{
historyEventEntities =
await Collection.Find(x => x.AppId == appId && x.Channel == channelPrefix).SortByDescending(x => x.Created).ThenByDescending(x => x.Version).Limit(count)
.ToListAsync();
}
else
{
historyEventEntities =
await Collection.Find(x => x.AppId == appId).SortByDescending(x => x.Created).ThenByDescending(x => x.Version).Limit(count)
.ToListAsync();
}
return historyEventEntities.Select(x => (IHistoryEventEntity)new ParsedHistoryEvent(x, texts)).ToList();
}

4
src/Squidex/app/features/content/pages/content/content-history.component.html

@ -13,11 +13,11 @@
<div class="panel-content panel-content-blank">
<div *ngFor="let event of events | async" class="event">
<div class="event-left">
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:'I'" [attr.src]="event.actor | sqxUserPictureRef" />
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:null" [attr.src]="event.actor | sqxUserPictureRef" />
</div>
<div class="event-main">
<div class="event-message">
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:'I'}}</span> <span [innerHTML]="format(event.message) | async"></span>
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:null}}</span> <span [innerHTML]="format(event.message) | async"></span>
</div>
<div class="event-created">{{event.created | sqxFromNow}}</div>

2
src/Squidex/app/features/content/pages/content/content-history.component.scss

@ -10,7 +10,7 @@
&-main {
@include flex-grow(1);
}
&-load {
& {
font-size: .9rem;

38
src/Squidex/app/features/content/pages/content/content-history.component.ts

@ -11,6 +11,7 @@ import { Observable } from 'rxjs';
import {
allParams,
AppContext,
formatHistoryMessage,
HistoryChannelUpdated,
HistoryEventDto,
HistoryService,
@ -19,8 +20,6 @@ import {
import { ContentVersionSelected } from './../messages';
const REPLACEMENT_TEMP = '$TEMP$';
@Component({
selector: 'sqx-history',
styleUrls: ['./content-history.component.scss'],
@ -58,44 +57,11 @@ export class ContentHistoryComponent {
) {
}
private userName(userId: string): Observable<string> {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.users.getUser(parts[1], 'Me').map(u => u.displayName);
} else {
if (parts[1].endsWith('client')) {
return Observable.of(parts[1]);
} else {
return Observable.of(`${parts[1]}-client`);
}
}
}
public loadVersion(version: number) {
this.ctx.bus.emit(new ContentVersionSelected(version));
}
public format(message: string): Observable<string> {
let foundUserId: string | null = null;
message = message.replace(/{([^\s:]*):([^}]*)}/, (match: string, type: string, id: string) => {
if (type === 'user') {
foundUserId = id;
return REPLACEMENT_TEMP;
} else {
return id;
}
});
message = message.replace(/{([^}]*)}/g, (match: string, marker: string) => {
return `<span class="marker-ref">${marker}</span>`;
});
if (foundUserId) {
return this.userName(foundUserId).map(t => message.replace(REPLACEMENT_TEMP, `<span class="user-ref">${t}</span>`));
}
return Observable.of(message);
return formatHistoryMessage(message, this.users);
}
}

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

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

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

@ -111,5 +111,24 @@
<chart type="line" [data]="chartStorageSize" [options]="chartOptions"></chart>
</div>
</div>
<div class="card card-lg">
<div class="card-header">
History
</div>
<div class="card-body card-history card-body-scroll">
<div *ngFor="let event of history" class="event">
<div class="event-left">
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:null" [attr.src]="event.actor | sqxUserPictureRef" />
</div>
<div class="event-main">
<div class="event-message">
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:null}}</span> <span [innerHTML]="format(event.message) | async"></span>
</div>
<div class="event-created">{{event.created | sqxFromNow}}</div>
</div>
</div>
</div>
</div>
</div>
</div>

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

@ -49,17 +49,16 @@
text-align: center;
}
&-text {
color: $color-text-decent;
font-weight: normal;
font-size: .9rem;
&-history {
min-height: 12.4rem;
max-height: 12.4rem;
overflow-y: auto;
}
&-more {
&-text {
color: $color-text-decent;
font-weight: normal;
font-size: .8rem;
margin-top: .4rem;
font-size: .9rem;
}
&-title {
@ -108,4 +107,41 @@
.app-name {
color: $color-title;
}
.event {
& {
@include flex-box;
margin-bottom: 1rem;
}
&-main {
@include flex-grow(1);
}
&-load {
& {
font-size: .9rem;
font-weight: normal;
cursor: pointer;
color: $color-theme-blue !important;
}
&:focus,
&:hover {
text-decoration: underline !important;
}
}
&-left {
min-width: 2.8rem;
max-width: 2.8rem;
margin-top: .3rem;
}
&-created {
font-size: .65rem;
font-weight: normal;
color: $color-text-decent;
}
}

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

@ -6,14 +6,18 @@
*/
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import {
AppContext,
AppDto,
DateTime,
fadeAnimation,
UsagesService
formatHistoryMessage,
HistoryEventDto,
HistoryService,
UsagesService,
UsersProviderService
} from 'shared';
declare var _urq: any;
@ -60,6 +64,8 @@ export class DashboardPageComponent implements OnDestroy, OnInit {
maintainAspectRatio: false
};
public history: HistoryEventDto[] = [];
public assetsCurrent = 0;
public assetsMax = 0;
@ -67,6 +73,8 @@ export class DashboardPageComponent implements OnDestroy, OnInit {
public callsMax = 0;
constructor(public readonly ctx: AppContext,
private readonly historyService: HistoryService,
private readonly users: UsersProviderService,
private readonly usagesService: UsagesService
) {
}
@ -96,6 +104,13 @@ export class DashboardPageComponent implements OnDestroy, OnInit {
this.callsMax = dto.maxAllowed;
}));
this.subscriptions.push(
this.app
.switchMap(app => this.historyService.getHistory(app.name, ''))
.subscribe(dto => {
this.history = dto;
}));
this.subscriptions.push(
this.app
.switchMap(app => this.usagesService.getStorageUsages(app.name, DateTime.today().addDays(-20), DateTime.today()))
@ -163,6 +178,10 @@ export class DashboardPageComponent implements OnDestroy, OnInit {
}));
}
public format(message: string): Observable<string> {
return formatHistoryMessage(message, this.users);
}
public showForum() {
_urq.push(['Feedback_Open']);
}

4
src/Squidex/app/shared/components/history.component.html

@ -13,11 +13,11 @@
<div class="panel-content panel-content-blank">
<div *ngFor="let event of events | async" class="event">
<div class="event-left">
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:'I'" [attr.src]="event.actor | sqxUserPictureRef" />
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:null" [attr.src]="event.actor | sqxUserPictureRef" />
</div>
<div class="event-main">
<div class="event-message">
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:'I'}}</span> <span [innerHTML]="format(event.message) | async"></span>
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:null}}</span> <span [innerHTML]="format(event.message) | async"></span>
</div>
<div class="event-created">{{event.created | sqxFromNow}}</div>
</div>

38
src/Squidex/app/shared/components/history.component.ts

@ -12,14 +12,13 @@ import { AppContext } from './app-context';
import {
allParams,
formatHistoryMessage,
HistoryChannelUpdated,
HistoryEventDto,
HistoryService,
UsersProviderService
} from './../declarations-base';
const REPLACEMENT_TEMP = '$TEMP$';
@Component({
selector: 'sqx-history',
styleUrls: ['./history.component.scss'],
@ -57,40 +56,7 @@ export class HistoryComponent {
) {
}
private userName(userId: string): Observable<string> {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.users.getUser(parts[1], 'Me').map(u => u.displayName);
} else {
if (parts[1].endsWith('client')) {
return Observable.of(parts[1]);
} else {
return Observable.of(`${parts[1]}-client`);
}
}
}
public format(message: string): Observable<string> {
let foundUserId: string | null = null;
message = message.replace(/{([^\s:]*):([^}]*)}/, (match: string, type: string, id: string) => {
if (type === 'user') {
foundUserId = id;
return REPLACEMENT_TEMP;
} else {
return id;
}
});
message = message.replace(/{([^}]*)}/g, (match: string, marker: string) => {
return `<span class="marker-ref">${marker}</span>`;
});
if (foundUserId) {
return this.userName(foundUserId).map(t => message.replace(REPLACEMENT_TEMP, `<span class="user-ref">${t}</span>`));
}
return Observable.of(message);
return formatHistoryMessage(message, this.users);
}
}

2
src/Squidex/app/shared/components/pipes.ts

@ -71,7 +71,7 @@ export class UserNameRefPipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector);
}
public transform(userId: string, placeholder = 'Me'): string | null {
public transform(userId: string, placeholder: string | null = 'Me'): string | null {
return super.transformInternal(userId, users => {
const parts = userId.split(':');

43
src/Squidex/app/shared/services/history.service.ts

@ -11,6 +11,8 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { UsersProviderService } from './users-provider.service';
import {
ApiUrlConfig,
HTTP,
@ -28,6 +30,47 @@ export class HistoryEventDto {
}
}
const REPLACEMENT_TEMP = '$TEMP$';
export function formatHistoryMessage(message: string, users: UsersProviderService): Observable<string> {
const userName = (userId: string) => {
const parts = userId.split(':');
if (parts.length === 1) {
return users.getUser(parts[0], null).map(u => u.displayName);
} else if (parts[0] === 'subject') {
return users.getUser(parts[1], null).map(u => u.displayName);
} else {
if (parts[1].endsWith('client')) {
return Observable.of(parts[1]);
} else {
return Observable.of(`${parts[1]}-client`);
}
}
};
let foundUserId: string | null = null;
message = message.replace(/{([^\s:]*):([^}]*)}/, (match: string, type: string, id: string) => {
if (type === 'user') {
foundUserId = id;
return REPLACEMENT_TEMP;
} else {
return id;
}
});
message = message.replace(/{([^}]*)}/g, (match: string, marker: string) => {
return `<span class="marker-ref">${marker}</span>`;
});
if (foundUserId) {
return userName(foundUserId).map(t => message.replace(REPLACEMENT_TEMP, `<span class="user-ref">${t}</span>`));
}
return Observable.of(message);
}
@Injectable()
export class HistoryService {
constructor(

2
src/Squidex/app/shared/services/users-provider.service.ts

@ -22,7 +22,7 @@ export class UsersProviderService {
) {
}
public getUser(id: string, me = 'Me'): Observable<UserDto> {
public getUser(id: string, me: string | null = 'Me'): Observable<UserDto> {
let result = this.caches[id];
if (!result) {

Loading…
Cancel
Save