mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-04-09 11:31:15 +00:00
Project readme support
This commit is contained in:
parent
8d795ebf10
commit
20f0b06a77
@ -67,6 +67,7 @@
|
||||
"d3-ng2-service": "^2.1.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"ini": "^1.3.5",
|
||||
"marked": "^1.1.1",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"ng-circle-progress": "^1.5.1",
|
||||
"ng2-file-upload": "^1.3.0",
|
||||
|
@ -279,6 +279,8 @@ import { ChangeHostnameActionComponent } from './components/project-map/context-
|
||||
import { ChangeHostnameDialogComponent } from './components/project-map/change-hostname-dialog/change-hostname-dialog.component';
|
||||
import { ApplianceInfoDialogComponent } from './components/project-map/new-template-dialog/appliance-info-dialog/appliance-info-dialog.component';
|
||||
import { ResetLinkActionComponent } from './components/project-map/context-menu/actions/reset-link/reset-link-action.component';
|
||||
import { ReadmeEditorComponent } from './components/projects/edit-project-dialog/readme-editor/readme-editor.component';
|
||||
import { MarkedDirective } from './directives/marked.directive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -462,7 +464,9 @@ import { ResetLinkActionComponent } from './components/project-map/context-menu/
|
||||
NewTemplateDialogComponent,
|
||||
ChangeHostnameActionComponent,
|
||||
ChangeHostnameDialogComponent,
|
||||
ApplianceInfoDialogComponent
|
||||
ApplianceInfoDialogComponent,
|
||||
ReadmeEditorComponent,
|
||||
MarkedDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -41,6 +41,11 @@
|
||||
Show interface labels at start
|
||||
</mat-checkbox>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Readme" *ngIf="server && project">
|
||||
<app-readme-editor #editor [server]="server" [project]="project"></app-readme-editor>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Global variables">
|
||||
<form [formGroup]="variableFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, Injectable } from '@angular/core';
|
||||
import { Component, OnInit, Injectable, ViewChild } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||
import { Server } from '../../../models/server';
|
||||
@ -6,6 +6,7 @@ import { Project, ProjectVariable } from '../../../models/project';
|
||||
import { ToasterService } from '../../../services/toaster.service';
|
||||
import { NonNegativeValidator } from '../../../validators/non-negative-validator';
|
||||
import { ProjectService } from '../../../services/project.service';
|
||||
import { ReadmeEditorComponent } from './readme-editor/readme-editor.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-project-dialog',
|
||||
@ -13,6 +14,8 @@ import { ProjectService } from '../../../services/project.service';
|
||||
styleUrls: ['./edit-project-dialog.component.scss']
|
||||
})
|
||||
export class EditProjectDialogComponent implements OnInit {
|
||||
@ViewChild('editor') editor: ReadmeEditorComponent;
|
||||
|
||||
server: Server;
|
||||
project: Project;
|
||||
formGroup: FormGroup;
|
||||
@ -89,8 +92,10 @@ export class EditProjectDialogComponent implements OnInit {
|
||||
this.project.auto_close = !this.project.auto_close;
|
||||
|
||||
this.projectService.update(this.server, this.project).subscribe((project: Project) => {
|
||||
this.toasterService.success(`Project ${project.name} updated.`);
|
||||
this.onNoClick();
|
||||
this.projectService.postReadmeFile(this.server, this.project.project_id, this.editor.markdown).subscribe((response) => {
|
||||
this.toasterService.success(`Project ${project.name} updated.`);
|
||||
this.onNoClick();
|
||||
});
|
||||
})
|
||||
} else {
|
||||
this.toasterService.error(`Fill all required fields with correct values.`);
|
||||
|
@ -0,0 +1,11 @@
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Write">
|
||||
<textarea class="editorWrapper" matInput type="text" [(ngModel)]="markdown"></textarea>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Preview">
|
||||
<span *ngIf="markdown">
|
||||
<div class="textWrapper" appMarked text={{markdown}}></div>
|
||||
</span>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
@ -0,0 +1,12 @@
|
||||
.textWrapper {
|
||||
background-color: white;
|
||||
height: 500px!important;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.editorWrapper {
|
||||
background-color: white;
|
||||
color: black;
|
||||
height: 500px!important;
|
||||
overflow-y: scroll;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { Component, OnInit, ViewEncapsulation, Input } from '@angular/core';
|
||||
import * as marked from 'marked';
|
||||
import { ProjectService } from '../../../../services/project.service';
|
||||
import { Server } from '../../../../models/server';
|
||||
import { Project } from '../../../../models/project';
|
||||
|
||||
@Component({
|
||||
selector: 'app-readme-editor',
|
||||
templateUrl: './readme-editor.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
styleUrls: ['./readme-editor.component.scss']
|
||||
})
|
||||
export class ReadmeEditorComponent implements OnInit {
|
||||
@Input() server: Server;
|
||||
@Input() project: Project;
|
||||
|
||||
public markdown = ``;
|
||||
|
||||
constructor(
|
||||
private projectService: ProjectService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.projectService.getReadmeFile(this.server, this.project.project_id).subscribe(file => {
|
||||
if (file) this.markdown = file;
|
||||
});
|
||||
}
|
||||
}
|
29
src/app/directives/marked.directive.ts
Normal file
29
src/app/directives/marked.directive.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Directive, ElementRef, OnInit, Renderer2, Input, OnChanges } from '@angular/core';
|
||||
import * as marked from 'marked';
|
||||
|
||||
@Directive({
|
||||
selector: '[appMarked]'
|
||||
})
|
||||
export class MarkedDirective implements OnInit, OnChanges {
|
||||
@Input() text: string;
|
||||
|
||||
constructor(private elementRef: ElementRef,
|
||||
private renderer: Renderer2) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
updateText() {
|
||||
const markText = this.text;
|
||||
|
||||
if (markText && markText.length > 0) {
|
||||
const markdownHtml = marked(markText);
|
||||
this.renderer.setProperty(this.elementRef.nativeElement, 'innerHTML', markdownHtml);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,14 @@ export class ProjectService {
|
||||
this.projectListSubject.next(true);
|
||||
}
|
||||
|
||||
getReadmeFile(server: Server, project_id: string) {
|
||||
return this.httpServer.get<any>(server, `/projects/${project_id}/files/README.txt`);
|
||||
}
|
||||
|
||||
postReadmeFile(server: Server, project_id: string, readme: string) {
|
||||
return this.httpServer.post<any>(server, `/projects/${project_id}/files/README.txt`, readme);
|
||||
}
|
||||
|
||||
get(server: Server, project_id: string) {
|
||||
return this.httpServer.get<Project>(server, `/projects/${project_id}`);
|
||||
}
|
||||
|
@ -7958,6 +7958,11 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
marked@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-1.1.1.tgz#e5d61b69842210d5df57b05856e0c91572703e6a"
|
||||
integrity sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==
|
||||
|
||||
matcher@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
|
||||
|
Loading…
x
Reference in New Issue
Block a user