Browse Source

Bugfixes

pull/1/head
Sebastian 10 years ago
parent
commit
0ddb7ab837
  1. 2
      src/Squidex/app-config/webpack.run.dev.js
  2. 2
      src/Squidex/app/app.module.ts
  3. 31
      src/Squidex/app/features/settings/pages/clients/clients-page.component.ts
  4. 4
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html
  5. 39
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts
  6. 4
      src/Squidex/app/features/settings/pages/languages/languages-page.component.html
  7. 37
      src/Squidex/app/features/settings/pages/languages/languages-page.component.ts
  8. 91
      src/Squidex/app/framework/angular/autocomplete.component.ts
  9. 1
      src/Squidex/app/framework/declarations.ts
  10. 42
      src/Squidex/app/framework/services/message-bus.spec.ts
  11. 35
      src/Squidex/app/framework/services/message-bus.ts
  12. 2
      src/Squidex/app/shared/components/history.component.html
  13. 45
      src/Squidex/app/shared/components/history.component.ts
  14. 2
      src/Squidex/app/shared/declarations.ts
  15. 8
      src/Squidex/app/shared/utils/messages.ts
  16. 2
      src/Squidex/tslint.json

2
src/Squidex/app-config/webpack.run.dev.js

@ -13,7 +13,7 @@ module.exports = webpackMerge(runConfig, {
* See: http://webpack.github.io/docs/configuration.html#devtool
* See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
*/
devtool: 'cheap-module-eval-source-map',
devtool: 'cheap-module-source-map',
//debug: true,

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

@ -25,6 +25,7 @@ import {
HistoryService,
LanguageService,
LocalStoreService,
MessageBus,
MustBeAuthenticatedGuard,
MustBeNotAuthenticatedGuard,
NotificationService,
@ -81,6 +82,7 @@ export function configCurrency() {
HistoryService,
LanguageService,
LocalStoreService,
MessageBus,
MustBeAuthenticatedGuard,
MustBeNotAuthenticatedGuard,
NotificationService,

31
src/Squidex/app/features/settings/pages/clients/clients-page.component.ts

@ -14,7 +14,9 @@ import {
AppComponentBase,
AppsStoreService,
CreateAppClientDto,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
NotificationService,
UpdateAppClientDto,
UsersProviderService
@ -44,6 +46,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly appClientsService: AppClientsService,
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(apps, notifications, users);
@ -57,7 +60,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
this.appName()
.switchMap(app => this.appClientsService.getClients(app).retry(2))
.subscribe(dtos => {
this.appClients = ImmutableArray.of(dtos);
this.updateClients(ImmutableArray.of(dtos));
}, error => {
this.notifyError(error);
});
@ -67,17 +70,19 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
this.appName()
.switchMap(app => this.appClientsService.deleteClient(app, client.id))
.subscribe(() => {
this.appClients = this.appClients.remove(client);
this.updateClients(this.appClients.remove(client));
}, error => {
this.notifyError(error);
});
}
public renameClient(client: AppClientDto, name: string) {
const request = new UpdateAppClientDto(name);
this.appName()
.switchMap(app => this.appClientsService.updateClient(app, client.id, new UpdateAppClientDto(name)))
.switchMap(app => this.appClientsService.updateClient(app, client.id, request))
.subscribe(() => {
this.appClients = this.appClients.replace(client, rename(client, name));
this.updateClients(this.appClients.replace(client, rename(client, name)));
}, error => {
this.notifyError(error);
});
@ -91,21 +96,27 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
const dto = new CreateAppClientDto(this.addClientForm.controls['name'].value);
const reset = () => {
this.addClientForm.reset();
this.addClientForm.enable();
};
this.appName()
.switchMap(app => this.appClientsService.postClient(app, dto))
.subscribe(dto => {
this.appClients = this.appClients.push(dto);
this.reset();
this.updateClients(this.appClients.push(dto));
reset();
}, error => {
this.notifyError(error);
this.reset();
reset();
});
}
}
private reset() {
this.addClientForm.reset();
this.addClientForm.enable();
private updateClients(clients: ImmutableArray<AppClientDto>) {
this.appClients = clients;
this.messageBus.publish(new HistoryChannelUpdated());
}
}

4
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html

@ -50,12 +50,12 @@
<span class="user-email">{{userEmail(contributor.contributorId) | async}}</span>
</td>
<td>
<select class="form-control" [(ngModel)]="contributor.permission" (ngModelChange)="changePermission(contributor, $event)" [disabled]="currentUserId === contributor.contributorId">
<select class="form-control" [ngModel]="contributor.permission" (ngModelChange)="changePermission(contributor, $event)" [disabled]="currentUserId === contributor.contributorId">
<option *ngFor="let permission of usersPermissions">{{permission}}</option>
</select>
</td>
<td>
<button type="button" class="btn btn-link btn-danger" [disabled]="currrentUserId === contributor.contributorId" (click)="removeContributor(contributor)">
<button type="button" class="btn btn-link btn-danger" [disabled]="currentUserId === contributor.contributorId" (click)="removeContributor(contributor)">
<i class="icon-bin"></i>
</button>
</td>

39
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts

@ -17,7 +17,9 @@ import {
AuthService,
AutocompleteItem,
AutocompleteSource,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
NotificationService,
UserDto,
UsersProviderService,
@ -63,6 +65,8 @@ function changePermission(contributor: AppContributorDto, permission: string): A
export class ContributorsPageComponent extends AppComponentBase implements OnInit {
public appContributors = ImmutableArray.empty<AppContributorDto>();
public currentUserId: string;
public usersDataSource: UsersDataSource;
public usersPermissions = [
'Owner',
@ -80,6 +84,7 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly appContributorsService: AppContributorsService,
private readonly messageBus: MessageBus,
private readonly usersService: UsersService,
private readonly authService: AuthService,
private readonly formBuilder: FormBuilder
@ -90,6 +95,8 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
}
public ngOnInit() {
this.currentUserId = this.authService.user.id;
this.load();
}
@ -97,19 +104,29 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
this.appName()
.switchMap(app => this.appContributorsService.getContributors(app).retry(2))
.subscribe(dtos => {
this.appContributors = ImmutableArray.of(dtos);
this.updateContributors(ImmutableArray.of(dtos));
}, error => {
this.notifyError(error);
});
}
public removeContributor(contributor: AppContributorDto) {
this.appName()
.switchMap(app => this.appContributorsService.deleteContributor(app, contributor.contributorId))
.subscribe(() => {
this.updateContributors(this.appContributors.remove(contributor));
}, error => {
this.notifyError(error);
});
}
public assignContributor() {
const contributor = new AppContributorDto(this.addContributorForm.get('user').value.model.id, 'Editor');
const newContributor = new AppContributorDto(this.addContributorForm.get('user').value.model.id, 'Editor');
this.appName()
.switchMap(app => this.appContributorsService.postContributor(app, contributor))
.switchMap(app => this.appContributorsService.postContributor(app, newContributor))
.subscribe(() => {
this.appContributors = this.appContributors.push(contributor);
this.updateContributors(this.appContributors.push(newContributor));
}, error => {
this.notifyError(error);
});
@ -123,20 +140,16 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
this.appName()
.switchMap(app => this.appContributorsService.postContributor(app, newContributor))
.subscribe(() => {
this.appContributors = this.appContributors.replace(contributor, newContributor);
this.updateContributors(this.appContributors.replace(contributor, newContributor));
}, error => {
this.notifyError(error);
});
}
public removeContributor(contributor: AppContributorDto) {
this.appName()
.switchMap(app => this.appContributorsService.deleteContributor(app, contributor.contributorId))
.subscribe(() => {
this.appContributors = this.appContributors.remove(contributor);
}, error => {
this.notifyError(error);
});
private updateContributors(contributors: ImmutableArray<AppContributorDto>) {
this.appContributors = contributors;
this.messageBus.publish(new HistoryChannelUpdated());
}
}

4
src/Squidex/app/features/settings/pages/languages/languages-page.component.html

@ -47,8 +47,8 @@
</span>
</td>
<td>
<label class="language-default" (click)="setMasterLanguage(language)">
<input type="radio" [value]="true" [checked]="language.isMasterLanguage"> Master Language
<label class="language-default">
<input type="radio" [value]="true" [checked]="language.isMasterLanguage" (click)="setMasterLanguage(language)"> Master Language
</label>
</td>
<td>

37
src/Squidex/app/features/settings/pages/languages/languages-page.component.ts

@ -14,7 +14,9 @@ import {
AppLanguageDto,
AppLanguagesService,
AppsStoreService,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
LanguageDto,
LanguageService,
NotificationService,
@ -45,6 +47,7 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly appLanguagesService: AppLanguagesService,
private readonly languagesService: LanguageService,
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(apps, notifications, users);
@ -65,39 +68,43 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
this.appName()
.switchMap(app => this.appLanguagesService.getLanguages(app).retry(2))
.subscribe(dtos => {
this.appLanguages = ImmutableArray.of(dtos);
this.updateLanguages(ImmutableArray.of(dtos));
}, error => {
this.notifyError(error);
});
}
public addLanguage() {
public removeLanguage(language: AppLanguageDto) {
this.appName()
.switchMap(app => this.appLanguagesService.postLanguages(app, new AddAppLanguageDto(this.addLanguageForm.get('language').value.iso2Code)))
.switchMap(app => this.appLanguagesService.deleteLanguage(app, language.iso2Code))
.subscribe(dto => {
this.appLanguages = this.appLanguages.push(dto);
this.updateLanguages(this.appLanguages.remove(dto));
}, error => {
this.notifyError(error);
});
this.addLanguageForm.reset();
}
public removeLanguage(language: AppLanguageDto) {
public addLanguage() {
const request = new AddAppLanguageDto(this.addLanguageForm.get('language').value.iso2Code);
this.appName()
.switchMap(app => this.appLanguagesService.deleteLanguage(app, language.iso2Code))
.switchMap(app => this.appLanguagesService.postLanguages(app, request))
.subscribe(dto => {
this.appLanguages = this.appLanguages.remove(dto);
this.updateLanguages(this.appLanguages.push(dto));
}, error => {
this.notifyError(error);
});
this.addLanguageForm.reset();
}
public setMasterLanguage(language: AppLanguageDto) {
const request = new UpdateAppLanguageDto(true);
this.appName()
.switchMap(app => this.appLanguagesService.updateLanguage(app, language.iso2Code, new UpdateAppLanguageDto(true)))
.switchMap(app => this.appLanguagesService.updateLanguage(app, language.iso2Code, request))
.subscribe(() => {
this.appLanguages = this.appLanguages.map(l => {
this.updateLanguages(this.appLanguages.map(l => {
const isMasterLanguage = l === language;
if (isMasterLanguage !== l.isMasterLanguage) {
@ -105,10 +112,16 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
} else {
return l;
}
});
}));
}, error => {
this.notifyError(error);
});
}
private updateLanguages(languages: ImmutableArray<AppLanguageDto>) {
this.appLanguages = languages;
this.messageBus.publish(new HistoryChannelUpdated());
}
}

91
src/Squidex/app/framework/angular/autocomplete.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable, Subscription } from 'rxjs';
@ -43,7 +43,7 @@ export const SQX_AUTOCOMPLETE_CONTROL_VALUE_ACCESSOR: any = {
templateUrl: './autocomplete.component.html',
providers: [SQX_AUTOCOMPLETE_CONTROL_VALUE_ACCESSOR]
})
export class AutocompleteComponent implements ControlValueAccessor, OnDestroy {
export class AutocompleteComponent implements ControlValueAccessor, OnDestroy, OnInit {
private subscription: Subscription | null = null;
private lastQuery: string | null;
private changeCallback: (value: any) => void = NOOP;
@ -60,10 +60,6 @@ export class AutocompleteComponent implements ControlValueAccessor, OnDestroy {
public queryInput = new FormControl();
constructor() {
this.queryInput.valueChanges.debounceTime(100).subscribe(query => this.loadItems(query));
}
public writeValue(value: any) {
if (!value) {
this.queryInput.setValue('');
@ -84,18 +80,6 @@ export class AutocompleteComponent implements ControlValueAccessor, OnDestroy {
this.reset();
}
public registerOnChange(fn: any) {
this.changeCallback = fn;
}
public registerOnTouched(fn: any) {
this.touchedCallback = fn;
}
public ngOnDestroy() {
this.cancelRequest();
}
public setDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.reset();
@ -105,63 +89,50 @@ export class AutocompleteComponent implements ControlValueAccessor, OnDestroy {
}
}
private cancelRequest() {
if (this.subscription != null) {
this.subscription.unsubscribe();
this.subscription = null;
}
public registerOnChange(fn: any) {
this.changeCallback = fn;
}
private loadItems(query: string) {
const source = this.source;
this.cancelRequest();
if (!source) {
return;
}
let isInvalidQuery = this.lastQuery === query || !query || query.trim() === '';
this.lastQuery = query;
if (isInvalidQuery) {
this.reset();
return;
}
public registerOnTouched(fn: any) {
this.touchedCallback = fn;
}
this.lastQuery = query;
public ngOnInit() {
this.subscription =
this.queryInput.valueChanges
.map(q => <string>q)
.map(q => q ? q.trim() : q)
.distinctUntilChanged()
.debounceTime(200)
.do(q => {
if (!q) {
this.reset();
}
})
.filter(q => !!q && !!this.source)
.switchMap(q => this.source.find(q)).catch(error => Observable.of([]))
.subscribe(r => {
this.reset();
this.items = r || [];
});
}
this.subscription = source.find(query)
.catch(error => {
return Observable.of([]);
})
.subscribe(result => {
this.reset();
this.items = result || [];
});
public ngOnDestroy() {
this.subscription.unsubscribe();
}
public keyDown(event: KeyboardEvent) {
switch (event.keyCode) {
case KEY_UP:
this.up();
event.stopPropagation();
event.preventDefault();
break;
return false;
case KEY_DOWN:
this.down();
event.stopPropagation();
event.preventDefault();
break;
return false;
case KEY_ENTER:
if (this.items.length > 0) {
this.chooseItem();
event.stopPropagation();
event.preventDefault();
return false;
}
break;
}

1
src/Squidex/app/framework/declarations.ts

@ -33,6 +33,7 @@ export * from './configurations';
export * from './services/clipboard.service';
export * from './services/drag.service';
export * from './services/local-store.service';
export * from './services/message-bus';
export * from './services/notification.service';
export * from './services/panel.service';
export * from './services/shortcut.service';

42
src/Squidex/app/framework/services/message-bus.spec.ts

@ -0,0 +1,42 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { MessageBus, MessageBusFactory } from './../';
class Event1 { }
class Event2 { }
describe('MessageBus', () => {
it('should instantiate from factory', () => {
const messageBus = MessageBusFactory();
expect(messageBus).toBeDefined();
});
it('should instantiate', () => {
const messageBus = new MessageBus();
expect(messageBus).toBeDefined();
});
it('should publish events and subscribe', () => {
const messageBus = new MessageBus();
const event1 = new Event1();
const event2 = new Event2();
let lastEvent: any = null;
messageBus.of(Event1).subscribe(event => {
lastEvent = event;
});
messageBus.publish(event1);
messageBus.publish(event2);
expect(lastEvent).toBe(event1);
});
});

35
src/Squidex/app/framework/services/message-bus.ts

@ -0,0 +1,35 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
interface Message {
channel: string;
data: any;
}
export const MessageBusFactory = () => {
return new MessageBus();
};
@Injectable()
export class MessageBus {
private message$ = new Subject<Message>();
public publish<T>(message: T): void {
const channel = (<any>message.constructor).name;
this.message$.next({ channel: channel, data: message });
}
public of<T>(messageType: { new(...args: any[]): T }): Observable<T> {
const channel = (<any>messageType).name;
return this.message$.filter(m => m.channel === channel).map(m => m.data);
}
}

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

@ -11,7 +11,7 @@
<div class="panel-main">
<div class="panel-content panel-content-blank">
<div *ngFor="let event of events" class="event">
<div *ngFor="let event of events | async" class="event">
<div class="event-created">{{event.created.toLocal() | fromNow}}</div>
<div class="event-message">
<span class="event-actor">{{actorName(event.actor) | async}}</span> <span [innerHTML]="format(event.message) | async"></span>

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

@ -7,12 +7,17 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import { ImmutableArray, NotificationService } from 'framework';
import {
ImmutableArray,
MessageBus,
NotificationService
} from 'framework';
import { AppComponentBase } from './../app-component-base';
import { AppsStoreService } from './../services/apps-store.service';
import { HistoryChannelUpdated } from './../utils/messages';
import { HistoryEventDto, HistoryService } from './../services/history.service';
import { UsersProviderService } from './../services/users-provider.service';
@ -25,41 +30,25 @@ const REPLACEMENT_TEMP = '$TEMP$';
styleUrls: ['./history.component.scss'],
templateUrl: './history.component.html'
})
export class HistoryComponent extends AppComponentBase implements OnDestroy, OnInit {
private interval: any;
export class HistoryComponent extends AppComponentBase {
public get channel(): string {
return this.route.snapshot.data['channel'];
}
public events = ImmutableArray.empty();
public events =
Observable.timer(0, 10000)
.merge(this.messageBus.of(HistoryChannelUpdated).delay(1000))
.switchMap(() => this.appName())
.switchMap(app => this.historyService.getHistory(app, this.channel).retry(2));
constructor(appsStore: AppsStoreService, notifications: NotificationService, usersProvider: UsersProviderService,
private readonly historyService: HistoryService,
private readonly messageBus: MessageBus,
private readonly route: ActivatedRoute
) {
super(appsStore, notifications, usersProvider);
}
public ngOnDestroy() {
clearInterval(this.interval);
}
public ngOnInit() {
this.load();
this.interval =
setInterval(() => {
this.load();
}, 5000);
}
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);
});
}
public actorName(actor: string): Observable<string> {
const parts = actor.split(':');

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

@ -25,6 +25,8 @@ export * from './services/schemas.service';
export * from './services/users-provider.service';
export * from './services/users.service';
export * from './utils/messages';
export * from './app-component-base';
export * from 'framework';

8
src/Squidex/app/shared/utils/messages.ts

@ -0,0 +1,8 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
export class HistoryChannelUpdated { }

2
src/Squidex/tslint.json

@ -65,7 +65,7 @@
"allow-declarations"
],
"ordered-imports": [
true
false
],
"prefer-for-of": true,
"quotemark": [

Loading…
Cancel
Save