mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 10:35:18 +00:00
FE-821: Added domain object review module (#76)
This commit is contained in:
parent
20a4485903
commit
9b6fa61686
14
src/app/domain/domain-modification-model.ts
Normal file
14
src/app/domain/domain-modification-model.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Reference } from '../gen-damsel/domain';
|
||||||
|
import { MetaStruct, MetaUnion } from '../damsel-meta';
|
||||||
|
|
||||||
|
export interface ModificationItem {
|
||||||
|
monacoContent: string;
|
||||||
|
meta: MetaStruct | MetaUnion;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DomainModificationModel {
|
||||||
|
ref: Reference;
|
||||||
|
objectType: string;
|
||||||
|
original: ModificationItem;
|
||||||
|
modified: ModificationItem;
|
||||||
|
}
|
@ -1,26 +1,30 @@
|
|||||||
<cc-card-container>
|
<div class="editor-container">
|
||||||
<div>
|
|
||||||
<button mat-button routerLink="/domain">
|
|
||||||
<mat-icon aria-label="Login">keyboard_arrow_left</mat-icon>
|
|
||||||
BACK TO DOMAIN
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="isLoading" fxLayout fxLayoutAlign="center stretch"><mat-spinner></mat-spinner></div>
|
<div *ngIf="isLoading" fxLayout fxLayoutAlign="center stretch"><mat-spinner></mat-spinner></div>
|
||||||
<mat-card *ngIf="initialized">
|
<mat-card *ngIf="initialized">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<mat-card-subtitle>{{ objectType }}</mat-card-subtitle>
|
<mat-card-title>Edit {{ model.objectType }}</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<cc-monaco-editor
|
<cc-monaco-editor
|
||||||
[file]="file"
|
class="editor"
|
||||||
|
[file]="modifiedFile"
|
||||||
(fileChange)="fileChange($event)"
|
(fileChange)="fileChange($event)"
|
||||||
[options]="options"
|
|
||||||
[codeLensProviders]="codeLensProviders"
|
[codeLensProviders]="codeLensProviders"
|
||||||
[completionProviders]="completionProviders"
|
[completionProviders]="completionProviders"
|
||||||
></cc-monaco-editor>
|
></cc-monaco-editor>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button mat-button [disabled]="!valid">COMMIT</button>
|
<div fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
<button mat-button routerLink="/domain">
|
||||||
|
<mat-icon aria-label="Login">keyboard_arrow_left</mat-icon>
|
||||||
|
BACK TO DOMAIN
|
||||||
|
</button>
|
||||||
|
<button mat-button color="warn" (click)="resetChanges()">RESET CHANGES</button>
|
||||||
|
<button mat-button (click)="reviewChanges()">
|
||||||
|
REVIEW CHANGES
|
||||||
|
<mat-icon aria-label="Login">keyboard_arrow_right</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</cc-card-container>
|
</div>
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
cc-monaco-editor {
|
|
||||||
display: block;
|
|
||||||
height: calc(100vh - 250px);
|
|
||||||
}
|
|
@ -1,69 +1,88 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material';
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
import {
|
import { MonacoFile, CodeLensProvider, CompletionProvider } from '../../monaco-editor/model';
|
||||||
IEditorOptions,
|
|
||||||
MonacoFile,
|
|
||||||
CodeLensProvider,
|
|
||||||
CompletionProvider
|
|
||||||
} from '../../monaco-editor/model';
|
|
||||||
import { DomainObjModificationService } from './domain-obj-modification.service';
|
import { DomainObjModificationService } from './domain-obj-modification.service';
|
||||||
import { DomainObjCodeLensProvider } from './domain-obj-code-lens-provider';
|
import { DomainObjCodeLensProvider } from './domain-obj-code-lens-provider';
|
||||||
import { DomainObjCompletionProvider } from './domain-obj-completion-provider';
|
import { DomainObjCompletionProvider } from './domain-obj-completion-provider';
|
||||||
|
import { DomainReviewService } from '../domain-review.service';
|
||||||
|
import { toMonacoFile } from '../utils';
|
||||||
|
import { DomainModificationModel } from '../domain-modification-model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './domain-obj-modification.component.html',
|
templateUrl: './domain-obj-modification.component.html',
|
||||||
styleUrls: ['domain-obj-modification.component.scss'],
|
styleUrls: ['../editor-container.scss'],
|
||||||
providers: [DomainObjModificationService]
|
providers: [DomainObjModificationService]
|
||||||
})
|
})
|
||||||
export class DomainObjModificationComponent implements OnInit {
|
export class DomainObjModificationComponent implements OnInit, OnDestroy {
|
||||||
initialized = false;
|
initialized = false;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
file: MonacoFile;
|
|
||||||
options: IEditorOptions = {
|
|
||||||
readOnly: false
|
|
||||||
};
|
|
||||||
objectType: string;
|
|
||||||
valid = false;
|
valid = false;
|
||||||
codeLensProviders: CodeLensProvider[];
|
codeLensProviders: CodeLensProvider[];
|
||||||
completionProviders: CompletionProvider[];
|
completionProviders: CompletionProvider[];
|
||||||
|
modifiedFile: MonacoFile;
|
||||||
|
|
||||||
|
private model: DomainModificationModel;
|
||||||
|
private initSub: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private router: Router,
|
||||||
private snackBar: MatSnackBar,
|
private snackBar: MatSnackBar,
|
||||||
private domainObjModificationService: DomainObjModificationService
|
private domainObjModService: DomainObjModificationService,
|
||||||
) {
|
private domainReviewService: DomainReviewService
|
||||||
this.domainObjModificationService.valueValid.subscribe(v => (this.valid = v));
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.initialize();
|
this.initSub = this.initialize();
|
||||||
this.codeLensProviders = [new DomainObjCodeLensProvider()];
|
this.codeLensProviders = [new DomainObjCodeLensProvider()];
|
||||||
this.completionProviders = [new DomainObjCompletionProvider()];
|
this.completionProviders = [new DomainObjCompletionProvider()];
|
||||||
}
|
}
|
||||||
|
|
||||||
fileChange({ content }: MonacoFile) {
|
ngOnDestroy() {
|
||||||
const meta = this.domainObjModificationService.applyValue(content);
|
if (this.initSub) {
|
||||||
console.log('BUILDED', meta);
|
this.initSub.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initialize() {
|
fileChange({ content }: MonacoFile) {
|
||||||
|
const { valid, payload } = this.domainObjModService.applyValue(
|
||||||
|
this.model.modified.meta,
|
||||||
|
content
|
||||||
|
);
|
||||||
|
this.valid = valid;
|
||||||
|
if (valid) {
|
||||||
|
this.model.modified = {
|
||||||
|
meta: payload,
|
||||||
|
monacoContent: content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reviewChanges() {
|
||||||
|
this.domainReviewService.addReviewModel(this.model);
|
||||||
|
this.router.navigate(['domain', JSON.stringify(this.model.ref), 'review']);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetChanges() {
|
||||||
|
this.model = this.domainObjModService.reset(this.model);
|
||||||
|
this.modifiedFile = toMonacoFile(this.model.modified.monacoContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize(): Subscription {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.domainObjModificationService.initialize().subscribe(
|
return this.domainObjModService.init().subscribe(
|
||||||
({ file, objectType }) => {
|
model => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.file = file;
|
this.model = model;
|
||||||
this.objectType = objectType;
|
this.modifiedFile = toMonacoFile(model.modified.monacoContent);
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.snackBar
|
this.snackBar.open(`An error occurred while initializing: ${err}`, 'OK');
|
||||||
.open(`An error occurred while initializing: ${err}`, 'RETRY', {
|
|
||||||
duration: 10000
|
|
||||||
})
|
|
||||||
.onAction()
|
|
||||||
.subscribe(() => this.initialize());
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,34 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable, combineLatest, Subject, BehaviorSubject } from 'rxjs';
|
import { Observable, combineLatest, Subject, of } from 'rxjs';
|
||||||
import { map, switchMap, tap } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
|
import cloneDeep from 'lodash-es/cloneDeep';
|
||||||
|
|
||||||
import { DomainObject, Reference } from '../../gen-damsel/domain';
|
import { DomainObject, Reference } from '../../gen-damsel/domain';
|
||||||
import { MetadataService } from '../metadata.service';
|
import { MetadataService } from '../metadata.service';
|
||||||
import { DomainService } from '../domain.service';
|
import { DomainService } from '../domain.service';
|
||||||
import { toJson } from '../../shared/thrift-json-converter';
|
|
||||||
import { extract } from '../../shared/thrift-utils';
|
|
||||||
import { MonacoFile } from '../../monaco-editor/model';
|
|
||||||
import { MetaBuilder } from '../../damsel-meta/meta-builder.service';
|
import { MetaBuilder } from '../../damsel-meta/meta-builder.service';
|
||||||
import { MetaStruct, MetaUnion } from '../../damsel-meta/model';
|
import { MetaStruct, MetaUnion, MetaPayload } from '../../damsel-meta/model';
|
||||||
import { ModificationPayload } from './modification-payload';
|
|
||||||
import { MetaApplicator } from '../../damsel-meta/meta-applicator.service';
|
import { MetaApplicator } from '../../damsel-meta/meta-applicator.service';
|
||||||
|
import { toMonacoContent, parseRef } from '../utils';
|
||||||
|
import { DomainReviewService } from '../domain-review.service';
|
||||||
|
import { DomainModificationModel } from '../domain-modification-model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomainObjModificationService {
|
export class DomainObjModificationService {
|
||||||
private meta: MetaStruct | MetaUnion;
|
|
||||||
private errors$: Subject<string> = new Subject();
|
private errors$: Subject<string> = new Subject();
|
||||||
private valueValid$: Subject<boolean> = new BehaviorSubject(false);
|
|
||||||
|
|
||||||
get errors(): Observable<string> {
|
get errors(): Observable<string> {
|
||||||
return this.errors$;
|
return this.errors$;
|
||||||
}
|
}
|
||||||
|
|
||||||
get valueValid(): Observable<boolean> {
|
|
||||||
return this.valueValid$;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private domainService: DomainService,
|
private domainService: DomainService,
|
||||||
private metadataService: MetadataService,
|
private metadataService: MetadataService,
|
||||||
private metaBuilder: MetaBuilder,
|
private metaBuilder: MetaBuilder,
|
||||||
private metaApplicator: MetaApplicator
|
private metaApplicator: MetaApplicator,
|
||||||
|
private domainReviewService: DomainReviewService
|
||||||
) {
|
) {
|
||||||
this.metaBuilder.errors.subscribe(e => {
|
this.metaBuilder.errors.subscribe(e => {
|
||||||
this.errors$.next(e);
|
this.errors$.next(e);
|
||||||
@ -42,29 +37,40 @@ export class DomainObjModificationService {
|
|||||||
this.metaApplicator.errors.subscribe(e => console.log('Apply meta error:', e));
|
this.metaApplicator.errors.subscribe(e => console.log('Apply meta error:', e));
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(namespace = 'domain'): Observable<ModificationPayload> {
|
init(namespace = 'domain'): Observable<DomainModificationModel> {
|
||||||
return this.route.params.pipe(
|
return combineLatest(this.route.params, this.domainReviewService.reviewModel).pipe(
|
||||||
map(({ ref }) => this.parseParams(ref)),
|
switchMap(([routeParams, model]) => {
|
||||||
switchMap(ref =>
|
if (model && JSON.stringify(model.ref) === routeParams.ref) {
|
||||||
combineLatest(
|
return of(model);
|
||||||
|
}
|
||||||
|
const ref = parseRef(routeParams.ref);
|
||||||
|
return combineLatest(
|
||||||
this.metadataService.getDomainObjectType(ref),
|
this.metadataService.getDomainObjectType(ref),
|
||||||
this.domainService.getDomainObject(ref)
|
this.domainService.getDomainObject(ref)
|
||||||
|
).pipe(
|
||||||
|
switchMap(([objectType, domainObj]) =>
|
||||||
|
this.build(ref, objectType, domainObj, namespace)
|
||||||
)
|
)
|
||||||
),
|
);
|
||||||
switchMap(([objectType, domainObj]) => this.buildMeta(objectType, domainObj, namespace))
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyValue(json: string): MetaStruct | MetaUnion | null {
|
applyValue(meta: MetaStruct | MetaUnion, json: string): MetaPayload {
|
||||||
if (!this.meta) {
|
return this.metaApplicator.apply(meta, json);
|
||||||
throw new Error('Service is not initialized');
|
|
||||||
}
|
|
||||||
const result = this.metaApplicator.apply(this.meta, json);
|
|
||||||
this.valueValid$.next(result.valid);
|
|
||||||
return result.payload;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildMeta(objectType, domainObj, namespace) {
|
reset(model: DomainModificationModel): DomainModificationModel {
|
||||||
|
model.modified = cloneDeep(model.original);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private build(
|
||||||
|
ref: Reference,
|
||||||
|
objectType: string,
|
||||||
|
domainObj: DomainObject,
|
||||||
|
namespace: string
|
||||||
|
): Observable<DomainModificationModel> {
|
||||||
if (!objectType) {
|
if (!objectType) {
|
||||||
throw new Error('Domain object type not found');
|
throw new Error('Domain object type not found');
|
||||||
}
|
}
|
||||||
@ -72,32 +78,26 @@ export class DomainObjModificationService {
|
|||||||
throw new Error('Domain object not found');
|
throw new Error('Domain object not found');
|
||||||
}
|
}
|
||||||
return this.metaBuilder.build(objectType, namespace).pipe(
|
return this.metaBuilder.build(objectType, namespace).pipe(
|
||||||
tap(({ payload, valid }) => {
|
map(({ payload, valid }) => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new Error('Build meta failed');
|
throw new Error('Build initial meta failed');
|
||||||
}
|
}
|
||||||
this.meta = payload;
|
const monacoContent = toMonacoContent(domainObj);
|
||||||
}),
|
const applyResult = this.metaApplicator.apply(payload, monacoContent);
|
||||||
map(() => ({
|
if (!applyResult.valid) {
|
||||||
file: this.toMonacoFile(domainObj),
|
throw new Error('Apply original value failed');
|
||||||
|
}
|
||||||
|
const reviewItem = {
|
||||||
|
monacoContent,
|
||||||
|
meta: applyResult.payload
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
ref,
|
||||||
|
original: cloneDeep(reviewItem),
|
||||||
|
modified: reviewItem,
|
||||||
objectType
|
objectType
|
||||||
}))
|
};
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseParams(ref: string): Reference {
|
|
||||||
try {
|
|
||||||
return JSON.parse(ref);
|
|
||||||
} catch {
|
|
||||||
throw new Error('Malformed domain object ref');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private toMonacoFile(domainObj: DomainObject | null): MonacoFile {
|
|
||||||
return {
|
|
||||||
uri: 'index.json',
|
|
||||||
language: 'json',
|
|
||||||
content: JSON.stringify(toJson(extract(domainObj)), null, 2)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import { MonacoFile } from '../../monaco-editor/model';
|
|
||||||
|
|
||||||
export interface ModificationPayload {
|
|
||||||
file: MonacoFile;
|
|
||||||
objectType: string;
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
<div class="editor-container">
|
||||||
|
<mat-card *ngIf="initialized">
|
||||||
|
<mat-card-header fxLayout="row" fxLayoutAlign="space-between stretch">
|
||||||
|
<mat-card-title>Review changes of {{ objectType }}</mat-card-title>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox
|
||||||
|
[checked]="options.renderSideBySide"
|
||||||
|
(change)="renderSideBySide($event)"
|
||||||
|
>Side by side</mat-checkbox
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<cc-monaco-diff-editor
|
||||||
|
class="editor"
|
||||||
|
[options]="options"
|
||||||
|
[original]="original"
|
||||||
|
[modified]="modified"
|
||||||
|
></cc-monaco-diff-editor>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
<button mat-button (click)="back()">
|
||||||
|
<mat-icon>keyboard_arrow_left</mat-icon>
|
||||||
|
BACK TO EDIT
|
||||||
|
</button>
|
||||||
|
<button mat-button color="primary">COMMIT</button>
|
||||||
|
</div>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card *ngIf="!initialized">
|
||||||
|
Nothing to review
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button (click)="back()">
|
||||||
|
<mat-icon>keyboard_arrow_left</mat-icon>
|
||||||
|
BACK TO EDIT
|
||||||
|
</button></mat-card-actions
|
||||||
|
>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { MatCheckboxChange } from '@angular/material';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
import { MonacoFile, IDiffEditorOptions } from '../../monaco-editor/model';
|
||||||
|
import { DomainReviewService } from '../domain-review.service';
|
||||||
|
import { toMonacoFile } from '../utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './domain-obj-review.component.html',
|
||||||
|
styleUrls: ['../editor-container.scss']
|
||||||
|
})
|
||||||
|
export class DomainObjReviewComponent implements OnInit, OnDestroy {
|
||||||
|
initialized = false;
|
||||||
|
original: MonacoFile;
|
||||||
|
modified: MonacoFile;
|
||||||
|
objectType: string;
|
||||||
|
options: IDiffEditorOptions = {
|
||||||
|
renderSideBySide: true
|
||||||
|
};
|
||||||
|
|
||||||
|
private ref: string;
|
||||||
|
private reviewModelSub: Subscription;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private domainReviewService: DomainReviewService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.reviewModelSub) {
|
||||||
|
this.reviewModelSub.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
back() {
|
||||||
|
this.router.navigate(['domain', this.ref]);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSideBySide(e: MatCheckboxChange) {
|
||||||
|
this.options = { ...this.options, renderSideBySide: e.checked };
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize() {
|
||||||
|
this.route.params.subscribe(({ ref }) => (this.ref = ref));
|
||||||
|
this.reviewModelSub = this.domainReviewService.reviewModel.subscribe(model => {
|
||||||
|
if (!model) {
|
||||||
|
this.initialized = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.original = toMonacoFile(model.original.monacoContent);
|
||||||
|
this.modified = toMonacoFile(model.modified.monacoContent);
|
||||||
|
this.objectType = model.objectType;
|
||||||
|
this.initialized = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
31
src/app/domain/domain-obj-review/domain-obj-review.module.ts
Normal file
31
src/app/domain/domain-obj-review/domain-obj-review.module.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import {
|
||||||
|
MatCardModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatCheckboxModule
|
||||||
|
} from '@angular/material';
|
||||||
|
|
||||||
|
import { DomainObjReviewComponent } from './domain-obj-review.component';
|
||||||
|
import { MonacoEditorModule } from '../../monaco-editor/monaco-editor.module';
|
||||||
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [DomainObjReviewComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
RouterModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MonacoEditorModule,
|
||||||
|
SharedModule,
|
||||||
|
MatIconModule
|
||||||
|
],
|
||||||
|
exports: [DomainObjReviewComponent]
|
||||||
|
})
|
||||||
|
export class DomainObjReviewModule {}
|
2
src/app/domain/domain-obj-review/index.ts
Normal file
2
src/app/domain/domain-obj-review/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './domain-obj-review.module';
|
||||||
|
export * from './domain-obj-review.component';
|
16
src/app/domain/domain-review.service.ts
Normal file
16
src/app/domain/domain-review.service.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject, Observable, BehaviorSubject } from 'rxjs';
|
||||||
|
import { DomainModificationModel } from './domain-modification-model';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DomainReviewService {
|
||||||
|
private reviewModel$: Subject<DomainModificationModel> = new BehaviorSubject(null);
|
||||||
|
|
||||||
|
get reviewModel(): Observable<DomainModificationModel> {
|
||||||
|
return this.reviewModel$;
|
||||||
|
}
|
||||||
|
|
||||||
|
addReviewModel(model: DomainModificationModel) {
|
||||||
|
this.reviewModel$.next(model);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { AppAuthGuardService } from '../app-auth-guard.service';
|
import { AppAuthGuardService } from '../app-auth-guard.service';
|
||||||
import { DomainInfoComponent } from './domain-info';
|
import { DomainInfoComponent } from './domain-info';
|
||||||
import { DomainObjModificationComponent } from './domain-obj-modification';
|
import { DomainObjModificationComponent } from './domain-obj-modification';
|
||||||
|
import { DomainObjReviewComponent } from './domain-obj-review';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -23,6 +24,14 @@ import { DomainObjModificationComponent } from './domain-obj-modification';
|
|||||||
data: {
|
data: {
|
||||||
roles: ['dmt:checkout']
|
roles: ['dmt:checkout']
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'domain/:ref/review',
|
||||||
|
component: DomainObjReviewComponent,
|
||||||
|
canActivate: [AppAuthGuardService],
|
||||||
|
data: {
|
||||||
|
roles: ['dmt:checkout']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
@ -6,9 +6,17 @@ import { MetadataService } from './metadata.service';
|
|||||||
import { DomainObjModificationModule } from './domain-obj-modification';
|
import { DomainObjModificationModule } from './domain-obj-modification';
|
||||||
import { DomainInfoModule } from './domain-info/domain-info.module';
|
import { DomainInfoModule } from './domain-info/domain-info.module';
|
||||||
import { DamselMetaModule } from '../damsel-meta/damsel-meta.module';
|
import { DamselMetaModule } from '../damsel-meta/damsel-meta.module';
|
||||||
|
import { DomainObjReviewModule } from './domain-obj-review';
|
||||||
|
import { DomainReviewService } from './domain-review.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [DomainRoutingModule, DomainInfoModule, DomainObjModificationModule, DamselMetaModule],
|
imports: [
|
||||||
providers: [DomainService, MetadataService]
|
DomainRoutingModule,
|
||||||
|
DomainInfoModule,
|
||||||
|
DomainObjModificationModule,
|
||||||
|
DomainObjReviewModule,
|
||||||
|
DamselMetaModule
|
||||||
|
],
|
||||||
|
providers: [DomainService, MetadataService, DomainReviewService]
|
||||||
})
|
})
|
||||||
export class DomainModule {}
|
export class DomainModule {}
|
||||||
|
8
src/app/domain/editor-container.scss
Normal file
8
src/app/domain/editor-container.scss
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.editor {
|
||||||
|
display: block;
|
||||||
|
height: calc(100vh - 200px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
23
src/app/domain/utils.ts
Normal file
23
src/app/domain/utils.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import * as uuid from 'uuid/v4';
|
||||||
|
|
||||||
|
import { Reference, DomainObject } from '../gen-damsel/domain';
|
||||||
|
import { MonacoFile } from '../monaco-editor';
|
||||||
|
import { toJson } from '../shared/thrift-json-converter';
|
||||||
|
import { extract } from '../shared/thrift-utils';
|
||||||
|
|
||||||
|
export function parseRef(ref: string): Reference {
|
||||||
|
try {
|
||||||
|
return JSON.parse(ref);
|
||||||
|
} catch {
|
||||||
|
throw new Error('Malformed domain object ref');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toMonacoFile = (content: string): MonacoFile => ({
|
||||||
|
uri: `${uuid()}.json`,
|
||||||
|
language: 'json',
|
||||||
|
content
|
||||||
|
});
|
||||||
|
|
||||||
|
export const toMonacoContent = (domainObj: DomainObject): string =>
|
||||||
|
JSON.stringify(toJson(extract(domainObj)), null, 2);
|
@ -1,4 +1,5 @@
|
|||||||
export type IEditorOptions = monaco.editor.IEditorOptions;
|
export type IEditorOptions = monaco.editor.IEditorOptions;
|
||||||
|
export type IDiffEditorOptions = monaco.editor.IDiffEditorOptions;
|
||||||
export type ITextModel = monaco.editor.ITextModel;
|
export type ITextModel = monaco.editor.ITextModel;
|
||||||
export type CancellationToken = monaco.CancellationToken;
|
export type CancellationToken = monaco.CancellationToken;
|
||||||
export type ProviderResult<T> = monaco.languages.ProviderResult<T>;
|
export type ProviderResult<T> = monaco.languages.ProviderResult<T>;
|
||||||
|
Loading…
Reference in New Issue
Block a user