mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-17 10:20:26 +00:00
Merge branch 'master-3.0' into Add-navigation-to-user-management-page
This commit is contained in:
commit
717336fbd1
16
angular.json
16
angular.json
@ -18,7 +18,6 @@
|
|||||||
"css-tree",
|
"css-tree",
|
||||||
"save-svg-as-png",
|
"save-svg-as-png",
|
||||||
"angular-draggable-droppable",
|
"angular-draggable-droppable",
|
||||||
"angular2-hotkeys",
|
|
||||||
"dom-set",
|
"dom-set",
|
||||||
"dom-plane",
|
"dom-plane",
|
||||||
"mousetrap",
|
"mousetrap",
|
||||||
@ -26,13 +25,9 @@
|
|||||||
"rxjs/Rx",
|
"rxjs/Rx",
|
||||||
"rxjs/add/operator/map",
|
"rxjs/add/operator/map",
|
||||||
"rxjs-compat/add/operator/map",
|
"rxjs-compat/add/operator/map",
|
||||||
"angular-react-core.js",
|
|
||||||
"react",
|
|
||||||
"react-dom",
|
|
||||||
"classnames",
|
"classnames",
|
||||||
"stylenames"
|
"stylenames"
|
||||||
],
|
],
|
||||||
"aot": true,
|
|
||||||
"outputPath": "dist",
|
"outputPath": "dist",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
@ -49,7 +44,13 @@
|
|||||||
"src/styles.scss",
|
"src/styles.scss",
|
||||||
"src/theme.scss"
|
"src/theme.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": [],
|
||||||
|
"vendorChunk": true,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"buildOptimizer": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"optimization": false,
|
||||||
|
"namedChunks": true
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
@ -67,7 +68,6 @@
|
|||||||
"styles": false
|
"styles": false
|
||||||
},
|
},
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
"buildOptimizer": true,
|
"buildOptimizer": true,
|
||||||
@ -89,7 +89,6 @@
|
|||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
"buildOptimizer": true,
|
"buildOptimizer": true,
|
||||||
@ -125,7 +124,6 @@
|
|||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
"buildOptimizer": true,
|
"buildOptimizer": true,
|
||||||
|
63
package.json
63
package.json
@ -41,39 +41,32 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-react/core": "^3.0.0",
|
"@angular/animations": "^12.0.2",
|
||||||
"@angular-react/fabric": "^3.0.0",
|
"@angular/cdk": "^12.0.2",
|
||||||
"@angular/animations": "^11.2.13",
|
"@angular/common": "^12.0.2",
|
||||||
"@angular/cdk": "^11.2.12",
|
"@angular/compiler": "^12.0.2",
|
||||||
"@angular/common": "^11.2.13",
|
"@angular/core": "^12.0.2",
|
||||||
"@angular/compiler": "^11.2.13",
|
"@angular/forms": "^12.0.2",
|
||||||
"@angular/core": "^11.2.13",
|
"@angular/material": "^12.0.2",
|
||||||
"@angular/forms": "^11.2.13",
|
"@angular/platform-browser": "^12.0.2",
|
||||||
"@angular/http": "^7.2.16",
|
"@angular/platform-browser-dynamic": "^12.0.2",
|
||||||
"@angular/material": "^11.2.12",
|
"@angular/router": "^12.0.2",
|
||||||
"@angular/platform-browser": "^11.2.13",
|
|
||||||
"@angular/platform-browser-dynamic": "^11.2.13",
|
|
||||||
"@angular/router": "^11.2.13",
|
|
||||||
"@sentry/browser": "^6.3.6",
|
"@sentry/browser": "^6.3.6",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/mocha": "^8.2.2",
|
"@types/mocha": "^8.2.2",
|
||||||
"@types/react": "^17.0.5",
|
"@types/react": "^17.0.5",
|
||||||
"@types/react-dom": "^17.0.3",
|
"@types/react-dom": "^17.0.3",
|
||||||
"angular-draggable-droppable": "^4.6.0",
|
"angular-draggable-droppable": "^4.6.0",
|
||||||
"angular-persistence": "^1.0.1",
|
|
||||||
"angular-resizable-element": "^3.3.5",
|
"angular-resizable-element": "^3.3.5",
|
||||||
"angular2-draggable": "^2.3.2",
|
|
||||||
"angular2-hotkeys": "^2.2.0",
|
|
||||||
"angular2-indexeddb": "^1.2.3",
|
|
||||||
"bootstrap": "^5.0.0",
|
"bootstrap": "^5.0.0",
|
||||||
"command-exists": "^1.2.9",
|
"command-exists": "^1.2.9",
|
||||||
"core-js": "^3.12.1",
|
"core-js": "^3.12.1",
|
||||||
"d3-ng2-service": "^2.2.0",
|
"d3-ng2-service": "^2.2.0",
|
||||||
"eev": "^0.1.5",
|
"eev": "^0.1.5",
|
||||||
"file-saver": "^2.0.5",
|
|
||||||
"ini": "^2.0.0",
|
"ini": "^2.0.0",
|
||||||
"marked": "^2.0.3",
|
"marked": "^2.0.3",
|
||||||
"material-design-icons": "^3.0.1",
|
"material-design-icons": "^3.0.1",
|
||||||
|
"mousetrap": "^1.6.5",
|
||||||
"ng-circle-progress": "^1.6.0",
|
"ng-circle-progress": "^1.6.0",
|
||||||
"ng2-file-upload": "^1.4.0",
|
"ng2-file-upload": "^1.4.0",
|
||||||
"ngx-childprocess": "^0.0.6",
|
"ngx-childprocess": "^0.0.6",
|
||||||
@ -81,16 +74,10 @@
|
|||||||
"ngx-electron": "^2.2.0",
|
"ngx-electron": "^2.2.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"notosans-fontface": "1.2.2",
|
"notosans-fontface": "1.2.2",
|
||||||
"office-ui-fabric-react": "^7.170.0",
|
|
||||||
"prettier-plugin-organize-imports": "^2.0.0",
|
"prettier-plugin-organize-imports": "^2.0.0",
|
||||||
"react": "^17.0.2",
|
"rxjs": "^6.5.3",
|
||||||
"react-bootstrap": "^1.5.2",
|
"rxjs-compat": "^6.5.3",
|
||||||
"react-dom": "^17.0.2",
|
|
||||||
"rxjs": "^6.6.7",
|
|
||||||
"rxjs-compat": "^6.6.7",
|
|
||||||
"save-html-as-image": "^1.5.2",
|
|
||||||
"save-svg-as-png": "^1.4.17",
|
"save-svg-as-png": "^1.4.17",
|
||||||
"schematics-scss-migrate": "^1.3.13",
|
|
||||||
"snyk": "^1.589.0",
|
"snyk": "^1.589.0",
|
||||||
"spark-md5": "^3.0.1",
|
"spark-md5": "^3.0.1",
|
||||||
"svg-crowbar": "^0.6.5",
|
"svg-crowbar": "^0.6.5",
|
||||||
@ -101,21 +88,21 @@
|
|||||||
"xterm-addon-attach": "^0.6.0",
|
"xterm-addon-attach": "^0.6.0",
|
||||||
"xterm-addon-fit": "^0.5.0",
|
"xterm-addon-fit": "^0.5.0",
|
||||||
"yargs": "^17.0.1",
|
"yargs": "^17.0.1",
|
||||||
"zone.js": "^0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^0.1102.12",
|
"@angular-devkit/build-angular": "^12.0.2",
|
||||||
"@angular/cli": "^11.2.12",
|
"@angular/cli": "^12.0.2",
|
||||||
"@angular/compiler-cli": "^11.2.13",
|
"@angular/compiler-cli": "^12.0.2",
|
||||||
"@angular/language-service": "^11.2.13",
|
"@angular/language-service": "^12.0.2",
|
||||||
"@sentry/cli": "^1.64.2",
|
"@sentry/cli": "^1.64.2",
|
||||||
"@sentry/electron": "^2.4.1",
|
"@sentry/electron": "^2.4.1",
|
||||||
"@types/jasmine": "^3.7.1",
|
"@types/jasmine": "^3.7.1",
|
||||||
"@types/jasminewd2": "^2.0.9",
|
"@types/jasminewd2": "^2.0.9",
|
||||||
"@types/node": "15.0.2",
|
"@types/node": "15.6.1",
|
||||||
"codelyzer": "^6.0.2",
|
"codelyzer": "^6.0.2",
|
||||||
"electron": "^12.0.7",
|
"electron": "^13.0.1",
|
||||||
"electron-builder": "22.11.1",
|
"electron-builder": "22.10.5",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"jasmine-core": "~3.7.1",
|
"jasmine-core": "~3.7.1",
|
||||||
"jasmine-spec-reporter": "~7.0.0",
|
"jasmine-spec-reporter": "~7.0.0",
|
||||||
@ -133,11 +120,11 @@
|
|||||||
"replace": "^1.2.1",
|
"replace": "^1.2.1",
|
||||||
"rxjs-tslint": "^0.1.8",
|
"rxjs-tslint": "^0.1.8",
|
||||||
"ts-mockito": "^2.6.1",
|
"ts-mockito": "^2.6.1",
|
||||||
"ts-node": "~9.1.1",
|
"ts-node": "~10.0.0",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"typescript": "4.0.2",
|
"typescript": "4.2.4",
|
||||||
"webpack": "5.36.2",
|
"webpack": "5.38.0",
|
||||||
"yarn-upgrade-all": "^0.5.4"
|
"yarn-upgrade-all": "^0.5.4"
|
||||||
},
|
},
|
||||||
"greenkeeper": {
|
"greenkeeper": {
|
||||||
@ -146,4 +133,4 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"snyk": true
|
"snyk": true
|
||||||
}
|
}
|
@ -3,7 +3,6 @@ import { RouterModule, Routes } from '@angular/router';
|
|||||||
import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component';
|
import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component';
|
||||||
import { DirectLinkComponent } from './components/direct-link/direct-link.component';
|
import { DirectLinkComponent } from './components/direct-link/direct-link.component';
|
||||||
import { HelpComponent } from './components/help/help.component';
|
import { HelpComponent } from './components/help/help.component';
|
||||||
import { ReportIssueComponent } from './components/help/report-issue/report-issue.component';
|
|
||||||
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
||||||
import { LoginComponent } from './components/login/login.component';
|
import { LoginComponent } from './components/login/login.component';
|
||||||
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
||||||
@ -57,6 +56,7 @@ import { LoginGuard } from './guards/login-guard';
|
|||||||
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
|
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
|
||||||
import { ServerResolve } from './resolvers/server-resolve';
|
import { ServerResolve } from './resolvers/server-resolve';
|
||||||
import { UserManagementComponent } from './components/user-management/user-management.component';
|
import { UserManagementComponent } from './components/user-management/user-management.component';
|
||||||
|
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -67,6 +67,7 @@ const routes: Routes = [
|
|||||||
{ path: 'servers', component: ServersComponent },
|
{ path: 'servers', component: ServersComponent },
|
||||||
{ path: 'bundled', component: BundledServerFinderComponent },
|
{ path: 'bundled', component: BundledServerFinderComponent },
|
||||||
{ path: 'server/:server_id/login', component: LoginComponent },
|
{ path: 'server/:server_id/login', component: LoginComponent },
|
||||||
|
{ path: 'server/:server_id/loggeduser', component: LoggedUserComponent },
|
||||||
{
|
{
|
||||||
path: 'server/:server_id/projects',
|
path: 'server/:server_id/projects',
|
||||||
component: ProjectsComponent,
|
component: ProjectsComponent,
|
||||||
@ -74,7 +75,6 @@ const routes: Routes = [
|
|||||||
resolve: { server: ServerResolve },
|
resolve: { server: ServerResolve },
|
||||||
},
|
},
|
||||||
{ path: 'help', component: HelpComponent },
|
{ path: 'help', component: HelpComponent },
|
||||||
{ path: 'help/reportissue', component: ReportIssueComponent },
|
|
||||||
{ path: 'settings', component: SettingsComponent },
|
{ path: 'settings', component: SettingsComponent },
|
||||||
{ path: 'settings/console', component: ConsoleComponent },
|
{ path: 'settings/console', component: ConsoleComponent },
|
||||||
{ path: 'installed-software', component: InstalledSoftwareComponent },
|
{ path: 'installed-software', component: InstalledSoftwareComponent },
|
||||||
|
@ -2,7 +2,6 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { PersistenceService } from 'angular-persistence';
|
|
||||||
import { ElectronService, NgxElectronModule } from 'ngx-electron';
|
import { ElectronService, NgxElectronModule } from 'ngx-electron';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { ProgressService } from './common/progress/progress.service';
|
import { ProgressService } from './common/progress/progress.service';
|
||||||
@ -21,12 +20,12 @@ describe('AppComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
imports: [RouterTestingModule, MatIconModule, NgxElectronModule],
|
imports: [RouterTestingModule, MatIconModule, NgxElectronModule],
|
||||||
providers: [SettingsService, PersistenceService, ProgressService],
|
providers: [SettingsService, ProgressService],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
electronService = TestBed.get(ElectronService);
|
electronService = TestBed.inject(ElectronService);
|
||||||
settingsService = TestBed.get(SettingsService);
|
settingsService = TestBed.inject(SettingsService);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -46,23 +45,18 @@ describe('AppComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should receive changed settings and forward to electron', async(() => {
|
it('should receive changed settings and forward to electron', async(() => {
|
||||||
const spy = createSpyObj('Electron.IpcRenderer', ['send']);
|
|
||||||
spyOnProperty(electronService, 'isElectronApp').and.returnValue(true);
|
spyOnProperty(electronService, 'isElectronApp').and.returnValue(true);
|
||||||
spyOnProperty(electronService, 'ipcRenderer').and.returnValue(spy);
|
settingsService.setReportsSettings(true);
|
||||||
settingsService.set('crash_reports', true);
|
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
settingsService.set('crash_reports', false);
|
settingsService.setReportsSettings(false);
|
||||||
expect(spy.send).toHaveBeenCalled();
|
|
||||||
expect(spy.send.calls.mostRecent().args[0]).toEqual('settings.changed');
|
|
||||||
expect(spy.send.calls.mostRecent().args[1].crash_reports).toEqual(false);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should receive changed settings and do not forward to electron', async(() => {
|
it('should receive changed settings and do not forward to electron', async(() => {
|
||||||
const spy = createSpyObj('Electron.IpcRenderer', ['send']);
|
const spy = createSpyObj('Electron.IpcRenderer', ['send']);
|
||||||
spyOnProperty(electronService, 'isElectronApp').and.returnValue(false);
|
spyOnProperty(electronService, 'isElectronApp').and.returnValue(false);
|
||||||
settingsService.set('crash_reports', true);
|
settingsService.setReportsSettings(true);
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
settingsService.set('crash_reports', false);
|
settingsService.setReportsSettings(false);
|
||||||
expect(spy.send).not.toHaveBeenCalled();
|
expect(spy.send).not.toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -37,12 +37,6 @@ export class AppComponent implements OnInit {
|
|||||||
@HostBinding('class') componentCssClass;
|
@HostBinding('class') componentCssClass;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.electronService.isElectronApp) {
|
|
||||||
this.settingsService.subscribe((settings) => {
|
|
||||||
this.electronService.ipcRenderer.send('settings.changed', settings);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.applyTheme(this.themeService.savedTheme + '-theme');
|
this.applyTheme(this.themeService.savedTheme + '-theme');
|
||||||
this.themeService.themeChanged.subscribe((event: string) => {
|
this.themeService.themeChanged.subscribe((event: string) => {
|
||||||
this.applyTheme(event);
|
this.applyTheme(event);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { AngularReactBrowserModule } from '@angular-react/core';
|
|
||||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
import { OverlayModule } from '@angular/cdk/overlay';
|
import { OverlayModule } from '@angular/cdk/overlay';
|
||||||
import { CdkTableModule } from '@angular/cdk/table';
|
import { CdkTableModule } from '@angular/cdk/table';
|
||||||
@ -9,7 +8,6 @@ import { MatSidenavModule } from '@angular/material/sidenav';
|
|||||||
import { BrowserModule, Title } from '@angular/platform-browser';
|
import { BrowserModule, Title } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { DragAndDropModule } from 'angular-draggable-droppable';
|
import { DragAndDropModule } from 'angular-draggable-droppable';
|
||||||
import { PersistenceModule } from 'angular-persistence';
|
|
||||||
import { ResizableModule } from 'angular-resizable-element';
|
import { ResizableModule } from 'angular-resizable-element';
|
||||||
import { D3Service } from 'd3-ng2-service';
|
import { D3Service } from 'd3-ng2-service';
|
||||||
import { NgCircleProgressModule } from 'ng-circle-progress';
|
import { NgCircleProgressModule } from 'ng-circle-progress';
|
||||||
@ -44,7 +42,6 @@ import { NodeLabelDraggedComponent } from './components/drawings-listeners/node-
|
|||||||
import { TextAddedComponent } from './components/drawings-listeners/text-added/text-added.component';
|
import { TextAddedComponent } from './components/drawings-listeners/text-added/text-added.component';
|
||||||
import { TextEditedComponent } from './components/drawings-listeners/text-edited/text-edited.component';
|
import { TextEditedComponent } from './components/drawings-listeners/text-edited/text-edited.component';
|
||||||
import { HelpComponent } from './components/help/help.component';
|
import { HelpComponent } from './components/help/help.component';
|
||||||
import { ReportIssueComponent } from './components/help/report-issue/report-issue.component';
|
|
||||||
import { InstallSoftwareComponent } from './components/installed-software/install-software/install-software.component';
|
import { InstallSoftwareComponent } from './components/installed-software/install-software/install-software.component';
|
||||||
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component';
|
||||||
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
|
||||||
@ -204,6 +201,7 @@ import { TemplateComponent } from './components/template/template.component';
|
|||||||
import { TopologySummaryComponent } from './components/topology-summary/topology-summary.component';
|
import { TopologySummaryComponent } from './components/topology-summary/topology-summary.component';
|
||||||
import { WebConsoleFullWindowComponent } from './components/web-console-full-window/web-console-full-window.component';
|
import { WebConsoleFullWindowComponent } from './components/web-console-full-window/web-console-full-window.component';
|
||||||
import { DataSourceFilter } from './filters/dataSourceFilter';
|
import { DataSourceFilter } from './filters/dataSourceFilter';
|
||||||
|
import { AuthImageFilter } from './filters/authImageFilter';
|
||||||
import { DateFilter } from './filters/dateFilter.pipe';
|
import { DateFilter } from './filters/dateFilter.pipe';
|
||||||
import { NameFilter } from './filters/nameFilter.pipe';
|
import { NameFilter } from './filters/nameFilter.pipe';
|
||||||
import { ProjectsFilter } from './filters/projectsFilter.pipe';
|
import { ProjectsFilter } from './filters/projectsFilter.pipe';
|
||||||
@ -226,7 +224,6 @@ import { ExternalSoftwareDefinitionService } from './services/external-software-
|
|||||||
import { Gns3vmService } from './services/gns3vm.service';
|
import { Gns3vmService } from './services/gns3vm.service';
|
||||||
import { GoogleAnalyticsService } from './services/google-analytics.service';
|
import { GoogleAnalyticsService } from './services/google-analytics.service';
|
||||||
import { HttpServer, ServerErrorHandler } from './services/http-server.service';
|
import { HttpServer, ServerErrorHandler } from './services/http-server.service';
|
||||||
import { IndexedDbService } from './services/indexed-db.service';
|
|
||||||
import { InfoService } from './services/info.service';
|
import { InfoService } from './services/info.service';
|
||||||
import { InstalledSoftwareService } from './services/installed-software.service';
|
import { InstalledSoftwareService } from './services/installed-software.service';
|
||||||
import { IosConfigurationService } from './services/ios-configuration.service';
|
import { IosConfigurationService } from './services/ios-configuration.service';
|
||||||
@ -274,10 +271,13 @@ import { LoginComponent } from './components/login/login.component';
|
|||||||
import { LoginService } from './services/login.service';
|
import { LoginService } from './services/login.service';
|
||||||
import { HttpRequestsInterceptor } from './interceptors/http.interceptor';
|
import { HttpRequestsInterceptor } from './interceptors/http.interceptor';
|
||||||
import { UserManagementComponent } from './components/user-management/user-management.component'
|
import { UserManagementComponent } from './components/user-management/user-management.component'
|
||||||
|
import { UserService } from './services/user.service';
|
||||||
|
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
LoggedUserComponent,
|
||||||
ProjectMapComponent,
|
ProjectMapComponent,
|
||||||
LoginComponent,
|
LoginComponent,
|
||||||
ServersComponent,
|
ServersComponent,
|
||||||
@ -382,6 +382,7 @@ import { UserManagementComponent } from './components/user-management/user-manag
|
|||||||
DataSourceFilter,
|
DataSourceFilter,
|
||||||
TemplateFilter,
|
TemplateFilter,
|
||||||
ProjectsFilter,
|
ProjectsFilter,
|
||||||
|
AuthImageFilter,
|
||||||
ListOfSnapshotsComponent,
|
ListOfSnapshotsComponent,
|
||||||
CustomAdaptersComponent,
|
CustomAdaptersComponent,
|
||||||
NodesMenuComponent,
|
NodesMenuComponent,
|
||||||
@ -458,11 +459,10 @@ import { UserManagementComponent } from './components/user-management/user-manag
|
|||||||
TemplateNameDialogComponent,
|
TemplateNameDialogComponent,
|
||||||
ConfigureCustomAdaptersDialogComponent,
|
ConfigureCustomAdaptersDialogComponent,
|
||||||
EditNetworkConfigurationDialogComponent,
|
EditNetworkConfigurationDialogComponent,
|
||||||
ReportIssueComponent,
|
UserManagementComponent,
|
||||||
UserManagementComponent
|
ProjectReadmeComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
AngularReactBrowserModule,
|
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
@ -471,7 +471,6 @@ import { UserManagementComponent } from './components/user-management/user-manag
|
|||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
CdkTableModule,
|
CdkTableModule,
|
||||||
CartographyModule,
|
CartographyModule,
|
||||||
PersistenceModule,
|
|
||||||
NgxElectronModule,
|
NgxElectronModule,
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
MatSidenavModule,
|
MatSidenavModule,
|
||||||
@ -496,7 +495,6 @@ import { UserManagementComponent } from './components/user-management/user-manag
|
|||||||
NodeService,
|
NodeService,
|
||||||
LinkService,
|
LinkService,
|
||||||
DrawingService,
|
DrawingService,
|
||||||
IndexedDbService,
|
|
||||||
HttpServer,
|
HttpServer,
|
||||||
SnapshotService,
|
SnapshotService,
|
||||||
ProgressDialogService,
|
ProgressDialogService,
|
||||||
@ -558,7 +556,8 @@ import { UserManagementComponent } from './components/user-management/user-manag
|
|||||||
Title,
|
Title,
|
||||||
ApplianceService,
|
ApplianceService,
|
||||||
UpdatesService,
|
UpdatesService,
|
||||||
LoginService
|
LoginService,
|
||||||
|
UserService
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AddServerDialogComponent,
|
AddServerDialogComponent,
|
||||||
|
@ -26,9 +26,7 @@ export class DrawingComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
try {
|
try {
|
||||||
this.drawing.element = this.svgToDrawingConverter.convert(this.drawing.svg);
|
this.drawing.element = this.svgToDrawingConverter.convert(this.drawing.svg);
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
console.log(`Cannot convert due to Error: '${error}'`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnDragging(evt) {
|
OnDragging(evt) {
|
||||||
|
@ -44,9 +44,7 @@ export class DrawingsWidget implements Widget {
|
|||||||
layer.drawings.forEach((d: MapDrawing) => {
|
layer.drawings.forEach((d: MapDrawing) => {
|
||||||
try {
|
try {
|
||||||
d.element = this.svgToDrawingConverter.convert(d.svg);
|
d.element = this.svgToDrawingConverter.convert(d.svg);
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
console.log(`Cannot convert due to Error: '${error}'`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return layer.drawings;
|
return layer.drawings;
|
||||||
},
|
},
|
||||||
@ -81,9 +79,7 @@ export class DrawingsWidget implements Widget {
|
|||||||
.on('start', (datum: MapDrawing) => {
|
.on('start', (datum: MapDrawing) => {
|
||||||
document.body.style.cursor = 'ns-resize';
|
document.body.style.cursor = 'ns-resize';
|
||||||
topEdge = datum.y;
|
topEdge = datum.y;
|
||||||
console.log('started');
|
|
||||||
y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||||
// startEvent = event;
|
|
||||||
})
|
})
|
||||||
.on('drag', (datum: MapDrawing) => {
|
.on('drag', (datum: MapDrawing) => {
|
||||||
const evt = event;
|
const evt = event;
|
||||||
@ -91,55 +87,10 @@ export class DrawingsWidget implements Widget {
|
|||||||
y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||||
let height = datum.element.height - dy;
|
let height = datum.element.height - dy;
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
// height = datum.y - startEvent.y;
|
|
||||||
datum.y += height;
|
datum.y += height;
|
||||||
height = topEdge - datum.y;
|
height = topEdge - datum.y;
|
||||||
// console.log(topEdge - datum.y);
|
|
||||||
}
|
}
|
||||||
console.log('Height', height);
|
|
||||||
datum.element.height = height;
|
datum.element.height = height;
|
||||||
|
|
||||||
// datum.element.height -= dy;
|
|
||||||
// if(datum.element.height < 0) {
|
|
||||||
// datum.y -= datum.element.height;
|
|
||||||
// datum.element.height = Math.abs(datum.element.height);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!isReflectedVertical) {
|
|
||||||
// if ((datum.element.height + evt.dy) < 0) {
|
|
||||||
// isReflectedVertical = true;
|
|
||||||
// y = topEdge;
|
|
||||||
// console.log(y);
|
|
||||||
// datum.element.height = Math.abs(datum.element.height + evt.dy);
|
|
||||||
// console.log(datum.element.height);
|
|
||||||
// } else {
|
|
||||||
// datum.element.height += evt.dy;
|
|
||||||
|
|
||||||
// if (datum.element instanceof EllipseElement){
|
|
||||||
// (datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy + evt.dy/2 < 0 ? 1 : (datum.element as EllipseElement).cy += evt.dy/2;
|
|
||||||
// (datum.element as EllipseElement).ry = (datum.element as EllipseElement).ry + evt.dy/2 < 0 ? 1 : (datum.element as EllipseElement).ry += evt.dy/2;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// dy = y - (evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y);
|
|
||||||
// y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
|
||||||
|
|
||||||
// if ((datum.element.height + dy) < 0){
|
|
||||||
// isReflectedVertical = false;
|
|
||||||
// y = topEdge;
|
|
||||||
// console.log(y);
|
|
||||||
// datum.element.height = Math.abs(datum.element.height + evt.dy);
|
|
||||||
// console.log(datum.element.height);
|
|
||||||
// } else {
|
|
||||||
// datum.y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
|
||||||
// datum.element.height += dy;
|
|
||||||
// if (datum.element instanceof EllipseElement) {
|
|
||||||
// (datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy + dy/2 < 0 ? 1 : (datum.element as EllipseElement).cy += dy/2;
|
|
||||||
// (datum.element as EllipseElement).ry = (datum.element as EllipseElement).ry + dy/2 < 0 ? 1 : (datum.element as EllipseElement).ry += dy/2;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.redrawDrawing(view, datum);
|
this.redrawDrawing(view, datum);
|
||||||
})
|
})
|
||||||
.on('end', (datum: MapDrawing) => {
|
.on('end', (datum: MapDrawing) => {
|
||||||
|
@ -46,9 +46,7 @@ export class DrawingsWidget implements Widget {
|
|||||||
layer.drawings.forEach((d: MapDrawing) => {
|
layer.drawings.forEach((d: MapDrawing) => {
|
||||||
try {
|
try {
|
||||||
d.element = this.svgToDrawingConverter.convert(d.svg);
|
d.element = this.svgToDrawingConverter.convert(d.svg);
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
console.log(`Cannot convert due to Error: '${error}'`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return layer.drawings;
|
return layer.drawings;
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { EventEmitter, Injectable } from '@angular/core';
|
import { EventEmitter, Injectable } from '@angular/core';
|
||||||
|
import { SymbolService } from '../../services/symbol.service';
|
||||||
import { event, select } from 'd3-selection';
|
import { event, select } from 'd3-selection';
|
||||||
import { MapSettingsService } from '../../services/mapsettings.service';
|
import { MapSettingsService } from '../../services/mapsettings.service';
|
||||||
import { ClickedDataEvent } from '../events/event-source';
|
import { ClickedDataEvent } from '../events/event-source';
|
||||||
@ -22,7 +23,8 @@ export class NodeWidget implements Widget {
|
|||||||
private selectionManager: SelectionManager,
|
private selectionManager: SelectionManager,
|
||||||
private labelWidget: LabelWidget,
|
private labelWidget: LabelWidget,
|
||||||
private nodesEventSource: NodesEventSource,
|
private nodesEventSource: NodesEventSource,
|
||||||
private mapSettingsService: MapSettingsService
|
private mapSettingsService: MapSettingsService,
|
||||||
|
private symbolService: SymbolService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public draw(view: SVGSelection) {
|
public draw(view: SVGSelection) {
|
||||||
@ -88,7 +90,13 @@ export class NodeWidget implements Widget {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
self.onContextConsoleMenu.emit(new NodeContextMenu(event, n));
|
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) => {
|
.attr('width', (n: MapNode) => {
|
||||||
if (!n.width) return 60;
|
if (!n.width) return 60;
|
||||||
return n.width;
|
return n.width;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Injector } from '@angular/core';
|
import { Injector } from '@angular/core';
|
||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
import { MockedSettingsService } from '../../services/settings.service.spec';
|
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { MockedToasterService } from '../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../services/toaster.service.spec';
|
||||||
import { SentryErrorHandler } from './sentry-error-handler';
|
import { SentryErrorHandler } from './sentry-error-handler';
|
||||||
@ -17,19 +16,21 @@ class MockedToasterErrorHandler extends ToasterErrorHandler {
|
|||||||
describe('ToasterErrorHandler', () => {
|
describe('ToasterErrorHandler', () => {
|
||||||
let handler: ToasterErrorHandler;
|
let handler: ToasterErrorHandler;
|
||||||
let toasterService: MockedToasterService;
|
let toasterService: MockedToasterService;
|
||||||
|
let settingsService: SettingsService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ToasterService, useClass: MockedToasterService },
|
{ provide: ToasterService, useClass: MockedToasterService },
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService},
|
||||||
SentryErrorHandler,
|
SentryErrorHandler,
|
||||||
ToasterErrorHandler,
|
ToasterErrorHandler,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
handler = new MockedToasterErrorHandler(TestBed.get(Injector));
|
handler = new MockedToasterErrorHandler(TestBed.inject(Injector));
|
||||||
toasterService = TestBed.get(ToasterService);
|
toasterService = TestBed.get(ToasterService);
|
||||||
|
settingsService = TestBed.inject(SettingsService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call toaster with error message', () => {
|
it('should call toaster with error message', () => {
|
||||||
|
@ -21,7 +21,15 @@ export class BundledServerFinderComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.progressService.activate();
|
this.progressService.activate();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let port = parseInt(this.document.location.port, 10) ? parseInt(this.document.location.port, 10) : 80;
|
let port;
|
||||||
|
|
||||||
|
if (parseInt(this.document.location.port, 10)) {
|
||||||
|
port = parseInt(this.document.location.port, 10);
|
||||||
|
} else if (this.document.location.protocol == "https:") {
|
||||||
|
port = 443;
|
||||||
|
} else {
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
|
||||||
this.serverService.getLocalServer(this.document.location.hostname, port).then((server: Server) => {
|
this.serverService.getLocalServer(this.document.location.hostname, port).then((server: Server) => {
|
||||||
this.progressService.deactivate();
|
this.progressService.deactivate();
|
||||||
|
@ -59,7 +59,6 @@ export class DirectLinkComponent implements OnInit {
|
|||||||
const servers = await this.serverService.findAll();
|
const servers = await this.serverService.findAll();
|
||||||
const server = servers.filter((server) => server.host === this.serverIp && server.port === this.serverPort)[0];
|
const server = servers.filter((server) => server.host === this.serverIp && server.port === this.serverPort)[0];
|
||||||
|
|
||||||
console.log(servers);
|
|
||||||
if (server) {
|
if (server) {
|
||||||
this.router.navigate(['/server', server.id, 'project', this.projectId]);
|
this.router.navigate(['/server', server.id, 'project', this.projectId]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -31,9 +31,6 @@
|
|||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
<button mat-button class="full-width">
|
<button mat-button color="primary" class="full-width" (click)="goToDocumentation()">Go to documentation</button>
|
||||||
<a href="https://docs.gns3.com/docs/"> Go to documentation </a>
|
|
||||||
</button>
|
|
||||||
<button mat-button routerLink="/help/reportissue" class="full-width">Report an issue</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.full-width {
|
.full-width {
|
||||||
width: 50%;
|
width: 100%;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,8 @@ export class HelpComponent implements OnInit {
|
|||||||
this.releasenotes = data.replace(new RegExp('\n', 'g'), '<br />');
|
this.releasenotes = data.replace(new RegExp('\n', 'g'), '<br />');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToDocumentation() {
|
||||||
|
window.location.href = "https://docs.gns3.com/docs/";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import React, {Component} from "react";
|
|
||||||
import Form from 'react-bootstrap/Form';
|
|
||||||
|
|
||||||
const formGroupStyle = {
|
|
||||||
margin: '20px'
|
|
||||||
};
|
|
||||||
|
|
||||||
class FilterComponent extends Component<any, any> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Form.Group style={formGroupStyle}>
|
|
||||||
<Form.Control size="lg" type="text" placeholder="Search by keyword" value={this.props.filter} onChange={this.props.handleChange} />
|
|
||||||
</Form.Group>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FilterComponent;
|
|
@ -1,95 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import Card from 'react-bootstrap/Card';
|
|
||||||
import Spinner from 'react-bootstrap/Spinner';
|
|
||||||
import IssueComponent from './issue';
|
|
||||||
import FilterComponent from './filter';
|
|
||||||
import e from '../../../event-bus';
|
|
||||||
|
|
||||||
const wrapperStyle = {
|
|
||||||
justifyContent: 'center' as 'center',
|
|
||||||
display: 'flex',
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row' as 'row',
|
|
||||||
flexWrap: 'wrap' as 'wrap',
|
|
||||||
margin: '20px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const cardStyle = {
|
|
||||||
width: '300px',
|
|
||||||
margin: '20px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const cardTitleStyle = {
|
|
||||||
color: 'red'
|
|
||||||
};
|
|
||||||
const message = 'Thank you for reporting the issue!';
|
|
||||||
const apiUrl = 'https://api.github.com/repos/GNS3/gns3-web-ui/issues';
|
|
||||||
const newIssueLink = 'https://github.com/GNS3/gns3-web-ui/issues/new';
|
|
||||||
|
|
||||||
class IssueListComponent extends Component<any, any> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
issues: [],
|
|
||||||
filteredIssues: [],
|
|
||||||
isFetching: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
fetch(apiUrl)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => this.setState({
|
|
||||||
issues: data,
|
|
||||||
filteredIssues: data,
|
|
||||||
isFetching: false
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (event) => {
|
|
||||||
let filter = event.target.value;
|
|
||||||
let filteredIssues = this.state.issues;
|
|
||||||
|
|
||||||
filteredIssues = filteredIssues.filter((issue) => {
|
|
||||||
return issue.title.toLowerCase().includes(filter.toLowerCase())
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
filteredIssues: filteredIssues
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
newIssueOpened = (event) => {
|
|
||||||
e.emit('message', { text: message });
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<FilterComponent handleChange={this.handleChange} filter={this.state.filter} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.state.isFetching ? (
|
|
||||||
<div style={wrapperStyle}>
|
|
||||||
<Spinner animation="grow" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div style={wrapperStyle}>
|
|
||||||
{this.state.filteredIssues.map(issue =>
|
|
||||||
<IssueComponent key={issue.html_url} data={issue}/>
|
|
||||||
)}
|
|
||||||
<Card style={cardStyle}>
|
|
||||||
<Card.Body>
|
|
||||||
<Card.Title style={cardTitleStyle}>Don't see your issue here?</Card.Title>
|
|
||||||
<Card.Link onClick={this.newIssueOpened} href={newIssueLink} target = "_blank">Open new issue</Card.Link>
|
|
||||||
</Card.Body>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default IssueListComponent;
|
|
@ -1,42 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import Card from 'react-bootstrap/Card';
|
|
||||||
|
|
||||||
const cardStyle = {
|
|
||||||
width: '300px',
|
|
||||||
margin: '20px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const cardTitleStyle = {
|
|
||||||
color: 'black'
|
|
||||||
};
|
|
||||||
|
|
||||||
const cardTextStyle = {
|
|
||||||
color: 'black',
|
|
||||||
overflow: 'auto',
|
|
||||||
height: '100px'
|
|
||||||
};
|
|
||||||
|
|
||||||
class IssueComponent extends Component<any, any> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
data: this.props.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const issue = this.state.data;
|
|
||||||
return (
|
|
||||||
<Card key={issue.html_url} style={cardStyle}>
|
|
||||||
<Card.Body>
|
|
||||||
<Card.Title style={cardTitleStyle}>{issue.title}</Card.Title>
|
|
||||||
<Card.Subtitle className="mb-2 text-muted">Status: {issue.state}</Card.Subtitle>
|
|
||||||
<Card.Text style={cardTextStyle}>{issue.body}</Card.Text>
|
|
||||||
<Card.Link href={issue.html_url} target = "_blank">{issue.html_url}</Card.Link>
|
|
||||||
</Card.Body>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default IssueComponent;
|
|
@ -1 +0,0 @@
|
|||||||
<span #issueListComponentContainer></span>
|
|
@ -1,52 +0,0 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import {
|
|
||||||
AfterViewInit,
|
|
||||||
Component,
|
|
||||||
ElementRef,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
OnChanges,
|
|
||||||
OnDestroy,
|
|
||||||
Output,
|
|
||||||
SimpleChanges,
|
|
||||||
ViewChild,
|
|
||||||
ViewEncapsulation,
|
|
||||||
AfterContentInit
|
|
||||||
} from '@angular/core';
|
|
||||||
import IssueListComponent from '../report-issue/issue-list';
|
|
||||||
import * as React from 'react';
|
|
||||||
import * as ReactDOM from 'react-dom';
|
|
||||||
import e from '../../../event-bus';
|
|
||||||
import { ToasterService } from '../../../services/toaster.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-report-issue',
|
|
||||||
templateUrl: './report-issue.component.html',
|
|
||||||
styleUrls: ['./report-issue.component.scss']
|
|
||||||
})
|
|
||||||
export class ReportIssueComponent implements OnDestroy, AfterViewInit, AfterContentInit {
|
|
||||||
@ViewChild('issueListComponentContainer') containerRef: ElementRef;
|
|
||||||
|
|
||||||
constructor(private toasterService: ToasterService) {}
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterContentInit() {
|
|
||||||
e.on('message', message => {
|
|
||||||
this.toasterService.success(message.text);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
private render() {
|
|
||||||
ReactDOM.render(<div>
|
|
||||||
<IssueListComponent />
|
|
||||||
</div>, this.containerRef.nativeElement);
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,7 @@
|
|||||||
<mat-error *ngIf="loginForm.get('username').hasError('required')">You must enter username</mat-error>
|
<mat-error *ngIf="loginForm.get('username').hasError('required')">You must enter username</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput formControlName="password" placeholder="Password" />
|
<input matInput type="password" formControlName="password" placeholder="Password" />
|
||||||
<mat-error *ngIf="loginForm.get('password').hasError('required')">You must enter password</mat-error>
|
<mat-error *ngIf="loginForm.get('password').hasError('required')">You must enter password</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
@ -18,9 +18,7 @@ export class CustomAdaptersComponent {
|
|||||||
public adapters: CustomAdapter[];
|
public adapters: CustomAdapter[];
|
||||||
public numberOfAdapters: number;
|
public numberOfAdapters: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {}
|
||||||
console.log(this.networkTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelConfigureCustomAdapters() {
|
cancelConfigureCustomAdapters() {
|
||||||
this.closeConfiguratorEmitter.emit(false);
|
this.closeConfiguratorEmitter.emit(false);
|
||||||
@ -28,8 +26,6 @@ export class CustomAdaptersComponent {
|
|||||||
|
|
||||||
configureCustomAdapters() {
|
configureCustomAdapters() {
|
||||||
this.adapters = [];
|
this.adapters = [];
|
||||||
console.log(this.customAdapters);
|
|
||||||
|
|
||||||
this.customAdapters.adapters.forEach((n) => {
|
this.customAdapters.adapters.forEach((n) => {
|
||||||
this.adapters.push({
|
this.adapters.push({
|
||||||
adapter_number: n.adapter_number,
|
adapter_number: n.adapter_number,
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
lazyimg
|
lazyimg
|
||||||
[ngClass]="{ imageSelected: isSelected === symbol.symbol_id }"
|
[ngClass]="{ imageSelected: isSelected === symbol.symbol_id }"
|
||||||
class="image"
|
class="image"
|
||||||
[src]="getImageSourceForTemplate(symbol.symbol_id)"
|
[src]="getImageSourceForTemplate(symbol.symbol_id)| authImage: server | async"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { Symbol } from '../../../../models/symbol';
|
import { Symbol } from '../../../../models/symbol';
|
||||||
import { SymbolService } from '../../../../services/symbol.service';
|
import { SymbolService } from '../../../../services/symbol.service';
|
||||||
@ -18,7 +19,7 @@ export class SymbolsComponent implements OnInit {
|
|||||||
isSelected: string = '';
|
isSelected: string = '';
|
||||||
searchText: string = '';
|
searchText: string = '';
|
||||||
|
|
||||||
constructor(private symbolService: SymbolService) {}
|
constructor(private symbolService: SymbolService, private domSanitizer: DomSanitizer) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.isSelected = this.symbol;
|
this.isSelected = this.symbol;
|
||||||
@ -76,6 +77,11 @@ export class SymbolsComponent implements OnInit {
|
|||||||
width=\"${imageToUpload.width}\">\n<image height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\" xlink:href=\"${image}\"/>\n</svg>`;
|
width=\"${imageToUpload.width}\">\n<image height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\" xlink:href=\"${image}\"/>\n</svg>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getImage(symbolFilename: string) {
|
||||||
|
let symbol = this.symbolService.get(symbolFilename);
|
||||||
|
return this.domSanitizer.bypassSecurityTrustUrl(`data:image/svg+xml;base64,${btoa(symbol.raw)}`);
|
||||||
|
}
|
||||||
|
|
||||||
getImageSourceForTemplate(symbol: string) {
|
getImageSourceForTemplate(symbol: string) {
|
||||||
return `${this.server.protocol}//${this.server.host}:${this.server.port}/v3/symbols/${symbol}/raw`;
|
return `${this.server.protocol}//${this.server.host}:${this.server.port}/v3/symbols/${symbol}/raw`;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,47 @@
|
|||||||
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
import { MapSettingsService } from '../../../services/mapsettings.service';
|
import { MapSettingsService } from '../../../services/mapsettings.service';
|
||||||
import { NodeConsoleService } from '../../../services/nodeConsole.service';
|
import { NodeConsoleService } from '../../../services/nodeConsole.service';
|
||||||
import { ThemeService } from '../../../services/theme.service';
|
import { ThemeService } from '../../../services/theme.service';
|
||||||
import { ConsoleWrapperComponent } from './console-wrapper.component';
|
import { ConsoleWrapperComponent } from './console-wrapper.component';
|
||||||
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
|
||||||
describe('ConsoleWrapperComponent', () => {
|
describe('ConsoleWrapperComponent', () => {
|
||||||
|
let fixture: ComponentFixture<ConsoleWrapperComponent>;
|
||||||
|
let component: ConsoleWrapperComponent;
|
||||||
|
|
||||||
|
let nodeConsoleService: NodeConsoleService;
|
||||||
|
let themeService: ThemeService;
|
||||||
|
let mapSettingsService: MapSettingsService;
|
||||||
|
let toasterService: ToasterService;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [RouterTestingModule, MatSnackBarModule],
|
||||||
|
providers: [NodeConsoleService, ThemeService, MapSettingsService, ToasterService]
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
toasterService = TestBed.inject(ToasterService);
|
||||||
|
nodeConsoleService = TestBed.inject(NodeConsoleService);
|
||||||
|
themeService = TestBed.inject(ThemeService);
|
||||||
|
mapSettingsService = TestBed.inject(MapSettingsService);
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ConsoleWrapperComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should get actual theme', () => {
|
it('should get actual theme', () => {
|
||||||
const consoleService = new NodeConsoleService();
|
|
||||||
|
|
||||||
const themeService = autoSpy(ThemeService);
|
|
||||||
themeService.getActualTheme.and.returnValue('light');
|
|
||||||
|
|
||||||
const mapSettingsService = autoSpy(MapSettingsService);
|
|
||||||
const component = new ConsoleWrapperComponent(consoleService, themeService, mapSettingsService);
|
|
||||||
|
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
|
|
||||||
expect(component.isLightThemeEnabled).toBe(true);
|
expect(component.isLightThemeEnabled).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { ElectronService } from 'ngx-electron';
|
import { ElectronService } from 'ngx-electron';
|
||||||
@ -20,7 +21,9 @@ import { ContextConsoleMenuComponent } from './context-console-menu.component';
|
|||||||
describe('ContextConsoleMenuComponent', () => {
|
describe('ContextConsoleMenuComponent', () => {
|
||||||
let component: ContextConsoleMenuComponent;
|
let component: ContextConsoleMenuComponent;
|
||||||
let fixture: ComponentFixture<ContextConsoleMenuComponent>;
|
let fixture: ComponentFixture<ContextConsoleMenuComponent>;
|
||||||
let toasterService: MockedToasterService = new MockedToasterService();
|
let nodeConsoleService: NodeConsoleService;
|
||||||
|
let mapSettingsService: MapSettingsService;
|
||||||
|
let toasterService: ToasterService;
|
||||||
let router = {
|
let router = {
|
||||||
url: '',
|
url: '',
|
||||||
navigate: jasmine.createSpy('navigate'),
|
navigate: jasmine.createSpy('navigate'),
|
||||||
@ -28,7 +31,6 @@ describe('ContextConsoleMenuComponent', () => {
|
|||||||
let node = {
|
let node = {
|
||||||
status: 'started',
|
status: 'started',
|
||||||
};
|
};
|
||||||
let mapSettingsService = new MapSettingsService();
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
const electronMock = {
|
const electronMock = {
|
||||||
@ -36,20 +38,25 @@ describe('ContextConsoleMenuComponent', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatMenuModule, BrowserModule],
|
imports: [MatMenuModule, BrowserModule, MatSnackBarModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ChangeDetectorRef },
|
{ provide: ChangeDetectorRef },
|
||||||
{ provide: ProjectService, useClass: MockedProjectService },
|
{ provide: ProjectService, useClass: MockedProjectService },
|
||||||
{ provide: ElectronService, useValue: electronMock },
|
{ provide: ElectronService, useValue: electronMock },
|
||||||
{ provide: MapSettingsService, useValue: mapSettingsService },
|
{ provide: MapSettingsService, useValue: mapSettingsService },
|
||||||
{ provide: NodeConsoleService },
|
|
||||||
{ provide: ConsoleService },
|
{ provide: ConsoleService },
|
||||||
{ provide: ToasterService, useValue: toasterService },
|
|
||||||
{ provide: Router, useValue: router },
|
{ provide: Router, useValue: router },
|
||||||
|
NodeConsoleService,
|
||||||
|
ToasterService,
|
||||||
|
MapSettingsService
|
||||||
],
|
],
|
||||||
declarations: [ContextConsoleMenuComponent, ConsoleDeviceActionComponent, ConsoleDeviceActionBrowserComponent],
|
declarations: [ContextConsoleMenuComponent, ConsoleDeviceActionComponent, ConsoleDeviceActionBrowserComponent],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
toasterService = TestBed.inject(ToasterService);
|
||||||
|
mapSettingsService = TestBed.inject(MapSettingsService);
|
||||||
|
nodeConsoleService = TestBed.inject(NodeConsoleService);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -7,7 +7,6 @@ import { NodeService } from '../../../../../services/node.service';
|
|||||||
import { ServerService } from '../../../../../services/server.service';
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
import { MockedServerService } from '../../../../../services/server.service.spec';
|
import { MockedServerService } from '../../../../../services/server.service.spec';
|
||||||
import { SettingsService } from '../../../../../services/settings.service';
|
import { SettingsService } from '../../../../../services/settings.service';
|
||||||
import { MockedSettingsService } from '../../../../../services/settings.service.spec';
|
|
||||||
import { ToasterService } from '../../../../../services/toaster.service';
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../../../../services/toaster.service.spec';
|
||||||
import { MockedNodeService } from '../../../project-map.component.spec';
|
import { MockedNodeService } from '../../../project-map.component.spec';
|
||||||
@ -18,7 +17,7 @@ describe('ConsoleDeviceActionComponent', () => {
|
|||||||
let fixture: ComponentFixture<ConsoleDeviceActionComponent>;
|
let fixture: ComponentFixture<ConsoleDeviceActionComponent>;
|
||||||
let electronService;
|
let electronService;
|
||||||
let server: Server;
|
let server: Server;
|
||||||
let mockedSettingsService: MockedSettingsService;
|
let settingsService: SettingsService;
|
||||||
let mockedServerService: MockedServerService;
|
let mockedServerService: MockedServerService;
|
||||||
let mockedToaster: MockedToasterService;
|
let mockedToaster: MockedToasterService;
|
||||||
let mockedNodeService: MockedNodeService = new MockedNodeService();
|
let mockedNodeService: MockedNodeService = new MockedNodeService();
|
||||||
@ -35,7 +34,6 @@ describe('ConsoleDeviceActionComponent', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
mockedSettingsService = new MockedSettingsService();
|
|
||||||
mockedServerService = new MockedServerService();
|
mockedServerService = new MockedServerService();
|
||||||
mockedToaster = new MockedToasterService();
|
mockedToaster = new MockedToasterService();
|
||||||
|
|
||||||
@ -47,13 +45,15 @@ describe('ConsoleDeviceActionComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: ElectronService, useValue: electronService },
|
{ provide: ElectronService, useValue: electronService },
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
{ provide: SettingsService, useValue: mockedSettingsService },
|
{ provide: SettingsService },
|
||||||
{ provide: ToasterService, useValue: mockedToaster },
|
{ provide: ToasterService, useValue: mockedToaster },
|
||||||
{ provide: NodeService, useValue: mockedNodeService },
|
{ provide: NodeService, useValue: mockedNodeService },
|
||||||
],
|
],
|
||||||
imports: [MatIconModule],
|
imports: [MatIconModule],
|
||||||
declarations: [ConsoleDeviceActionComponent],
|
declarations: [ConsoleDeviceActionComponent],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
settingsService = TestBed.inject(SettingsService);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -85,7 +85,7 @@ describe('ConsoleDeviceActionComponent', () => {
|
|||||||
component.nodes = nodes;
|
component.nodes = nodes;
|
||||||
component.server = server;
|
component.server = server;
|
||||||
|
|
||||||
mockedSettingsService.set('console_command', 'command');
|
settingsService.setConsoleSettings('command');
|
||||||
spyOn(component, 'openConsole');
|
spyOn(component, 'openConsole');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ describe('ConsoleDeviceActionComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set command when it is not defined', async () => {
|
it('should set command when it is not defined', async () => {
|
||||||
mockedSettingsService.set('console_command', undefined);
|
settingsService.setConsoleSettings(undefined);
|
||||||
await component.console();
|
await component.console();
|
||||||
expect(component.openConsole).toHaveBeenCalled();
|
expect(component.openConsole).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
@ -26,8 +26,8 @@ export class ConsoleDeviceActionComponent implements OnInit {
|
|||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
async console() {
|
async console() {
|
||||||
let consoleCommand = this.settingsService.get<string>('console_command')
|
let consoleCommand = this.settingsService.getConsoleSettings()
|
||||||
? this.settingsService.get<string>('console_command')
|
? this.settingsService.getConsoleSettings()
|
||||||
: this.nodeService.getDefaultCommand();
|
: this.nodeService.getDefaultCommand();
|
||||||
const startedNodes = this.nodes.filter((node) => node.status === 'started');
|
const startedNodes = this.nodes.filter((node) => node.status === 'started');
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<button mat-menu-item (click)="delete()">
|
<button mat-menu-item (click)="confirmDelete()">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
@ -24,7 +25,7 @@ describe('DeleteActionComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatIconModule, MatMenuModule, NoopAnimationsModule],
|
imports: [MatIconModule, MatMenuModule, NoopAnimationsModule, MatBottomSheetModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: NodesDataSource, useClass: NodesDataSource },
|
{ provide: NodesDataSource, useClass: NodesDataSource },
|
||||||
{ provide: DrawingsDataSource, useClass: DrawingsDataSource },
|
{ provide: DrawingsDataSource, useClass: DrawingsDataSource },
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||||
|
import { ConfirmationBottomSheetComponent } from 'app/components/projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
|
||||||
import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource';
|
import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource';
|
||||||
import { LinksDataSource } from '../../../../../cartography/datasources/links-datasource';
|
import { LinksDataSource } from '../../../../../cartography/datasources/links-datasource';
|
||||||
import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource';
|
import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource';
|
||||||
@ -26,11 +28,23 @@ export class DeleteActionComponent implements OnInit {
|
|||||||
private linksDataSource: LinksDataSource,
|
private linksDataSource: LinksDataSource,
|
||||||
private nodeService: NodeService,
|
private nodeService: NodeService,
|
||||||
private drawingService: DrawingService,
|
private drawingService: DrawingService,
|
||||||
private linkService: LinkService
|
private linkService: LinkService,
|
||||||
|
private bottomSheet: MatBottomSheet
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
|
confirmDelete() {
|
||||||
|
this.bottomSheet.open(ConfirmationBottomSheetComponent);
|
||||||
|
let bottomSheetRef = this.bottomSheet._openedBottomSheetRef;
|
||||||
|
bottomSheetRef.instance.message = 'Do you want to delete all selected objects?';
|
||||||
|
const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => {
|
||||||
|
if (result) {
|
||||||
|
this.delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.nodes.forEach((node) => {
|
this.nodes.forEach((node) => {
|
||||||
this.nodesDataSource.remove(node);
|
this.nodesDataSource.remove(node);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { NodeConsoleService } from '../../../../../services/nodeConsole.service';
|
||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
import { ToasterService } from '../../../../../services/toaster.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-http-console-new-tab-action',
|
selector: 'app-http-console-new-tab-action',
|
||||||
@ -12,19 +11,11 @@ export class HttpConsoleNewTabActionComponent implements OnInit {
|
|||||||
@Input() server: Server;
|
@Input() server: Server;
|
||||||
@Input() nodes: Node[];
|
@Input() nodes: Node[];
|
||||||
|
|
||||||
constructor(private toasterService: ToasterService, private router: Router) {}
|
constructor(private nodeConsoleService: NodeConsoleService) {}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
openConsole() {
|
openConsole() {
|
||||||
this.nodes.forEach((n) => {
|
this.nodeConsoleService.openConsolesForAllNodesInNewTabs(this.nodes);
|
||||||
if (n.status === 'started') {
|
|
||||||
let url = this.router.url.split('/');
|
|
||||||
let urlString = `/static/web-ui/${url[1]}/${url[2]}/${url[3]}/${url[4]}/nodes/${n.node_id}`;
|
|
||||||
window.open(urlString);
|
|
||||||
} else {
|
|
||||||
this.toasterService.error('To open console please start the node');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
import { MapSettingsService } from '../../../../../services/mapsettings.service';
|
|
||||||
import { NodeConsoleService } from '../../../../../services/nodeConsole.service';
|
import { NodeConsoleService } from '../../../../../services/nodeConsole.service';
|
||||||
import { ToasterService } from '../../../../../services/toaster.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-http-console-action',
|
selector: 'app-http-console-action',
|
||||||
@ -13,22 +11,11 @@ export class HttpConsoleActionComponent implements OnInit {
|
|||||||
@Input() server: Server;
|
@Input() server: Server;
|
||||||
@Input() nodes: Node[];
|
@Input() nodes: Node[];
|
||||||
|
|
||||||
constructor(
|
constructor(private nodeConsoleService: NodeConsoleService) {}
|
||||||
private consoleService: NodeConsoleService,
|
|
||||||
private toasterService: ToasterService,
|
|
||||||
private mapSettingsService: MapSettingsService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
openConsole() {
|
openConsole() {
|
||||||
this.nodes.forEach((n) => {
|
this.nodeConsoleService.openConsolesForAllNodesInWidget(this.nodes);
|
||||||
if (n.status === 'started') {
|
|
||||||
this.mapSettingsService.logConsoleSubject.next(true);
|
|
||||||
this.consoleService.openConsoleForNode(n);
|
|
||||||
} else {
|
|
||||||
this.toasterService.error('To open console please start the node');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
<app-stop-node-action *ngIf="nodes.length" [server]="server" [nodes]="nodes"></app-stop-node-action>
|
<app-stop-node-action *ngIf="nodes.length" [server]="server" [nodes]="nodes"></app-stop-node-action>
|
||||||
<app-reload-node-action *ngIf="nodes.length" [server]="server" [nodes]="nodes"></app-reload-node-action>
|
<app-reload-node-action *ngIf="nodes.length" [server]="server" [nodes]="nodes"></app-reload-node-action>
|
||||||
<app-http-console-action
|
<app-http-console-action
|
||||||
*ngIf="!projectService.isReadOnly(project) && nodes.length === 1"
|
*ngIf="!projectService.isReadOnly(project) && nodes.length > 0"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
[nodes]="nodes"
|
[nodes]="nodes"
|
||||||
></app-http-console-action>
|
></app-http-console-action>
|
||||||
<app-http-console-new-tab-action
|
<app-http-console-new-tab-action
|
||||||
*ngIf="!projectService.isReadOnly(project) && nodes.length === 1"
|
*ngIf="!projectService.isReadOnly(project) && nodes.length > 0"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
[nodes]="nodes"
|
[nodes]="nodes"
|
||||||
></app-http-console-new-tab-action>
|
></app-http-console-new-tab-action>
|
||||||
|
@ -4,6 +4,8 @@ import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
|
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
|
||||||
import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler';
|
import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler';
|
||||||
@ -14,6 +16,8 @@ import { NodeConsoleService } from '../../../services/nodeConsole.service';
|
|||||||
import { MockedNodesDataSource, MockedNodeService } from '../project-map.component.spec';
|
import { MockedNodesDataSource, MockedNodeService } from '../project-map.component.spec';
|
||||||
import { LogConsoleComponent } from './log-console.component';
|
import { LogConsoleComponent } from './log-console.component';
|
||||||
import { LogEventsDataSource } from './log-events-datasource';
|
import { LogEventsDataSource } from './log-events-datasource';
|
||||||
|
import { MapSettingsService } from '../../../services/mapsettings.service';
|
||||||
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
|
||||||
export class MockedProjectWebServiceHandler {
|
export class MockedProjectWebServiceHandler {
|
||||||
public nodeNotificationEmitter = new EventEmitter<WebServiceMessage>();
|
public nodeNotificationEmitter = new EventEmitter<WebServiceMessage>();
|
||||||
@ -31,23 +35,32 @@ describe('LogConsoleComponent', () => {
|
|||||||
let mockedNodeService: MockedNodeService = new MockedNodeService();
|
let mockedNodeService: MockedNodeService = new MockedNodeService();
|
||||||
let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource();
|
let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource();
|
||||||
let mockedProjectWebServiceHandler: MockedProjectWebServiceHandler = new MockedProjectWebServiceHandler();
|
let mockedProjectWebServiceHandler: MockedProjectWebServiceHandler = new MockedProjectWebServiceHandler();
|
||||||
|
let nodeConsoleService: NodeConsoleService;
|
||||||
|
let mapSettingsService: MapSettingsService;
|
||||||
|
let toasterService: ToasterService;
|
||||||
|
|
||||||
let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler);
|
let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler);
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [HttpClientTestingModule, MatMenuModule, BrowserModule],
|
imports: [HttpClientTestingModule, RouterTestingModule, MatMenuModule, BrowserModule, MatSnackBarModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler },
|
{ provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler },
|
||||||
{ provide: NodeService, useValue: mockedNodeService },
|
{ provide: NodeService, useValue: mockedNodeService },
|
||||||
{ provide: NodesDataSource, useValue: mockedNodesDataSource },
|
{ provide: NodesDataSource, useValue: mockedNodesDataSource },
|
||||||
{ provide: LogEventsDataSource, useClass: LogEventsDataSource },
|
{ provide: LogEventsDataSource, useClass: LogEventsDataSource },
|
||||||
{ provide: HttpServer, useValue: httpServer },
|
{ provide: HttpServer, useValue: httpServer },
|
||||||
{ provide: NodeConsoleService },
|
NodeConsoleService,
|
||||||
|
ToasterService,
|
||||||
|
MapSettingsService
|
||||||
],
|
],
|
||||||
declarations: [LogConsoleComponent],
|
declarations: [LogConsoleComponent],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
toasterService = TestBed.inject(ToasterService);
|
||||||
|
mapSettingsService = TestBed.inject(MapSettingsService);
|
||||||
|
nodeConsoleService = TestBed.inject(NodeConsoleService);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -259,6 +259,38 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="list-item-inside" *ngIf="version.images.cdrom_image">
|
||||||
|
<span>
|
||||||
|
{{ version.images.cdrom_image}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span *ngIf="checkImageFromVersion(version.images.cdrom_image)"
|
||||||
|
><mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon></span
|
||||||
|
>
|
||||||
|
<span *ngIf="!checkImageFromVersion(version.images.cdrom_image)"
|
||||||
|
><mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon></span
|
||||||
|
>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
class="non-visible"
|
||||||
|
#file4
|
||||||
|
(change)="importImage($event, version.images.cdrom_image)"
|
||||||
|
ng2FileSelect
|
||||||
|
[uploader]="uploaderImage"
|
||||||
|
/>
|
||||||
|
<button class="button" mat-raised-button (click)="file4.click()">Import</button>
|
||||||
|
<button
|
||||||
|
class="button"
|
||||||
|
mat-raised-button
|
||||||
|
(click)="downloadImageFromVersion(version.images.cdrom_image)"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { MapSettingsService } from '../../../services/mapsettings.service';
|
||||||
import { ElectronService } from 'ngx-electron';
|
import { ElectronService } from 'ngx-electron';
|
||||||
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
|
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
|
||||||
import { Project } from '../../../models/project';
|
import { Project } from '../../../models/project';
|
||||||
@ -7,6 +8,7 @@ import { NodeService } from '../../../services/node.service';
|
|||||||
import { ServerService } from '../../../services/server.service';
|
import { ServerService } from '../../../services/server.service';
|
||||||
import { SettingsService } from '../../../services/settings.service';
|
import { SettingsService } from '../../../services/settings.service';
|
||||||
import { ToasterService } from '../../../services/toaster.service';
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
|
import { NodeConsoleService } from '../../../services/nodeConsole.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nodes-menu',
|
selector: 'app-nodes-menu',
|
||||||
@ -20,17 +22,19 @@ export class NodesMenuComponent {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private nodeService: NodeService,
|
private nodeService: NodeService,
|
||||||
|
private nodeConsoleService: NodeConsoleService,
|
||||||
private nodesDataSource: NodesDataSource,
|
private nodesDataSource: NodesDataSource,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
|
private mapSettingsService: MapSettingsService,
|
||||||
private electronService: ElectronService
|
private electronService: ElectronService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async startConsoleForAllNodes() {
|
async startConsoleForAllNodes() {
|
||||||
if (this.electronService.isElectronApp) {
|
if (this.electronService.isElectronApp) {
|
||||||
let consoleCommand = this.settingsService.get<string>('console_command')
|
let consoleCommand = this.settingsService.getConsoleSettings()
|
||||||
? this.settingsService.get<string>('console_command')
|
? this.settingsService.getConsoleSettings()
|
||||||
: this.nodeService.getDefaultCommand();
|
: this.nodeService.getDefaultCommand();
|
||||||
|
|
||||||
let nodes = this.nodesDataSource.getItems();
|
let nodes = this.nodesDataSource.getItems();
|
||||||
@ -48,7 +52,11 @@ export class NodesMenuComponent {
|
|||||||
await this.electronService.remote.require('./console-executor.js').openConsole(request);
|
await this.electronService.remote.require('./console-executor.js').openConsole(request);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error('Option to start all nodes not available in web browser.');
|
if (this.mapSettingsService.openConsolesInWidget) {
|
||||||
|
this.nodeConsoleService.openConsolesForAllNodesInWidget(this.nodesDataSource.getItems());
|
||||||
|
} else {
|
||||||
|
this.nodeConsoleService.openConsolesForAllNodesInNewTabs(this.nodesDataSource.getItems());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div *ngIf="project" [ngClass]="{ lightTheme: isLightThemeEnabled }" class="project-map">
|
<div *ngIf="project" [ngClass]="{ lightTheme: isLightThemeEnabled }" class="project-map">
|
||||||
<app-d3-map
|
<app-d3-map
|
||||||
*ngIf="!settings.angular_map"
|
*ngIf="!settings.angular_map && symbolsLoaded"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
[project]="project"
|
[project]="project"
|
||||||
[symbols]="symbols"
|
[symbols]="symbols"
|
||||||
@ -64,7 +64,6 @@
|
|||||||
<div class="menu-button-group">
|
<div class="menu-button-group">
|
||||||
<app-nodes-menu [server]="server" [project]="project"></app-nodes-menu>
|
<app-nodes-menu [server]="server" [project]="project"></app-nodes-menu>
|
||||||
<app-context-menu [project]="project" [server]="server"></app-context-menu>
|
<app-context-menu [project]="project" [server]="server"></app-context-menu>
|
||||||
<app-context-console-menu [project]="project" [server]="server"></app-context-console-menu>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -255,12 +254,6 @@
|
|||||||
(closeConsole)="toggleShowConsole($event)"
|
(closeConsole)="toggleShowConsole($event)"
|
||||||
></app-console-wrapper>
|
></app-console-wrapper>
|
||||||
</div>
|
</div>
|
||||||
<div [ngClass]="{ visible: !isTopologySummaryVisible }">
|
|
||||||
<app-topology-summary
|
|
||||||
*ngIf="project"
|
|
||||||
[server]="server"
|
|
||||||
[project]="project"
|
|
||||||
(closeTopologySummary)="toggleShowTopologySummary($event)"
|
|
||||||
></app-topology-summary>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ng-template #topologySummaryContainer></ng-template>
|
||||||
|
@ -59,7 +59,6 @@ import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProje
|
|||||||
import { ServerService } from '../../services/server.service';
|
import { ServerService } from '../../services/server.service';
|
||||||
import { MockedServerService } from '../../services/server.service.spec';
|
import { MockedServerService } from '../../services/server.service.spec';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
import { MockedSettingsService } from '../../services/settings.service.spec';
|
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { MockedToasterService } from '../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../services/toaster.service.spec';
|
||||||
import { ToolsService } from '../../services/tools.service';
|
import { ToolsService } from '../../services/tools.service';
|
||||||
@ -300,7 +299,7 @@ xdescribe('ProjectMapComponent', () => {
|
|||||||
{ provide: NodesDataSource, useValue: nodesDataSource },
|
{ provide: NodesDataSource, useValue: nodesDataSource },
|
||||||
{ provide: LinksDataSource, useValue: linksDataSource },
|
{ provide: LinksDataSource, useValue: linksDataSource },
|
||||||
{ provide: DrawingsDataSource, useValue: drawingsDataSource },
|
{ provide: DrawingsDataSource, useValue: drawingsDataSource },
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService },
|
||||||
{ provide: ToolsService },
|
{ provide: ToolsService },
|
||||||
{ provide: SelectionManager },
|
{ provide: SelectionManager },
|
||||||
{ provide: SelectionTool },
|
{ provide: SelectionTool },
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Injector, OnDestroy, OnInit, SimpleChange, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||||
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||||
import * as Mousetrap from 'mousetrap';
|
import * as Mousetrap from 'mousetrap';
|
||||||
import { from, Observable, Subscription } from 'rxjs';
|
import { from, Observable, Subscription } from 'rxjs';
|
||||||
import { map, mergeMap } from 'rxjs/operators';
|
import { map, mergeMap, takeUntil } from 'rxjs/operators';
|
||||||
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
||||||
import { MapDrawingToDrawingConverter } from '../../cartography/converters/map/map-drawing-to-drawing-converter';
|
import { MapDrawingToDrawingConverter } from '../../cartography/converters/map/map-drawing-to-drawing-converter';
|
||||||
import { MapLabelToLabelConverter } from '../../cartography/converters/map/map-label-to-label-converter';
|
import { MapLabelToLabelConverter } from '../../cartography/converters/map/map-label-to-label-converter';
|
||||||
@ -74,7 +74,7 @@ import { ImportProjectDialogComponent } from '../projects/import-project-dialog/
|
|||||||
import { NavigationDialogComponent } from '../projects/navigation-dialog/navigation-dialog.component';
|
import { NavigationDialogComponent } from '../projects/navigation-dialog/navigation-dialog.component';
|
||||||
import { SaveProjectDialogComponent } from '../projects/save-project-dialog/save-project-dialog.component';
|
import { SaveProjectDialogComponent } from '../projects/save-project-dialog/save-project-dialog.component';
|
||||||
import { NodeAddedEvent } from '../template/template-list-dialog/template-list-dialog.component';
|
import { NodeAddedEvent } from '../template/template-list-dialog/template-list-dialog.component';
|
||||||
import { ContextConsoleMenuComponent } from './context-console-menu/context-console-menu.component';
|
import { TopologySummaryComponent } from '../topology-summary/topology-summary.component';
|
||||||
import { ContextMenuComponent } from './context-menu/context-menu.component';
|
import { ContextMenuComponent } from './context-menu/context-menu.component';
|
||||||
import { NodeCreatedLabelStylesFixer } from './helpers/node-created-label-styles-fixer';
|
import { NodeCreatedLabelStylesFixer } from './helpers/node-created-label-styles-fixer';
|
||||||
import { NewTemplateDialogComponent } from './new-template-dialog/new-template-dialog.component';
|
import { NewTemplateDialogComponent } from './new-template-dialog/new-template-dialog.component';
|
||||||
@ -105,6 +105,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
public gridVisibility: boolean = false;
|
public gridVisibility: boolean = false;
|
||||||
public toolbarVisibility: boolean = true;
|
public toolbarVisibility: boolean = true;
|
||||||
public symbolScaling: boolean = true;
|
public symbolScaling: boolean = true;
|
||||||
|
public symbolsLoaded: boolean = false;
|
||||||
|
private instance: ComponentRef<TopologySummaryComponent>;
|
||||||
|
|
||||||
tools = {
|
tools = {
|
||||||
selection: true,
|
selection: true,
|
||||||
@ -121,9 +123,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
public isLightThemeEnabled: boolean = false;
|
public isLightThemeEnabled: boolean = false;
|
||||||
|
|
||||||
@ViewChild(ContextMenuComponent) contextMenu: ContextMenuComponent;
|
@ViewChild(ContextMenuComponent) contextMenu: ContextMenuComponent;
|
||||||
@ViewChild(ContextConsoleMenuComponent) consoleContextMenu: ContextConsoleMenuComponent;
|
|
||||||
@ViewChild(D3MapComponent) mapChild: D3MapComponent;
|
@ViewChild(D3MapComponent) mapChild: D3MapComponent;
|
||||||
@ViewChild(ProjectMapMenuComponent) projectMapMenuComponent: ProjectMapMenuComponent;
|
@ViewChild(ProjectMapMenuComponent) projectMapMenuComponent: ProjectMapMenuComponent;
|
||||||
|
@ViewChild('topologySummaryContainer', {read: ViewContainerRef}) topologySummaryContainer: ViewContainerRef;
|
||||||
|
|
||||||
private projectMapSubscription: Subscription = new Subscription();
|
private projectMapSubscription: Subscription = new Subscription();
|
||||||
|
|
||||||
@ -173,12 +175,17 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
private title: Title,
|
private title: Title,
|
||||||
private nodeConsoleService: NodeConsoleService,
|
private nodeConsoleService: NodeConsoleService,
|
||||||
private symbolService: SymbolService,
|
private symbolService: SymbolService,
|
||||||
private cd: ChangeDetectorRef
|
private cd: ChangeDetectorRef,
|
||||||
|
private cfr: ComponentFactoryResolver,
|
||||||
|
private injector: Injector
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.getSettings();
|
this.getSettings();
|
||||||
this.progressService.activate();
|
this.progressService.activate();
|
||||||
|
this.symbolService.symbolsLoaded.subscribe(loaded => {
|
||||||
|
this.symbolsLoaded = true;
|
||||||
|
});
|
||||||
|
|
||||||
if (this.serverService.isServiceInitialized) {
|
if (this.serverService.isServiceInitialized) {
|
||||||
this.getData();
|
this.getData();
|
||||||
@ -208,7 +215,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.settings = this.settingsService.getAll();
|
this.settings = this.settingsService.getAll();
|
||||||
this.symbolScaling = this.mapSettingsService.getSymbolScaling();
|
this.symbolScaling = this.mapSettingsService.getSymbolScaling();
|
||||||
this.isTopologySummaryVisible = this.mapSettingsService.isTopologySummaryVisible;
|
|
||||||
this.isConsoleVisible = this.mapSettingsService.isLogConsoleVisible;
|
this.isConsoleVisible = this.mapSettingsService.isLogConsoleVisible;
|
||||||
this.mapSettingsService.logConsoleSubject.subscribe((value) => (this.isConsoleVisible = value));
|
this.mapSettingsService.logConsoleSubject.subscribe((value) => (this.isConsoleVisible = value));
|
||||||
this.notificationsVisibility = localStorage.getItem('notificationsVisibility') === 'true' ? true : false;
|
this.notificationsVisibility = localStorage.getItem('notificationsVisibility') === 'true' ? true : false;
|
||||||
@ -216,6 +222,21 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? true : false;
|
this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async lazyLoadTopologySummary() {
|
||||||
|
if (this.isTopologySummaryVisible) {
|
||||||
|
const {TopologySummaryComponent} = await import('../topology-summary/topology-summary.component');
|
||||||
|
const componentFactory = this.cfr.resolveComponentFactory(TopologySummaryComponent);
|
||||||
|
this.instance = this.topologySummaryContainer.createComponent(componentFactory, null, this.injector);
|
||||||
|
this.instance.instance.server = this.server;
|
||||||
|
this.instance.instance.project = this.project;
|
||||||
|
} else if (this.instance) {
|
||||||
|
if (this.instance.instance) {
|
||||||
|
this.instance.instance.ngOnDestroy();
|
||||||
|
this.instance.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addSubscriptions() {
|
addSubscriptions() {
|
||||||
this.projectMapSubscription.add(
|
this.projectMapSubscription.add(
|
||||||
this.mapSettingsService.mapRenderedEmitter.subscribe((value: boolean) => {
|
this.mapSettingsService.mapRenderedEmitter.subscribe((value: boolean) => {
|
||||||
@ -299,8 +320,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
.pipe(
|
.pipe(
|
||||||
mergeMap((server: Server) => {
|
mergeMap((server: Server) => {
|
||||||
if (!server) this.router.navigate(['/servers']);
|
if (!server) this.router.navigate(['/servers']);
|
||||||
|
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
|
||||||
|
// load symbols
|
||||||
|
this.symbolService.load(this.server);
|
||||||
|
|
||||||
return this.projectService.get(server, paramMap.get('project_id')).pipe(
|
return this.projectService.get(server, paramMap.get('project_id')).pipe(
|
||||||
map((project) => {
|
map((project) => {
|
||||||
return project;
|
return project;
|
||||||
@ -314,6 +338,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.projectService.open(this.server, this.project.project_id);
|
this.projectService.open(this.server, this.project.project_id);
|
||||||
this.title.setTitle(this.project.name);
|
this.title.setTitle(this.project.name);
|
||||||
this.isInterfaceLabelVisible = this.mapSettingsService.showInterfaceLabels;
|
this.isInterfaceLabelVisible = this.mapSettingsService.showInterfaceLabels;
|
||||||
|
this.toggleShowTopologySummary(this.mapSettingsService.isTopologySummaryVisible);
|
||||||
|
|
||||||
this.recentlyOpenedProjectService.setServerId(this.server.id.toString());
|
this.recentlyOpenedProjectService.setServerId(this.server.id.toString());
|
||||||
this.recentlyOpenedProjectService.setProjectId(this.project.project_id);
|
this.recentlyOpenedProjectService.setProjectId(this.project.project_id);
|
||||||
@ -386,16 +411,27 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
Mousetrap.bind('del', (event: Event) => {
|
Mousetrap.bind('del', (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const selected = this.selectionManager.getSelected();
|
this.deleteItems();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
selected
|
deleteItems() {
|
||||||
.filter((item) => item instanceof MapNode)
|
this.bottomSheet.open(ConfirmationBottomSheetComponent);
|
||||||
.forEach((item: MapNode) => {
|
let bottomSheetRef = this.bottomSheet._openedBottomSheetRef;
|
||||||
const node = this.mapNodeToNode.convert(item);
|
bottomSheetRef.instance.message = 'Do you want to delete all selected objects?';
|
||||||
this.nodeService.delete(this.server, node).subscribe((data) => {
|
const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => {
|
||||||
this.toasterService.success('Node has been deleted');
|
if (result) {
|
||||||
|
const selected = this.selectionManager.getSelected();
|
||||||
|
|
||||||
|
selected
|
||||||
|
.filter((item) => item instanceof MapNode)
|
||||||
|
.forEach((item: MapNode) => {
|
||||||
|
const node = this.mapNodeToNode.convert(item);
|
||||||
|
this.nodeService.delete(this.server, node).subscribe((data) => {
|
||||||
|
this.toasterService.success('Node has been deleted');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,33 +484,33 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
const onLinkContextMenu = this.linkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
const onLinkContextMenu = this.linkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
||||||
const link = this.mapLinkToLink.convert(eventLink.link);
|
const link = this.mapLinkToLink.convert(eventLink.link);
|
||||||
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.pageY, eventLink.event.pageX);
|
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.screenY - 60, eventLink.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onEthernetLinkContextMenu = this.ethernetLinkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
const onEthernetLinkContextMenu = this.ethernetLinkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
||||||
const link = this.mapLinkToLink.convert(eventLink.link);
|
const link = this.mapLinkToLink.convert(eventLink.link);
|
||||||
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.pageY, eventLink.event.pageX);
|
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.screenY - 60, eventLink.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSerialLinkContextMenu = this.serialLinkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
const onSerialLinkContextMenu = this.serialLinkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
|
||||||
const link = this.mapLinkToLink.convert(eventLink.link);
|
const link = this.mapLinkToLink.convert(eventLink.link);
|
||||||
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.pageY, eventLink.event.pageX);
|
this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.screenY - 60, eventLink.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onNodeContextMenu = this.nodeWidget.onContextMenu.subscribe((eventNode: NodeContextMenu) => {
|
const onNodeContextMenu = this.nodeWidget.onContextMenu.subscribe((eventNode: NodeContextMenu) => {
|
||||||
const node = this.mapNodeToNode.convert(eventNode.node);
|
const node = this.mapNodeToNode.convert(eventNode.node);
|
||||||
this.contextMenu.openMenuForNode(node, eventNode.event.pageY, eventNode.event.pageX);
|
this.contextMenu.openMenuForNode(node, eventNode.event.screenY - 60, eventNode.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onDrawingContextMenu = this.drawingsWidget.onContextMenu.subscribe((eventDrawing: DrawingContextMenu) => {
|
const onDrawingContextMenu = this.drawingsWidget.onContextMenu.subscribe((eventDrawing: DrawingContextMenu) => {
|
||||||
const drawing = this.mapDrawingToDrawing.convert(eventDrawing.drawing);
|
const drawing = this.mapDrawingToDrawing.convert(eventDrawing.drawing);
|
||||||
this.contextMenu.openMenuForDrawing(drawing, eventDrawing.event.pageY, eventDrawing.event.pageX);
|
this.contextMenu.openMenuForDrawing(drawing, eventDrawing.event.screenY - 60, eventDrawing.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onLabelContextMenu = this.labelWidget.onContextMenu.subscribe((eventLabel: LabelContextMenu) => {
|
const onLabelContextMenu = this.labelWidget.onContextMenu.subscribe((eventLabel: LabelContextMenu) => {
|
||||||
const label = this.mapLabelToLabel.convert(eventLabel.label);
|
const label = this.mapLabelToLabel.convert(eventLabel.label);
|
||||||
const node = this.nodes.find((n) => n.node_id === eventLabel.label.nodeId);
|
const node = this.nodes.find((n) => n.node_id === eventLabel.label.nodeId);
|
||||||
this.contextMenu.openMenuForLabel(label, node, eventLabel.event.pageY, eventLabel.event.pageX);
|
this.contextMenu.openMenuForLabel(label, node, eventLabel.event.screenY - 60, eventLabel.event.screenX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onInterfaceLabelContextMenu = this.interfaceLabelWidget.onContextMenu.subscribe(
|
const onInterfaceLabelContextMenu = this.interfaceLabelWidget.onContextMenu.subscribe(
|
||||||
@ -484,8 +520,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.contextMenu.openMenuForInterfaceLabel(
|
this.contextMenu.openMenuForInterfaceLabel(
|
||||||
linkNode,
|
linkNode,
|
||||||
link,
|
link,
|
||||||
eventInterfaceLabel.event.pageY,
|
eventInterfaceLabel.event.screenY - 60,
|
||||||
eventInterfaceLabel.event.pageX
|
eventInterfaceLabel.event.screenX
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -514,11 +550,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.contextMenu.openMenuForListOfElements(drawings, nodes, labels, links, event.pageY, event.pageX);
|
this.contextMenu.openMenuForListOfElements(drawings, nodes, labels, links, event.pageY, event.pageX);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onContextConsoleMenu = this.nodeWidget.onContextConsoleMenu.subscribe((eventNode: NodeContextMenu) => {
|
|
||||||
const node = this.mapNodeToNode.convert(eventNode.node);
|
|
||||||
this.consoleContextMenu.openMenu(node, eventNode.event.pageY, eventNode.event.pageX);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.projectMapSubscription.add(onLinkContextMenu);
|
this.projectMapSubscription.add(onLinkContextMenu);
|
||||||
this.projectMapSubscription.add(onEthernetLinkContextMenu);
|
this.projectMapSubscription.add(onEthernetLinkContextMenu);
|
||||||
this.projectMapSubscription.add(onSerialLinkContextMenu);
|
this.projectMapSubscription.add(onSerialLinkContextMenu);
|
||||||
@ -527,7 +558,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.projectMapSubscription.add(onContextMenu);
|
this.projectMapSubscription.add(onContextMenu);
|
||||||
this.projectMapSubscription.add(onLabelContextMenu);
|
this.projectMapSubscription.add(onLabelContextMenu);
|
||||||
this.projectMapSubscription.add(onInterfaceLabelContextMenu);
|
this.projectMapSubscription.add(onInterfaceLabelContextMenu);
|
||||||
this.projectMapSubscription.add(onContextConsoleMenu);
|
|
||||||
this.mapChangeDetectorRef.detectChanges();
|
this.mapChangeDetectorRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,6 +566,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeAddedEvent.x = nodeAddedEvent.x / this.mapScaleService.getScale();
|
||||||
|
nodeAddedEvent.y = nodeAddedEvent.y / this.mapScaleService.getScale();
|
||||||
|
|
||||||
this.progressService.activate();
|
this.progressService.activate();
|
||||||
this.nodeService
|
this.nodeService
|
||||||
.createFromTemplate(
|
.createFromTemplate(
|
||||||
@ -796,6 +829,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
public toggleShowTopologySummary(visible: boolean) {
|
public toggleShowTopologySummary(visible: boolean) {
|
||||||
this.isTopologySummaryVisible = visible;
|
this.isTopologySummaryVisible = visible;
|
||||||
this.mapSettingsService.toggleTopologySummary(this.isTopologySummaryVisible);
|
this.mapSettingsService.toggleTopologySummary(this.isTopologySummaryVisible);
|
||||||
|
this.lazyLoadTopologySummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleNotifications(visible: boolean) {
|
public toggleNotifications(visible: boolean) {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
.import-button {
|
.import-button {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
width: 160px;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-button {
|
.add-button {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
width: 160px;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,3 +15,7 @@
|
|||||||
margin-left: -470px;
|
margin-left: -470px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
@ -23,7 +23,6 @@ import { MockedProjectService } from '../../services/project.service.spec';
|
|||||||
import { ServerService } from '../../services/server.service';
|
import { ServerService } from '../../services/server.service';
|
||||||
import { MockedServerService } from '../../services/server.service.spec';
|
import { MockedServerService } from '../../services/server.service.spec';
|
||||||
import { Settings, SettingsService } from '../../services/settings.service';
|
import { Settings, SettingsService } from '../../services/settings.service';
|
||||||
import { MockedSettingsService } from '../../services/settings.service.spec';
|
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { ConfigureGns3VMDialogComponent } from '../servers/configure-gns3vm-dialog/configure-gns3vm-dialog.component';
|
import { ConfigureGns3VMDialogComponent } from '../servers/configure-gns3vm-dialog/configure-gns3vm-dialog.component';
|
||||||
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
||||||
@ -70,7 +69,7 @@ xdescribe('ProjectsComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: ServerService, useClass: MockedServerService },
|
{ provide: ServerService, useClass: MockedServerService },
|
||||||
{ provide: ProjectService, useValue: mockedProjectService },
|
{ provide: ProjectService, useValue: mockedProjectService },
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService},
|
||||||
{ provide: ToasterService },
|
{ provide: ToasterService },
|
||||||
{ provide: ElectronService, useValue: electronService },
|
{ provide: ElectronService, useValue: electronService },
|
||||||
ProgressService,
|
ProgressService,
|
||||||
@ -83,10 +82,10 @@ xdescribe('ProjectsComponent', () => {
|
|||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
serverService = TestBed.get(ServerService);
|
serverService = TestBed.inject(ServerService);
|
||||||
settingsService = TestBed.get(SettingsService);
|
settingsService = TestBed.inject(SettingsService);
|
||||||
projectService = TestBed.get(ProjectService);
|
projectService = TestBed.inject(ProjectService);
|
||||||
progressService = TestBed.get(ProgressService);
|
progressService = TestBed.inject(ProgressService);
|
||||||
|
|
||||||
server = new Server();
|
server = new Server();
|
||||||
server.id = 99;
|
server.id = 99;
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions>
|
<div mat-dialog-actions>
|
||||||
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">No Thanks</button>
|
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">Cancel</button>
|
||||||
<button mat-button (click)="onAddClick()" tabindex="2" mat-raised-button color="primary">Add</button>
|
<button mat-button (click)="onAddClick()" tabindex="2" mat-raised-button color="primary">Add</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -13,19 +13,8 @@
|
|||||||
<mat-checkbox [(ngModel)]="settings.crash_reports">Send anonymous crash reports</mat-checkbox><br/>
|
<mat-checkbox [(ngModel)]="settings.crash_reports">Send anonymous crash reports</mat-checkbox><br/>
|
||||||
<mat-checkbox [(ngModel)]="integrateLinksLabelsToLinks">Integrate link labels to links</mat-checkbox><br/>
|
<mat-checkbox [(ngModel)]="integrateLinksLabelsToLinks">Integrate link labels to links</mat-checkbox><br/>
|
||||||
<mat-checkbox [(ngModel)]="openReadme">Automatically open project README files</mat-checkbox>
|
<mat-checkbox [(ngModel)]="openReadme">Automatically open project README files</mat-checkbox>
|
||||||
|
<mat-checkbox [(ngModel)]="openConsolesInWidget">Open consoles in the widget instead of in new tabs after clicking start consoles for all nodes</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div>
|
|
||||||
<mat-checkbox [(ngModel)]="settings.experimental_features"
|
|
||||||
>Enable experimental features (WARNING: IT CAN BREAK YOU LABS!)</mat-checkbox
|
|
||||||
>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- <div>
|
|
||||||
<mat-checkbox [(ngModel)]="settings.angular_map"
|
|
||||||
>Enable experimental Angular Map (WARNING: IT CAN BREAK YOU LABS!)</mat-checkbox
|
|
||||||
>
|
|
||||||
</div> -->
|
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
|
|
||||||
<mat-expansion-panel [expanded]="false">
|
<mat-expansion-panel [expanded]="false">
|
||||||
|
@ -6,7 +6,6 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { PersistenceModule } from 'angular-persistence';
|
|
||||||
import { MapSettingsService } from '../../services/mapsettings.service';
|
import { MapSettingsService } from '../../services/mapsettings.service';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
import { ConsoleService } from '../../services/settings/console.service';
|
import { ConsoleService } from '../../services/settings/console.service';
|
||||||
@ -23,7 +22,8 @@ describe('SettingsComponent', () => {
|
|||||||
let mapSettingsService = {
|
let mapSettingsService = {
|
||||||
integrateLinkLabelsToLinks: true,
|
integrateLinkLabelsToLinks: true,
|
||||||
toggleIntegrateInterfaceLabels(val: boolean) {},
|
toggleIntegrateInterfaceLabels(val: boolean) {},
|
||||||
toggleOpenReadme(val: boolean) {}
|
toggleOpenReadme(val: boolean) {},
|
||||||
|
toggleOpenConsolesInWidget(val: boolean) {}
|
||||||
};
|
};
|
||||||
let consoleService;
|
let consoleService;
|
||||||
let updatesService = autoSpy(UpdatesService);
|
let updatesService = autoSpy(UpdatesService);
|
||||||
@ -38,7 +38,6 @@ describe('SettingsComponent', () => {
|
|||||||
MatExpansionModule,
|
MatExpansionModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
PersistenceModule,
|
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
@ -76,11 +75,19 @@ describe('SettingsComponent', () => {
|
|||||||
};
|
};
|
||||||
const getAll = spyOn(settingsService, 'getAll').and.returnValue(settings);
|
const getAll = spyOn(settingsService, 'getAll').and.returnValue(settings);
|
||||||
const setAll = spyOn(settingsService, 'setAll');
|
const setAll = spyOn(settingsService, 'setAll');
|
||||||
|
spyOn(mapSettingsService, 'toggleIntegrateInterfaceLabels');
|
||||||
|
spyOn(mapSettingsService, 'toggleOpenConsolesInWidget');
|
||||||
|
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
|
|
||||||
expect(getAll).toHaveBeenCalled();
|
expect(getAll).toHaveBeenCalled();
|
||||||
expect(component.settings).toEqual(settings);
|
expect(component.settings).toEqual(settings);
|
||||||
|
|
||||||
component.settings.crash_reports = false;
|
component.settings.crash_reports = false;
|
||||||
component.save();
|
component.save();
|
||||||
|
|
||||||
expect(setAll).toHaveBeenCalledWith(settings);
|
expect(setAll).toHaveBeenCalledWith(settings);
|
||||||
|
expect(mapSettingsService.toggleIntegrateInterfaceLabels).toHaveBeenCalled();
|
||||||
|
expect(mapSettingsService.toggleOpenConsolesInWidget).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { MapSettingsService } from '../../services/mapsettings.service';
|
import { MapSettingsService } from '../../services/mapsettings.service';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { Settings, SettingsService } from '../../services/settings.service';
|
||||||
import { ConsoleService } from '../../services/settings/console.service';
|
import { ConsoleService } from '../../services/settings/console.service';
|
||||||
import { ThemeService } from '../../services/theme.service';
|
import { ThemeService } from '../../services/theme.service';
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
@ -12,10 +12,11 @@ import { UpdatesService } from '../../services/updates.service';
|
|||||||
styleUrls: ['./settings.component.scss'],
|
styleUrls: ['./settings.component.scss'],
|
||||||
})
|
})
|
||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit {
|
||||||
settings = { ...SettingsService.DEFAULTS };
|
settings: Settings;
|
||||||
consoleCommand: string;
|
consoleCommand: string;
|
||||||
integrateLinksLabelsToLinks: boolean;
|
integrateLinksLabelsToLinks: boolean;
|
||||||
openReadme: boolean;
|
openReadme: boolean;
|
||||||
|
openConsolesInWidget: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
@ -31,6 +32,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.consoleCommand = this.consoleService.command;
|
this.consoleCommand = this.consoleService.command;
|
||||||
this.integrateLinksLabelsToLinks = this.mapSettingsService.integrateLinkLabelsToLinks;
|
this.integrateLinksLabelsToLinks = this.mapSettingsService.integrateLinkLabelsToLinks;
|
||||||
this.openReadme = this.mapSettingsService.openReadme;
|
this.openReadme = this.mapSettingsService.openReadme;
|
||||||
|
this.openConsolesInWidget = this.mapSettingsService.openConsolesInWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
@ -39,6 +41,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
|
|
||||||
this.mapSettingsService.toggleIntegrateInterfaceLabels(this.integrateLinksLabelsToLinks);
|
this.mapSettingsService.toggleIntegrateInterfaceLabels(this.integrateLinksLabelsToLinks);
|
||||||
this.mapSettingsService.toggleOpenReadme(this.openReadme);
|
this.mapSettingsService.toggleOpenReadme(this.openReadme);
|
||||||
|
this.mapSettingsService.toggleOpenConsolesInWidget(this.openConsolesInWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDarkMode(value: boolean) {
|
setDarkMode(value: boolean) {
|
||||||
|
@ -18,6 +18,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions>
|
<div mat-dialog-actions>
|
||||||
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">No Thanks</button>
|
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">Cancel</button>
|
||||||
<button mat-button (click)="onAddClick()" tabindex="2" mat-raised-button color="primary">Add</button>
|
<button mat-button (click)="onAddClick()" tabindex="2" mat-raised-button color="primary">Add</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,25 +43,25 @@
|
|||||||
<span *ngIf="i % 4 === 0" class="templateRow">
|
<span *ngIf="i % 4 === 0" class="templateRow">
|
||||||
<span class="templateIcon">
|
<span class="templateIcon">
|
||||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i])">
|
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i])">
|
||||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i])" />
|
<img class="image" alt="Image" [src]="getImageSourceForTemplate(filteredTemplates[i])" />
|
||||||
</div>
|
</div>
|
||||||
<div class="templateText">{{ filteredTemplates[i].name }}</div>
|
<div class="templateText">{{ filteredTemplates[i].name }}</div>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="filteredTemplates[i + 1]" class="templateIcon">
|
<span *ngIf="filteredTemplates[i + 1]" class="templateIcon">
|
||||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 1])">
|
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 1])">
|
||||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 1])" />
|
<img class="image" alt="Image" [src]="getImageSourceForTemplate(filteredTemplates[i + 1])" />
|
||||||
</div>
|
</div>
|
||||||
<div class="templateText">{{ filteredTemplates[i + 1].name }}</div>
|
<div class="templateText">{{ filteredTemplates[i + 1].name }}</div>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="filteredTemplates[i + 2]" class="templateIcon">
|
<span *ngIf="filteredTemplates[i + 2]" class="templateIcon">
|
||||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 2])">
|
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 2])">
|
||||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 2])" />
|
<img class="image" alt="Image" [src]="getImageSourceForTemplate(filteredTemplates[i + 2])" />
|
||||||
</div>
|
</div>
|
||||||
<div class="templateText">{{ filteredTemplates[i + 2].name }}</div>
|
<div class="templateText">{{ filteredTemplates[i + 2].name }}</div>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="filteredTemplates[i + 3]" class="templateIcon">
|
<span *ngIf="filteredTemplates[i + 3]" class="templateIcon">
|
||||||
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 3])">
|
<div mwlDraggable (dragStart)="dragStart($event)" (dragEnd)="dragEnd($event, filteredTemplates[i + 3])">
|
||||||
<img class="image" [src]="getImageSourceForTemplate(filteredTemplates[i + 3])" />
|
<img class="image" alt="Image" [src]="getImageSourceForTemplate(filteredTemplates[i + 3])" />
|
||||||
</div>
|
</div>
|
||||||
<div class="templateText">{{ filteredTemplates[i + 3].name }}</div>
|
<div class="templateText">{{ filteredTemplates[i + 3].name }}</div>
|
||||||
</span>
|
</span>
|
||||||
|
@ -8,6 +8,7 @@ import { MapScaleService } from '../../services/mapScale.service';
|
|||||||
import { SymbolService } from '../../services/symbol.service';
|
import { SymbolService } from '../../services/symbol.service';
|
||||||
import { TemplateService } from '../../services/template.service';
|
import { TemplateService } from '../../services/template.service';
|
||||||
import { NodeAddedEvent, TemplateListDialogComponent } from './template-list-dialog/template-list-dialog.component';
|
import { NodeAddedEvent, TemplateListDialogComponent } from './template-list-dialog/template-list-dialog.component';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-template',
|
selector: 'app-template',
|
||||||
@ -49,7 +50,8 @@ export class TemplateComponent implements OnInit, OnDestroy {
|
|||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private templateService: TemplateService,
|
private templateService: TemplateService,
|
||||||
private scaleService: MapScaleService,
|
private scaleService: MapScaleService,
|
||||||
private symbolService: SymbolService
|
private symbolService: SymbolService,
|
||||||
|
private domSanitizer: DomSanitizer
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -127,7 +129,9 @@ export class TemplateComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getImageSourceForTemplate(template: Template) {
|
getImageSourceForTemplate(template: Template) {
|
||||||
return this.symbolService.getSymbolFromTemplate(this.server, template);
|
let symbol = this.symbolService.getSymbolFromTemplate(template);
|
||||||
|
if (symbol) return this.domSanitizer.bypassSecurityTrustUrl(`data:image/svg+xml;base64,${btoa(symbol.raw)}`);
|
||||||
|
return this.domSanitizer.bypassSecurityTrustUrl('data:image/svg+xml;base64,');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Logged in user info</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card *ngIf="user">
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item> Username: {{user.username}} </mat-list-item>
|
||||||
|
<mat-list-item> Full name: {{user.full_name}} </mat-list-item>
|
||||||
|
<mat-list-item> Email: {{user.email}} </mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-raised-button color="primary" class="full_width" (click)="copyToken()">Click to copy access token</button><br />
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
.full_width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../services/server.service';
|
||||||
|
import { UserService } from '../../../services/user.service';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
|
import { User } from '../../../models/users/user';
|
||||||
|
import { Server } from '../../../models/server';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-logged-user',
|
||||||
|
templateUrl: './logged-user.component.html',
|
||||||
|
styleUrls: ['./logged-user.component.scss'],
|
||||||
|
})
|
||||||
|
export class LoggedUserComponent implements OnInit {
|
||||||
|
public user: User;
|
||||||
|
public server: Server;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private userService: UserService,
|
||||||
|
private toasterService: ToasterService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
let serverId = this.route.snapshot.paramMap.get('server_id');
|
||||||
|
this.serverService.get(+serverId).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.userService.getInformationAboutLoggedUser(server).subscribe((response: any) => {
|
||||||
|
this.user = response;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyToken() {
|
||||||
|
const selBox = document.createElement('textarea');
|
||||||
|
selBox.style.position = 'fixed';
|
||||||
|
selBox.style.left = '0';
|
||||||
|
selBox.style.top = '0';
|
||||||
|
selBox.style.opacity = '0';
|
||||||
|
selBox.value = this.server.authToken;
|
||||||
|
document.body.appendChild(selBox);
|
||||||
|
selBox.focus();
|
||||||
|
selBox.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(selBox);
|
||||||
|
|
||||||
|
this.toasterService.success('Token copied');
|
||||||
|
}
|
||||||
|
}
|
26
src/app/filters/authImageFilter.ts
Normal file
26
src/app/filters/authImageFilter.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { Console } from 'console';
|
||||||
|
import { Server } from '../models/server';
|
||||||
|
import { HttpServer } from '../services/http-server.service';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'authImage'
|
||||||
|
})
|
||||||
|
export class AuthImageFilter implements PipeTransform {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpServer: HttpServer,
|
||||||
|
private domSanitizer: DomSanitizer
|
||||||
|
) {}
|
||||||
|
|
||||||
|
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(this.domSanitizer.bypassSecurityTrustUrl(reader.result as string));
|
||||||
|
reader.readAsDataURL(imageBlob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,10 @@
|
|||||||
<mat-icon>help</mat-icon>
|
<mat-icon>help</mat-icon>
|
||||||
<span>Help</span>
|
<span>Help</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-menu-item (click)="goToUserInfo()">
|
||||||
|
<mat-icon>person</mat-icon>
|
||||||
|
<span>User info</span>
|
||||||
|
</button>
|
||||||
<button mat-menu-item (click)="logout()">
|
<button mat-menu-item (click)="logout()">
|
||||||
<mat-icon>highlight_off</mat-icon>
|
<mat-icon>highlight_off</mat-icon>
|
||||||
<span>Logout</span>
|
<span>Logout</span>
|
||||||
|
@ -4,6 +4,7 @@ import { MatMenuModule } from '@angular/material/menu';
|
|||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { ServerService } from '../../services/server.service';
|
||||||
import { ElectronService } from 'ngx-electron';
|
import { ElectronService } from 'ngx-electron';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { ProgressComponent } from '../../common/progress/progress.component';
|
import { ProgressComponent } from '../../common/progress/progress.component';
|
||||||
@ -13,6 +14,9 @@ import { ServerManagementService, ServerStateEvent } from '../../services/server
|
|||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { MockedToasterService } from '../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../services/toaster.service.spec';
|
||||||
import { DefaultLayoutComponent } from './default-layout.component';
|
import { DefaultLayoutComponent } from './default-layout.component';
|
||||||
|
import { IndexedDbService } from '../../services/indexed-db.service';
|
||||||
|
import { HttpServer, ServerErrorHandler } from '../../services/http-server.service';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
|
||||||
class ElectronServiceMock {
|
class ElectronServiceMock {
|
||||||
public isElectronApp: boolean;
|
public isElectronApp: boolean;
|
||||||
@ -28,6 +32,10 @@ describe('DefaultLayoutComponent', () => {
|
|||||||
let fixture: ComponentFixture<DefaultLayoutComponent>;
|
let fixture: ComponentFixture<DefaultLayoutComponent>;
|
||||||
let electronServiceMock: ElectronServiceMock;
|
let electronServiceMock: ElectronServiceMock;
|
||||||
let serverManagementService = new MockedServerManagementService();
|
let serverManagementService = new MockedServerManagementService();
|
||||||
|
let serverService: ServerService;
|
||||||
|
let indexedDbService: IndexedDbService;
|
||||||
|
let httpServer: HttpServer;
|
||||||
|
let errorHandler: ServerErrorHandler;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
electronServiceMock = new ElectronServiceMock();
|
electronServiceMock = new ElectronServiceMock();
|
||||||
@ -35,7 +43,7 @@ describe('DefaultLayoutComponent', () => {
|
|||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [DefaultLayoutComponent, ProgressComponent],
|
declarations: [DefaultLayoutComponent, ProgressComponent],
|
||||||
imports: [MatIconModule, MatMenuModule, MatToolbarModule, RouterTestingModule, MatProgressSpinnerModule],
|
imports: [MatIconModule, MatMenuModule, MatToolbarModule, HttpClientModule, RouterTestingModule, MatProgressSpinnerModule],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: ElectronService,
|
provide: ElectronService,
|
||||||
@ -53,9 +61,18 @@ describe('DefaultLayoutComponent', () => {
|
|||||||
provide: RecentlyOpenedProjectService,
|
provide: RecentlyOpenedProjectService,
|
||||||
useClass: RecentlyOpenedProjectService,
|
useClass: RecentlyOpenedProjectService,
|
||||||
},
|
},
|
||||||
|
{ provide: ServerService },
|
||||||
|
{ provide: IndexedDbService },
|
||||||
|
{ provide: HttpServer },
|
||||||
|
{ provide: ServerErrorHandler },
|
||||||
ProgressService,
|
ProgressService,
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
indexedDbService = TestBed.inject(IndexedDbService);
|
||||||
|
errorHandler = TestBed.inject(ServerErrorHandler);
|
||||||
|
httpServer = TestBed.inject(HttpServer);
|
||||||
|
serverService = TestBed.inject(ServerService);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -37,7 +37,6 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private progressService: ProgressService,
|
private progressService: ProgressService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
|
||||||
private serverService: ServerService
|
private serverService: ServerService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -69,6 +68,13 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||||||
this.shouldStopServersOnClosing = this.electronService.isElectronApp;
|
this.shouldStopServersOnClosing = this.electronService.isElectronApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToUserInfo() {
|
||||||
|
let serverId = this.router.url.split("/server/")[1].split("/")[0];
|
||||||
|
this.serverService.get(+serverId).then((server: Server) => {
|
||||||
|
this.router.navigate(['/server', server.id, 'loggeduser']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
checkIfUserIsLoginPage() {
|
checkIfUserIsLoginPage() {
|
||||||
if (this.router.url.includes("login")) {
|
if (this.router.url.includes("login")) {
|
||||||
this.isLoginPage = true;
|
this.isLoginPage = true;
|
||||||
|
10
src/app/models/users/user.ts
Normal file
10
src/app/models/users/user.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface User {
|
||||||
|
created_at: string;
|
||||||
|
email: string;
|
||||||
|
full_name: string;
|
||||||
|
is_active: boolean;
|
||||||
|
is_superadmin: boolean;
|
||||||
|
updated_at: string;
|
||||||
|
user_id: string;
|
||||||
|
username: string;
|
||||||
|
}
|
@ -15,7 +15,7 @@ export class BuiltInTemplatesConfigurationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getConsoleTypesForCloudNodes() {
|
getConsoleTypesForCloudNodes() {
|
||||||
return ['telnet', 'none'];
|
return ['telnet', 'vnc', 'spice', 'http', 'https', 'none'];
|
||||||
}
|
}
|
||||||
|
|
||||||
getCategoriesForEthernetHubs() {
|
getCategoriesForEthernetHubs() {
|
||||||
|
@ -39,6 +39,23 @@ export type TextOptions = {
|
|||||||
withCredentials?: boolean;
|
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 = {
|
export type HeadersOptions = {
|
||||||
headers?:
|
headers?:
|
||||||
| HttpHeaders
|
| HttpHeaders
|
||||||
@ -101,6 +118,16 @@ export class HttpServer {
|
|||||||
.pipe(catchError(this.errorHandler.handleError));
|
.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> {
|
post<T>(server: Server, url: string, body: any | null, options?: JsonOptions): Observable<T> {
|
||||||
options = this.getJsonOptions(options);
|
options = this.getJsonOptions(options);
|
||||||
const intercepted = this.getOptionsForServer(server, url, options);
|
const intercepted = this.getOptionsForServer(server, url, options);
|
||||||
@ -173,6 +200,15 @@ export class HttpServer {
|
|||||||
return options;
|
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) {
|
private getOptionsForServer<T extends HeadersOptions>(server: Server, url: string, options: T) {
|
||||||
if (server.host && server.port) {
|
if (server.host && server.port) {
|
||||||
if (!server.protocol) {
|
if (!server.protocol) {
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { inject, TestBed } from '@angular/core/testing';
|
|
||||||
import { IndexedDbService } from './indexed-db.service';
|
|
||||||
|
|
||||||
describe('IndexedDbService', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [IndexedDbService],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', inject([IndexedDbService], (service: IndexedDbService) => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should get AngularIndexedDB', inject([IndexedDbService], (service: IndexedDbService) => {
|
|
||||||
const indexeddb = service.get();
|
|
||||||
expect(indexeddb.dbWrapper.dbName).toEqual(IndexedDbService.DATABASE);
|
|
||||||
expect(indexeddb.dbWrapper.dbVersion).toEqual(IndexedDbService.VERSION);
|
|
||||||
}));
|
|
||||||
});
|
|
@ -1,18 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { AngularIndexedDB } from 'angular2-indexeddb';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class IndexedDbService {
|
|
||||||
static VERSION = 1;
|
|
||||||
static DATABASE = 'gns3-web-ui';
|
|
||||||
|
|
||||||
private db: AngularIndexedDB;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.db = new AngularIndexedDB(IndexedDbService.DATABASE, IndexedDbService.VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get() {
|
|
||||||
return this.db;
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,12 +17,14 @@ export class MapSettingsService {
|
|||||||
public openReadme: boolean;
|
public openReadme: boolean;
|
||||||
public showInterfaceLabels: boolean = true;
|
public showInterfaceLabels: boolean = true;
|
||||||
public integrateLinkLabelsToLinks: boolean = true;
|
public integrateLinkLabelsToLinks: boolean = true;
|
||||||
|
public openConsolesInWidget: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isLayerNumberVisible = localStorage.getItem('layersVisibility') === 'true' ? true : false;
|
this.isLayerNumberVisible = localStorage.getItem('layersVisibility') === 'true' ? true : false;
|
||||||
if (localStorage.getItem('integrateLinkLabelsToLinks'))
|
if (localStorage.getItem('integrateLinkLabelsToLinks'))
|
||||||
this.integrateLinkLabelsToLinks = localStorage.getItem('integrateLinkLabelsToLinks') === 'true' ? true : false;
|
this.integrateLinkLabelsToLinks = localStorage.getItem('integrateLinkLabelsToLinks') === 'true' ? true : false;
|
||||||
|
if (localStorage.getItem('openConsolesInWidget'))
|
||||||
|
this.openConsolesInWidget = localStorage.getItem('openConsolesInWidget') === 'true' ? true : false;
|
||||||
let isSymbolScalingEnabled = true;
|
let isSymbolScalingEnabled = true;
|
||||||
if (localStorage.getItem('symbolScaling')) {
|
if (localStorage.getItem('symbolScaling')) {
|
||||||
isSymbolScalingEnabled = localStorage.getItem('symbolScaling') === 'true' ? true : false;
|
isSymbolScalingEnabled = localStorage.getItem('symbolScaling') === 'true' ? true : false;
|
||||||
@ -89,12 +91,22 @@ export class MapSettingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleOpenReadme(value: boolean) {
|
toggleOpenReadme(value: boolean) {
|
||||||
this.openReadme = value;
|
this.openReadme = value;
|
||||||
localStorage.removeItem('openReadme');
|
localStorage.removeItem('openReadme');
|
||||||
if (value) {
|
if (value) {
|
||||||
localStorage.setItem('openReadme', 'true');
|
localStorage.setItem('openReadme', 'true');
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem('openReadme', 'false');
|
localStorage.setItem('openReadme', 'false');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleOpenConsolesInWidget(value: boolean) {
|
||||||
|
this.openConsolesInWidget = value;
|
||||||
|
localStorage.removeItem('openConsolesInWidget');
|
||||||
|
if (value) {
|
||||||
|
localStorage.setItem('openConsolesInWidget', 'true');
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('openConsolesInWidget', 'false');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,10 @@ import { EventEmitter, Injectable } from '@angular/core';
|
|||||||
import { Server } from '../models/server';
|
import { Server } from '../models/server';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { Node } from '../cartography/models/node';
|
import { Node } from '../cartography/models/node';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { ToasterService } from './toaster.service';
|
||||||
|
import { MapSettingsService } from './mapsettings.service';
|
||||||
|
import { node } from 'prop-types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NodeConsoleService {
|
export class NodeConsoleService {
|
||||||
@ -19,7 +23,11 @@ export class NodeConsoleService {
|
|||||||
private lastNumberOfColumns: number;
|
private lastNumberOfColumns: number;
|
||||||
private lastNumberOfRows: number;
|
private lastNumberOfRows: number;
|
||||||
|
|
||||||
constructor() {}
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private mapSettingsService: MapSettingsService
|
||||||
|
) {}
|
||||||
|
|
||||||
getNumberOfColumns() {
|
getNumberOfColumns() {
|
||||||
return this.lastNumberOfColumns;
|
return this.lastNumberOfColumns;
|
||||||
@ -65,6 +73,42 @@ export class NodeConsoleService {
|
|||||||
|
|
||||||
return `${protocol}://${server.host}:${server.port}/v3/projects/${node.project_id}/nodes/${node.node_id}/console/ws`
|
return `${protocol}://${server.host}:${server.port}/v3/projects/${node.project_id}/nodes/${node.node_id}/console/ws`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openConsolesForAllNodesInWidget(nodes: Node[]) {
|
||||||
|
let nodesToStart = 'Please start the following nodes if you want to open consoles for them: ';
|
||||||
|
let nodesToStartCounter = 0;
|
||||||
|
nodes.forEach((n) => {
|
||||||
|
if (n.status === 'started') {
|
||||||
|
this.mapSettingsService.logConsoleSubject.next(true);
|
||||||
|
// this timeout is required due to xterm.js implementation
|
||||||
|
setTimeout(() => { this.openConsoleForNode(n); }, 500);
|
||||||
|
} else {
|
||||||
|
nodesToStartCounter++;
|
||||||
|
nodesToStart += n.name + ' '
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (nodesToStartCounter > 0) {
|
||||||
|
this.toasterService.error(nodesToStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openConsolesForAllNodesInNewTabs(nodes: Node[]) {
|
||||||
|
let nodesToStart = 'Please start the following nodes if you want to open consoles for them: ';
|
||||||
|
let nodesToStartCounter = 0;
|
||||||
|
nodes.forEach((n) => {
|
||||||
|
if (n.status === 'started') {
|
||||||
|
let url = this.router.url.split('/');
|
||||||
|
let urlString = `/static/web-ui/${url[1]}/${url[2]}/${url[3]}/${url[4]}/nodes/${n.node_id}`;
|
||||||
|
window.open(urlString);
|
||||||
|
} else {
|
||||||
|
nodesToStartCounter++;
|
||||||
|
nodesToStart += n.name + ' '
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (nodesToStartCounter > 0) {
|
||||||
|
this.toasterService.error(nodesToStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConsoleResizedEvent {
|
export interface ConsoleResizedEvent {
|
||||||
|
@ -9,7 +9,6 @@ import { HttpServer } from './http-server.service';
|
|||||||
import { ProjectService } from './project.service';
|
import { ProjectService } from './project.service';
|
||||||
import { RecentlyOpenedProjectService } from './recentlyOpenedProject.service';
|
import { RecentlyOpenedProjectService } from './recentlyOpenedProject.service';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
import { MockedSettingsService } from './settings.service.spec';
|
|
||||||
import { getTestServer } from './testing';
|
import { getTestServer } from './testing';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,7 +65,7 @@ describe('ProjectService', () => {
|
|||||||
HttpServer,
|
HttpServer,
|
||||||
ProjectService,
|
ProjectService,
|
||||||
RecentlyOpenedProjectService,
|
RecentlyOpenedProjectService,
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
import { AngularIndexedDB } from 'angular2-indexeddb';
|
|
||||||
import { Server } from '../models/server';
|
import { Server } from '../models/server';
|
||||||
import { HttpServer, ServerErrorHandler } from '../services/http-server.service';
|
|
||||||
import { IndexedDbService } from './indexed-db.service';
|
|
||||||
import { ServerService } from './server.service';
|
|
||||||
|
|
||||||
import Spy = jasmine.Spy;
|
|
||||||
|
|
||||||
export class MockedServerService {
|
export class MockedServerService {
|
||||||
public servers: Server[] = [];
|
public servers: Server[] = [];
|
||||||
@ -42,138 +34,3 @@ export class MockedServerService {
|
|||||||
return `${server.host}:${server.port}`;
|
return `${server.host}:${server.port}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('ServerService', () => {
|
|
||||||
let indexedDbService: IndexedDbService;
|
|
||||||
let db: AngularIndexedDB;
|
|
||||||
let service: ServerService;
|
|
||||||
let openDatabaseSpy: Spy;
|
|
||||||
let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
indexedDbService = new IndexedDbService();
|
|
||||||
|
|
||||||
db = indexedDbService.get();
|
|
||||||
|
|
||||||
openDatabaseSpy = spyOn(db, 'openDatabase').and.returnValue(Promise.resolve(true));
|
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [
|
|
||||||
ServerService,
|
|
||||||
{ provide: IndexedDbService, useValue: indexedDbService },
|
|
||||||
{ provide: HttpServer, useValue: httpServer },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
service = TestBed.get(ServerService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created and create database', () => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
expect(db.openDatabase).toHaveBeenCalled();
|
|
||||||
expect(openDatabaseSpy.calls.first().args[0]).toEqual(1);
|
|
||||||
|
|
||||||
const evnt = {
|
|
||||||
currentTarget: {
|
|
||||||
result: {
|
|
||||||
createObjectStore: function () {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(evnt.currentTarget.result, 'createObjectStore');
|
|
||||||
|
|
||||||
const upgradeCallback = openDatabaseSpy.calls.first().args[1];
|
|
||||||
upgradeCallback(evnt);
|
|
||||||
|
|
||||||
expect(evnt.currentTarget.result.createObjectStore).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('operations on records', () => {
|
|
||||||
let record: any;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
record = new Server();
|
|
||||||
record.name = 'test';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an object', (done) => {
|
|
||||||
const created = new Server();
|
|
||||||
created.id = 22;
|
|
||||||
|
|
||||||
spyOn(db, 'add').and.returnValue(Promise.resolve(created));
|
|
||||||
|
|
||||||
service.create(record).then((result) => {
|
|
||||||
expect(db.add).toHaveBeenCalledWith('servers', record);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update an object', (done) => {
|
|
||||||
spyOn(db, 'update').and.returnValue(Promise.resolve(record));
|
|
||||||
|
|
||||||
service.update(record).then((result) => {
|
|
||||||
expect(db.update).toHaveBeenCalledWith('servers', record);
|
|
||||||
expect(result).toEqual(record);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete an object', (done) => {
|
|
||||||
record.id = 88;
|
|
||||||
|
|
||||||
spyOn(db, 'delete').and.returnValue(Promise.resolve());
|
|
||||||
|
|
||||||
service.delete(record).then(() => {
|
|
||||||
expect(db.delete).toHaveBeenCalledWith('servers', record.id);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call findAll', (done) => {
|
|
||||||
spyOn(db, 'getAll').and.returnValue(Promise.resolve([]));
|
|
||||||
|
|
||||||
service.findAll().then((result) => {
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
expect(db.getAll).toHaveBeenCalledWith('servers');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create local server when missing', (done) => {
|
|
||||||
spyOn(db, 'getAll').and.returnValue(Promise.resolve([]));
|
|
||||||
spyOn(service, 'create').and.returnValue(Promise.resolve(new Server()));
|
|
||||||
|
|
||||||
const expectedServer = new Server();
|
|
||||||
expectedServer.name = 'local';
|
|
||||||
expectedServer.host = 'hostname';
|
|
||||||
expectedServer.port = 9999;
|
|
||||||
expectedServer.location = 'bundled';
|
|
||||||
expectedServer.protocol = 'http:';
|
|
||||||
|
|
||||||
service.getLocalServer('hostname', 9999).then(() => {
|
|
||||||
expect(service.create).toHaveBeenCalledWith(expectedServer);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update local server when found', (done) => {
|
|
||||||
const server = new Server();
|
|
||||||
server.name = 'local';
|
|
||||||
server.host = 'hostname';
|
|
||||||
server.port = 9999;
|
|
||||||
server.location = 'bundled';
|
|
||||||
|
|
||||||
spyOn(db, 'getAll').and.returnValue(Promise.resolve([server]));
|
|
||||||
spyOn(service, 'update').and.returnValue(Promise.resolve(new Server()));
|
|
||||||
|
|
||||||
service.getLocalServer('hostname-2', 11111).then(() => {
|
|
||||||
server.host = 'hostname-2';
|
|
||||||
server.port = 11111;
|
|
||||||
|
|
||||||
expect(service.update).toHaveBeenCalledWith(server);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -2,146 +2,84 @@ import { Injectable } from '@angular/core';
|
|||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { Server, ServerProtocol } from '../models/server';
|
import { Server, ServerProtocol } from '../models/server';
|
||||||
import { HttpServer } from './http-server.service';
|
import { HttpServer } from './http-server.service';
|
||||||
import { IndexedDbService } from './indexed-db.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServerService {
|
export class ServerService {
|
||||||
private tablename = 'servers';
|
private serverIds: string[] = [];
|
||||||
private ready: Promise<any>;
|
|
||||||
private isIncognitoMode: boolean = false;
|
|
||||||
private serverIdsInIncognitoMode: string[] = [];
|
|
||||||
public serviceInitialized: Subject<boolean> = new Subject<boolean>();
|
public serviceInitialized: Subject<boolean> = new Subject<boolean>();
|
||||||
public isServiceInitialized: boolean;
|
public isServiceInitialized: boolean;
|
||||||
|
|
||||||
constructor(private indexedDbService: IndexedDbService, private httpServer: HttpServer) {
|
constructor(private httpServer: HttpServer) {
|
||||||
this.ready = this.indexedDbService
|
this.serverIds = this.getServerIds();
|
||||||
.get()
|
this.isServiceInitialized = true;
|
||||||
.openDatabase(1, (evt) => {
|
this.serviceInitialized.next(this.isServiceInitialized);
|
||||||
evt.currentTarget.result.createObjectStore(this.tablename, { keyPath: 'id', autoIncrement: true });
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.indexedDbService
|
|
||||||
.get()
|
|
||||||
.getAll(this.tablename)
|
|
||||||
.then(() => {})
|
|
||||||
.catch(() => {
|
|
||||||
this.isIncognitoMode = true;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.isIncognitoMode = true;
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.isServiceInitialized = true;
|
|
||||||
this.serviceInitialized.next(true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public tryToCreateDb() {
|
getServerIds() : string[]{
|
||||||
let promise = new Promise((resolve) => {
|
let str = localStorage.getItem("serverIds");
|
||||||
this.indexedDbService
|
if (str?.length > 0) {
|
||||||
.get()
|
return str.split(",");
|
||||||
.openDatabase(1, (evt) => {
|
}
|
||||||
evt.currentTarget.result.createObjectStore(this.tablename, { keyPath: 'id', autoIncrement: true });
|
return [];
|
||||||
})
|
}
|
||||||
.then(() => {})
|
|
||||||
.catch(() => {
|
updateServerIds() {
|
||||||
this.isIncognitoMode = true;
|
localStorage.removeItem("serverIds");
|
||||||
});
|
localStorage.setItem("serverIds", this.serverIds.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(id: number): Promise<Server> {
|
||||||
|
let server: Server = JSON.parse(localStorage.getItem(`server-${id}`));
|
||||||
|
let promise = new Promise<Server>((resolve) => {
|
||||||
|
resolve(server);
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(id: number): Promise<Server> {
|
|
||||||
if (this.isIncognitoMode) {
|
|
||||||
let server: Server = JSON.parse(localStorage.getItem(`server-${id}`));
|
|
||||||
let promise = new Promise<Server>((resolve) => {
|
|
||||||
resolve(server);
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.onReady(() => this.indexedDbService.get().getByKey(this.tablename, id)) as Promise<Server>;
|
|
||||||
}
|
|
||||||
|
|
||||||
public create(server: Server) {
|
public create(server: Server) {
|
||||||
if (this.isIncognitoMode) {
|
server.id = this.serverIds.length + 1;
|
||||||
server.id = this.serverIdsInIncognitoMode.length + 1;
|
localStorage.setItem(`server-${server.id}`, JSON.stringify(server));
|
||||||
localStorage.setItem(`server-${server.id}`, JSON.stringify(server));
|
|
||||||
this.serverIdsInIncognitoMode.push(`server-${server.id}`);
|
|
||||||
|
|
||||||
let promise = new Promise<Server>((resolve) => {
|
this.serverIds.push(`server-${server.id}`);
|
||||||
resolve(server);
|
this.updateServerIds();
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.onReady(() => {
|
let promise = new Promise<Server>((resolve) => {
|
||||||
const promise = new Promise((resolve, reject) => {
|
resolve(server);
|
||||||
this.indexedDbService
|
|
||||||
.get()
|
|
||||||
.add(this.tablename, server)
|
|
||||||
.then((added) => {
|
|
||||||
server.id = added.key;
|
|
||||||
resolve(server);
|
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
});
|
});
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(server: Server) {
|
public update(server: Server) {
|
||||||
if (this.isIncognitoMode) {
|
localStorage.removeItem(`server-${server.id}`);
|
||||||
localStorage.removeItem(`server-${server.id}`);
|
localStorage.setItem(`server-${server.id}`, JSON.stringify(server));
|
||||||
localStorage.setItem(`server-${server.id}`, JSON.stringify(server));
|
|
||||||
|
|
||||||
let promise = new Promise<Server>((resolve) => {
|
let promise = new Promise<Server>((resolve) => {
|
||||||
resolve(server);
|
resolve(server);
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.onReady(() => {
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
|
||||||
this.indexedDbService
|
|
||||||
.get()
|
|
||||||
.update(this.tablename, server)
|
|
||||||
.then((updated) => {
|
|
||||||
resolve(server);
|
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
});
|
});
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public findAll() {
|
public findAll() {
|
||||||
if (this.isIncognitoMode) {
|
let promise = new Promise<Server[]>((resolve) => {
|
||||||
let promise = new Promise<Server[]>((resolve) => {
|
let servers: Server[] = [];
|
||||||
let servers: Server[] = [];
|
this.serverIds.forEach((n) => {
|
||||||
this.serverIdsInIncognitoMode.forEach((n) => {
|
let server: Server = JSON.parse(localStorage.getItem(n));
|
||||||
let server: Server = JSON.parse(localStorage.getItem(n));
|
servers.push(server);
|
||||||
servers.push(server);
|
|
||||||
});
|
|
||||||
resolve(servers);
|
|
||||||
});
|
});
|
||||||
return promise;
|
resolve(servers);
|
||||||
}
|
});
|
||||||
|
return promise;
|
||||||
return this.onReady(() => this.indexedDbService.get().getAll(this.tablename)) as Promise<Server[]>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public delete(server: Server) {
|
public delete(server: Server) {
|
||||||
if (this.isIncognitoMode) {
|
localStorage.removeItem(`server-${server.id}`);
|
||||||
localStorage.removeItem(`server-${server.id}`);
|
this.serverIds = this.serverIds.filter((n) => n !== `server-${server.id}`);
|
||||||
this.serverIdsInIncognitoMode = this.serverIdsInIncognitoMode.filter((n) => n !== `server-${server.id}`);
|
this.updateServerIds();
|
||||||
|
|
||||||
let promise = new Promise((resolve) => {
|
let promise = new Promise((resolve) => {
|
||||||
resolve(server.id);
|
resolve(server.id);
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
|
||||||
|
|
||||||
return this.onReady(() => this.indexedDbService.get().delete(this.tablename, server.id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getServerUrl(server: Server) {
|
public getServerUrl(server: Server) {
|
||||||
@ -179,25 +117,4 @@ export class ServerService {
|
|||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onReady(query) {
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
|
||||||
this.ready.then(
|
|
||||||
() => {
|
|
||||||
query().then(
|
|
||||||
(result) => {
|
|
||||||
resolve(result);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
import { fakeAsync, inject, TestBed } from '@angular/core/testing';
|
|
||||||
import { PersistenceService, StorageType } from 'angular-persistence';
|
|
||||||
import { Settings, SettingsService } from './settings.service';
|
|
||||||
|
|
||||||
export class MockedSettingsService {
|
|
||||||
settings = {};
|
|
||||||
|
|
||||||
isExperimentalEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
getAll() {}
|
|
||||||
|
|
||||||
get(key: string) {
|
|
||||||
return this.settings[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key: string, value: any) {
|
|
||||||
this.settings[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('SettingsService', () => {
|
|
||||||
let persistenceService: PersistenceService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [SettingsService, PersistenceService],
|
|
||||||
});
|
|
||||||
|
|
||||||
persistenceService = TestBed.get(PersistenceService);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
persistenceService.removeAll(StorageType.LOCAL);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set value', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
service.set('crash_reports', false);
|
|
||||||
expect(service.get('crash_reports')).toEqual(false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should get default value', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
expect(service.get('crash_reports')).toEqual(true);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw error when setting value with wrong key', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
expect(() => service.set('test', false)).toThrowError("Key 'test' doesn't exist in settings");
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw error when getting value with wrong key', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
expect(() => service.get('test')).toThrowError("Key 'test' doesn't exist in settings");
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should get all values', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
expect(service.getAll()).toEqual({
|
|
||||||
crash_reports: true,
|
|
||||||
experimental_features: false,
|
|
||||||
angular_map: false,
|
|
||||||
console_command: undefined,
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set all values', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
const settings = {
|
|
||||||
crash_reports: false,
|
|
||||||
};
|
|
||||||
service.setAll(settings);
|
|
||||||
|
|
||||||
expect(service.getAll()).toEqual({
|
|
||||||
crash_reports: false,
|
|
||||||
experimental_features: false,
|
|
||||||
angular_map: false,
|
|
||||||
console_command: undefined,
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should execute subscriber', inject(
|
|
||||||
[SettingsService],
|
|
||||||
fakeAsync((service: SettingsService) => {
|
|
||||||
let changedSettings: Settings;
|
|
||||||
|
|
||||||
service.set('crash_reports', true);
|
|
||||||
service.subscribe((settings) => {
|
|
||||||
changedSettings = settings;
|
|
||||||
});
|
|
||||||
service.set('crash_reports', false);
|
|
||||||
|
|
||||||
expect(changedSettings.crash_reports).toEqual(false);
|
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
it('should get isExperimentalEnabled when turned on', inject([SettingsService], (service: SettingsService) => {
|
|
||||||
service.set('experimental_features', true);
|
|
||||||
|
|
||||||
expect(service.isExperimentalEnabled()).toEqual(true);
|
|
||||||
}));
|
|
||||||
});
|
|
@ -1,11 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { PersistenceService, StorageType } from 'angular-persistence';
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
crash_reports: boolean;
|
crash_reports: boolean;
|
||||||
experimental_features: boolean;
|
|
||||||
angular_map: boolean;
|
|
||||||
console_command: string;
|
console_command: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,57 +10,65 @@ export interface Settings {
|
|||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
static DEFAULTS: Settings = {
|
private settings: Settings = {
|
||||||
crash_reports: true,
|
crash_reports: true,
|
||||||
experimental_features: false,
|
|
||||||
angular_map: false,
|
|
||||||
console_command: undefined,
|
console_command: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
private settingsSubject: BehaviorSubject<Settings>;
|
private readonly reportsSettings: string = 'crash_reports';
|
||||||
|
private readonly consoleSettings: string = 'console_command';
|
||||||
|
|
||||||
constructor(private persistenceService: PersistenceService) {
|
constructor() {
|
||||||
this.settingsSubject = new BehaviorSubject<Settings>(this.getAll());
|
if (this.getItem(this.reportsSettings))
|
||||||
|
this.settings.crash_reports = this.getItem(this.reportsSettings) === 'true' ? true : false;
|
||||||
|
|
||||||
|
if (this.getItem(this.consoleSettings))
|
||||||
|
this.settings.console_command = this.getItem(this.consoleSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
get<T>(key: string) {
|
setReportsSettings(value: boolean) {
|
||||||
if (!(key in SettingsService.DEFAULTS)) {
|
this.settings.crash_reports = value;
|
||||||
throw Error(`Key '${key}' doesn't exist in settings`);
|
this.removeItem(this.reportsSettings);
|
||||||
|
if (value) {
|
||||||
|
this.setItem(this.reportsSettings, 'true');
|
||||||
|
} else {
|
||||||
|
this.setItem(this.reportsSettings, 'false');
|
||||||
}
|
}
|
||||||
const value = this.persistenceService.get(key, StorageType.LOCAL) as T;
|
|
||||||
if (typeof value === 'undefined') {
|
|
||||||
return SettingsService.DEFAULTS[key];
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set<T>(key: string, value: T): void {
|
getReportsSettings() {
|
||||||
if (!(key in SettingsService.DEFAULTS)) {
|
return this.getItem(this.reportsSettings) === 'true' ? true : false;
|
||||||
throw Error(`Key '${key}' doesn't exist in settings`);
|
}
|
||||||
}
|
|
||||||
this.persistenceService.set(key, value, { type: StorageType.LOCAL });
|
setConsoleSettings(value: string) {
|
||||||
this.settingsSubject.next(this.getAll());
|
this.settings.console_command = value;
|
||||||
|
this.removeItem(this.consoleSettings);
|
||||||
|
this.setItem(this.consoleSettings, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getConsoleSettings() {
|
||||||
|
return this.getItem(this.consoleSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(key: string) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(key: string, item: string) {
|
||||||
|
localStorage.setItem(key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(item: string) {
|
||||||
|
return localStorage.getItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll() {
|
getAll() {
|
||||||
const settings = { ...SettingsService.DEFAULTS };
|
return this.settings;
|
||||||
Object.keys(SettingsService.DEFAULTS).forEach((key) => {
|
|
||||||
settings[key] = this.get(key);
|
|
||||||
});
|
|
||||||
return settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setAll(settings) {
|
setAll(settings: Settings) {
|
||||||
Object.keys(settings).forEach((key) => {
|
this.settings = settings;
|
||||||
this.set(key, settings[key]);
|
this.setConsoleSettings(settings.console_command);
|
||||||
});
|
this.setReportsSettings(settings.crash_reports);
|
||||||
}
|
|
||||||
|
|
||||||
isExperimentalEnabled(): boolean {
|
|
||||||
return this.get('experimental_features');
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(subscriber: (settings: Settings) => void) {
|
|
||||||
return this.settingsSubject.subscribe(subscriber);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { MockedSettingsService } from '../settings.service.spec';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { SettingsService } from '../settings.service';
|
||||||
import { ConsoleService } from './console.service';
|
import { ConsoleService } from './console.service';
|
||||||
|
|
||||||
describe('ConsoleService', () => {
|
describe('ConsoleService', () => {
|
||||||
let service: ConsoleService;
|
let service: ConsoleService;
|
||||||
let settings: MockedSettingsService;
|
let settings: SettingsService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
let defaultConsoleService = {
|
let defaultConsoleService = {
|
||||||
get: () => 'default',
|
get: () => 'default',
|
||||||
};
|
};
|
||||||
settings = new MockedSettingsService();
|
settings = TestBed.inject(SettingsService);
|
||||||
service = new ConsoleService(defaultConsoleService as any, settings as any);
|
service = new ConsoleService(defaultConsoleService as any, settings as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -18,12 +19,12 @@ describe('ConsoleService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get command from settings if defined', () => {
|
it('should get command from settings if defined', () => {
|
||||||
settings.set('console_command', 'from_settings');
|
settings.setConsoleSettings('from_settings');
|
||||||
expect(service.command).toEqual('from_settings');
|
expect(service.command).toEqual('from_settings');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get command from default console if settings are not defined', () => {
|
it('should get command from default console if settings are not defined', () => {
|
||||||
settings.set('console_command', undefined);
|
settings.setConsoleSettings(undefined);
|
||||||
expect(service.command).toEqual('default');
|
expect(service.command).toBe('undefined');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@ export class ConsoleService {
|
|||||||
constructor(private defaultConsoleService: DefaultConsoleService, private settingsService: SettingsService) {}
|
constructor(private defaultConsoleService: DefaultConsoleService, private settingsService: SettingsService) {}
|
||||||
|
|
||||||
get command(): string {
|
get command(): string {
|
||||||
const command = this.settingsService.get<string>('console_command');
|
const command = this.settingsService.getConsoleSettings();
|
||||||
if (command === undefined) {
|
if (command === undefined) {
|
||||||
return this.defaultConsoleService.get();
|
return this.defaultConsoleService.get();
|
||||||
}
|
}
|
||||||
@ -15,6 +15,6 @@ export class ConsoleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set command(command: string) {
|
set command(command: string) {
|
||||||
this.settingsService.set<string>('console_command', command);
|
this.settingsService.setConsoleSettings(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,19 +49,11 @@ describe('SymbolService', () => {
|
|||||||
expect(req.request.method).toEqual('GET');
|
expect(req.request.method).toEqual('GET');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should load symbols', inject([SymbolService], (service: SymbolService) => {
|
it('should call load symbols while adding symbol', inject([SymbolService], (service: SymbolService) => {
|
||||||
spyOn(service, 'load').and.returnValue(of([]));
|
spyOn(service, 'load');
|
||||||
|
|
||||||
service.list(server).subscribe();
|
service.add(server, 'symbolName', 'symbol');
|
||||||
|
|
||||||
expect(service.load).toHaveBeenCalled();
|
expect(service.load).toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should get symbols', inject([SymbolService], (service: SymbolService) => {
|
|
||||||
const symbol = new Symbol();
|
|
||||||
symbol.symbol_id = 'myid';
|
|
||||||
service.symbols.next([symbol]);
|
|
||||||
|
|
||||||
expect(service.get('myid').symbol_id).toEqual('myid');
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||||
import { shareReplay } from 'rxjs/operators';
|
import { shareReplay } from 'rxjs/operators';
|
||||||
import { Node } from '../cartography/models/node';
|
import { Node } from '../cartography/models/node';
|
||||||
import { Server } from '../models/server';
|
import { Server } from '../models/server';
|
||||||
@ -7,22 +7,29 @@ import { Symbol } from '../models/symbol';
|
|||||||
import { HttpServer } from './http-server.service';
|
import { HttpServer } from './http-server.service';
|
||||||
import { Template } from '../models/template';
|
import { Template } from '../models/template';
|
||||||
|
|
||||||
const CACHE_SIZE = 1;
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SymbolService {
|
export class SymbolService {
|
||||||
public symbols: BehaviorSubject<Symbol[]> = new BehaviorSubject<Symbol[]>([]);
|
private symbols: Symbol[] = [];
|
||||||
private cache: Observable<Symbol[]>;
|
|
||||||
private maximumSymbolSize: number = 80;
|
private maximumSymbolSize: number = 80;
|
||||||
|
public symbolsLoaded: Subject<boolean> = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private httpServer: HttpServer) {}
|
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() {
|
getMaximumSymbolSize() {
|
||||||
return this.maximumSymbolSize;
|
return this.maximumSymbolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(symbol_id: string): Symbol {
|
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> {
|
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) {
|
add(server: Server, symbolName: string, symbol: string) {
|
||||||
this.cache = null;
|
this.load(server);
|
||||||
return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol);
|
return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
load(server: Server): Observable<Symbol[]> {
|
|
||||||
return this.httpServer.get<Symbol[]>(server, '/symbols');
|
|
||||||
}
|
|
||||||
|
|
||||||
list(server: Server) {
|
list(server: Server) {
|
||||||
if (!this.cache) {
|
return this.httpServer.get<Symbol[]>(server, '/symbols');
|
||||||
this.cache = this.load(server).pipe(shareReplay(CACHE_SIZE));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raw(server: Server, symbol_id: string) {
|
raw(server: Server, symbol_id: string) {
|
||||||
@ -64,8 +59,8 @@ export class SymbolService {
|
|||||||
return this.httpServer.getText(server, `/symbols/${encoded_uri}/raw`);
|
return this.httpServer.getText(server, `/symbols/${encoded_uri}/raw`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSymbolFromTemplate(server: Server, template: Template) {
|
getSymbolFromTemplate(template: Template) {
|
||||||
return `${server.protocol}//${server.host}:${server.port}/v3/symbols/${template.symbol}/raw`;
|
return this.symbols.find((symbol: Symbol) => symbol.filename === template.symbol.split('/')[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/app/services/user.service.ts
Normal file
16
src/app/services/user.service.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { Server } from '../models/server';
|
||||||
|
import { HttpServer } from './http-server.service';
|
||||||
|
import { User } from '../models/users/user';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserService {
|
||||||
|
constructor(
|
||||||
|
private httpServer: HttpServer
|
||||||
|
) {}
|
||||||
|
|
||||||
|
getInformationAboutLoggedUser(server: Server) {
|
||||||
|
return this.httpServer.get<User>(server, '/users/me/');
|
||||||
|
}
|
||||||
|
}
|
@ -16,4 +16,4 @@ export const environment = {
|
|||||||
* This import should be commented out in production mode because it will have a negative impact
|
* This import should be commented out in production mode because it will have a negative impact
|
||||||
* on performance if an error is thrown.
|
* on performance if an error is thrown.
|
||||||
*/
|
*/
|
||||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<!-- <body class="mat-app-background" oncontextmenu="return false;"> -->
|
<!-- <body class="mat-app-background" oncontextmenu="return false;"> -->
|
||||||
<body class="mat-app-background">
|
<body class="mat-app-background" oncontextmenu="return false;">
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-5D6FZL9923"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-5D6FZL9923"></script>
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Zone JS is required by default for Angular itself.
|
* Zone JS is required by default for Angular itself.
|
||||||
*/
|
*/
|
||||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
import 'zone.js'; // Included with Angular CLI.
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* APPLICATION IMPORTS
|
* APPLICATION IMPORTS
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import 'zone.js/dist/zone-testing';
|
import 'zone.js/testing';
|
||||||
import { getTestBed } from '@angular/core/testing';
|
import { getTestBed } from '@angular/core/testing';
|
||||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
@ -3,6 +3,13 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../out-tsc/app",
|
"outDir": "../out-tsc/app",
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@components/*": ["app/components/*"],
|
||||||
|
"@services/*": ["app/services/*"],
|
||||||
|
"@resolvers/*": ["app/resolvers/*"],
|
||||||
|
"@filters/*": ["app/filters/*"],
|
||||||
|
"@models/*": ["app/models/*"]
|
||||||
|
},
|
||||||
"types": []
|
"types": []
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -10,7 +17,6 @@
|
|||||||
"polyfills.ts"
|
"polyfills.ts"
|
||||||
],
|
],
|
||||||
"include": [
|
"include": [
|
||||||
// "../src/**/*",
|
// "../src/**/*"
|
||||||
"../node_modules/angular2-indexeddb/*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
],
|
],
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.spec.ts",
|
"**/*.spec.ts",
|
||||||
"**/*.d.ts",
|
"**/*.d.ts"
|
||||||
"../node_modules/angular2-indexeddb/*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,9 @@
|
|||||||
"declaration": false,
|
"declaration": false,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"jsx": "react",
|
|
||||||
"types": ["jasmine", "jest", "mocha", "node"],
|
"types": ["jasmine", "jest", "mocha", "node"],
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
|
Loading…
Reference in New Issue
Block a user