Browse Source

UI fixes.

pull/285/head
Sebastian 8 years ago
parent
commit
cdd17a145a
  1. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  2. 2
      src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs
  3. 3
      src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs
  4. 7
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  5. 16
      src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs
  6. 10
      src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs
  7. 2
      src/Squidex.Domain.Apps.Entities/SquidexCommand.cs
  8. 4
      src/Squidex.Domain.Apps.Events/Contents/ContentChangesPublished.cs
  9. 2
      src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs
  10. 1
      src/Squidex/app/features/content/declarations.ts
  11. 2
      src/Squidex/app/features/content/module.ts
  12. 61
      src/Squidex/app/features/content/pages/content/content-page.component.html
  13. 26
      src/Squidex/app/features/content/pages/content/content-page.component.scss
  14. 53
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  15. 31
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  16. 46
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  17. 3
      src/Squidex/app/features/content/shared/content-item.component.html
  18. 2
      src/Squidex/app/features/content/shared/content-status.component.html
  19. 4
      src/Squidex/app/features/content/shared/content-status.component.scss
  20. 30
      src/Squidex/app/features/content/shared/due-time-selector.component.html
  21. 2
      src/Squidex/app/features/content/shared/due-time-selector.component.scss
  22. 52
      src/Squidex/app/features/content/shared/due-time-selector.component.ts
  23. 6
      src/Squidex/app/features/schemas/pages/schema/field.component.html
  24. 60
      src/Squidex/app/shared/state/contents.state.ts

2
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
}
else
{
return contentsPublished.FindContentAsync(app, schema, id);
return contentsDraft.FindContentAsync(app, schema, id);
}
}

2
src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs

@ -197,7 +197,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
public void ConfirmChanges(ChangeContentStatus command)
{
RaiseEvent(SimpleMapper.Map(command, new ContentChangesConfirmed()));
RaiseEvent(SimpleMapper.Map(command, new ContentChangesPublished()));
}
public void DiscardChanges(DiscardChanges command)

3
src/Squidex.Domain.Apps.Entities/Contents/ContentHistoryEventsCreator.cs

@ -31,6 +31,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
AddEventMessage<ContentChangesDiscarded>(
"discarded pending changes of {[Schema]} content.");
AddEventMessage<ContentChangesPublished>(
"published changes of {[Schema]} content.");
AddEventMessage<ContentUpdateProposed>(
"proposed update for {[Schema]} content.");

7
src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs

@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var isFrontendClient = IsFrontendClient(user);
var isVersioned = version > EtagVersion.Empty;
var parsedStatus = isFrontendClient ? new[] { Status.Published } : null;
var parsedStatus = isFrontendClient ? null : new[] { Status.Published };
var content =
isVersioned ?
@ -156,7 +156,10 @@ namespace Squidex.Domain.Apps.Entities.Contents
result.Data = result.Data.ToApiModel(schema.SchemaDef, app.LanguagesConfig, isFrontendClient, isTypeChecking);
}
result.DataDraft = result.DataDraft.ToApiModel(schema.SchemaDef, app.LanguagesConfig, isFrontendClient, isTypeChecking);
if (result.DataDraft != null)
{
result.DataDraft = result.DataDraft.ToApiModel(schema.SchemaDef, app.LanguagesConfig, isFrontendClient, isTypeChecking);
}
yield return result;
}

16
src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs

@ -6,6 +6,7 @@
// ==========================================================================
using System;
using System.Threading;
using System.Threading.Tasks;
using NodaTime;
using Orleans;
@ -23,6 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly Lazy<IContentRepository> contentRepository;
private readonly Lazy<ICommandBus> commandBus;
private readonly IClock clock;
private TaskScheduler scheduler;
public ContentSchedulerGrain(
Lazy<IContentRepository> contentRepository,
@ -40,6 +42,8 @@ namespace Squidex.Domain.Apps.Entities.Contents
public override Task OnActivateAsync()
{
scheduler = TaskScheduler.Current;
DelayDeactivation(TimeSpan.FromDays(1));
RegisterOrUpdateReminder("Default", TimeSpan.Zero, TimeSpan.FromMinutes(10));
@ -59,9 +63,12 @@ namespace Squidex.Domain.Apps.Entities.Contents
return contentRepository.Value.QueryScheduledWithoutDataAsync(now, content =>
{
var command = new ChangeContentStatus { ContentId = content.Id, Status = content.ScheduledTo.Value, Actor = content.ScheduledBy };
return Dispatch(() =>
{
var command = new ChangeContentStatus { ContentId = content.Id, Status = content.ScheduledTo.Value, Actor = content.ScheduledBy };
return commandBus.Value.PublishAsync(command);
return commandBus.Value.PublishAsync(command);
});
});
}
@ -69,5 +76,10 @@ namespace Squidex.Domain.Apps.Entities.Contents
{
return TaskHelper.Done;
}
private Task Dispatch(Func<Task> task)
{
return Task<Task>.Factory.StartNew(() => task(), CancellationToken.None, TaskCreationOptions.None, scheduler ?? TaskScheduler.Default).Unwrap();
}
}
}

10
src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs

@ -59,8 +59,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.State
protected void On(ContentUpdated @event)
{
Data = @event.Data;
DataDraft = @event.Data;
if (Data != null)
{
Data = @event.Data;
}
}
protected void On(ContentUpdateProposed @event)
@ -77,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.State
IsPending = false;
}
protected void On(ContentChangesConfirmed @event)
protected void On(ContentChangesPublished @event)
{
Data = DataDraft;
@ -102,8 +106,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.State
if (@event.Status == Status.Published)
{
Data = DataDraft;
IsPending = false;
}
}

2
src/Squidex.Domain.Apps.Entities/SquidexCommand.cs

@ -17,6 +17,6 @@ namespace Squidex.Domain.Apps.Entities
public ClaimsPrincipal User { get; set; }
public long ExpectedVersion { get; set; }
public long ExpectedVersion { get; set; } = EtagVersion.Any;
}
}

4
src/Squidex.Domain.Apps.Events/Contents/ContentChangesConfirmed.cs → src/Squidex.Domain.Apps.Events/Contents/ContentChangesPublished.cs

@ -9,8 +9,8 @@ using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Events.Contents
{
[EventType(nameof(ContentChangesConfirmed))]
public sealed class ContentChangesConfirmed : ContentEvent
[EventType(nameof(ContentChangesPublished))]
public sealed class ContentChangesPublished : ContentEvent
{
}
}

2
src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs

@ -27,6 +27,8 @@ namespace Squidex.Pipeline.CommandMiddlewares
{
if (httpContextAccessor.HttpContext == null)
{
await next();
return;
}

1
src/Squidex/app/features/content/declarations.ts

@ -16,4 +16,5 @@ export * from './shared/assets-editor.component';
export * from './shared/content-item.component';
export * from './shared/content-status.component';
export * from './shared/contents-selector.component';
export * from './shared/due-time-selector.component';
export * from './shared/references-editor.component';

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

@ -28,6 +28,7 @@ import {
ContentsPageComponent,
ContentsSelectorComponent,
ContentStatusComponent,
DueTimeSelectorComponent,
ReferencesEditorComponent,
SchemasPageComponent,
SearchFormComponent
@ -93,6 +94,7 @@ const routes: Routes = [
ContentStatusComponent,
ContentsPageComponent,
ContentsSelectorComponent,
DueTimeSelectorComponent,
ReferencesEditorComponent,
SchemasPageComponent,
SearchFormComponent

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

@ -31,17 +31,56 @@
<sqx-shortcut keys="ctrl+s" (trigger)="saveAndPublish()"></sqx-shortcut>
</ng-container>
<ng-template #notNew>
<span class="btn btn btn-outline-secondary">
<sqx-content-status
[status]="content.status"
[scheduledTo]="content.scheduledTo"
[scheduledAt]="content.scheduledAt"
[isPending]="content.isPending">
</sqx-content-status>
</span>
<div class="dropdown dropdown-options" *ngIf="content">
<button type="button" class="btn btn-outline-secondary" (click)="dropdown.toggle()" [class.active]="dropdown.isOpen | async" #optionsButton>
<sqx-content-status
[status]="content.status"
[scheduledTo]="content.scheduledTo"
[scheduledAt]="content.scheduledAt"
[isPending]="content.isPending"
showLabel="true">
</sqx-content-status>
</button>
<div class="dropdown-menu" *sqxModalView="dropdown" [sqxModalTarget]="optionsButton" @fade>
<ng-container *ngIf="content.isPending">
<a class="dropdown-item" (click)="discardChanges()">
Discard changes
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" (click)="publishChanges()">
Publish changes
</a>
</ng-container>
<a class="dropdown-item" (click)="publish()" *ngIf="content.status === 'Draft'">
Publish
</a>
<a class="dropdown-item" (click)="unpublish()" *ngIf="content.status === 'Published'">
Unpublish
</a>
<a class="dropdown-item" (click)="archive()" *ngIf="content.status !== 'Archived'">
Archive
</a>
<a class="dropdown-item" (click)="restore()" *ngIf="content.status === 'Archived'">
Restore
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="delete()"
confirmTitle="Delete content"
confirmText="Do you really want to delete the content?">
Delete
</a>
</div>
</div>
<ng-container *ngIf="content.status !== 'Archived'">
<button type="button" class="btn btn-secondary" (click)="saveAsProposal()">
<button type="button" class="btn btn-secondary" (click)="saveAsProposal()" *ngIf="content.status === 'Published'">
Save as Proposal
</button>
@ -86,4 +125,6 @@
</sqx-panel>
</form>
<router-outlet></router-outlet>
<router-outlet></router-outlet>
<sqx-due-time-selector #dueTimeSelector></sqx-due-time-selector>

26
src/Squidex/app/features/content/pages/content/content-page.component.scss

@ -1,26 +1,2 @@
@import '_vars';
@import '_mixins';
.content-status {
& {
color: $color-text;
cursor: default !important;
}
&:hover {
background: transparent;
}
}
.discard-changes {
& {
color: $color-theme-blue !important;
cursor: pointer;
font-size: .9rem;
font-weight: normal;
}
&:hover {
text-decoration: underline !important;
}
}
@import '_mixins';

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

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable, Subscription } from 'rxjs';
@ -19,18 +19,25 @@ import {
ContentsState,
DialogService,
EditContentForm,
fadeAnimation,
ImmutableArray,
LanguagesState,
MessageBus,
ModalView,
SchemaDetailsDto,
SchemasState,
Version
} from '@app/shared';
import { DueTimeSelectorComponent } from './../../shared/due-time-selector.component';
@Component({
selector: 'sqx-content-page',
styleUrls: ['./content-page.component.scss'],
templateUrl: './content-page.component.html'
templateUrl: './content-page.component.html',
animations: [
fadeAnimation
]
})
export class ContentPageComponent implements CanComponentDeactivate, OnDestroy, OnInit {
private languagesSubscription: Subscription;
@ -44,9 +51,14 @@ export class ContentPageComponent implements CanComponentDeactivate, OnDestroy,
public contentVersion: Version | null;
public contentForm: EditContentForm;
public dropdown = new ModalView(false, true);
public language: AppLanguageDto;
public languages: ImmutableArray<AppLanguageDto>;
@ViewChild('dueTimeSelector')
public dueTimeSelector: DueTimeSelectorComponent;
constructor(
public readonly appsState: AppsState,
private readonly contentsState: ContentsState,
@ -162,6 +174,43 @@ export class ContentPageComponent implements CanComponentDeactivate, OnDestroy,
this.contentForm.loadData(data, this.content && this.content.status === 'Archived');
}
public publishChanges() {
this.contentsState.publishChanges(this.content).onErrorResumeNext().subscribe();
}
public discardChanges() {
this.contentsState.discardChanges(this.content).onErrorResumeNext().subscribe();
}
public publish() {
this.changeContentItems('Publish', 'Published');
}
public unpublish() {
this.changeContentItems('Unpublish', 'Draft');
}
public archive() {
this.changeContentItems('Archive', 'Archived');
}
public restore() {
this.changeContentItems('Restore', 'Draft');
}
public delete() {
this.contentsState.deleteMany([this.content]).onErrorResumeNext()
.subscribe(() => {
this.back();
});
}
private changeContentItems(action: string, status: string) {
this.dueTimeSelector.selectDueTime(action)
.switchMap(d => this.contentsState.changeStatus(this.content, action, status, d)).onErrorResumeNext()
.subscribe();
}
private loadVersion(version: Version) {
if (this.content) {
this.contentsState.loadVersion(this.content, version)

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

@ -118,33 +118,4 @@
</ng-container>
</sqx-panel>
<ng-container *sqxModalView="dueTimeDialog;onRoot:true">
<sqx-modal-dialog (closed)="cancelStatusChange()">
<ng-container title>
{{dueTimeAction}} content item(s)
</ng-container>
<ng-container content>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Immediately" id="immediately">
<label class="form-check-label" for="immediately">
{{dueTimeAction}} content item(s) immediately.
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Scheduled" id="scheduled">
<label class="form-check-label" for="scheduled">
{{dueTimeAction}} content item(s) at a later point date and time.
</label>
</div>
<sqx-date-time-editor [disabled]="dueTimeMode === 'Immediately'" mode="DateTime" hideClear="true" [(ngModel)]="dueTime"></sqx-date-time-editor>
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancelStatusChange()">Cancel</button>
<button type="button" class="float-right btn btn-primary" [disabled]="dueTimeMode === 'Scheduled' && !dueTime" (click)="confirmStatusChange()" sqxFocusOnInit>Confirm</button>
</ng-container>
</sqx-modal-dialog>
</ng-container>
<sqx-due-time-selector #dueTimeSelector></sqx-due-time-selector>

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

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs';
import {
@ -20,6 +20,8 @@ import {
SchemasState
} from '@app/shared';
import { DueTimeSelectorComponent } from './../../shared/due-time-selector.component';
@Component({
selector: 'sqx-contents-page',
styleUrls: ['./contents-page.component.scss'],
@ -34,12 +36,6 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
public searchModal = new ModalView();
public dueTimeDialog = new ModalView();
public dueTime: string | null = '';
public dueTimeFunction: Function | null;
public dueTimeAction: string | null = '';
public dueTimeMode = 'Immediately';
public selectedItems: { [id: string]: boolean; } = {};
public selectionCount = 0;
@ -51,6 +47,9 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
public isAllSelected = false;
@ViewChild('dueTimeSelector')
public dueTimeSelector: DueTimeSelectorComponent;
constructor(
public readonly appsState: AppsState,
public readonly contentsState: ContentsState,
@ -131,26 +130,24 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
return;
}
this.dueTimeFunction = () => {
this.resetSelection();
this.contentsState.changeStatus(contents, action, this.dueTime).onErrorResumeNext().subscribe();
};
this.dueTimeAction = action;
this.dueTimeDialog.show();
this.dueTimeSelector.selectDueTime(action)
.do(() => {
this.resetSelection();
})
.switchMap(d => this.contentsState.changeManyStatus(contents, action, d)).onErrorResumeNext()
.subscribe();
}
public deleteSelected() {
this.resetSelection();
this.contentsState.delete(this.select()).onErrorResumeNext().subscribe();
this.contentsState.deleteMany(this.select()).onErrorResumeNext().subscribe();
}
public delete(content: ContentDto) {
this.resetSelection();
this.contentsState.delete([content]).onErrorResumeNext().subscribe();
this.contentsState.deleteMany([content]).onErrorResumeNext().subscribe();
}
public goArchive(isArchive: boolean) {
@ -203,21 +200,6 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
this.updateSelectionSummary();
}
public confirmStatusChange() {
this.dueTimeFunction!();
this.dueTimeFunction = null;
this.dueTimeMode = 'Immediately';
this.dueTimeDialog.hide();
this.dueTime = null;
}
public cancelStatusChange() {
this.dueTimeMode = 'Immediately';
this.dueTimeDialog.hide();
this.dueTimeFunction = null;
this.dueTime = null;
}
public trackByContent(content: ContentDto): string {
return content.id;
}

3
src/Squidex/app/features/content/shared/content-item.component.html

@ -99,6 +99,9 @@
<a class="dropdown-item" (click)="restoring.emit(); $event.stopPropagation()" *ngIf="content.status === 'Archived'">
Restore
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="deleting.emit()"
confirmTitle="Delete content"

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

@ -14,4 +14,4 @@
<sqx-tooltip [target]="statusIcon">Will be set to '{{scheduledTo}}' at {{scheduledAt | sqxFullDateTime}}</sqx-tooltip>
</span>
<span *ngIf="showLabel">{{displayStatus}}</span>
<span class="content-status-label" *ngIf="showLabel">{{displayStatus}}</span>

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

@ -22,6 +22,10 @@
color: $color-dark-black;
}
&-label {
color: $color-text;
}
&-tooltip {
@include border-radius;
background: $color-tooltip;

30
src/Squidex/app/features/content/shared/due-time-selector.component.html

@ -0,0 +1,30 @@
<ng-container *sqxModalView="dueTimeDialog;onRoot:true">
<sqx-modal-dialog (closed)="cancelStatusChange()">
<ng-container title>
{{dueTimeAction}} content item(s)
</ng-container>
<ng-container content>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Immediately" id="immediately">
<label class="form-check-label" for="immediately">
{{dueTimeAction}} content item(s) immediately.
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Scheduled" id="scheduled">
<label class="form-check-label" for="scheduled">
{{dueTimeAction}} content item(s) at a later point date and time.
</label>
</div>
<sqx-date-time-editor [disabled]="dueTimeMode === 'Immediately'" mode="DateTime" hideClear="true" [(ngModel)]="dueTime"></sqx-date-time-editor>
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancelStatusChange()">Cancel</button>
<button type="button" class="float-right btn btn-primary" [disabled]="dueTimeMode === 'Scheduled' && !dueTime" (click)="confirmStatusChange()" sqxFocusOnInit>Confirm</button>
</ng-container>
</sqx-modal-dialog>
</ng-container>

2
src/Squidex/app/features/content/shared/due-time-selector.component.scss

@ -0,0 +1,2 @@
@import '_vars';
@import '_mixins';

52
src/Squidex/app/features/content/shared/due-time-selector.component.ts

@ -0,0 +1,52 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { fadeAnimation, ModalView } from '@app/shared';
@Component({
selector: 'sqx-due-time-selector',
styleUrls: ['./due-time-selector.component.scss'],
templateUrl: './due-time-selector.component.html',
animations: [
fadeAnimation
]
})
export class DueTimeSelectorComponent {
public dueTimeDialog = new ModalView();
public dueTime: string | null = '';
public dueTimeFunction: Subject<string | null>;
public dueTimeAction: string | null = '';
public dueTimeMode = 'Immediately';
public selectDueTime(action: string): Observable<string | null> {
this.dueTimeAction = action;
this.dueTimeFunction = new Subject<string | null>();
this.dueTimeDialog.show();
return this.dueTimeFunction;
}
public confirmStatusChange() {
const result = this.dueTimeMode === 'Immediately' ? null : this.dueTime;
this.dueTimeFunction.next(result);
this.dueTimeFunction.complete();
this.cancelStatusChange();
}
public cancelStatusChange() {
this.dueTimeMode = 'Immediately';
this.dueTimeDialog.hide();
this.dueTimeFunction = null!;
this.dueTime = null;
}
}

6
src/Squidex/app/features/schemas/pages/schema/field.component.html

@ -39,12 +39,18 @@
<a class="dropdown-item" (click)="showField()" *ngIf="field.isHidden" [class.disabled]="field.isLocked">
Show in API
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" *ngIf="!field.isLocked"
(sqxConfirmClick)="lockField()"
confirmTitle="Lock field"
confirmText="Do you really want to lock the field? Lock fields cannot be deleted or changed.">
Lock and prevent changes
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete" [class.disabled]="field.isLocked"
(sqxConfirmClick)="deleteField()"
confirmTitle="Delete field"

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

@ -254,7 +254,7 @@ export abstract class ContentsStateBase extends State<Snapshot> {
.notify(this.dialogs);
}
public changeStatus(contents: ContentDto[], action: string, dueTime: string | null): Observable<any> {
public changeManyStatus(contents: ContentDto[], action: string, dueTime: string | null): Observable<any> {
return Observable.forkJoin(
contents.map(c =>
this.contentsService.changeContentStatus(this.appName, this.schemaName, c.id, action, dueTime, c.version)
@ -271,7 +271,7 @@ export abstract class ContentsStateBase extends State<Snapshot> {
.switchMap(() => this.loadInternal());
}
public delete(contents: ContentDto[]): Observable<any> {
public deleteMany(contents: ContentDto[]): Observable<any> {
return Observable.forkJoin(
contents.map(c =>
this.contentsService.deleteContent(this.appName, this.schemaName, c.id, c.version)
@ -288,10 +288,20 @@ export abstract class ContentsStateBase extends State<Snapshot> {
.switchMap(() => this.loadInternal());
}
public changeStatus(content: ContentDto, action: string, status: string, dueTime: string | null, now?: DateTime): Observable<any> {
return this.contentsService.changeContentStatus(this.appName, this.schemaName, content.id, action, dueTime, content.version)
.do(dto => {
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(changeStatus(content, status, dueTime, this.user, dto.version, now));
})
.notify(this.dialogs);
}
public update(content: ContentDto, request: any, now?: DateTime): Observable<any> {
return this.contentsService.putContent(this.appName, this.schemaName, content.id, request, false, content.version)
.do(dto => {
this.dialogs.notifyInfo('Contents updated successfully.');
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(updateData(content, dto.payload, this.user, dto.version, now));
})
@ -308,12 +318,22 @@ export abstract class ContentsStateBase extends State<Snapshot> {
.notify(this.dialogs);
}
public revertProposal(content: ContentDto, now?: DateTime): Observable<any> {
public publishChanges(content: ContentDto, now?: DateTime): Observable<any> {
return this.contentsService.changeContentStatus(this.appName, this.schemaName, content.id, 'Publish', null, content.version)
.do(dto => {
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(confirmChanges(content, this.user, dto.version, now));
})
.notify(this.dialogs);
}
public discardChanges(content: ContentDto, now?: DateTime): Observable<any> {
return this.contentsService.discardChanges(this.appName, this.schemaName, content.id, content.version)
.do(dto => {
this.dialogs.notifyInfo('Content updated successfully.');
this.replaceContent(revertDataDraft(content, this.user, dto.version, now));
this.replaceContent(discardChanges(content, this.user, dto.version, now));
})
.notify(this.dialogs);
}
@ -411,6 +431,20 @@ export class ManualContentsState extends ContentsStateBase {
}
}
const changeStatus = (content: ContentDto, status: string, dueTime: string | null, user: string, version: Version, now?: DateTime) =>
new ContentDto(
content.id,
dueTime ? content.status : status,
content.createdBy, user,
content.created, now || DateTime.now(),
dueTime ? status : null,
dueTime ? user : null,
dueTime ? DateTime.parseISO_UTC(dueTime) : null,
content.isPending,
content.data,
content.dataDraft,
version);
const updateData = (content: ContentDto, data: any, user: string, version: Version, now?: DateTime) =>
new ContentDto(
content.id,
@ -439,7 +473,21 @@ const updateDataDraft = (content: ContentDto, data: any, user: string, version:
data,
version);
const revertDataDraft = (content: ContentDto, user: string, version: Version, now?: DateTime) =>
const confirmChanges = (content: ContentDto, user: string, version: Version, now?: DateTime) =>
new ContentDto(
content.id,
content.status,
content.createdBy, user,
content.created, now || DateTime.now(),
content.scheduledTo,
content.scheduledBy,
content.scheduledAt,
false,
content.dataDraft,
content.dataDraft,
version);
const discardChanges = (content: ContentDto, user: string, version: Version, now?: DateTime) =>
new ContentDto(
content.id,
content.status,

Loading…
Cancel
Save