Show read-only editor in versions (not actually versioning yet)
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Garrett Mills 2020-11-02 22:33:13 -06:00
parent 26e8d6ecd6
commit ab811bb54c
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
12 changed files with 56 additions and 147 deletions

View File

@ -17,7 +17,7 @@ const routes: Routes = [
},
{
path: 'editor',
loadChildren: () => import('./pages/editor/editor.module').then( m => m.EditorPageModule)
loadChildren: () => import('./components/components.module').then( m => m.ComponentsModule)
}
];

View File

@ -31,6 +31,8 @@ import {MarkdownComponent as MarkdownEditorComponent} from './nodes/markdown/mar
import {DirectivesModule} from '../directives/directives.module';
import {MarkdownModule} from 'ngx-markdown';
import {VersionModalComponent} from './version-modal/version-modal.component';
import {EditorPageRoutingModule} from '../pages/editor/editor-routing.module';
import {EditorPage} from '../pages/editor/editor.page';
@NgModule({
declarations: [
@ -58,6 +60,7 @@ import {VersionModalComponent} from './version-modal/version-modal.component';
NormComponent,
MarkdownEditorComponent,
VersionModalComponent,
EditorPage,
],
imports: [
CommonModule,
@ -69,6 +72,7 @@ import {VersionModalComponent} from './version-modal/version-modal.component';
MonacoEditorModule,
DirectivesModule,
MarkdownModule,
EditorPageRoutingModule,
],
entryComponents: [
NodePickerComponent,
@ -95,6 +99,7 @@ import {VersionModalComponent} from './version-modal/version-modal.component';
NormComponent,
MarkdownEditorComponent,
VersionModalComponent,
EditorPage,
],
exports: [
NodePickerComponent,
@ -121,6 +126,7 @@ import {VersionModalComponent} from './version-modal/version-modal.component';
NormComponent,
MarkdownEditorComponent,
VersionModalComponent,
EditorPage,
]
})
export class ComponentsModule {}

View File

@ -19,7 +19,7 @@
</ion-item>
</ion-list>
<div class="preview">
Page preview will be here.
<app-editor [pageId]="pageId" *ngIf="selectedVersion" [hosted]="true" [readonly]="true" #editor></app-editor>
</div>
</div>
</div>

View File

@ -23,7 +23,7 @@
.contents {
height: 100%;
overflow-y: scroll;
overflow-y: hidden;
display: flex;
flex-direction: row;
@ -35,6 +35,8 @@
.preview {
flex: 1;
height: 100%;
overflow-y: scroll;
}
.version-date {

View File

@ -1,7 +1,8 @@
import {Component, Input, OnInit} from '@angular/core';
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {AlertController, ModalController} from '@ionic/angular';
import {EditorService} from '../../service/editor.service';
import {PageVersionRecord} from '../../structures/PageRecord';
import {EditorPage} from '../../pages/editor/editor.page';
@Component({
selector: 'app-version-modal',
@ -10,6 +11,8 @@ import {PageVersionRecord} from '../../structures/PageRecord';
})
export class VersionModalComponent implements OnInit {
@Input() pageId: string;
@ViewChild('editor') editor: EditorPage;
public pageVersions: PageVersionRecord[] = [];
public selectedVersion?: PageVersionRecord;
@ -23,7 +26,10 @@ export class VersionModalComponent implements OnInit {
async ngOnInit() {
this.pageVersions = await this.editorService.loadPageVersions(this.pageId);
await this.onVersionClick(this.pageVersions[0]);
this.selectedVersion = this.pageVersions[0];
setTimeout(() => {
this.onVersionClick(this.pageVersions[0]);
}, 100);
}
dismiss() {
@ -32,5 +38,8 @@ export class VersionModalComponent implements OnInit {
async onVersionClick(version: PageVersionRecord) {
this.selectedVersion = version;
if ( this.editor ) {
this.editor.ionViewDidEnter();
}
}
}

View File

@ -1,22 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { EditorPageRoutingModule } from './editor-routing.module';
import { EditorPage } from './editor.page';
import {ComponentsModule} from '../../components/components.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
EditorPageRoutingModule,
ComponentsModule
],
declarations: [EditorPage]
})
export class EditorPageModule {}

View File

@ -7,6 +7,7 @@
<ion-title #titleBar>
<ion-input
[(ngModel)]="editorService.mutablePageName"
[readonly]="!editorService.canEdit()"
placeholder="Click to edit page name..."
class="title-input"
></ion-input>
@ -43,7 +44,7 @@
>
<div class="host-icons">
<i class="type-icon fa" [ngClass]="typeIcons[(node.isNorm() ? 'node' : node.type)] + ' ' + (node.isNorm() ? 'node' : node.type)"></i>
<button (click)="onOptionsClick($event, node)">
<button (click)="onOptionsClick($event, node)" *ngIf="editorService.canEdit()">
<i class="fa fa-ellipsis-v" title="Node options"></i>
</button>
</div>
@ -63,7 +64,7 @@
<editor-files style="flex: 1;" [nodeId]="node.UUID" [editorUUID]="editorService.instanceUUID"></editor-files>
</ng-container>
</div>
<button class="host-add-button" (click)="onAddClick($event)">
<button *ngIf="editorService.canEdit()" class="host-add-button" (click)="onAddClick($event)">
<i class="fa fa-plus"></i> Add Node
</button>
</div>

View File

@ -17,6 +17,17 @@ import {VersionModalComponent} from '../../components/version-modal/version-moda
export class EditorPage implements OnInit {
public typeIcons = NodeTypeIcons;
@Input() pageId: string;
@Input() hosted = false;
@Input() version?: number;
@Input()
set readonly(val: boolean) {
this.editorService.forceReadonly = val;
}
get readonly() {
return this.editorService.forceReadonly;
}
constructor(
protected route: ActivatedRoute,
@ -39,7 +50,7 @@ export class EditorPage implements OnInit {
ionViewDidEnter() {
if ( this.pageId ) {
this.editorService.startEditing(this.pageId);
} else {
} else if ( !this.hosted ) {
this.router.navigate(['/home']);
}
}

View File

@ -1,10 +0,0 @@
export interface RedirectAction {
type: 'redirect';
args: {
destination: string
blank?: boolean
appUrl?: boolean
};
}
export type Action = RedirectAction;

View File

@ -1,27 +0,0 @@
import { Injectable } from '@angular/core';
import { Action } from './action.types';
import {SessionService} from './session.service';
@Injectable({
providedIn: 'root'
})
export class ActionsService {
constructor(
protected readonly session: SessionService,
) { }
async perform(action: Action) {
if ( action.type === 'redirect' ) {
let destination = action.args.destination;
if ( action.args.appUrl ) {
destination = this.session.buildAppUrl(destination);
}
if ( action.args.blank ) {
window.open(destination, '_blank');
} else {
window.location.href = destination;
}
}
}
}

View File

@ -31,6 +31,7 @@ export class EditorService {
protected ready$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
protected subs: Subscription[] = [];
protected saving = false;
public forceReadonly = false;
protected saveTriggered = false;
public notAvailable = false;
public readonly instanceUUID: string;
@ -139,7 +140,7 @@ export class EditorService {
}
async save() {
if ( !(await this.needsSave()) || this.saving ) {
if ( !(await this.needsSave()) || this.saving || this.forceReadonly ) {
return;
}
@ -170,6 +171,10 @@ export class EditorService {
throw new NoPageLoadedError();
}
if ( this.forceReadonly ) {
return;
}
const nodeIndex = this.currentNodes.findIndex(maybeNode => maybeNode.UUID === node.UUID);
if ( nodeIndex < 0 ) {
return;
@ -417,6 +422,10 @@ export class EditorService {
}
async needsSave() {
if ( this.forceReadonly ) {
return false;
}
if ( this.dirtyOverride ) {
return true;
}
@ -432,6 +441,10 @@ export class EditorService {
throw new NoPageLoadedError();
}
if ( this.forceReadonly ) {
return;
}
const node = this.currentNodes.find(maybeNode => maybeNode.UUID === nodeId);
if ( !node ) {
throw new Error('Invalid node ID.');
@ -463,6 +476,10 @@ export class EditorService {
throw new NoPageLoadedError();
}
if ( this.forceReadonly ) {
return;
}
const baseHost = new HostRecord();
baseHost.type = type;
baseHost.PageId = this.currentPage.UUID;
@ -495,11 +512,7 @@ export class EditorService {
}
canEdit() {
if ( !this.currentPage ) {
throw new NoPageLoadedError();
}
return !this.currentPage.isViewOnly();
return this.currentPage && !this.currentPage.isViewOnly() && !this.forceReadonly;
}
async registerNodeEditor(nodeId: string, editor: EditorNodeContract) {

View File

@ -1,74 +0,0 @@
import {Host, Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import PageRecord from '../structures/PageRecord';
import {ApiService} from './api.service';
import HostRecord from '../structures/HostRecord';
@Injectable({
providedIn: 'root'
})
export class PageService {
constructor(
protected api: ApiService,
) { }
load(id: string): Observable<PageRecord> {
return new Observable<PageRecord>(sub => {
this.api.get(`/page/${id}`).subscribe(response => {
if ( response.status === 200 ) {
sub.next(new PageRecord(response.data));
sub.complete();
} else {
throw new Error(response.message);
}
});
});
}
save(page: PageRecord): Observable<PageRecord> {
return new Observable<PageRecord>(sub => {
this.api.post(`/page/${page.UUID}/save`, page.toSave()).subscribe(res => {
sub.next(new PageRecord(res.data));
sub.complete();
});
});
}
get_nodes(page: PageRecord): Observable<Array<HostRecord>> {
return new Observable<Array<HostRecord>>(sub => {
this.api.get(`/page/${page.UUID}/nodes`).subscribe(res => {
const returns = [];
res.data.forEach(rec => {
const host = new HostRecord(rec.Value.Value);
host.load(rec);
returns.push(host);
});
sub.next(returns);
sub.complete();
});
});
}
save_nodes(page: PageRecord, nodes: Array<HostRecord>): Observable<Array<HostRecord>> {
return new Observable<Array<HostRecord>>(sub => {
nodes = nodes.map(x => {
x.PageId = page.UUID;
return x.toSave();
});
this.api.post(`/page/${page.UUID}/nodes/save`, nodes).subscribe(res => {
const returns = [];
res.data.forEach(rec => {
const host = new HostRecord(rec.Value.Value);
host.load(rec);
returns.push(host);
});
sub.next(returns);
sub.complete();
});
});
}
}