Browse Source

DialogService and NotificationService unified

pull/100/head
Sebastian Stehle 9 years ago
parent
commit
35150fda81
  1. 8
      src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts
  2. 6
      src/Squidex/app/features/administration/pages/users/user-page.component.ts
  3. 6
      src/Squidex/app/features/administration/pages/users/users-page.component.ts
  4. 6
      src/Squidex/app/features/api/api-area.component.ts
  5. 8
      src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts
  6. 6
      src/Squidex/app/features/assets/pages/assets-page.component.ts
  7. 6
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  8. 6
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  9. 6
      src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts
  10. 8
      src/Squidex/app/features/content/shared/assets-editor.component.ts
  11. 6
      src/Squidex/app/features/content/shared/content-item.component.ts
  12. 6
      src/Squidex/app/features/content/shared/references-editor.component.ts
  13. 6
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts
  14. 6
      src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts
  15. 2
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  16. 6
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  17. 6
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts
  18. 8
      src/Squidex/app/features/settings/pages/clients/client.component.ts
  19. 6
      src/Squidex/app/features/settings/pages/clients/clients-page.component.ts
  20. 6
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts
  21. 6
      src/Squidex/app/features/settings/pages/languages/languages-page.component.ts
  22. 6
      src/Squidex/app/features/settings/pages/plans/plans-page.component.ts
  23. 6
      src/Squidex/app/features/settings/settings-area.component.ts
  24. 6
      src/Squidex/app/features/webhooks/pages/webhook-events-page.component.ts
  25. 6
      src/Squidex/app/features/webhooks/pages/webhooks-page.component.ts
  26. 53
      src/Squidex/app/framework/angular/confirm-click.directive.ts
  27. 6
      src/Squidex/app/framework/angular/copy.directive.ts
  28. 27
      src/Squidex/app/framework/angular/dialog-renderer.component.html
  29. 28
      src/Squidex/app/framework/angular/dialog-renderer.component.scss
  30. 92
      src/Squidex/app/framework/angular/dialog-renderer.component.ts
  31. 2
      src/Squidex/app/framework/angular/root-view.directive.ts
  32. 4
      src/Squidex/app/framework/declarations.ts
  33. 10
      src/Squidex/app/framework/module.ts
  34. 94
      src/Squidex/app/framework/services/dialog.service.spec.ts
  35. 38
      src/Squidex/app/framework/services/dialog.service.ts
  36. 3
      src/Squidex/app/framework/services/local-cache.service.ts
  37. 57
      src/Squidex/app/framework/services/notification.service.spec.ts
  38. 3
      src/Squidex/app/framework/services/resource-loader.service.ts
  39. 6
      src/Squidex/app/shared/components/app.component-base.ts
  40. 6
      src/Squidex/app/shared/components/asset.component.ts
  41. 12
      src/Squidex/app/shared/components/component-base.ts
  42. 6
      src/Squidex/app/shared/components/history.component.ts
  43. 9
      src/Squidex/app/shell/pages/internal/internal-area.component.html
  44. 9
      src/Squidex/app/shell/pages/internal/internal-area.component.scss
  45. 34
      src/Squidex/app/shell/pages/internal/internal-area.component.ts

8
src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts

@ -10,12 +10,12 @@ import { Observable, Subscription } from 'rxjs';
import {
ComponentBase,
DialogService,
EventConsumerDto,
EventConsumersService,
fadeAnimation,
ImmutableArray,
ModalView,
NotificationService
ModalView
} from 'shared';
@Component({
@ -33,10 +33,10 @@ export class EventConsumersPageComponent extends ComponentBase implements OnInit
public eventConsumerError = '';
public eventConsumers = ImmutableArray.empty<EventConsumerDto>();
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly eventConsumersService: EventConsumersService
) {
super(notifications);
super(dialogs);
}
public ngOnInit() {

6
src/Squidex/app/features/administration/pages/users/user-page.component.ts

@ -12,8 +12,8 @@ import { ActivatedRoute, Router } from '@angular/router';
import {
AuthService,
ComponentBase,
DialogService,
MessageBus,
NotificationService,
UserDto,
UserManagementService,
ValidatorsEx
@ -38,7 +38,7 @@ export class UserPageComponent extends ComponentBase implements OnInit {
public isCurrentUser = false;
public isNewMode = false;
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly authService: AuthService,
private readonly formBuilder: FormBuilder,
private readonly messageBus: MessageBus,
@ -46,7 +46,7 @@ export class UserPageComponent extends ComponentBase implements OnInit {
private readonly router: Router,
private readonly userManagementService: UserManagementService
) {
super(notifications);
super(dialogs);
}
public ngOnInit() {

6
src/Squidex/app/features/administration/pages/users/users-page.component.ts

@ -12,9 +12,9 @@ import { Subscription } from 'rxjs';
import {
AuthService,
ComponentBase,
DialogService,
ImmutableArray,
MessageBus,
NotificationService,
Pager,
UserDto,
UserManagementService
@ -38,12 +38,12 @@ export class UsersPageComponent extends ComponentBase implements OnDestroy, OnIn
public usersFilter = new FormControl();
public usersQuery = '';
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly userManagementService: UserManagementService,
private readonly authService: AuthService,
private readonly messageBus: MessageBus
) {
super(notifications);
super(dialogs);
}
public ngOnDestroy() {

6
src/Squidex/app/features/api/api-area.component.ts

@ -10,7 +10,7 @@ import { Component } from '@angular/core';
import {
AppComponentBase,
AppsStoreService,
NotificationService
DialogService
} from 'shared';
@Component({
@ -19,8 +19,8 @@ import {
templateUrl: './api-area.component.html'
})
export class ApiAreaComponent extends AppComponentBase {
constructor(apps: AppsStoreService, notifications: NotificationService
constructor(apps: AppsStoreService, dialogs: DialogService
) {
super(notifications, apps);
super(dialogs, apps);
}
}

8
src/Squidex/app/features/api/pages/graphql/graphql-page.component.ts

@ -18,9 +18,9 @@ const GraphiQL = require('graphiql');
import {
AppComponentBase,
AppsStoreService,
DialogService,
GraphQlService,
LocalStoreService,
NotificationService
LocalStoreService
} from 'shared';
@Component({
@ -33,11 +33,11 @@ export class GraphQLPageComponent extends AppComponentBase implements OnInit {
@ViewChild('graphiQLContainer')
public graphiQLContainer: ElementRef;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly graphQlService: GraphQlService,
private readonly localStoreService: LocalStoreService
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/assets/pages/assets-page.component.ts

@ -17,9 +17,9 @@ import {
AssetDto,
AssetsService,
AssetUpdated,
DialogService,
ImmutableArray,
MessageBus,
NotificationService,
Pager
} from 'shared';
@ -38,11 +38,11 @@ export class AssetsPageComponent extends AppComponentBase implements OnDestroy,
public assetsFilter = new FormControl();
public assertQuery = '';
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly assetsService: AssetsService,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -25,10 +25,10 @@ import {
CanComponentDeactivate,
ContentDto,
ContentsService,
DialogService,
fadeAnimation,
ModalView,
MessageBus,
NotificationService,
SchemaDetailsDto,
Version
} from 'shared';
@ -59,14 +59,14 @@ export class ContentPageComponent extends AppComponentBase implements CanCompone
public languages: AppLanguageDto[] = [];
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly authService: AuthService,
private readonly contentsService: ContentsService,
private readonly route: ActivatedRoute,
private readonly router: Router,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnDestroy() {

6
src/Squidex/app/features/content/pages/contents/contents-page.component.ts

@ -24,10 +24,10 @@ import {
AuthService,
ContentDto,
ContentsService,
DialogService,
FieldDto,
ImmutableArray,
MessageBus,
NotificationService,
Pager,
SchemaDetailsDto
} from 'shared';
@ -57,13 +57,13 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
public columnWidth: number;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly authService: AuthService,
private readonly contentsService: ContentsService,
private readonly route: ActivatedRoute,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnDestroy() {

6
src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts

@ -12,7 +12,7 @@ import { Observable } from 'rxjs';
import {
AppComponentBase,
AppsStoreService,
NotificationService,
DialogService,
SchemaDto,
SchemasService
} from 'shared';
@ -52,10 +52,10 @@ export class SchemasPageComponent extends AppComponentBase {
});
});
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly schemasService: SchemasService
) {
super(notifications, apps);
super(dialogs, apps);
}
private loadSchemas(): Observable<SchemaDto[]> {

8
src/Squidex/app/features/content/shared/assets-editor.component.ts

@ -17,9 +17,9 @@ import {
AssetDto,
AssetsService,
AssetUpdated,
DialogService,
ImmutableArray,
MessageBus,
NotificationService
MessageBus
} from 'shared';
const NOOP = () => { /* NOOP */ };
@ -44,11 +44,11 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
public isDisabled = false;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly assetsService: AssetsService,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/content/shared/content-item.component.ts

@ -11,10 +11,10 @@ import {
AppComponentBase,
AppsStoreService,
ContentDto,
DialogService,
fadeAnimation,
FieldDto,
ModalView,
NotificationService,
SchemaDto
} from 'shared';
@ -60,8 +60,8 @@ export class ContentItemComponent extends AppComponentBase implements OnInit, On
public values: any[] = [];
constructor(apps: AppsStoreService, notifications: NotificationService) {
super(notifications, apps);
constructor(apps: AppsStoreService, dialogs: DialogService) {
super(dialogs, apps);
}
public ngOnChanges() {

6
src/Squidex/app/features/content/shared/references-editor.component.ts

@ -15,9 +15,9 @@ import {
AppsStoreService,
ContentDto,
ContentsService,
DialogService,
FieldDto,
ImmutableArray,
NotificationService,
SchemaDetailsDto,
SchemasService
} from 'shared';
@ -54,11 +54,11 @@ export class ReferencesEditorComponent extends AppComponentBase implements Contr
public isDisabled = false;
public isInvalidSchema = false;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly contentsService: ContentsService,
private readonly schemasService: SchemasService
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

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

@ -12,8 +12,8 @@ import {
AppsStoreService,
AuthService,
DateTime,
DialogService,
fadeAnimation,
NotificationService,
UsagesService
} from 'shared';
@ -60,11 +60,11 @@ export class DashboardPageComponent extends AppComponentBase implements OnInit {
public callsCurrent = 0;
public callsMax = 0;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly authService: AuthService,
private readonly usagesService: UsagesService
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts

@ -10,7 +10,7 @@ import { FormBuilder, Validators } from '@angular/forms';
import {
ComponentBase,
NotificationService,
DialogService,
SchemaPropertiesDto,
SchemasService,
Version
@ -53,11 +53,11 @@ export class SchemaEditFormComponent extends ComponentBase implements OnInit {
]]
});
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly schemas: SchemasService,
private readonly formBuilder: FormBuilder
) {
super(notifications);
super(dialogs);
}
public ngOnInit() {

2
src/Squidex/app/features/schemas/pages/schema/schema-page.component.html

@ -22,7 +22,7 @@
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="editOptionsDropdown" closeAlways="true" [sqxModalTarget]="optionsButton" position="right" [@fade]>
<a class="dropdown-item dropdown-item-delete" (click)="confirmDeleteDialog.show()">
<a class="dropdown-item dropdown-item-delete" (sqxConfirmClick)="deleteSchema()" confirmTitle="Delete schema" confirmText="Do you really want to delete the schema?">
Delete
</a>
</div>

6
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -15,13 +15,13 @@ import {
AppsStoreService,
AuthService,
createProperties,
DialogService,
fadeAnimation,
FieldDto,
fieldTypes,
HistoryChannelUpdated,
MessageBus,
ModalView,
NotificationService,
SchemaDetailsDto,
SchemaDto,
SchemaPropertiesDto,
@ -73,7 +73,7 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
return this.addFieldForm.controls['name'].value && this.addFieldForm.controls['name'].value.length > 0;
}
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly authService: AuthService,
private readonly formBuilder: FormBuilder,
private readonly messageBus: MessageBus,
@ -81,7 +81,7 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
private readonly router: Router,
private readonly schemasService: SchemasService
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts

@ -13,11 +13,11 @@ import { Subscription } from 'rxjs';
import {
AppComponentBase,
AppsStoreService,
DialogService,
fadeAnimation,
ImmutableArray,
MessageBus,
ModalView,
NotificationService,
SchemaDto,
SchemasService
} from 'shared';
@ -43,12 +43,12 @@ export class SchemasPageComponent extends AppComponentBase implements OnDestroy,
public schemasFilter = new FormControl();
public schemasFiltered = ImmutableArray.empty<SchemaDto>();
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly schemasService: SchemasService,
private readonly messageBus: MessageBus,
private readonly route: ActivatedRoute
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnDestroy() {

8
src/Squidex/app/features/settings/pages/clients/client.component.ts

@ -13,9 +13,9 @@ import {
AppClientDto,
AppClientsService,
ComponentBase,
DialogService,
fadeAnimation,
ModalView,
NotificationService
ModalView
} from 'shared';
const ESCAPE_KEY = 27;
@ -60,11 +60,11 @@ export class ClientComponent extends ComponentBase {
return this.renameForm.controls['name'].value !== this.client.name;
}
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly appClientsService: AppClientsService,
private readonly formBuilder: FormBuilder
) {
super(notifications);
super(dialogs);
}
public cancelRename() {

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

@ -14,10 +14,10 @@ import {
AppComponentBase,
AppsStoreService,
CreateAppClientDto,
DialogService,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
NotificationService,
UpdateAppClientDto,
ValidatorsEx,
Version
@ -47,12 +47,12 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
return this.addClientForm.controls['name'].value && this.addClientForm.controls['name'].value.length > 0;
}
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly appClientsService: AppClientsService,
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

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

@ -17,10 +17,10 @@ import {
AppsStoreService,
AuthService,
AutocompleteSource,
DialogService,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
NotificationService,
UsersService,
Version
} from 'shared';
@ -81,13 +81,13 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
]]
});
constructor(apps: AppsStoreService, notifications: NotificationService, usersService: UsersService,
constructor(apps: AppsStoreService, dialogs: DialogService, usersService: UsersService,
private readonly appContributorsService: AppContributorsService,
private readonly messageBus: MessageBus,
private readonly authService: AuthService,
private readonly formBuilder: FormBuilder
) {
super(notifications, apps);
super(dialogs, apps);
this.usersDataSource = new UsersDataSource(usersService, this);
}

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

@ -14,12 +14,12 @@ import {
AppLanguageDto,
AppLanguagesService,
AppsStoreService,
DialogService,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
LanguageDto,
LanguagesService,
NotificationService,
Version
} from 'shared';
@ -42,13 +42,13 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
]
});
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly appLanguagesService: AppLanguagesService,
private readonly languagesService: LanguagesService,
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/settings/pages/plans/plans-page.component.ts

@ -16,7 +16,7 @@ import {
AppsStoreService,
AuthService,
ChangePlanDto,
NotificationService,
DialogService,
PlansService,
Version
} from 'shared';
@ -38,13 +38,13 @@ export class PlansPageComponent extends AppComponentBase implements OnDestroy, O
public isDisabled = false;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly authService: AuthService,
private readonly plansService: PlansService,
private readonly route: ActivatedRoute,
private readonly apiUrl: ApiUrlConfig
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnDestroy() {

6
src/Squidex/app/features/settings/settings-area.component.ts

@ -10,7 +10,7 @@ import { Component } from '@angular/core';
import {
AppComponentBase,
AppsStoreService,
NotificationService
DialogService
} from 'shared';
@Component({
@ -19,8 +19,8 @@ import {
templateUrl: './settings-area.component.html'
})
export class SettingsAreaComponent extends AppComponentBase {
constructor(apps: AppsStoreService, notifications: NotificationService
constructor(apps: AppsStoreService, dialogs: DialogService
) {
super(notifications, apps);
super(dialogs, apps);
}
}

6
src/Squidex/app/features/webhooks/pages/webhook-events-page.component.ts

@ -10,8 +10,8 @@ import { Component, OnInit } from '@angular/core';
import {
AppComponentBase,
AppsStoreService,
DialogService,
ImmutableArray,
NotificationService,
Pager,
WebhookEventDto,
WebhooksService
@ -28,10 +28,10 @@ export class WebhookEventsPageComponent extends AppComponentBase implements OnIn
public selectedEventId: string;
constructor(notifications: NotificationService, appsStore: AppsStoreService,
constructor(dialogs: DialogService, appsStore: AppsStoreService,
private readonly webhooksService: WebhooksService
) {
super(notifications, appsStore);
super(dialogs, appsStore);
}
public ngOnInit() {

6
src/Squidex/app/features/webhooks/pages/webhooks-page.component.ts

@ -12,8 +12,8 @@ import {
AppComponentBase,
AppsStoreService,
CreateWebhookDto,
DialogService,
ImmutableArray,
NotificationService,
SchemaDto,
SchemasService,
Version,
@ -52,12 +52,12 @@ export class WebhooksPageComponent extends AppComponentBase implements OnInit {
return this.addWebhookForm.controls['url'].value && this.addWebhookForm.controls['url'].value.length > 0;
}
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly schemasService: SchemasService,
private readonly webhooksService: WebhooksService,
private readonly formBuilder: FormBuilder
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

53
src/Squidex/app/framework/angular/confirm-click.directive.ts

@ -0,0 +1,53 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { DialogService } from './../services/dialog.service';
@Directive({
selector: '[sqxConfirmClick]'
})
export class ConfirmClickDirective {
@Input()
public confirmTitle: string;
@Input()
public confirmText: string;
@Output('sqxConfirmClick')
public click = new EventEmitter();
constructor(
private readonly dialogService: DialogService
) {
}
@HostListener('click', ['$event'])
public onClick(event: Event) {
if (this.confirmTitle &&
this.confirmTitle.length > 0 &&
this.confirmText &&
this.confirmText.length > 0) {
let subscription =
this.dialogService.confirm(this.confirmTitle, this.confirmText)
.subscribe(result => {
if (result) {
this.click.emit();
}
subscription.unsubscribe();
});
} else {
this.click.emit();
}
event.stopPropagation();
event.preventDefault();
}
}

6
src/Squidex/app/framework/angular/copy.directive.ts

@ -7,7 +7,7 @@
import { Directive, HostListener, Input } from '@angular/core';
import { Notification, NotificationService } from './../services/notification.service';
import { DialogService, Notification } from './../services/dialog.service';
@Directive({
selector: '[sqxCopy]'
@ -17,7 +17,7 @@ export class CopyDirective {
public inputElement: any;
constructor(
private readonly notifications: NotificationService
private readonly dialogs: DialogService
) {
}
@ -43,7 +43,7 @@ export class CopyDirective {
try {
document.execCommand('copy');
this.notifications.notify(Notification.info('Value has been added to your clipboard.'));
this.dialogs.notify(Notification.info('Value has been added to your clipboard.'));
} catch (e) {
console.log('Copy failed');
}

27
src/Squidex/app/framework/angular/dialog-renderer.component.html

@ -0,0 +1,27 @@
<div class="modal" *sqxModalView="dialogView;onRoot:true" [@fade]>
<div class="modal-backdrop"></div>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">{{dialogRequest.title}}</h4>
</div>
<div class="modal-body">
{{dialogRequest.text}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" (click)="confirm()">Yes</button>
<button type="button" class="btn btn-secondary" (click)="cancel()">No</button>
</div>
</div>
</div>
</div>
<div class="notification-container notification-container-{{position}}">
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of notifications" (click)="close(notification)" [@fade]>
<button type="button" class="close" data-dismiss="alert" (close)="close(notification)">&times;</button>
{{notification.message}}
</div>
</div>

28
src/Squidex/app/framework/angular/dialog-renderer.component.scss

@ -0,0 +1,28 @@
@import '_mixins';
@import '_vars';
.notification-container {
& {
margin: .625rem;
max-width: 20rem;
min-width: 20rem;
position: fixed;
z-index: 100000;
}
&-righttop {
@include fixed(0, 0, auto, auto);
}
&-rightbottom {
@include fixed(auto, 0, 0, auto);
}
&-lefttop {
@include fixed(0, auto, auto, 0);
}
&-leftbottom {
@include fixed(auto, auto, 0, 0);
}
}

92
src/Squidex/app/framework/angular/dialog-renderer.component.ts

@ -0,0 +1,92 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights r vbeserved
*/
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { fadeAnimation } from './animations';
import {
DialogRequest,
DialogService,
Notification
} from './../services/dialog.service';
import { ModalView } from './../utils/modal-view';
@Component({
selector: 'sqx-dialog-renderer',
styleUrls: ['./dialog-renderer.component.scss'],
templateUrl: './dialog-renderer.component.html',
animations: [
fadeAnimation
]
})
export class DialogRendererComponent implements OnDestroy, OnInit {
private dialogsSubscription: Subscription;
private notificationsSubscription: Subscription;
public dialogView = new ModalView(false, true);
public dialogRequest: DialogRequest;
public notifications: Notification[] = [];
@Input()
public position = 'bottomright';
constructor(
private readonly dialogService: DialogService
) {
}
public ngOnDestroy() {
this.notificationsSubscription.unsubscribe();
this.dialogsSubscription.unsubscribe();
}
public ngOnInit() {
this.notificationsSubscription =
this.dialogService.notifications.subscribe(notification => {
this.notifications.push(notification);
if (notification.displayTime > 0) {
setTimeout(() => {
this.close(notification);
}, notification.displayTime);
}
});
this.dialogsSubscription =
this.dialogService.dialogs
.subscribe(request => {
this.cancel();
this.dialogRequest = request;
this.dialogView.show();
});
}
public cancel() {
if (this.dialogRequest) {
this.dialogRequest.complete(false);
this.dialogRequest = null;
this.dialogView.hide();
}
}
public confirm() {
if (this.dialogRequest) {
this.dialogRequest.complete(true);
this.dialogRequest = null;
this.dialogView.hide();
}
}
public close(notification: Notification) {
this.notifications.splice(this.notifications.indexOf(notification), 1);
}
}

2
src/Squidex/app/framework/angular/root-view.directive.ts

@ -13,7 +13,7 @@ import { RootViewService } from './../services/root-view.service';
selector: '[sqxRootView]'
})
export class RootViewDirective {
constructor(viewContainer: ViewContainerRef, rootViewService: RootViewService) {
constructor(public viewContainer: ViewContainerRef, rootViewService: RootViewService) {
rootViewService.init(viewContainer);
}
}

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

@ -8,10 +8,12 @@
export * from './angular/animations';
export * from './angular/autocomplete.component';
export * from './angular/can-deactivate.guard';
export * from './angular/confirm-click.directive';
export * from './angular/control-errors.component';
export * from './angular/copy.directive';
export * from './angular/date-time-editor.component';
export * from './angular/date-time.pipes';
export * from './angular/dialog-renderer.component';
export * from './angular/dropdown.component';
export * from './angular/file-drop.directive';
export * from './angular/focus-on-init.directive';
@ -49,10 +51,10 @@ export * from './angular/validators';
export * from './configurations';
export * from './services/clipboard.service';
export * from './services/dialog.service';
export * from './services/local-store.service';
export * from './services/local-cache.service';
export * from './services/message-bus';
export * from './services/notification.service';
export * from './services/resource-loader.service';
export * from './services/root-view.service';
export * from './services/shortcut.service';

10
src/Squidex/app/framework/module.ts

@ -15,11 +15,14 @@ import {
AutocompleteComponent,
CanDeactivateGuard,
ClipboardService,
ConfirmClickDirective,
ControlErrorsComponent,
CopyDirective,
DateTimeEditorComponent,
DayOfWeekPipe,
DayPipe,
DialogService,
DialogRendererComponent,
DisplayNamePipe,
DropdownComponent,
DurationPipe,
@ -41,7 +44,6 @@ import {
ModalViewDirective,
MoneyPipe,
MonthPipe,
NotificationService,
PanelContainerDirective,
PanelComponent,
ParentLinkDirective,
@ -77,11 +79,13 @@ import {
],
declarations: [
AutocompleteComponent,
ConfirmClickDirective,
ControlErrorsComponent,
CopyDirective,
DateTimeEditorComponent,
DayOfWeekPipe,
DayPipe,
DialogRendererComponent,
DisplayNamePipe,
DropdownComponent,
DurationPipe,
@ -122,11 +126,13 @@ import {
],
exports: [
AutocompleteComponent,
ConfirmClickDirective,
ControlErrorsComponent,
CopyDirective,
DateTimeEditorComponent,
DayOfWeekPipe,
DayPipe,
DialogRendererComponent,
DisplayNamePipe,
DropdownComponent,
DurationPipe,
@ -178,10 +184,10 @@ export class SqxFrameworkModule {
providers: [
CanDeactivateGuard,
ClipboardService,
DialogService,
LocalCacheService,
LocalStoreService,
MessageBus,
NotificationService,
ResourceLoaderService,
RootViewService,
ShortcutService,

94
src/Squidex/app/framework/services/dialog.service.spec.ts

@ -0,0 +1,94 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import {
Notification,
DialogRequest,
DialogService,
DialogServiceFactory
} from './../';
describe('DialogService', () => {
it('should instantiate from factory', () => {
const dialogService = DialogServiceFactory();
expect(dialogService).toBeDefined();
});
it('should instantiate', () => {
const dialogService = new DialogService();
expect(dialogService).toBeDefined();
});
it('should create error notification', () => {
const notification = Notification.error('MyError');
expect(notification.displayTime).toBe(5000);
expect(notification.message).toBe('MyError');
expect(notification.messageType).toBe('danger');
});
it('should create info notification', () => {
const notification = Notification.info('MyInfo');
expect(notification.displayTime).toBe(5000);
expect(notification.message).toBe('MyInfo');
expect(notification.messageType).toBe('info');
});
it('should create dialog request', () => {
const dialog = new DialogRequest('MyTitle', 'MyText');
expect(dialog.title).toBe('MyTitle');
expect(dialog.text).toBe('MyText');
});
it('should confirm dialog', () => {
const dialog = new DialogRequest('MyTitle', 'MyText');
let isCompleted = false;
let isNext = false;
dialog.closed.subscribe(result => {
isNext = result;
}, undefined, () => {
isCompleted = true;
})
expect(isCompleted).toBeTruthy();
expect(isNext).toBeTruthy();
});
it('should publish notification', () => {
const dialogService = new DialogService();
const notification = Notification.error('Message');
let publishedNotification: Notification | null = null;
dialogService.notifications.subscribe(result => {
publishedNotification = result;
});
dialogService.notify(notification);
expect(publishedNotification).toBe(notification);
});
it('should publish dialog request', () => {
const dialogService = new DialogService();
let pushedDialog: DialogRequest | null = null;
dialogService.dialogs.subscribe(result => {
pushedDialog = result;
});
dialogService.confirm('MyTitle', 'MyText');
expect(pushedDialog).toEqual(new DialogRequest('MyTitle', 'MyText'));
});
});

38
src/Squidex/app/framework/services/notification.service.ts → src/Squidex/app/framework/services/dialog.service.ts

@ -8,10 +8,29 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
export const NotificationServiceFactory = () => {
return new NotificationService();
export const DialogServiceFactory = () => {
return new DialogService();
};
export class DialogRequest {
private readonly resultStream$ = new Subject<boolean>();
public get closed(): Observable<boolean> {
return this.resultStream$;
}
constructor(
public readonly title: string,
public readonly text: string
) {
}
public complete(value: boolean) {
this.resultStream$.next(value);
this.resultStream$.complete();
}
}
export class Notification {
constructor(
public readonly message: string,
@ -30,9 +49,14 @@ export class Notification {
}
@Injectable()
export class NotificationService {
export class DialogService {
private readonly requestStream$ = new Subject<DialogRequest>();
private readonly notificationsStream$ = new Subject<Notification>();
public get dialogs(): Observable<DialogRequest> {
return this.requestStream$;
}
public get notifications(): Observable<Notification> {
return this.notificationsStream$;
}
@ -40,4 +64,12 @@ export class NotificationService {
public notify(notification: Notification) {
this.notificationsStream$.next(notification);
}
public confirm(title: string, text: string): Observable<boolean> {
const request = new DialogRequest(title, text);
this.requestStream$.next(request);
return request.closed;
}
}

3
src/Squidex/app/framework/services/local-cache.service.ts

@ -5,12 +5,15 @@
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Injectable } from '@angular/core';
interface Entry { value: any, expires: number };
export const LocalCacheServiceFactory = () => {
return new LocalCacheService();
};
@Injectable()
export class LocalCacheService {
private readonly entries: { [key: string]: Entry } = {};

57
src/Squidex/app/framework/services/notification.service.spec.ts

@ -1,57 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import {
Notification,
NotificationService,
NotificationServiceFactory
} from './../';
describe('NotificationService', () => {
it('should instantiate from factory', () => {
const notificationService = NotificationServiceFactory();
expect(notificationService).toBeDefined();
});
it('should instantiate', () => {
const notificationService = new NotificationService();
expect(notificationService).toBeDefined();
});
it('should create error', () => {
const notification = Notification.error('MyError');
expect(notification.displayTime).toBe(5000);
expect(notification.message).toBe('MyError');
expect(notification.messageType).toBe('danger');
});
it('should create info', () => {
const notification = Notification.info('MyInfo');
expect(notification.displayTime).toBe(5000);
expect(notification.message).toBe('MyInfo');
expect(notification.messageType).toBe('info');
});
it('should publish notification', () => {
const notificationService = new NotificationService();
const notification = Notification.error('Message');
let publishedNotification: Notification | null = null;
notificationService.notifications.subscribe(result => {
publishedNotification = result;
});
notificationService.notify(notification);
expect(publishedNotification).toBe(notification);
});
});

3
src/Squidex/app/framework/services/resource-loader.service.ts

@ -5,6 +5,9 @@
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Injectable } from '@angular/core';
@Injectable()
export class ResourceLoaderService {
private cache: { [path: string]: Promise<any> } = {};

6
src/Squidex/app/shared/components/app.component-base.ts

@ -7,17 +7,17 @@
import { Observable } from 'rxjs';
import { AppsStoreService, NotificationService } from './../declarations-base';
import { AppsStoreService, DialogService } from './../declarations-base';
import { ComponentBase } from './component-base';
export abstract class AppComponentBase extends ComponentBase {
private appName$: Observable<string>;
constructor(notifications: NotificationService,
constructor(dialogs: DialogService,
private readonly appsStore: AppsStoreService
) {
super(notifications);
super(dialogs);
this.appName$ = this.appsStore.selectedApp.filter(a => !!a).map(a => a!.name);
}

6
src/Squidex/app/shared/components/asset.component.ts

@ -16,9 +16,9 @@ import {
AssetReplacedDto,
AssetsService,
AuthService,
DialogService,
fadeAnimation,
ModalView,
NotificationService,
UpdateAssetDto,
Version
} from './../declarations-base';
@ -70,12 +70,12 @@ export class AssetComponent extends AppComponentBase implements OnInit {
public progress = 0;
constructor(apps: AppsStoreService, notifications: NotificationService,
constructor(apps: AppsStoreService, dialogs: DialogService,
private readonly formBuilder: FormBuilder,
private readonly assetsService: AssetsService,
private readonly authService: AuthService
) {
super(notifications, apps);
super(dialogs, apps);
}
public ngOnInit() {

12
src/Squidex/app/shared/components/component-base.ts

@ -6,26 +6,26 @@
*/
import {
DialogService,
ErrorDto,
Notification,
NotificationService
Notification
} from './../declarations-base';
export abstract class ComponentBase {
constructor(
private readonly notifications: NotificationService
private readonly dialogs: DialogService
) {
}
protected notifyError(error: string | ErrorDto) {
if (error instanceof ErrorDto) {
this.notifications.notify(Notification.error(error.displayMessage));
this.dialogs.notify(Notification.error(error.displayMessage));
} else {
this.notifications.notify(Notification.error(error));
this.dialogs.notify(Notification.error(error));
}
}
protected notifyInfo(error: string) {
this.notifications.notify(Notification.info(error));
this.dialogs.notify(Notification.info(error));
}
}

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

@ -14,11 +14,11 @@ import { AppComponentBase } from './app.component-base';
import {
allParams,
AppsStoreService,
DialogService,
HistoryChannelUpdated,
HistoryEventDto,
HistoryService,
MessageBus,
NotificationService,
UsersProviderService
} from './../declarations-base';
@ -54,13 +54,13 @@ export class HistoryComponent extends AppComponentBase {
.switchMap(() => this.appNameOnce())
.switchMap(app => this.historyService.getHistory(app, this.channel).retry(2));
constructor(appsStore: AppsStoreService, notifications: NotificationService,
constructor(appsStore: AppsStoreService, dialogs: DialogService,
private readonly users: UsersProviderService,
private readonly historyService: HistoryService,
private readonly messageBus: MessageBus,
private readonly route: ActivatedRoute
) {
super(notifications, appsStore);
super(dialogs, appsStore);
}
private userName(userId: string): Observable<string> {

9
src/Squidex/app/shell/pages/internal/internal-area.component.html

@ -16,14 +16,6 @@
<router-outlet></router-outlet>
</div>
<div class="notification-container">
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of notifications" (click)="close(notification)" [@fade]>
<button type="button" class="close" data-dismiss="alert" (close)="close(notification)">&times;</button>
{{notification.message}}
</div>
</div>
<a class="github-button" href="https://github.com/Squidex/squidex/issues" target="_blank">
<i class="icon-github github-icon"></i>
@ -31,5 +23,6 @@
</a>
<sqx-user-report></sqx-user-report>
<sqx-dialog-renderer></sqx-dialog-renderer>
<div sqxRootView></div>

9
src/Squidex/app/shell/pages/internal/internal-area.component.scss

@ -64,13 +64,4 @@
text-align: center;
color: $color-dark-foreground;
}
}
.notification {
&-container {
@include fixed(auto, .625rem, .625rem, auto);
max-width: 20rem;
min-width: 20rem;
z-index: 100000;
}
}

34
src/Squidex/app/shell/pages/internal/internal-area.component.ts

@ -9,66 +9,42 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import {
fadeAnimation,
Notification,
NotificationService
} from 'shared';
import { DialogService, Notification } from 'shared';
@Component({
selector: 'sqx-internal-area',
styleUrls: ['./internal-area.component.scss'],
templateUrl: './internal-area.component.html',
animations: [
fadeAnimation
]
templateUrl: './internal-area.component.html'
})
export class InternalAreaComponent implements OnInit, OnDestroy {
private notificationsSubscription: Subscription;
private queryParamsSubscription: Subscription;
public notifications: Notification[] = [];
constructor(
private readonly notificationService: NotificationService,
private readonly dialogs: DialogService,
private readonly route: ActivatedRoute
) {
}
public ngOnDestroy() {
this.queryParamsSubscription.unsubscribe();
this.notificationsSubscription.unsubscribe();
}
public ngOnInit() {
this.notificationsSubscription =
this.notificationService.notifications.subscribe(notification => {
this.notifications.push(notification);
if (notification.displayTime > 0) {
setTimeout(() => {
this.close(notification);
}, notification.displayTime);
}
});
this.queryParamsSubscription =
this.route.queryParams.subscribe(params => {
const successMessage = params['successMessage'];
if (successMessage) {
this.notificationService.notify(Notification.info(successMessage));
this.dialogs.notify(Notification.info(successMessage));
}
const errorMessage = params['errorMessage'];
if (errorMessage) {
this.notificationService.notify(Notification.error(errorMessage));
this.dialogs.notify(Notification.error(errorMessage));
}
});
}
public close(notification: Notification) {
this.notifications.splice(this.notifications.indexOf(notification), 1);
}
}
Loading…
Cancel
Save