mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-02-22 10:20:48 +00:00
Fix for icons on map
This commit is contained in:
parent
96919f8c05
commit
350ed9a4aa
@ -204,6 +204,7 @@ import { TemplateComponent } from './components/template/template.component';
|
||||
import { TopologySummaryComponent } from './components/topology-summary/topology-summary.component';
|
||||
import { WebConsoleFullWindowComponent } from './components/web-console-full-window/web-console-full-window.component';
|
||||
import { DataSourceFilter } from './filters/dataSourceFilter';
|
||||
import { AuthImageFilter } from './filters/authImageFilter';
|
||||
import { DateFilter } from './filters/dateFilter.pipe';
|
||||
import { NameFilter } from './filters/nameFilter.pipe';
|
||||
import { ProjectsFilter } from './filters/projectsFilter.pipe';
|
||||
@ -381,6 +382,7 @@ import { HttpRequestsInterceptor } from './interceptors/http.interceptor';
|
||||
DataSourceFilter,
|
||||
TemplateFilter,
|
||||
ProjectsFilter,
|
||||
AuthImageFilter,
|
||||
ListOfSnapshotsComponent,
|
||||
CustomAdaptersComponent,
|
||||
NodesMenuComponent,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { SymbolService } from '../../services/symbol.service';
|
||||
import { event, select } from 'd3-selection';
|
||||
import { MapSettingsService } from '../../services/mapsettings.service';
|
||||
import { ClickedDataEvent } from '../events/event-source';
|
||||
@ -22,7 +23,8 @@ export class NodeWidget implements Widget {
|
||||
private selectionManager: SelectionManager,
|
||||
private labelWidget: LabelWidget,
|
||||
private nodesEventSource: NodesEventSource,
|
||||
private mapSettingsService: MapSettingsService
|
||||
private mapSettingsService: MapSettingsService,
|
||||
private symbolService: SymbolService
|
||||
) {}
|
||||
|
||||
public draw(view: SVGSelection) {
|
||||
@ -88,7 +90,13 @@ export class NodeWidget implements Widget {
|
||||
event.preventDefault();
|
||||
self.onContextConsoleMenu.emit(new NodeContextMenu(event, n));
|
||||
})
|
||||
.attr('xnode:href', (n: MapNode) => n.symbolUrl)
|
||||
.attr('xnode:href', (n: MapNode) => {
|
||||
let symbol = this.symbolService.get(n.symbol.split('/')[2]);
|
||||
if (symbol) {
|
||||
return 'data:image/svg+xml;base64,' + btoa(symbol.raw);
|
||||
}
|
||||
return '';
|
||||
})
|
||||
.attr('width', (n: MapNode) => {
|
||||
if (!n.width) return 60;
|
||||
return n.width;
|
||||
|
@ -32,7 +32,7 @@
|
||||
lazyimg
|
||||
[ngClass]="{ imageSelected: isSelected === symbol.symbol_id }"
|
||||
class="image"
|
||||
[src]="getImageSourceForTemplate(symbol.symbol_id)"
|
||||
[src]="getImageSourceForTemplate(symbol.symbol_id) | authImage: server | async"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div *ngIf="project" [ngClass]="{ lightTheme: isLightThemeEnabled }" class="project-map">
|
||||
<app-d3-map
|
||||
*ngIf="!settings.angular_map"
|
||||
*ngIf="!settings.angular_map && symbolsLoaded"
|
||||
[server]="server"
|
||||
[project]="project"
|
||||
[symbols]="symbols"
|
||||
|
@ -104,6 +104,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
public gridVisibility: boolean = false;
|
||||
public toolbarVisibility: boolean = true;
|
||||
public symbolScaling: boolean = true;
|
||||
public symbolsLoaded: boolean = false;
|
||||
|
||||
tools = {
|
||||
selection: true,
|
||||
@ -177,6 +178,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this.getSettings();
|
||||
this.progressService.activate();
|
||||
this.symbolService.symbolsLoaded.subscribe(loaded => {
|
||||
this.symbolsLoaded = true;
|
||||
});
|
||||
|
||||
if (this.serverService.isServiceInitialized) {
|
||||
this.getData();
|
||||
@ -297,8 +301,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
.pipe(
|
||||
mergeMap((server: Server) => {
|
||||
if (!server) this.router.navigate(['/servers']);
|
||||
|
||||
this.server = server;
|
||||
|
||||
// load symbols
|
||||
this.symbolService.load(this.server);
|
||||
|
||||
return this.projectService.get(server, paramMap.get('project_id')).pipe(
|
||||
map((project) => {
|
||||
return project;
|
||||
|
@ -43,25 +43,25 @@
|
||||
<span *ngIf="i % 4 === 0" class="templateRow">
|
||||
<span class="templateIcon">
|
||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i])">
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i])" />
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i]) | authImage: server | async" />
|
||||
</div>
|
||||
<div class="templateText">{{ filteredTemplates[i].name }}</div>
|
||||
</span>
|
||||
<span *ngIf="filteredTemplates[i + 1]" class="templateIcon">
|
||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 1])">
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 1])" />
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 1]) | authImage: server | async" />
|
||||
</div>
|
||||
<div class="templateText">{{ filteredTemplates[i + 1].name }}</div>
|
||||
</span>
|
||||
<span *ngIf="filteredTemplates[i + 2]" class="templateIcon">
|
||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 2])">
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 2])" />
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 2]) | authImage: server | async" />
|
||||
</div>
|
||||
<div class="templateText">{{ filteredTemplates[i + 2].name }}</div>
|
||||
</span>
|
||||
<span *ngIf="filteredTemplates[i + 3]" class="templateIcon">
|
||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 3])">
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 3])" />
|
||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 3]) | authImage: server | async" />
|
||||
</div>
|
||||
<div class="templateText">{{ filteredTemplates[i + 3].name }}</div>
|
||||
</span>
|
||||
|
24
src/app/filters/authImageFilter.ts
Normal file
24
src/app/filters/authImageFilter.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { Console } from 'console';
|
||||
import { Server } from '../models/server';
|
||||
import { HttpServer } from '../services/http-server.service';
|
||||
|
||||
@Pipe({
|
||||
name: 'authImage'
|
||||
})
|
||||
export class AuthImageFilter implements PipeTransform {
|
||||
|
||||
constructor(
|
||||
private httpServer: HttpServer
|
||||
) {}
|
||||
|
||||
async transform(src: string, server: Server) {
|
||||
let url = src.split('v3')[1];
|
||||
const imageBlob: Blob = await this.httpServer.getBlob(server, url).toPromise();
|
||||
const reader = new FileReader();
|
||||
return new Promise((resolve, reject) => {
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.readAsDataURL(imageBlob);
|
||||
});
|
||||
}
|
||||
}
|
@ -39,6 +39,23 @@ export type TextOptions = {
|
||||
withCredentials?: boolean;
|
||||
};
|
||||
|
||||
export type BlobOptions = {
|
||||
headers?:
|
||||
| HttpHeaders
|
||||
| {
|
||||
[header: string]: string | string[];
|
||||
};
|
||||
observe?: 'body';
|
||||
params?:
|
||||
| HttpParams
|
||||
| {
|
||||
[param: string]: string | string[];
|
||||
};
|
||||
reportProgress?: boolean;
|
||||
responseType: 'blob';
|
||||
withCredentials?: boolean;
|
||||
};
|
||||
|
||||
export type HeadersOptions = {
|
||||
headers?:
|
||||
| HttpHeaders
|
||||
@ -101,6 +118,16 @@ export class HttpServer {
|
||||
.pipe(catchError(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
getBlob(server: Server, url: string, options?: BlobOptions): Observable<Blob> {
|
||||
options = this.getBlobOptions(options);
|
||||
const intercepted = this.getOptionsForServer<BlobOptions>(server, url, options);
|
||||
this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`);
|
||||
|
||||
return this.http
|
||||
.get(intercepted.url, intercepted.options as BlobOptions)
|
||||
.pipe(catchError(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
post<T>(server: Server, url: string, body: any | null, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
@ -173,6 +200,15 @@ export class HttpServer {
|
||||
return options;
|
||||
}
|
||||
|
||||
private getBlobOptions(options: BlobOptions): BlobOptions {
|
||||
if (!options) {
|
||||
return {
|
||||
responseType: 'blob',
|
||||
};
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
private getOptionsForServer<T extends HeadersOptions>(server: Server, url: string, options: T) {
|
||||
if (server.host && server.port) {
|
||||
if (!server.protocol) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { shareReplay } from 'rxjs/operators';
|
||||
import { Node } from '../cartography/models/node';
|
||||
import { Server } from '../models/server';
|
||||
@ -7,22 +7,29 @@ import { Symbol } from '../models/symbol';
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { Template } from '../models/template';
|
||||
|
||||
const CACHE_SIZE = 1;
|
||||
|
||||
@Injectable()
|
||||
export class SymbolService {
|
||||
public symbols: BehaviorSubject<Symbol[]> = new BehaviorSubject<Symbol[]>([]);
|
||||
private cache: Observable<Symbol[]>;
|
||||
private symbols: Symbol[] = [];
|
||||
private maximumSymbolSize: number = 80;
|
||||
public symbolsLoaded: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
constructor(private httpServer: HttpServer) {}
|
||||
|
||||
async load(server: Server) {
|
||||
let symbols = await this.httpServer.get<Symbol[]>(server, '/symbols').toPromise();
|
||||
await symbols.forEach(async symbol => {
|
||||
symbol.raw = await this.raw(server, symbol.symbol_id).toPromise();
|
||||
this.symbols.push(symbol);
|
||||
});
|
||||
this.symbolsLoaded.next(true);
|
||||
}
|
||||
|
||||
getMaximumSymbolSize() {
|
||||
return this.maximumSymbolSize;
|
||||
}
|
||||
|
||||
get(symbol_id: string): Symbol {
|
||||
return this.symbols.getValue().find((symbol: Symbol) => symbol.symbol_id === symbol_id);
|
||||
return this.symbols.find((symbol: Symbol) => symbol.filename === symbol_id);
|
||||
}
|
||||
|
||||
getDimensions(server: Server, symbol_id: string): Observable<SymbolDimension> {
|
||||
@ -38,25 +45,13 @@ export class SymbolService {
|
||||
};
|
||||
}
|
||||
|
||||
getByFilename(symbol_filename: string) {
|
||||
return this.symbols.getValue().find((symbol: Symbol) => symbol.filename === symbol_filename);
|
||||
}
|
||||
|
||||
add(server: Server, symbolName: string, symbol: string) {
|
||||
this.cache = null;
|
||||
this.load(server);
|
||||
return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol);
|
||||
}
|
||||
|
||||
load(server: Server): Observable<Symbol[]> {
|
||||
return this.httpServer.get<Symbol[]>(server, '/symbols');
|
||||
}
|
||||
|
||||
list(server: Server) {
|
||||
if (!this.cache) {
|
||||
this.cache = this.load(server).pipe(shareReplay(CACHE_SIZE));
|
||||
}
|
||||
|
||||
return this.cache;
|
||||
return this.httpServer.get<Symbol[]>(server, '/symbols');
|
||||
}
|
||||
|
||||
raw(server: Server, symbol_id: string) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user