Browse Source

Improved cancellation.

pull/356/head
Sebastian Stehle 8 years ago
parent
commit
572ac6d191
  1. 2
      src/Squidex/app/features/assets/pages/assets-page.component.html
  2. 1
      src/Squidex/app/features/content/pages/content/content-page.component.html
  3. 4
      src/Squidex/app/features/content/shared/content-status.component.html
  4. 8
      src/Squidex/app/features/content/shared/content-status.component.scss
  5. 3
      src/Squidex/app/features/content/shared/content-status.component.ts
  6. 20
      src/Squidex/app/framework/utils/rxjs-extensions.ts
  7. 70
      src/Squidex/app/shared/components/asset-uploader.component.html
  8. 4
      src/Squidex/app/shared/components/asset-uploader.component.ts
  9. 6
      src/Squidex/app/shared/components/asset.component.ts
  10. 11
      src/Squidex/app/shared/components/markdown-editor.component.ts
  11. 17
      src/Squidex/app/shared/components/rich-editor.component.ts
  12. 8
      src/Squidex/app/shared/state/apps.state.ts
  13. 58
      src/Squidex/app/shared/state/asset-uploader.state.ts
  14. 8
      src/Squidex/app/shared/state/assets.state.ts
  15. 106
      src/Squidex/app/shared/state/contents.state.ts
  16. 8
      src/Squidex/app/shared/state/plans.state.ts
  17. 6
      src/Squidex/app/shared/state/rule-events.state.ts
  18. 17
      src/Squidex/app/shared/state/schemas.state.ts
  19. 8
      src/Squidex/app/shared/state/ui.state.ts

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

@ -7,7 +7,7 @@
<ng-container menu>
<div class="row no-gutters pl-1">
<div class="col-auto offset-xl-4">
<div class="col-auto offset-xl-2">
<sqx-shortcut keys="ctrl+shift+r" (trigger)="reload()"></sqx-shortcut>
<button type="button" class="btn btn-text-secondary" (click)="reload()" title="Refresh Contents (CTRL + SHIFT + R)">

1
src/Squidex/app/features/content/pages/content/content-page.component.html

@ -38,7 +38,6 @@
<button type="button" class="btn btn-outline-secondary btn-status" (click)="dropdown.toggle()" [disabled]="schema.isSingleton && !content.isPending"
[class.active]="dropdown.isOpen | async" #optionsButton>
<sqx-content-status
[alignMiddle]="false"
[status]="content.status"
[scheduledTo]="content.scheduleJob?.status"
[scheduledAt]="content.scheduleJob?.dueTime"

4
src/Squidex/app/features/content/shared/content-status.component.html

@ -1,11 +1,11 @@
<ng-container *ngIf="scheduledTo; else noSchedule">
<span class="content-status content-status-{{scheduledTo | lowercase}} mr-1" [class.middle]="alignMiddle" title="{{tooltipText}}" titlePosition="top">
<span class="content-status content-status-{{scheduledTo | lowercase}} mr-1" title="{{tooltipText}}" titlePosition="top">
<i class="icon-clock"></i>
</span>
</ng-container>
<ng-template #noSchedule>
<span class="content-status content-status-{{displayStatus | lowercase}} mr-1" [class.middle]="alignMiddle" title="{{tooltipText}}" titlePosition="top">
<span class="content-status content-status-{{displayStatus | lowercase}} mr-1" title="{{tooltipText}}" titlePosition="top">
<i class="icon-circle"></i>
</span>
</ng-template>

8
src/Squidex/app/features/content/shared/content-status.component.scss

@ -2,6 +2,10 @@
@import '_mixins';
.content-status {
& {
vertical-align: middle;
}
&-published {
color: $color-theme-green;
}
@ -31,8 +35,4 @@
color: $color-dark-foreground;
padding: .75rem;
}
}
.middle {
vertical-align: middle;
}

3
src/Squidex/app/features/content/shared/content-status.component.ts

@ -31,9 +31,6 @@ export class ContentStatusComponent {
@Input()
public showLabel = false;
@Input()
public alignMiddle = true;
public get tooltipText() {
if (this.scheduledAt) {
return `Will be set to '${this.scheduledTo}' at ${this.scheduledAt.toStringFormat('LLLL')}`;

20
src/Squidex/app/framework/utils/rxjs-extensions.ts

@ -7,8 +7,8 @@
// tslint:disable: only-arrow-functions
import { Observable } from 'rxjs';
import { map, onErrorResumeNext, shareReplay, switchMap } from 'rxjs/operators';
import { empty, Observable } from 'rxjs';
import { catchError, map, onErrorResumeNext, publishReplay, refCount, switchMap } from 'rxjs/operators';
import { DialogService } from './../services/dialog.service';
@ -30,13 +30,17 @@ type Options<T, R = T> = { silent?: boolean, project?: ((value: T) => R) };
export function shareSubscribed<T, R = T>(dialogs: DialogService, options?: Options<T, R>) {
return function mapOperation(source: Observable<T>) {
const shared = source.pipe(shareReplay());
const shared = source.pipe(publishReplay(), refCount());
shared.subscribe(undefined, error => {
if (dialogs && (!options || !options.silent)) {
dialogs.notifyError(error);
}
});
shared.pipe(
catchError(error => {
if (!options || !options.silent) {
dialogs.notifyError(error);
}
return empty();
}))
.subscribe();
if (options && !!options.project) {
const project = options.project;

70
src/Squidex/app/shared/components/asset-uploader.component.html

@ -1,42 +1,44 @@
<ul class="nav navbar-nav" *ngIf="assetUploader.uploads | async; let uploads" (sqxFileDrop)="addFiles($event)">
<li class="nav-item dropdown">
<span class="nav-link dropdown-toggle" (click)="modalMenu.toggle()">
<i class="icon-upload-3"></i>
<ng-container *ngIf="appsState.selectedApp | async">
<ul class="nav navbar-nav" *ngIf="assetUploader.uploads | async; let uploads" (sqxFileDrop)="addFiles($event)">
<li class="nav-item dropdown">
<span class="nav-link dropdown-toggle" (click)="modalMenu.toggle()">
<i class="icon-upload-3"></i>
<span>{{uploads.length}}</span>
</span>
<span>{{uploads.length}}</span>
</span>
<div class="dropdown-menu container" *ngIf="modalMenu.isOpen | async" (sqxFileDrop)="addFiles($event)" @fade>
<div class="uploads">
<small class="uploads-empty text-muted" *ngIf="uploads.length === 0">
No upload in progress, drop files here.
</small>
<div class="upload row no-gutters" *ngFor="let upload of uploads; trackBy: trackByUpload">
<div class="col-auto" [ngSwitch]="upload.status">
<div *ngSwitchCase="'Failed'" class="upload-status upload-status-failed">
<i class="icon-exclamation"></i>
<div class="dropdown-menu container" *ngIf="modalMenu.isOpen | async" (sqxFileDrop)="addFiles($event)" @fade>
<div class="uploads">
<small class="uploads-empty text-muted" *ngIf="uploads.length === 0">
No upload in progress, drop files here.
</small>
<div class="upload row no-gutters" *ngFor="let upload of uploads; trackBy: trackByUpload">
<div class="col-auto" [ngSwitch]="upload.status">
<div *ngSwitchCase="'Failed'" class="upload-status upload-status-failed">
<i class="icon-exclamation"></i>
</div>
<div *ngSwitchCase="'Completed'" class="upload-status upload-status-success">
<i class="icon-checkmark"></i>
</div>
<div *ngSwitchDefault class="upload-status upload-status-running">
<i class="icon-hour-glass"></i>
</div>
</div>
<div *ngSwitchCase="'Completed'" class="upload-status upload-status-success">
<i class="icon-checkmark"></i>
<div class="col-6">
<div class="upload-name">{{upload.name}}</div>
</div>
<div *ngSwitchDefault class="upload-status upload-status-running">
<i class="icon-hour-glass"></i>
<div class="col">
<sqx-progress-bar [value]="upload.progress" [trailWidth]="1.5" [strokeWidth]="1.5" [showText]="false" [animated]="false"></sqx-progress-bar>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text-secondary" (click)="stopUpload(upload)">
<i class="icon-close"></i>
</button>
</div>
</div>
<div class="col-6">
<div class="upload-name">{{upload.name}}</div>
</div>
<div class="col">
<sqx-progress-bar [value]="upload.progress" [trailWidth]="1.5" [strokeWidth]="1.5" [showText]="false" [animated]="false"></sqx-progress-bar>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text-secondary" (click)="stopUpload(upload)">
<i class="icon-close"></i>
</button>
</div>
</div>
</div>
</div>
</li>
</ul>
</li>
</ul>
</ng-container>

4
src/Squidex/app/shared/components/asset-uploader.component.ts

@ -8,6 +8,7 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
AppsState,
AssetsState,
AssetUploaderState,
DialogModel,
@ -25,9 +26,10 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssetUploaderComponent {
public modalMenu = new DialogModel(true);
public modalMenu = new DialogModel();
constructor(
public readonly appsState: AppsState,
public readonly assetUploader: AssetUploaderState,
public readonly assetsState: AssetsState
) {

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

@ -15,7 +15,7 @@ import {
StatefulComponent,
Types
} from '@app/shared/internal';
import { AssetUploaderState } from '../state/asset-uploader.state';
import { AssetUploaderState, UploadCanceled } from '../state/asset-uploader.state';
interface State {
progress: number;
@ -101,7 +101,9 @@ export class AssetComponent extends StatefulComponent<State> implements OnInit {
this.emitLoad(dto);
}
}, error => {
this.dialogs.notifyError(error);
if (!Types.is(error, UploadCanceled)) {
this.dialogs.notifyError(error);
}
this.emitLoadError(error);
});

11
src/Squidex/app/shared/components/markdown-editor.component.ts

@ -10,12 +10,13 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
import {
AssetDto,
AssetUploaderState,
DialogModel,
ResourceLoaderService,
StatefulControlComponent,
Types
Types,
UploadCanceled
} from '@app/shared/internal';
import { AssetUploaderState } from '../state/asset-uploader.state';
declare var SimpleMDE: any;
@ -245,8 +246,10 @@ export class MarkdownEditorComponent extends StatefulControlComponent<State, str
if (Types.is(asset, AssetDto)) {
replaceText(`![${asset.fileName}](${asset.url} '${asset.fileName}')`);
}
}, () => {
replaceText('FAILED');
}, error => {
if (!Types.is(error, UploadCanceled)) {
replaceText('FAILED');
}
});
}
}

17
src/Squidex/app/shared/components/rich-editor.component.ts

@ -12,12 +12,13 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
import {
AssetDto,
AssetUploaderState,
DialogModel,
ResourceLoaderService,
StatefulControlComponent,
Types
Types,
UploadCanceled
} from '@app/shared/internal';
import { AssetUploaderState } from '../state/asset-uploader.state';
declare var tinymce: any;
@ -99,8 +100,10 @@ export class RichEditorComponent extends StatefulControlComponent<any, string> i
if (Types.is(asset, AssetDto)) {
success(asset.url);
}
}, () => {
failed();
}, error => {
if (!Types.is(error, UploadCanceled)) {
failed();
}
});
},
@ -215,8 +218,10 @@ export class RichEditorComponent extends StatefulControlComponent<any, string> i
if (Types.is(asset, AssetDto)) {
replaceText(`<img src="${asset.url}" alt="${asset.fileName}" />`);
}
}, () => {
replaceText('FAILED');
}, error => {
if (!Types.is(error, UploadCanceled)) {
replaceText('FAILED');
}
});
}
}

8
src/Squidex/app/shared/state/apps.state.ts

@ -69,9 +69,9 @@ export class AppsState extends State<Snapshot> {
public load(): Observable<any> {
return this.appsService.getApps().pipe(
tap((dto: AppDto[]) => {
tap(payload => {
this.next(s => {
const apps = ImmutableArray.of(dto);
const apps = ImmutableArray.of(payload);
return { ...s, apps };
});
@ -81,9 +81,9 @@ export class AppsState extends State<Snapshot> {
public create(request: CreateAppDto): Observable<AppDto> {
return this.appsService.postApp(request).pipe(
tap(dto => {
tap(payload => {
this.next(s => {
const apps = s.apps.push(dto).sortByStringAsc(x => x.name);
const apps = s.apps.push(payload).sortByStringAsc(x => x.name);
return { ...s, apps };
});

58
src/Squidex/app/shared/state/asset-uploader.state.ts

@ -6,8 +6,8 @@
*/
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject, Subject, Subscription } from 'rxjs';
import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';
import { distinctUntilChanged, map, publishReplay, refCount, takeUntil } from 'rxjs/operators';
import {
DateTime,
@ -31,10 +31,7 @@ export interface Upload {
name: string;
// The upload subscription.
subscription?: Subscription;
// The subject to notify subscribers.
subject: ReplaySubject<UploadResult>;
cancel: Subject<any>;
// The progress.
progress: number;
@ -48,6 +45,8 @@ interface Snapshot {
uploads: UploadList;
}
export class UploadCanceled { }
type UploadList = ImmutableArray<Upload>;
type UploadResult = AssetDto | number;
@ -67,10 +66,7 @@ export class AssetUploaderState extends State<Snapshot> {
}
public stopUpload(upload: Upload) {
if (upload.subscription) {
upload.subscription.unsubscribe();
upload.subject.complete();
}
upload.cancel.error(new UploadCanceled());
this.next(s => {
const uploads = s.uploads.removeBy('id', upload);
@ -82,55 +78,49 @@ export class AssetUploaderState extends State<Snapshot> {
public uploadFile(file: File, target?: AssetsState, now?: DateTime): Observable<UploadResult> {
const stream = this.assetsService.uploadFile(this.appName, file, this.user, now || DateTime.now());
return this.upload(stream, MathHelper.guid(), file, (asset, subject) => {
return this.upload(stream, MathHelper.guid(), file, asset => {
if (asset.isDuplicate) {
this.dialogs.notifyError('Asset has already been uploaded.');
} else if (target) {
target.add(asset);
}
subject.next(asset);
return asset;
});
}
public uploadAsset(asset: AssetDto, file: File, now?: DateTime): Observable<UploadResult> {
const stream = this.assetsService.replaceFile(this.appName, asset.id, file, asset.version);
return this.upload(stream, asset.id, file, ({ version, payload }, subject) => {
subject.next(asset.update(payload, this.user, version, now));
});
return this.upload(stream, asset.id, file, ({ version, payload }) => asset.update(payload, this.user, version, now));
}
private upload<T, R>(stream: Observable<number | R>, id: string, file: File, complete: (completion: R, subject: Subject<UploadResult>) => void) {
const subject = new ReplaySubject<UploadResult>();
let upload = { id, name: file.name, progress: 1, status: 'Running', subject };
private upload<T>(source: Observable<number | T>, id: string, file: File, complete: ((completion: T) => AssetDto)) {
let upload = { id, name: file.name, progress: 1, status: 'Running', cancel: new Subject() };
this.addUpload(upload);
const subscription = stream.subscribe(event => {
const stream = source.pipe(takeUntil(upload.cancel),
map(event => {
if (Types.isNumber(event)) {
return event;
} else {
return complete(event);
}
}),
publishReplay(), refCount());
stream.subscribe(event => {
if (Types.isNumber(event)) {
upload = this.update(upload, { progress: event });
subject.next(event);
} else {
complete(event, subject);
}
}, error => {
subject.error(error);
}, () => {
upload = this.remove(upload, { status: 'Failed' });
}, () => {
if (!subject.isStopped) {
subject.complete();
}
upload = this.remove(upload, { status: 'Completed', progress: 100 });
});
upload = this.update(upload, { subscription });
return subject.pipe(shareReplay());
return stream;
}
private remove(upload: Upload, update: Partial<Upload>) {

8
src/Squidex/app/shared/state/assets.state.ts

@ -95,16 +95,16 @@ export class AssetsState extends State<Snapshot> {
Object.keys(this.snapshot.tagsSelected)),
this.assetsService.getTags(this.appName)
).pipe(
tap(dtos => {
tap(([ { items, total }, tags ]) => {
if (isReload) {
this.dialogs.notifyInfo('Assets reloaded.');
}
this.next(s => {
const assets = ImmutableArray.of(dtos[0].items);
const assetsPager = s.assetsPager.setCount(dtos[0].total);
const assets = ImmutableArray.of(items);
const assetsPager = s.assetsPager.setCount(total);
return { ...s, assets, assetsPager, isLoaded: true, tags: dtos[1] };
return { ...s, assets, assetsPager, isLoaded: true, tags };
});
}),
shareSubscribed(this.dialogs));

106
src/Squidex/app/shared/state/contents.state.ts

@ -14,6 +14,7 @@ import {
DialogService,
ErrorDto,
ImmutableArray,
mapVersioned,
Pager,
shareSubscribed,
State,
@ -118,20 +119,24 @@ export abstract class ContentsStateBase extends State<Snapshot> {
return this.loadInternal(isReload);
}
private loadInternal(isReload = false): Observable<any> {
private loadInternal(isReload = false) {
return this.loadInternalCore(isReload).pipe(shareSubscribed(this.dialogs));
}
private loadInternalCore(isReload = false) {
return this.contentsService.getContents(this.appName, this.schemaName,
this.snapshot.contentsPager.pageSize,
this.snapshot.contentsPager.skip,
this.snapshot.contentsQuery, undefined,
this.snapshot.isArchive).pipe(
tap(dtos => {
tap(({ total, items }) => {
if (isReload) {
this.dialogs.notifyInfo('Contents reloaded.');
}
return this.next(s => {
const contents = ImmutableArray.of(dtos.items);
const contentsPager = s.contentsPager.setCount(dtos.total);
const contents = ImmutableArray.of(items);
const contentsPager = s.contentsPager.setCount(total);
let selectedContent = s.selectedContent;
@ -141,17 +146,16 @@ export abstract class ContentsStateBase extends State<Snapshot> {
return { ...s, contents, contentsPager, selectedContent, isLoaded: true };
});
}),
shareSubscribed(this.dialogs));
}));
}
public create(request: any, publish: boolean): Observable<ContentDto> {
return this.contentsService.postContent(this.appName, this.schemaName, request, publish).pipe(
tap(dto => {
tap(payload => {
this.dialogs.notifyInfo('Contents created successfully.');
return this.next(s => {
const contents = s.contents.pushFront(dto);
const contents = s.contents.pushFront(payload);
const contentsPager = s.contentsPager.incrementCount();
return { ...s, contents, contentsPager };
@ -174,7 +178,8 @@ export abstract class ContentsStateBase extends State<Snapshot> {
return of(error);
}),
switchMap(() => this.loadInternal()));
switchMap(() => this.loadInternalCore()),
shareSubscribed(this.dialogs, { silent: true }));
}
public deleteMany(contents: ContentDto[]): Observable<any> {
@ -191,92 +196,97 @@ export abstract class ContentsStateBase extends State<Snapshot> {
return of(error);
}),
switchMap(() => this.loadInternal()));
switchMap(() => this.loadInternal()),
shareSubscribed(this.dialogs, { silent: true }));
}
public publishChanges(content: ContentDto, dueTime: string | null, now?: DateTime): Observable<any> {
public publishChanges(content: ContentDto, dueTime: string | null, now?: DateTime): Observable<ContentDto> {
return this.contentsService.changeContentStatus(this.appName, this.schemaName, content.id, 'Publish', dueTime, content.version).pipe(
tap(dto => {
this.dialogs.notifyInfo('Content updated successfully.');
mapVersioned(({ version }) => {
if (dueTime) {
this.replaceContent(changeScheduleStatus(content, 'Published', dueTime, this.user, dto.version, now));
return changeScheduleStatus(content, 'Published', dueTime, this.user, version, now);
} else {
this.replaceContent(confirmChanges(content, this.user, dto.version, now));
return confirmChanges(content, this.user, version, now);
}
}),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(payload);
}),
shareSubscribed(this.dialogs));
}
public changeStatus(content: ContentDto, action: string, status: string, dueTime: string | null, now?: DateTime): Observable<any> {
public changeStatus(content: ContentDto, action: string, status: string, dueTime: string | null, now?: DateTime): Observable<ContentDto> {
return this.contentsService.changeContentStatus(this.appName, this.schemaName, content.id, action, dueTime, content.version).pipe(
tap(dto => {
this.dialogs.notifyInfo('Content updated successfully.');
mapVersioned(({ version }) => {
if (dueTime) {
this.replaceContent(changeScheduleStatus(content, status, dueTime, this.user, dto.version, now));
return changeScheduleStatus(content, status, dueTime, this.user, version, now);
} else {
this.replaceContent(changeStatus(content, status, this.user, dto.version, now));
return changeStatus(content, status, this.user, version, now);
}
}),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(payload);
}),
shareSubscribed(this.dialogs));
}
public update(content: ContentDto, request: any, now?: DateTime): Observable<any> {
public update(content: ContentDto, request: any, now?: DateTime): Observable<ContentDto> {
return this.contentsService.putContent(this.appName, this.schemaName, content.id, request, false, content.version).pipe(
tap(dto => {
mapVersioned((payload, version) => updateData(content, payload, this.user, version, now)),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
if (dto.version.value !== content.version.value) {
this.replaceContent(updateData(content, dto.payload, this.user, dto.version, now));
}
this.replaceContent(payload, content.version);
}),
shareSubscribed(this.dialogs));
}
public proposeUpdate(content: ContentDto, request: any, now?: DateTime): Observable<any> {
public proposeUpdate(content: ContentDto, request: any, now?: DateTime): Observable<ContentDto> {
return this.contentsService.putContent(this.appName, this.schemaName, content.id, request, true, content.version).pipe(
tap(dto => {
mapVersioned((payload, version) => updateDataDraft(content, payload, this.user, version, now)),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
if (dto.version.value !== content.version.value) {
this.replaceContent(updateDataDraft(content, dto.payload, this.user, dto.version, now));
}
this.replaceContent(payload, content.version);
}),
shareSubscribed(this.dialogs));
}
public discardChanges(content: ContentDto, now?: DateTime): Observable<any> {
public discardChanges(content: ContentDto, now?: DateTime): Observable<ContentDto> {
return this.contentsService.discardChanges(this.appName, this.schemaName, content.id, content.version).pipe(
tap(dto => {
mapVersioned((_, version) => discardChanges(content, this.user, version, now)),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
if (dto.version.value !== content.version.value) {
this.replaceContent(discardChanges(content, this.user, dto.version, now));
}
this.replaceContent(payload, content.version);
}),
shareSubscribed(this.dialogs));
}
public patch(content: ContentDto, request: any, now?: DateTime): Observable<any> {
public patch(content: ContentDto, request: any, now?: DateTime): Observable<ContentDto> {
return this.contentsService.patchContent(this.appName, this.schemaName, content.id, request, content.version).pipe(
tap(dto => {
mapVersioned((data, version) => updateData(content, data, this.user, version, now)),
tap(({ payload }) => {
this.dialogs.notifyInfo('Content updated successfully.');
if (dto.version.value !== content.version.value) {
this.replaceContent(updateData(content, dto.payload, this.user, dto.version, now));
}
this.replaceContent(payload, content.version);
}),
shareSubscribed(this.dialogs));
}
private replaceContent(content: ContentDto) {
return this.next(s => {
const contents = s.contents.replaceBy('id', content);
const selectedContent = s.selectedContent && s.selectedContent.id === content.id ? content : s.selectedContent;
private replaceContent(content: ContentDto, oldVersion?: Version) {
if (!oldVersion || oldVersion.eq(content.version)) {
return this.next(s => {
const contents = s.contents.replaceBy('id', content);
const selectedContent = s.selectedContent && s.selectedContent.id === content.id ? content : s.selectedContent;
return { ...s, contents, selectedContent };
});
return { ...s, contents, selectedContent };
});
}
}
public goArchive(isArchive: boolean): Observable<any> {

8
src/Squidex/app/shared/state/plans.state.ts

@ -112,14 +112,14 @@ export class PlansState extends State<Snapshot> {
public change(planId: string): Observable<any> {
return this.plansService.putPlan(this.appName, { planId }, this.version).pipe(
tap(dto => {
if (dto.payload.redirectUri && dto.payload.redirectUri.length > 0) {
this.window.location.href = dto.payload.redirectUri;
tap(({ payload, version }) => {
if (payload.redirectUri && payload.redirectUri.length > 0) {
this.window.location.href = payload.redirectUri;
} else {
this.next(s => {
const plans = s.plans.map(x => this.createPlan(x.plan, planId));
return { ...s, plans, isOwner: true, version: dto.version };
return { ...s, plans, isOwner: true, version };
});
}
}),

6
src/Squidex/app/shared/state/rule-events.state.ts

@ -66,14 +66,14 @@ export class RuleEventsState extends State<Snapshot> {
return this.rulesService.getEvents(this.appName,
this.snapshot.ruleEventsPager.pageSize,
this.snapshot.ruleEventsPager.skip).pipe(
tap(dtos => {
tap(({ total, items }) => {
if (isReload) {
this.dialogs.notifyInfo('RuleEvents reloaded.');
}
return this.next(s => {
const ruleEvents = ImmutableArray.of(dtos.items);
const ruleEventsPager = s.ruleEventsPager.setCount(dtos.total);
const ruleEvents = ImmutableArray.of(items);
const ruleEventsPager = s.ruleEventsPager.setCount(total);
return { ...s, ruleEvents, ruleEventsPager, isLoaded: true };
});

17
src/Squidex/app/shared/state/schemas.state.ts

@ -93,7 +93,7 @@ export class SchemasState extends State<Snapshot> {
private readonly dialogs: DialogService,
private readonly schemasService: SchemasService
) {
super({ schemas: ImmutableArray.empty(), categories: {} });
super({ schemas: ImmutableArray.empty(), categories: buildCategories({}) });
}
public select(idOrName: string | null): Observable<SchemaDetailsDto | null> {
@ -137,9 +137,9 @@ export class SchemasState extends State<Snapshot> {
public create(request: CreateSchemaDto, now?: DateTime): Observable<SchemaDetailsDto> {
return this.schemasService.postSchema(this.appName, request, this.user, now || DateTime.now()).pipe(
tap(dto => {
tap(payload => {
this.next(s => {
const schemas = s.schemas.push(dto).sortByStringAsc(x => x.displayName);
const schemas = s.schemas.push(payload).sortByStringAsc(x => x.displayName);
return { ...s, schemas };
});
@ -375,7 +375,7 @@ export class SchemasState extends State<Snapshot> {
}
}
function buildCategories(categories: { [name: string]: boolean }, schemas: SchemasList) {
function buildCategories(categories: { [name: string]: boolean }, schemas?: SchemasList) {
categories = { ...categories };
for (let category in categories) {
@ -385,10 +385,15 @@ function buildCategories(categories: { [name: string]: boolean }, schemas: Schem
}
}
}
for (let schema of schemas.values) {
categories[schema.category || ''] = false;
if (schemas) {
for (let schema of schemas.values) {
categories[schema.category || ''] = false;
}
}
categories[''] = true;
return categories;
}

8
src/Squidex/app/shared/state/ui.state.ts

@ -55,15 +55,15 @@ export class UIState extends State<Snapshot> {
this.next(s => updateAppSettings(s, {}));
this.uiService.getSettings(this.appName)
.subscribe(dtos => {
this.next(s => updateAppSettings(s, dtos));
.subscribe(payload => {
this.next(s => updateAppSettings(s, payload));
});
}
private loadCommon() {
this.uiService.getCommonSettings()
.subscribe(dtos => {
this.next(s => updateCommonSettings(s, dtos));
.subscribe(payload => {
this.next(s => updateCommonSettings(s, payload));
});
}

Loading…
Cancel
Save