diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c6921a334..a232a8a0a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: Build on: push: branches: - - '**' + - '**' pull_request: branches: - master @@ -10,16 +10,19 @@ on: jobs: build: - runs-on: windows-latest - + runs-on: ubuntu-latest + strategy: + matrix: + node: [ 14, 16, 18 ] + name: Node ${{ matrix.node }} steps: - - uses: actions/checkout@v2 - - name: Setup node 14 - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - name: Setup Node ${{ matrix.node }} + uses: actions/setup-node@v3 with: - node-version: 14.x - - uses: c-hive/gha-yarn-cache@v1 + node-version: ${{ matrix.node }} + cache: 'yarn' - name: Install JS dependencies - run: yarn install + run: yarn install --frozen-lockfile --immutable - name: Test run: yarn test diff --git a/.gitignore b/.gitignore index 7db8bef87..9a40f6266 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /scripts/build /scripts/dist /env +/.angular # dependencies /node_modules diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..2e2264550 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "angular.enable-strict-mode-prompt": false +} \ No newline at end of file diff --git a/.yarnclean b/.yarnclean index 0d63cb688..6afee6427 100644 --- a/.yarnclean +++ b/.yarnclean @@ -3,11 +3,11 @@ __tests__ node_modules/*/test node_modules/*/tests powered-test -e2e +#e2e # asset directories docs -doc +#doc website images diff --git a/angular.json b/angular.json index 44ca2b36b..d1920ac95 100644 --- a/angular.json +++ b/angular.json @@ -1,246 +1,234 @@ { - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "gns3-web-ui": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "allowedCommonJsDependencies": [ - "rxjs", - "rxjs-compat", - "uuid", - "css-tree", - "save-svg-as-png", - "angular-draggable-droppable", - "dom-set", - "dom-plane", - "mousetrap", - "@mattlewis92/dom-autoscroller", - "rxjs/Rx", - "rxjs/add/operator/map", - "rxjs-compat/add/operator/map", - "classnames", - "stylenames" - ], - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "tsConfig": "src/tsconfig.app.json", - "polyfills": "src/polyfills.ts", - "assets": [ - "src/assets", - "src/favicon.ico", - "src/ReleaseNotes.txt" - ], - "styles": [ - "node_modules/bootstrap/dist/css/bootstrap.min.css", - "node_modules/notosans-fontface/css/notosans-fontface.min.css", - "src/styles.scss", - "src/theme.scss" - ], - "scripts": [], - "vendorChunk": true, - "extractLicenses": false, - "buildOptimizer": true, - "sourceMap": true, - "optimization": false, - "namedChunks": true, - "aot": true - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": { - "hidden": true, - "scripts": true, - "styles": false - }, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ] - }, - "electronProd": { - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.electron.prod.ts" - } - ] - }, - "electronDev": { - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ], - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.electron.ts" - } - ] - }, - "githubProd": { - "budgets": [ - { - "type": "anyComponentStyle", - "maximumWarning": "6kb" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.github.prod.ts" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "gns3-web-ui:build" - }, - "configurations": { - "production": { - "browserTarget": "gns3-web-ui:build:production" - }, - "electronProd": { - "browserTarget": "gns3-web-ui:build:electronProd" - }, - "electronDev": { - "browserTarget": "gns3-web-ui:build:electronDev" - }, - "githubProd": { - "browserTarget": "gns3-web-ui:build:githubProd" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "gns3-web-ui:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "karmaConfig": "./karma.conf.js", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "scripts": [], - "styles": [ - "node_modules/bootstrap/dist/css/bootstrap.min.css", - "node_modules/notosans-fontface/css/notosans-fontface.min.css", - "src/styles.scss", - "src/theme.scss" - ], - "sourceMap": false, - "assets": [ - "src/assets", - "src/favicon.ico" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [ - "**/node_modules/**", - "**/*.spec.ts" - ] - } - } - }, - "schematics": { - "@schematics/angular:component": { - "style": "scss" - } - } - }, - "gns3-web-ui-e2e": { - "root": "e2e", - "sourceRoot": "e2e", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "./protractor.conf.js", - "devServerTarget": "gns3-web-ui:serve" - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "e2e/tsconfig.e2e.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - } - } - } - }, - "defaultProject": "gns3-web-ui", - "schematics": { - "@schematics/angular:component": { - "prefix": "app", - "style": "scss" - }, - "@schematics/angular:directive": { - "prefix": "app" - } - }, - "cli": { - "analytics": false - } -} \ No newline at end of file + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "gns3-web-ui": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "allowedCommonJsDependencies": [ + "rxjs", + "rxjs-compat", + "uuid", + "css-tree", + "save-svg-as-png", + "angular-draggable-droppable", + "dom-set", + "dom-plane", + "mousetrap", + "@mattlewis92/dom-autoscroller", + "rxjs/Rx", + "rxjs/add/operator/map", + "rxjs-compat/add/operator/map", + "classnames", + "stylenames", + "source-map-js", + "spark-md5", + "xterm", + "xterm-addon-attach", + "xterm-addon-fit" + ], + "outputPath": "dist", + "index": "src/index.html", + "main": "src/main.ts", + "tsConfig": "src/tsconfig.app.json", + "polyfills": "src/polyfills.ts", + "assets": [ + "src/assets", + "src/favicon.ico", + "src/ReleaseNotes.txt" + ], + "styles": [ + "node_modules/bootstrap/dist/css/bootstrap.min.css", + "node_modules/notosans-fontface/css/notosans-fontface.min.css", + "src/styles.scss", + "src/theme.scss" + ], + "scripts": [], + "vendorChunk": true, + "extractLicenses": false, + "buildOptimizer": true, + "sourceMap": true, + "optimization": false, + "namedChunks": true, + "aot": true + }, + "configurations": { + "production": { + "budgets": [{ + "type": "anyComponentStyle", + "maximumWarning": "6kb" + }], + "optimization": true, + "outputHashing": "all", + "sourceMap": { + "hidden": true, + "scripts": true, + "styles": false + }, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "fileReplacements": [{ + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + }] + }, + "electronProd": { + "budgets": [{ + "type": "anyComponentStyle", + "maximumWarning": "6kb" + }], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "fileReplacements": [{ + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.electron.prod.ts" + }] + }, + "electronDev": { + "budgets": [{ + "type": "anyComponentStyle", + "maximumWarning": "6kb" + }], + "fileReplacements": [{ + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.electron.ts" + }] + }, + "githubProd": { + "budgets": [{ + "type": "anyComponentStyle", + "maximumWarning": "6kb" + }], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "fileReplacements": [{ + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.github.prod.ts" + }] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "gns3-web-ui:build" + }, + "configurations": { + "production": { + "browserTarget": "gns3-web-ui:build:production" + }, + "electronProd": { + "browserTarget": "gns3-web-ui:build:electronProd" + }, + "electronDev": { + "browserTarget": "gns3-web-ui:build:electronDev" + }, + "githubProd": { + "browserTarget": "gns3-web-ui:build:githubProd" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "gns3-web-ui:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "karmaConfig": "./karma.conf.js", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "scripts": [], + "styles": [ + "node_modules/bootstrap/dist/css/bootstrap.min.css", + "node_modules/notosans-fontface/css/notosans-fontface.min.css", + "src/styles.scss", + "src/theme.scss" + ], + "sourceMap": false, + "assets": [ + "src/assets", + "src/favicon.ico" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**", + "**/*.spec.ts" + ] + } + } + }, + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + } + }, + "gns3-web-ui-e2e": { + "root": "e2e", + "sourceRoot": "e2e", + "projectType": "application", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "./protractor.conf.js", + "devServerTarget": "gns3-web-ui:serve" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "e2e/tsconfig.e2e.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "schematics": { + "@schematics/angular:component": { + "prefix": "app", + "style": "scss" + }, + "@schematics/angular:directive": { + "prefix": "app" + } + }, + "cli": { + "analytics": false + } +} diff --git a/e2e/controllers.e2e-spec.ts b/e2e/controllers.e2e-spec.ts new file mode 100644 index 000000000..ff046a80e --- /dev/null +++ b/e2e/controllers.e2e-spec.ts @@ -0,0 +1,43 @@ +import { TestHelper } from './helpers/common.po'; +import { ControllersPage } from './helpers/controller.po'; + +describe('Controllers page', () => { + let page: ControllersPage; + let helper: TestHelper; + + beforeEach(() => { + page = new ControllersPage(); + helper = new TestHelper(); + }); + + xit('user should have possibility to add controller', async () => { + // arrange + page.maximizeWindow(); + await page.navigateToControllersPage(); + + // act + let text = await page.getAddControllerNotificationText(); + + // assert + expect(text).toBe("We've discovered GNS3 controller on 127.0.0.1:3080, would you like to add to the list?"); + }); + + it('user should see added controller in the list', async () => { + // arrange + page.maximizeWindow(); + await page.navigateToControllersPage(); + await page.clickAddController(); + helper.sleep(1000); + + // act + let firstRowOfControllersTable = await page.checkControllersTable(); + let controllerData = []; + await helper.asyncForEach(firstRowOfControllersTable, async (element) => { + controllerData.push(await element.getText()); + }); + + // assert + expect(controllerData).toContain('127.0.0.1'); + expect(controllerData).toContain('3080'); + }); +}); diff --git a/e2e/helpers/server.po.ts b/e2e/helpers/controller.po.ts similarity index 61% rename from e2e/helpers/server.po.ts rename to e2e/helpers/controller.po.ts index 90250c7ee..90b6e6dc0 100644 --- a/e2e/helpers/server.po.ts +++ b/e2e/helpers/controller.po.ts @@ -1,41 +1,41 @@ import { browser, by } from 'protractor'; import { TestHelper } from './common.po'; -export class ServersPage { +export class ControllersPage { helper = new TestHelper(); maximizeWindow() { browser.driver.manage().window().maximize(); } - navigateToServersPage() { - return browser.get('/servers'); + navigateToControllersPage() { + return browser.get('/controllers'); } - getAddServerNotificationText() { + getAddControllerNotificationText() { return browser.driver.findElement(by.className('mat-card-content')).getText(); } - async clickAddServer() { - let serversTable = await this.checkServersTable(); - if (serversTable.length === 0) { + async clickAddController() { + let controllerTable = await this.checkControllersTable(); + if (controllerTable.length === 0) { let buttons = await browser.driver.findElements(by.className('mat-button mat-button-base')); await buttons[3].click(); } } - checkServersTable() { + checkControllersTable() { return browser.driver.findElements(by.css('mat-cell')); } - async navigateToServerProjects() { + async navigateToControllerProjects() { this.helper.sleep(2000); let hyperlinks = await browser.driver.findElements(by.css('a.table-link')); - let serverLink; + let controllerLink; await this.helper.asyncForEach(hyperlinks, async (element) => { let text = await element.getText(); - if (text === '127.0.0.1') serverLink = element; + if (text === '127.0.0.1') controllerLink = element; }); - await serverLink.click(); + await controllerLink.click(); } } diff --git a/e2e/project-map.e2e-spec.ts b/e2e/project-map.e2e-spec.ts index 8986d97a6..faa7a5acf 100644 --- a/e2e/project-map.e2e-spec.ts +++ b/e2e/project-map.e2e-spec.ts @@ -1,24 +1,24 @@ import { TestHelper } from './helpers/common.po'; import { ProjectMapPage } from './helpers/project-map.po'; import { ProjectsPage } from './helpers/project.po'; -import { ServersPage } from './helpers/server.po'; +import { ControllersPage } from './helpers/controller.po'; describe('Project map page', () => { - let serversPage: ServersPage; + let controllersPage: ControllersPage; let projectsPage: ProjectsPage; let projectMapPage: ProjectMapPage; let helper: TestHelper; beforeEach(async () => { - serversPage = new ServersPage(); + controllersPage = new ControllersPage(); projectsPage = new ProjectsPage(); projectMapPage = new ProjectMapPage(); helper = new TestHelper(); - serversPage.maximizeWindow(); - await serversPage.navigateToServersPage(); - await serversPage.clickAddServer(); - await serversPage.navigateToServerProjects(); + controllersPage.maximizeWindow(); + await controllersPage.navigateToControllersPage(); + await controllersPage.clickAddController(); + await controllersPage.navigateToControllerProjects(); await projectsPage.openAddProjectDialog(); helper.sleep(2000); await projectsPage.createProject(); diff --git a/e2e/projects.e2e-spec.ts b/e2e/projects.e2e-spec.ts index 01df6aeed..6c0220455 100644 --- a/e2e/projects.e2e-spec.ts +++ b/e2e/projects.e2e-spec.ts @@ -1,24 +1,24 @@ import { TestHelper } from './helpers/common.po'; import { ProjectsPage } from './helpers/project.po'; -import { ServersPage } from './helpers/server.po'; +import { ControllersPage } from './helpers/controller.po'; describe('Projects page', () => { - let serversPage: ServersPage; + let controllersPage: ControllersPage; let projectsPage: ProjectsPage; let helper: TestHelper; beforeEach(() => { - serversPage = new ServersPage(); + controllersPage = new ControllersPage(); projectsPage = new ProjectsPage(); helper = new TestHelper(); }); it('user should have possibility to create new project', async () => { // arrange - serversPage.maximizeWindow(); - await serversPage.navigateToServersPage(); - await serversPage.clickAddServer(); - await serversPage.navigateToServerProjects(); + controllersPage.maximizeWindow(); + await controllersPage.navigateToControllersPage(); + await controllersPage.clickAddController(); + await controllersPage.navigateToControllerProjects(); helper.sleep(2000); //act @@ -28,6 +28,6 @@ describe('Projects page', () => { helper.sleep(2000); //assert - expect(helper.getCurrentUrl()).toMatch('server/1/project/'); + expect(helper.getCurrentUrl()).toMatch('controller/1/project/'); }); }); diff --git a/e2e/servers.e2e-spec.ts b/e2e/servers.e2e-spec.ts deleted file mode 100644 index 45da0436d..000000000 --- a/e2e/servers.e2e-spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { TestHelper } from './helpers/common.po'; -import { ServersPage } from './helpers/server.po'; - -describe('Servers page', () => { - let page: ServersPage; - let helper: TestHelper; - - beforeEach(() => { - page = new ServersPage(); - helper = new TestHelper(); - }); - - xit('user should have possibility to add server', async () => { - // arrange - page.maximizeWindow(); - await page.navigateToServersPage(); - - // act - let text = await page.getAddServerNotificationText(); - - // assert - expect(text).toBe("We've discovered GNS3 server on 127.0.0.1:3080, would you like to add to the list?"); - }); - - it('user should see added server in the list', async () => { - // arrange - page.maximizeWindow(); - await page.navigateToServersPage(); - await page.clickAddServer(); - helper.sleep(1000); - - // act - let firstRowOfServersTable = await page.checkServersTable(); - let serverData = []; - await helper.asyncForEach(firstRowOfServersTable, async (element) => { - serverData.push(await element.getText()); - }); - - // assert - expect(serverData).toContain('127.0.0.1'); - expect(serverData).toContain('3080'); - }); -}); diff --git a/electron-builder.yml b/electron-builder.yml index 8800de069..cd9196c58 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -15,7 +15,7 @@ files: - renderer.js - sentry.js - installed-software.js - - local-server.js + - local-controller.js - console-executor.js - package.json diff --git a/karma.conf.js b/karma.conf.js index e1b8be2ca..25c86d9b6 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -19,13 +19,13 @@ module.exports = function (config) { dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], fixWebpackSourcePaths: true }, - + reporters: ['progress', 'kjhtml'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, - browsers: ['Chrome'], + browsers: ['ChromeHeadless'], singleRun: true }); }; diff --git a/local-server.js b/local-controller.js similarity index 54% rename from local-server.js rename to local-controller.js index a8948c30d..aabf3eb0e 100644 --- a/local-server.js +++ b/local-controller.js @@ -8,9 +8,9 @@ const { app } = require('electron') const isWin = /^win/.test(process.platform); -let runningServers = {}; +let runningControllers = {}; -exports.getLocalServerPath = async () => { +exports.getLocalControllerPath = async () => { let binary = isWin ? 'gns3server.exe': 'gns3server'; return findBinary('exe.', binary); } @@ -20,27 +20,27 @@ exports.getUbridgePath = async () => { return findBinary('ubridge', binary); } -exports.startLocalServer = async (server) => { - return await run(server, { +exports.startLocalController = async (controller) => { + return await run(controller, { logStdout: true }); } -exports.stopLocalServer = async (server) => { - return await stop(server.name); +exports.stopLocalController = async (controller) => { + return await stop(controller.name); } -exports.getRunningServers = () => { - return Object.keys(runningServers); +exports.getRunningControllers = () => { + return Object.keys(runningControllers); } -exports.stopAllLocalServers = async () => { +exports.stopAllLocalControllers = async () => { return await stopAll(); } async function findBinary(binaryDirectory, filename) { const lookupDirectories = [ - __dirname, + __dirname, path.dirname(app.getPath('exe')) ]; @@ -60,7 +60,7 @@ async function findBinaryInDirectory(baseDirectory, binaryDirectory, filename) { } const files = fs.readdirSync(distDirectory); - + let binaryPath = null; files.forEach((directory) => { @@ -77,33 +77,33 @@ async function findBinaryInDirectory(baseDirectory, binaryDirectory, filename) { } -function getServerArguments(server, overrides, configPath) { - let serverArguments = []; - if(server.host) { - serverArguments.push('--host'); - serverArguments.push(server.host); +function getControllerArguments(controller, overrides, configPath) { + let controllerArguments = []; + if(controller.host) { + controllerArguments.push('--host'); + controllerArguments.push(controller.host); } - if(server.port) { - serverArguments.push('--port'); - serverArguments.push(server.port); + if(controller.port) { + controllerArguments.push('--port'); + controllerArguments.push(controller.port); } - serverArguments.push('--local'); + controllerArguments.push('--local'); if(configPath) { - serverArguments.push('--config'); - serverArguments.push(configPath); + controllerArguments.push('--config'); + controllerArguments.push(configPath); } - return serverArguments; + return controllerArguments; } -function getChannelForServer(server) { - return `local-server-run-${server.name}`; +function getChannelForController(controller) { + return `local-controller-run-${controller.name}`; } function notifyStatus(status) { - ipcMain.emit('local-server-status-events', status); + ipcMain.emit('local-controller-status-events', status); } function filterOutput(line) { @@ -120,44 +120,44 @@ function filterOutput(line) { } async function stopAll() { - for(var serverName in runningServers) { - let result, error = await stop(serverName); + for(var controllerName in runningControllers) { + let result, error = await stop(controllerName); } - console.log(`Stopped all servers`); + console.log(`Stopped all controllers`); } -async function stop(serverName) { +async function stop(controllerName) { let pid = undefined; - const runningServer = runningServers[serverName]; + const runningController = runningControllers[controllerName]; - if(runningServer !== undefined && runningServer.process) { - pid = runningServer.process.pid; + if(runningController !== undefined && runningController.process) { + pid = runningController.process.pid; } - console.log(`Stopping '${serverName}' with PID='${pid}'`); - + console.log(`Stopping '${controllerName}' with PID='${pid}'`); + const stopped = new Promise((resolve, reject) => { if(pid === undefined) { - resolve(`Server '${serverName} is already stopped`); - delete runningServers[serverName]; + resolve(`Controller '${controllerName} is already stopped`); + delete runningControllers[controllerName]; return; } kill(pid, (error) => { if(error) { - console.error(`Error occured during stopping '${serverName}' with PID='${pid}'`); + console.error(`Error occured during stopping '${controllerName}' with PID='${pid}'`); reject(error); } else { - delete runningServers[serverName]; - console.log(`Stopped '${serverName}' with PID='${pid}'`); - resolve(`Stopped '${serverName}' with PID='${pid}'`); + delete runningControllers[controllerName]; + console.log(`Stopped '${controllerName}' with PID='${pid}'`); + resolve(`Stopped '${controllerName}' with PID='${pid}'`); notifyStatus({ - serverName: serverName, + controllerName: controllerName, status: 'stopped', - message: `Server '${serverName}' stopped'` + message: `Controller '${controllerName}' stopped'` }); } }); @@ -166,11 +166,11 @@ async function stop(serverName) { return stopped; } -async function getIniFile(server) { - return path.join(app.getPath('userData'), `gns3_server_${server.id}.ini`); +async function getIniFile(controller) { + return path.join(app.getPath('userData'), `gns3_controller_${controller.id}.ini`); } -async function configure(configPath, server) { +async function configure(configPath, controller) { if(!fs.existsSync(configPath)) { fs.closeSync(fs.openSync(configPath, 'w')); console.log(`Configuration file '${configPath}' has been created.`); @@ -178,20 +178,20 @@ async function configure(configPath, server) { var config = ini.parse(fs.readFileSync(configPath, 'utf-8')); - if(server.path) { - config.path = server.path; + if(controller.path) { + config.path = controller.path; } - if(server.host) { - config.host = server.host; + if(controller.host) { + config.host = controller.host; } - if(server.port) { - config.port = server.port; + if(controller.port) { + config.port = controller.port; } - if(server.ubridge_path) { - config.ubridge_path = server.ubridge_path; + if(controller.ubridge_path) { + config.ubridge_path = controller.ubridge_path; } - fs.writeFileSync(configPath, ini.stringify(config, { section: 'Server' })); + fs.writeFileSync(configPath, ini.stringify(config, { section: 'Controller' })); } async function setPATHEnv() { @@ -216,7 +216,7 @@ async function setPATHEnv() { process.env.PATH = extra.join(";"); } -async function run(server, options) { +async function run(controller, options) { if(!options) { options = {}; } @@ -226,34 +226,34 @@ async function run(server, options) { console.log(`Configuring`); - const configPath = await getIniFile(server); - await configure(configPath, server); + const configPath = await getIniFile(controller); + await configure(configPath, controller); console.log(`Setting up PATH`); await setPATHEnv(); - console.log(`Running '${server.path}'`); + console.log(`Running '${controller.path}'`); - let serverProcess = spawn(server.path, getServerArguments(server, {}, configPath)); + let controllerProcess = spawn(controller.path, getControllerArguments(controller, {}, configPath)); notifyStatus({ - serverName: server.name, + controllerName: controller.name, status: 'started', - message: `Server '${server.name}' started'` + message: `Controller '${controller.name}' started'` }); - - runningServers[server.name] = { - process: serverProcess + + runningControllers[controller.name] = { + process: controllerProcess }; - serverProcess.stdout.on('data', function(data) { + controllerProcess.stdout.on('data', function(data) { const line = data.toString(); const { isCritical, errorMessage } = filterOutput(line); if(isCritical) { notifyStatus({ - serverName: server.name, + controllerName: controller.name, status: 'stderr', - message: `Server reported error: '${errorMessage}` + message: `Controller reported error: '${errorMessage}` }); } @@ -262,25 +262,25 @@ async function run(server, options) { } }); - serverProcess.stderr.on('data', function(data) { + controllerProcess.stderr.on('data', function(data) { if(logSterr) { console.log(data.toString()); } }); - serverProcess.on('exit', (code, signal) => { + controllerProcess.on('exit', (code, signal) => { notifyStatus({ - serverName: server.name, + controllerName: controller.name, status: 'errored', - message: `Server '${server.name}' has exited with status='${code}'` + message: `controller '${controller.name}' has exited with status='${code}'` }); }); - serverProcess.on('error', (err) => { + controllerProcess.on('error', (err) => { notifyStatus({ - serverName: server.name, + controllerName: controller.name, status: 'errored', - message: `Server errored: '${err}` + message: `Controller errored: '${err}` }); }); @@ -297,9 +297,9 @@ async function main() { } if(ipcMain) { - ipcMain.on('local-server-run', async function (event, server) { - const responseChannel = getChannelForServer(); - await run(server); + ipcMain.on('local-controller-run', async function (event, controller) { + const responseChannel = getChannelForController(); + await run(controller); event.sender.send(responseChannel, { success: true }); @@ -318,4 +318,4 @@ if (require.main === module) { }); main(); -} \ No newline at end of file +} diff --git a/package.json b/package.json index f523064a8..62c26edc6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gns3-web-ui", - "version": "2.2.38.dev1", + "version": "3.0.0a3", "author": { "name": "GNS3 Technology Inc.", "email": "developers@gns3.com" @@ -36,97 +36,100 @@ "generate-licenses-file": "yarn license-checker --production --csv --out licenses.csv", "prebuildforelectron": "node set-variables-in-env.js --set src/environments/environment.electron.prod.ts", "postbuildforelectron": "node set-variables-in-env.js --unset src/environments/environment.electron.prod.ts", - "postinstall": "ngcc --properties es5 browser module main --first-only --create-ivy-entry-points && ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points", - "snyk-protect": "snyk protect", + "postinstall": "ngcc --properties es2020 browser module main --first-only --create-ivy-entry-points --tsconfig \"./src/tsconfig.app.json\" && ngcc --properties es2020 browser module main --first-only --create-ivy-entry-points --tsconfig \"./src/tsconfig.app.json\"", + "snyk-protect": "snyk-protect", "prepare": "yarn run snyk-protect" }, "private": true, "dependencies": { - "@angular/animations": "^12.2.12", - "@angular/cdk": "^12.2.12", - "@angular/common": "^12.2.12", - "@angular/compiler": "^12.2.12", - "@angular/core": "^12.2.12", - "@angular/forms": "^12.2.12", - "@angular/material": "^12.2.12", - "@angular/platform-browser": "^12.2.12", - "@angular/platform-browser-dynamic": "^12.2.12", - "@angular/router": "^12.2.12", + "@angular/animations": "^14.3.0", + "@angular/cdk": "^14.2.7", + "@angular/common": "^14.3.0", + "@angular/compiler": "^14.3.0", + "@angular/core": "^14.3.0", + "@angular/forms": "^14.3.0", + "@angular/material": "^14.2.7", + "@angular/platform-browser": "^14.3.0", + "@angular/platform-browser-dynamic": "^14.3.0", + "@angular/router": "^14.3.0", "@sentry/browser": "^6.14.1", + "@snyk/protect": "^1.972.0", "@types/jest": "^27.0.2", - "@types/mocha": "^9.0.0", + "@types/mocha": "^9.1.1", "@types/react": "^17.0.34", "@types/react-dom": "^17.0.11", - "angular-draggable-droppable": "^5.0.0", + "angular-draggable-droppable": "^6.1.0", "angular-resizable-element": "^3.4.0", + "autoprefixer": "10.4.5", "bootstrap": "^5.1.3", "command-exists": "^1.2.9", - "core-js": "^3.19.1", - "css-tree": "^1.1.3", + "core-js": "^3.22.3", + "css-tree": "^2.1.0", "d3-ng2-service": "^2.2.0", "eev": "^0.1.5", - "ini": "^2.0.0", + "ini": "^3.0.0", + "marked": "^4.0.14", "material-design-icons": "^3.0.1", "mousetrap": "^1.6.5", "ng-circle-progress": "^1.6.0", - "ng2-file-upload": "^1.4.0", + "ng2-file-upload": "^3.0.0", "ngx-childprocess": "^0.0.6", - "ngx-device-detector": "^2.1.1", + "ngx-device-detector": "4.0.1", "ngx-electron": "^2.2.0", "node-fetch": "^3.2.10", - "notosans-fontface": "1.2.2", + "notosans-fontface": "^1.3.0", + "postcss-loader": "^6.2.1", "prettier-plugin-organize-imports": "^2.3.4", "rxjs": "^6.6.7", "rxjs-compat": "^6.6.7", "save-svg-as-png": "^1.4.17", - "snyk": "^1.1064.0", "spark-md5": "^3.0.2", "svg-crowbar": "^0.7.0", "tree-kill": "^1.2.2", - "tslib": "^2.3.1", + "tslib": "^2.4.0", "typeface-roboto": "^1.1.13", - "xterm": "^4.15.0", + "xterm": "^4.18.0", "xterm-addon-attach": "^0.6.0", "xterm-addon-fit": "^0.5.0", - "yargs": "^17.2.1", - "zone.js": "~0.11.4" + "yargs": "^17.4.1", + "zone.js": "^0.11.5" }, "devDependencies": { - "@angular-devkit/build-angular": "^12.2.12", - "@angular/cli": "^12.2.12", - "@angular/compiler-cli": "^12.2.12", - "@angular/language-service": "^12.2.12", - "@sentry/cli": "^1.71.0", - "@sentry/electron": "^2.5.4", - "@types/jasmine": "^3.10.2", + "@angular-devkit/build-angular": "^14.2.12", + "@angular/cli": "^14.2.12", + "@angular/compiler-cli": "^14.3.0", + "@angular/language-service": "^14.3.0", + "@sentry/cli": "^2.0.4", + "@sentry/electron": "^3.0.7", + "@types/jasmine": "^4.0.3", "@types/jasminewd2": "^2.0.10", - "@types/node": "16.11.6", - "codelyzer": "^6.0.2", - "electron": "^13.6.6", - "electron-builder": "^22.9.1", + "@types/node": "^17.0.31", + "codelyzer": "^0.0.28", + "electron": "13.6.6", + "electron-builder": "^23.0.3", "file-loader": "^6.2.0", - "jasmine-core": "~3.10.1", - "jasmine-spec-reporter": "~7.0.0", + "jasmine-core": "^4.1.0", + "jasmine-spec-reporter": "^7.0.0", "jquery": "^3.6.0", - "karma": "^6.3.16", - "karma-chrome-launcher": "~3.1.0", + "karma": "^6.3.19", + "karma-chrome-launcher": "^3.1.1", "karma-cli": "^2.0.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.1", + "karma-coverage-istanbul-reporter": "^3.0.3", + "karma-jasmine": "^5.0.0", "karma-jasmine-html-reporter": "^1.7.0", "license-checker": "^25.0.1", "popper.js": "^1.16.1", - "prettier": "^2.4.1", + "prettier": "^2.6.2", "protractor": "^7.0.0", "replace": "^1.2.1", "rxjs-tslint": "^0.1.8", "ts-mockito": "^2.6.1", - "ts-node": "~10.4.0", + "ts-node": "^10.7.0", "tslint": "^6.1.3", "tslint-config-prettier": "^1.18.0", - "typescript": "4.2.3", - "webpack": "5.62.1", - "yarn-upgrade-all": "^0.5.4" + "typescript": "4.6.4", + "webpack": "^5.72.0", + "yarn-upgrade-all": "^0.7.1" }, "greenkeeper": { "ignore": [ @@ -134,4 +137,4 @@ ] }, "snyk": true -} +} \ No newline at end of file diff --git a/scripts/requirements.txt b/scripts/requirements.txt index cb3b3dbcd..8954eed15 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,6 +1,6 @@ setuptools==65.5.1 cx_Freeze==5.1.1 -requests==2.25.1 +requests==2.31.0 packaging==20.9 appdirs==1.4.4 psutil==5.8.0 diff --git a/src/ReleaseNotes.txt b/src/ReleaseNotes.txt index 2f336cb8a..87a2f5fcc 100644 --- a/src/ReleaseNotes.txt +++ b/src/ReleaseNotes.txt @@ -1,10 +1,9 @@ GNS3 WebUI is web implementation of user interface for GNS3 software. -Current version: 2.2.32 +Current version: 2.2.24 Bug Fixes & enhancements -- Fixed generated capture file is not valid -- Fixed Docker additional directories +- security fixes Current version: 2020.4.0-beta.1 @@ -68,7 +67,7 @@ GNS3 Web UI 2020.2.0-beta.4 Bug Fixes - New port setting for GNS3 VM preferences - Option to auto-hide menu toolbar on the left side -- Server type in template preferences +-Controller type in template preferences - Error when selecting existing Docker image - Default values in templates - TypeError: Cannot read property 'message' of undefined diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 539d1efb3..a700e532f 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,9 +1,10 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component'; +import { BundledControllerFinderComponent } from './components/bundled-controller-finder/bundled-controller-finder.component'; import { DirectLinkComponent } from './components/direct-link/direct-link.component'; import { HelpComponent } from './components/help/help.component'; import { InstalledSoftwareComponent } from './components/installed-software/installed-software.component'; +import { LoginComponent } from './components/login/login.component'; import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component'; import { BuiltInPreferencesComponent } from './components/preferences/built-in/built-in-preferences.component'; import { CloudNodesAddTemplateComponent } from './components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component'; @@ -23,7 +24,6 @@ import { AddIosTemplateComponent } from './components/preferences/dynamips/add-i import { CopyIosTemplateComponent } from './components/preferences/dynamips/copy-ios-template/copy-ios-template.component'; import { IosTemplateDetailsComponent } from './components/preferences/dynamips/ios-template-details/ios-template-details.component'; import { IosTemplatesComponent } from './components/preferences/dynamips/ios-templates/ios-templates.component'; -import { Gns3vmComponent } from './components/preferences/gns3vm/gns3vm.component'; import { AddIouTemplateComponent } from './components/preferences/ios-on-unix/add-iou-template/add-iou-template.component'; import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component'; import { IouTemplateDetailsComponent } from './components/preferences/ios-on-unix/iou-template-details/iou-template-details.component'; @@ -44,157 +44,266 @@ import { VpcsTemplateDetailsComponent } from './components/preferences/vpcs/vpcs import { VpcsTemplatesComponent } from './components/preferences/vpcs/vpcs-templates/vpcs-templates.component'; import { ProjectMapComponent } from './components/project-map/project-map.component'; import { ProjectsComponent } from './components/projects/projects.component'; -import { ServersComponent } from './components/servers/servers.component'; +import { ControllersComponent } from './components/controllers/controllers.component'; import { ConsoleComponent } from './components/settings/console/console.component'; import { SettingsComponent } from './components/settings/settings.component'; import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapshots/list-of-snapshots.component'; import { SystemStatusComponent } from './components/system-status/system-status.component'; import { WebConsoleFullWindowComponent } from './components/web-console-full-window/web-console-full-window.component'; import { ConsoleGuard } from './guards/console-guard'; +import { LoginGuard } from './guards/login-guard'; import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component'; -import { ServerResolve } from './resolvers/server-resolve'; +import { ControllerResolve } from './resolvers/controller-resolve'; +import { UserManagementComponent } from './components/user-management/user-management.component'; +import { LoggedUserComponent } from './components/users/logged-user/logged-user.component'; +import { ImageManagerComponent } from './components/image-manager/image-manager.component'; +import { UserDetailComponent } from "./components/user-management/user-detail/user-detail.component"; +import { UserDetailResolver } from "./resolvers/user-detail.resolver"; +import { ManagementComponent } from "./components/management/management.component"; +import { PermissionResolver } from "./resolvers/permission.resolver"; +import { UserGroupsResolver } from "./resolvers/user-groups.resolver"; +import { UserPermissionsResolver } from "./resolvers/user-permissions.resolver"; +import { GroupManagementComponent } from "./components/group-management/group-management.component"; +import { RoleManagementComponent } from "./components/role-management/role-management.component"; +import { PermissionsManagementComponent } from "./components/permissions-management/permissions-management.component"; +import { GroupDetailsComponent } from "./components/group-details/group-details.component"; +import { GroupMembersResolver } from "./resolvers/group-members.resolver"; +import { GroupResolver } from "./resolvers/group.resolver"; +import { GroupRoleResolver } from "./resolvers/group-role.resolver"; +import { RoleDetailComponent } from "./components/role-management/role-detail/role-detail.component"; +import { RoleDetailResolver } from "./resolvers/role-detail.resolver"; +import { RolePermissionsComponent } from "./components/role-management/role-detail/role-permissions/role-permissions.component"; +import { UserPermissionsComponent } from "./components/user-management/user-detail/user-permissions/user-permissions.component"; const routes: Routes = [ { path: '', component: DefaultLayoutComponent, children: [ - { path: '', redirectTo: 'servers', pathMatch: 'full' }, - { path: 'servers', component: ServersComponent }, - { path: 'bundled', component: BundledServerFinderComponent }, + { path: '', redirectTo: 'controllers', pathMatch: 'full' }, + { path: 'controllers', component: ControllersComponent }, + { path: 'bundled', component: BundledControllerFinderComponent }, + { path: 'controller/:controller_id/login', component: LoginComponent }, + { path: 'controller/:controller_id/loggeduser', component: LoggedUserComponent }, + {path : 'controller/:controller_id/image-manager', component: ImageManagerComponent}, { - path: 'server/:server_id/projects', + path: 'controller/:controller_id/projects', component: ProjectsComponent, - resolve: { server: ServerResolve }, + canActivate: [LoginGuard], + resolve: { controller: ControllerResolve }, + }, + { path: 'controller/:controller_id/help', component: HelpComponent }, + { path: 'controller/:controller_id/settings', component: SettingsComponent }, + { path: 'controller/:controller_id/settings/console', component: ConsoleComponent }, + { + path: 'controller/:controller_id/management/users/:user_id', + component: UserDetailComponent, + canActivate: [LoginGuard], + resolve: { + user: UserDetailResolver, + groups: UserGroupsResolver, + permissions: UserPermissionsResolver, + controller: ControllerResolve}, }, - { path: 'help', component: HelpComponent }, - { path: 'settings', component: SettingsComponent }, - { path: 'settings/console', component: ConsoleComponent }, { path: 'installed-software', component: InstalledSoftwareComponent }, - { path: 'server/:server_id/systemstatus', component: SystemStatusComponent }, + { path: 'controller/:controller_id/systemstatus', component: SystemStatusComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_ip/:server_port/project/:project_id', component: DirectLinkComponent }, + { path: 'controller/:controller_ip/:controller_port/project/:project_id', component: DirectLinkComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/project/:project_id/snapshots', + path: 'controller/:controller_id/project/:project_id/snapshots', component: ListOfSnapshotsComponent, - resolve: { server: ServerResolve }, + canActivate: [LoginGuard], + resolve: { controller: ControllerResolve }, }, - { path: 'server/:server_id/preferences', component: PreferencesComponent }, - { path: 'server/:server_id/preferences/gns3vm', component: Gns3vmComponent }, - // { path: 'server/:server_id/preferences/general', component: GeneralPreferencesComponent }, - { path: 'server/:server_id/preferences/builtin', component: BuiltInPreferencesComponent }, + { path: 'controller/:controller_id/preferences', component: PreferencesComponent, canActivate: [LoginGuard] }, + // { path: 'controller/:controller_id/preferences/general', component: GeneralPreferencesComponent }, + { path: 'controller/:controller_id/preferences/builtin', component: BuiltInPreferencesComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/builtin/ethernet-hubs', component: EthernetHubsTemplatesComponent }, + { path: 'controller/:controller_id/preferences/builtin/ethernet-hubs', component: EthernetHubsTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/ethernet-hubs/addtemplate', + path: 'controller/:controller_id/preferences/builtin/ethernet-hubs/addtemplate', component: EthernetHubsAddTemplateComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/ethernet-hubs/:template_id', + path: 'controller/:controller_id/preferences/builtin/ethernet-hubs/:template_id', component: EthernetHubsTemplateDetailsComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/ethernet-switches', + path: 'controller/:controller_id/preferences/builtin/ethernet-switches', component: EthernetSwitchesTemplatesComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/ethernet-switches/addtemplate', + path: 'controller/:controller_id/preferences/builtin/ethernet-switches/addtemplate', component: EthernetSwitchesAddTemplateComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/ethernet-switches/:template_id', + path: 'controller/:controller_id/preferences/builtin/ethernet-switches/:template_id', component: EthernetSwitchesTemplateDetailsComponent, + canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/builtin/cloud-nodes', component: CloudNodesTemplatesComponent }, + { path: 'controller/:controller_id/preferences/builtin/cloud-nodes', component: CloudNodesTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/cloud-nodes/addtemplate', + path: 'controller/:controller_id/preferences/builtin/cloud-nodes/addtemplate', component: CloudNodesAddTemplateComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/builtin/cloud-nodes/:template_id', + path: 'controller/:controller_id/preferences/builtin/cloud-nodes/:template_id', component: CloudNodesTemplateDetailsComponent, + canActivate: [LoginGuard] }, - //{ path: 'server/:server_id/preferences/dynamips', component: DynamipsPreferencesComponent }, - { path: 'server/:server_id/preferences/dynamips/templates', component: IosTemplatesComponent }, - { path: 'server/:server_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent }, - { path: 'server/:server_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent }, + //{ path: 'controller/:controller_id/preferences/dynamips', component: DynamipsPreferencesComponent }, + { path: 'controller/:controller_id/preferences/dynamips/templates', component: IosTemplatesComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/dynamips/templates/:template_id/copy', + path: 'controller/:controller_id/preferences/dynamips/templates/:template_id/copy', component: CopyIosTemplateComponent, + canActivate: [LoginGuard] }, - // { path: 'server/:server_id/preferences/qemu', component: QemuPreferencesComponent }, - { path: 'server/:server_id/preferences/qemu/templates', component: QemuVmTemplatesComponent }, + // { path: 'controller/:controller_id/preferences/qemu', component: QemuPreferencesComponent }, + { path: 'controller/:controller_id/preferences/qemu/templates', component: QemuVmTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/qemu/templates/:template_id/copy', + path: 'controller/:controller_id/preferences/qemu/templates/:template_id/copy', component: CopyQemuVmTemplateComponent, + canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/qemu/templates/:template_id', component: QemuVmTemplateDetailsComponent }, - { path: 'server/:server_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent }, + { path: 'controller/:controller_id/preferences/qemu/templates/:template_id', component: QemuVmTemplateDetailsComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent, canActivate: [LoginGuard] }, - // { path: 'server/:server_id/preferences/vpcs', component: VpcsPreferencesComponent }, - { path: 'server/:server_id/preferences/vpcs/templates', component: VpcsTemplatesComponent }, - { path: 'server/:server_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent }, - { path: 'server/:server_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent }, + // { path: 'controller/:controller_id/preferences/vpcs', component: VpcsPreferencesComponent }, + { path: 'controller/:controller_id/preferences/vpcs/templates', component: VpcsTemplatesComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent, canActivate: [LoginGuard] }, - // { path: 'server/:server_id/preferences/virtualbox', component: VirtualBoxPreferencesComponent }, - { path: 'server/:server_id/preferences/virtualbox/templates', component: VirtualBoxTemplatesComponent }, + // { path: 'controller/:controller_id/preferences/virtualbox', component: VirtualBoxPreferencesComponent }, + { path: 'controller/:controller_id/preferences/virtualbox/templates', component: VirtualBoxTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/virtualbox/templates/:template_id', + path: 'controller/:controller_id/preferences/virtualbox/templates/:template_id', component: VirtualBoxTemplateDetailsComponent, + canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/virtualbox/addtemplate', component: AddVirtualBoxTemplateComponent }, + { path: 'controller/:controller_id/preferences/virtualbox/addtemplate', component: AddVirtualBoxTemplateComponent, canActivate: [LoginGuard] }, - // { path: 'server/:server_id/preferences/vmware', component: VmwarePreferencesComponent }, - { path: 'server/:server_id/preferences/vmware/templates', component: VmwareTemplatesComponent }, + // { path: 'controller/:controller_id/preferences/vmware', component: VmwarePreferencesComponent }, + { path: 'controller/:controller_id/preferences/vmware/templates', component: VmwareTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/vmware/templates/:template_id', + path: 'controller/:controller_id/preferences/vmware/templates/:template_id', component: VmwareTemplateDetailsComponent, + canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent }, - - // { path: 'server/:server_id/preferences/traceng', component: TracengPreferencesComponent }, - // { path: 'server/:server_id/preferences/traceng/templates', component: TracengTemplatesComponent }, - // { path: 'server/:server_id/preferences/traceng/templates/:template_id', component: TracengTemplateDetailsComponent }, - // { path: 'server/:server_id/preferences/traceng/addtemplate', component: AddTracengTemplateComponent }, + { path: 'controller/:controller_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent }, + { path: 'controller/:controller_id/preferences/docker/templates', component: DockerTemplatesComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/docker/templates/:template_id', + path: 'controller/:controller_id/preferences/docker/templates/:template_id', component: DockerTemplateDetailsComponent, + canActivate: [LoginGuard] }, { - path: 'server/:server_id/preferences/docker/templates/:template_id/copy', + path: 'controller/:controller_id/preferences/docker/templates/:template_id/copy', component: CopyDockerTemplateComponent, + canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/docker/addtemplate', component: AddDockerTemplateComponent }, - - { path: 'server/:server_id/preferences/iou/templates', component: IouTemplatesComponent }, - { path: 'server/:server_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent }, - { path: 'server/:server_id/preferences/iou/templates/:template_id/copy', component: CopyIouTemplateComponent }, - { path: 'server/:server_id/preferences/iou/addtemplate', component: AddIouTemplateComponent }, + { path: 'controller/:controller_id/preferences/docker/addtemplate', component: AddDockerTemplateComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/iou/templates', component: IouTemplatesComponent, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent, canActivate: [LoginGuard] }, + { + path: 'controller/:controller_id/preferences/iou/templates/:template_id/copy', + component: CopyIouTemplateComponent, + canActivate: [LoginGuard] + }, + { path: 'controller/:controller_id/preferences/iou/addtemplate', component: AddIouTemplateComponent, canActivate: [LoginGuard] }, + { + path: 'controller/:controller_id/management', + component: ManagementComponent, + children: [ + { + path: 'users', + component: UserManagementComponent + }, + { + path: 'groups', + component: GroupManagementComponent + }, + { + path: 'roles', + component: RoleManagementComponent + }, + { + path: 'permissions', + component: PermissionsManagementComponent + } + ] + }, + { + path: 'controller/:controller_id/management/groups/:user_group_id', + component: GroupDetailsComponent, + resolve: { + members: GroupMembersResolver, + controller: ControllerResolve, + group: GroupResolver, + roles: GroupRoleResolver + } + }, + { + path: 'controller/:controller_id/management/roles/:role_id', + component: RoleDetailComponent, + resolve: { + role: RoleDetailResolver, + controller: ControllerResolve + } + }, + { + path: 'controller/:controller_id/management/roles/:role_id/permissions', + component: RolePermissionsComponent, + resolve: { + role: RoleDetailResolver, + controller: ControllerResolve, + permissions: PermissionResolver + } + }, + { + path: 'controller/:controller_id/management/users/:user_id/permissions', + component: UserPermissionsComponent, + resolve: { + user: UserDetailResolver, + userPermissions: UserPermissionsResolver, + controller: ControllerResolve, + permissions: PermissionResolver + } + } ], }, { - path: 'server/:server_id/project/:project_id', + path: 'controller/:controller_id/project/:project_id', component: ProjectMapComponent, + canActivate: [LoginGuard], canDeactivate: [ConsoleGuard], }, { - path: 'server/:server_id/project/:project_id/nodes/:node_id', + path: 'controller/:controller_id/project/:project_id/nodes/:node_id', component: WebConsoleFullWindowComponent, + canActivate: [LoginGuard] }, { - path: 'static/web-ui/server/:server_id/project/:project_id/nodes/:node_id', + path: 'static/web-ui/controller/:controller_id/project/:project_id/nodes/:node_id', component: WebConsoleFullWindowComponent, + canActivate: [LoginGuard] }, { path: '**', component: PageNotFoundComponent, - }, + } + ]; @NgModule({ @@ -207,4 +316,5 @@ const routes: Routes = [ ], exports: [RouterModule], }) -export class AppRoutingModule {} +export class AppRoutingModule { +} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 0de4b0c6e..f129ea9d2 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,5 +1,5 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { RouterTestingModule } from '@angular/router/testing'; import { ElectronService, NgxElectronModule } from 'ngx-electron'; @@ -16,8 +16,8 @@ describe('AppComponent', () => { let electronService: ElectronService; let settingsService: SettingsService; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [AppComponent], imports: [RouterTestingModule, MatIconModule, NgxElectronModule], providers: [SettingsService, ProgressService], @@ -26,7 +26,7 @@ describe('AppComponent', () => { electronService = TestBed.inject(ElectronService); settingsService = TestBed.inject(SettingsService); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AppComponent); @@ -34,29 +34,29 @@ describe('AppComponent', () => { fixture.detectChanges(); }); - it('should create the app', async(() => { + it('should create the app', async() => { const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - })); + await expect(app).toBeTruthy(); + }); - it('should have footer', async(() => { + it('should have footer', async() => { const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('router-outlet').textContent).toEqual(''); - })); + await expect(compiled.querySelector('router-outlet').textContent).toEqual(''); + }); - it('should receive changed settings and forward to electron', async(() => { - spyOnProperty(electronService, 'isElectronApp').and.returnValue(true); + it('should receive changed settings and forward to electron', async() => { + await spyOnProperty(electronService, 'isElectronApp').and.returnValue(true); settingsService.setReportsSettings(true); component.ngOnInit(); settingsService.setReportsSettings(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']); spyOnProperty(electronService, 'isElectronApp').and.returnValue(false); settingsService.setReportsSettings(true); component.ngOnInit(); settingsService.setReportsSettings(false); - expect(spy.send).not.toHaveBeenCalled(); - })); + await expect(spy.send).not.toHaveBeenCalled(); + }); }); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1769c4db8..28c86726f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,8 @@ +/* tslint:disable */ import { DragDropModule } from '@angular/cdk/drag-drop'; import { OverlayModule } from '@angular/cdk/overlay'; import { CdkTableModule } from '@angular/cdk/table'; -import { HttpClientModule } from '@angular/common/http'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { ErrorHandler, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatSidenavModule } from '@angular/material/sidenav'; @@ -29,7 +30,7 @@ import { ProgressDialogService } from './common/progress-dialog/progress-dialog. import { ProgressComponent } from './common/progress/progress.component'; import { ProgressService } from './common/progress/progress.service'; import { AdbutlerComponent } from './components/adbutler/adbutler.component'; -import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component'; +import { BundledControllerFinderComponent } from './components/bundled-controller-finder/bundled-controller-finder.component'; import { InformationDialogComponent } from './components/dialogs/information-dialog.component'; import { DirectLinkComponent } from './components/direct-link/direct-link.component'; import { DrawingAddedComponent } from './components/drawings-listeners/drawing-added/drawing-added.component'; @@ -74,7 +75,6 @@ import { DynamipsPreferencesComponent } from './components/preferences/dynamips/ import { IosTemplateDetailsComponent } from './components/preferences/dynamips/ios-template-details/ios-template-details.component'; import { IosTemplatesComponent } from './components/preferences/dynamips/ios-templates/ios-templates.component'; import { GeneralPreferencesComponent } from './components/preferences/general/general-preferences.component'; -import { Gns3vmComponent } from './components/preferences/gns3vm/gns3vm.component'; import { AddIouTemplateComponent } from './components/preferences/ios-on-unix/add-iou-template/add-iou-template.component'; import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component'; import { IouTemplateDetailsComponent } from './components/preferences/ios-on-unix/iou-template-details/iou-template-details.component'; @@ -85,10 +85,6 @@ import { CopyQemuVmTemplateComponent } from './components/preferences/qemu/copy- import { QemuPreferencesComponent } from './components/preferences/qemu/qemu-preferences/qemu-preferences.component'; import { QemuVmTemplateDetailsComponent } from './components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component'; import { QemuVmTemplatesComponent } from './components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component'; -import { AddTracengTemplateComponent } from './components/preferences/traceng/add-traceng/add-traceng-template.component'; -import { TracengPreferencesComponent } from './components/preferences/traceng/traceng-preferences/traceng-preferences.component'; -import { TracengTemplateDetailsComponent } from './components/preferences/traceng/traceng-template-details/traceng-template-details.component'; -import { TracengTemplatesComponent } from './components/preferences/traceng/traceng-templates/traceng-templates.component'; import { AddVirtualBoxTemplateComponent } from './components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component'; import { VirtualBoxPreferencesComponent } from './components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component'; import { VirtualBoxTemplateDetailsComponent } from './components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component'; @@ -117,6 +113,7 @@ import { DeleteActionComponent } from './components/project-map/context-menu/act import { DuplicateActionComponent } from './components/project-map/context-menu/actions/duplicate-action/duplicate-action.component'; import { EditConfigActionComponent } from './components/project-map/context-menu/actions/edit-config/edit-config-action.component'; import { EditStyleActionComponent } from './components/project-map/context-menu/actions/edit-style-action/edit-style-action.component'; +import { EditLinkStyleActionComponent } from './components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component'; import { EditTextActionComponent } from './components/project-map/context-menu/actions/edit-text-action/edit-text-action.component'; import { ExportConfigActionComponent } from './components/project-map/context-menu/actions/export-config/export-config-action.component'; import { HttpConsoleNewTabActionComponent } from './components/project-map/context-menu/actions/http-console-new-tab/http-console-new-tab-action.component'; @@ -134,13 +131,16 @@ import { StartCaptureOnStartedLinkActionComponent } from './components/project-m import { StartCaptureActionComponent } from './components/project-map/context-menu/actions/start-capture/start-capture-action.component'; import { StartNodeActionComponent } from './components/project-map/context-menu/actions/start-node-action/start-node-action.component'; import { StopCaptureActionComponent } from './components/project-map/context-menu/actions/stop-capture/stop-capture-action.component'; -import { StopNodeActionComponent } from './components/project-map/context-menu/actions/stop-node-action/stop-node-action.component'; +import { IsolateNodeActionComponent } from './components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component'; +import { UnisolateNodeActionComponent } from './components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component'; +import {StopNodeActionComponent } from './components/project-map/context-menu/actions/stop-node-action/stop-node-action.component'; import { SuspendLinkActionComponent } from './components/project-map/context-menu/actions/suspend-link/suspend-link-action.component'; import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component'; import { ContextMenuComponent } from './components/project-map/context-menu/context-menu.component'; import { ConfigDialogComponent } from './components/project-map/context-menu/dialogs/config-dialog/config-dialog.component'; import { DrawLinkToolComponent } from './components/project-map/draw-link-tool/draw-link-tool.component'; import { StyleEditorDialogComponent } from './components/project-map/drawings-editors/style-editor/style-editor.component'; +import { LinkStyleEditorDialogComponent } from './components/project-map/drawings-editors/link-style-editor/link-style-editor.component'; import { TextEditorDialogComponent } from './components/project-map/drawings-editors/text-editor/text-editor.component'; import { HelpDialogComponent } from './components/project-map/help-dialog/help-dialog.component'; import { NodeCreatedLabelStylesFixer } from './components/project-map/helpers/node-created-label-styles-fixer'; @@ -165,7 +165,6 @@ import { ConfiguratorDialogNatComponent } from './components/project-map/node-ed import { ConfiguratorDialogQemuComponent } from './components/project-map/node-editors/configurator/qemu/configurator-qemu.component'; import { QemuImageCreatorComponent } from './components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component'; import { ConfiguratorDialogSwitchComponent } from './components/project-map/node-editors/configurator/switch/configurator-switch.component'; -import { ConfiguratorDialogTracengComponent } from './components/project-map/node-editors/configurator/traceng/configurator-traceng.component'; import { ConfiguratorDialogVirtualBoxComponent } from './components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component'; import { ConfiguratorDialogVmwareComponent } from './components/project-map/node-editors/configurator/vmware/configurator-vmware.component'; import { ConfiguratorDialogVpcsComponent } from './components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component'; @@ -175,6 +174,7 @@ import { PacketFiltersDialogComponent } from './components/project-map/packet-ca import { StartCaptureDialogComponent } from './components/project-map/packet-capturing/start-capture/start-capture.component'; import { ProjectMapMenuComponent } from './components/project-map/project-map-menu/project-map-menu.component'; import { ProjectMapComponent } from './components/project-map/project-map.component'; +import { ProjectReadmeComponent } from './components/project-map/project-readme/project-readme.component'; import { ScreenshotDialogComponent } from './components/project-map/screenshot-dialog/screenshot-dialog.component'; import { WebConsoleComponent } from './components/project-map/web-console/web-console.component'; import { AddBlankProjectDialogComponent } from './components/projects/add-blank-project-dialog/add-blank-project-dialog.component'; @@ -182,15 +182,15 @@ import { ChooseNameDialogComponent } from './components/projects/choose-name-dia import { ConfirmationBottomSheetComponent } from './components/projects/confirmation-bottomsheet/confirmation-bottomsheet.component'; import { ConfirmationDialogComponent } from './components/projects/confirmation-dialog/confirmation-dialog.component'; import { EditProjectDialogComponent } from './components/projects/edit-project-dialog/edit-project-dialog.component'; +import { ReadmeEditorComponent } from './components/projects/edit-project-dialog/readme-editor/readme-editor.component'; import { ImportProjectDialogComponent } from './components/projects/import-project-dialog/import-project-dialog.component'; import { ProjectNameValidator } from './components/projects/models/projectNameValidator'; import { NavigationDialogComponent } from './components/projects/navigation-dialog/navigation-dialog.component'; import { ProjectsComponent } from './components/projects/projects.component'; import { SaveProjectDialogComponent } from './components/projects/save-project-dialog/save-project-dialog.component'; -import { AddServerDialogComponent } from './components/servers/add-server-dialog/add-server-dialog.component'; -import { ConfigureGns3VMDialogComponent } from './components/servers/configure-gns3vm-dialog/configure-gns3vm-dialog.component'; -import { ServerDiscoveryComponent } from './components/servers/server-discovery/server-discovery.component'; -import { ServersComponent } from './components/servers/servers.component'; +import { AddControllerDialogComponent } from './components/controllers/add-controller-dialog/add-controller-dialog.component'; +import { ControllerDiscoveryComponent } from './components/controllers/controller-discovery/controller-discovery.component'; +import { ControllersComponent } from './components/controllers/controllers.component'; import { ConsoleComponent } from './components/settings/console/console.component'; import { SettingsComponent } from './components/settings/settings.component'; import { CreateSnapshotDialogComponent } from './components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component'; @@ -204,16 +204,18 @@ import { TemplateComponent } from './components/template/template.component'; import { TopologySummaryComponent } from './components/topology-summary/topology-summary.component'; import { WebConsoleFullWindowComponent } from './components/web-console-full-window/web-console-full-window.component'; import { DataSourceFilter } from './filters/dataSourceFilter'; +import { AuthImageFilter } from './filters/authImageFilter'; import { DateFilter } from './filters/dateFilter.pipe'; import { NameFilter } from './filters/nameFilter.pipe'; import { ProjectsFilter } from './filters/projectsFilter.pipe'; import { SearchFilter } from './filters/searchFilter.pipe'; import { TemplateFilter } from './filters/templateFilter.pipe'; import { ConsoleGuard } from './guards/console-guard'; +import { LoginGuard } from './guards/login-guard'; import { ProjectWebServiceHandler } from './handlers/project-web-service-handler'; import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component'; import { MATERIAL_IMPORTS } from './material.imports'; -import { ServerResolve } from './resolvers/server-resolve'; +import { ControllerResolve } from './resolvers/controller-resolve'; import { ApplianceService } from './services/appliances.service'; import { BuiltInTemplatesConfigurationService } from './services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from './services/built-in-templates.service'; @@ -222,9 +224,8 @@ import { DockerConfigurationService } from './services/docker-configuration.serv import { DockerService } from './services/docker.service'; import { DrawingService } from './services/drawing.service'; import { ExternalSoftwareDefinitionService } from './services/external-software-definition.service'; -import { Gns3vmService } from './services/gns3vm.service'; import { GoogleAnalyticsService } from './services/google-analytics.service'; -import { HttpServer, ServerErrorHandler } from './services/http-server.service'; +import { HttpController, ControllerErrorHandler } from './services/http-controller.service'; import { InfoService } from './services/info.service'; import { InstalledSoftwareService } from './services/installed-software.service'; import { IosConfigurationService } from './services/ios-configuration.service'; @@ -243,10 +244,10 @@ import { ProjectService } from './services/project.service'; import { QemuConfigurationService } from './services/qemu-configuration.service'; import { QemuService } from './services/qemu.service'; import { RecentlyOpenedProjectService } from './services/recentlyOpenedProject.service'; -import { ServerManagementService } from './services/server-management.service'; -import { ServerSettingsService } from './services/server-settings.service'; -import { ServerDatabase } from './services/server.database'; -import { ServerService } from './services/server.service'; +import { ControllerManagementService } from './services/controller-management.service'; +import { ControllerSettingsService } from './services/controller-settings.service'; +import { ControllerDatabase } from './services/controller.database'; +import { ControllerService } from './services/controller.service'; import { SettingsService } from './services/settings.service'; import { ConsoleService } from './services/settings/console.service'; import { DefaultConsoleService } from './services/settings/default-console.service'; @@ -257,7 +258,6 @@ import { TemplateService } from './services/template.service'; import { ThemeService } from './services/theme.service'; import { ToasterService } from './services/toaster.service'; import { ToolsService } from './services/tools.service'; -import { TracengService } from './services/traceng.service'; import { UpdatesService } from './services/updates.service'; import { VersionService } from './services/version.service'; import { VirtualBoxConfigurationService } from './services/virtual-box-configuration.service'; @@ -268,336 +268,404 @@ import { VpcsConfigurationService } from './services/vpcs-configuration.service' import { VpcsService } from './services/vpcs.service'; import { NonNegativeValidator } from './validators/non-negative-validator'; import { RotationValidator } from './validators/rotation-validator'; +import { MarkedDirective } from './directives/marked.directive'; +import { LoginComponent } from './components/login/login.component'; +import { LoginService } from './services/login.service'; +import { HttpRequestsInterceptor } from './interceptors/http.interceptor'; +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'; +import { AddUserDialogComponent } from './components/user-management/add-user-dialog/add-user-dialog.component'; +import { UserFilterPipe } from './filters/user-filter.pipe'; +import { GroupManagementComponent } from './components/group-management/group-management.component'; +import { GroupFilterPipe } from './filters/group-filter.pipe'; +import { AddGroupDialogComponent } from './components/group-management/add-group-dialog/add-group-dialog.component'; +import { DeleteGroupDialogComponent } from './components/group-management/delete-group-dialog/delete-group-dialog.component'; +import { DeleteUserDialogComponent } from './components/user-management/delete-user-dialog/delete-user-dialog.component'; +import { GroupDetailsComponent } from './components/group-details/group-details.component'; +import { UserDetailComponent } from './components/user-management/user-detail/user-detail.component'; +import { AddUserToGroupDialogComponent } from './components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component'; +import { RemoveToGroupDialogComponent } from '@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component'; +import { PaginatorPipe } from './components/group-details/paginator.pipe'; +import { MembersFilterPipe } from './components/group-details/members-filter.pipe'; +import { ManagementComponent } from './components/management/management.component'; +import {MatCheckboxModule} from "@angular/material/checkbox"; +import { RoleManagementComponent } from './components/role-management/role-management.component'; +import { RoleFilterPipe } from './components/role-management/role-filter.pipe'; +import { AddRoleDialogComponent } from './components/role-management/add-role-dialog/add-role-dialog.component'; +import { DeleteRoleDialogComponent } from './components/role-management/delete-role-dialog/delete-role-dialog.component'; +import { RoleDetailComponent } from './components/role-management/role-detail/role-detail.component'; +import { PermissionEditorComponent } from './components/role-management/role-detail/permission-editor/permission-editor.component'; +import { EditablePermissionComponent } from './components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component'; +import { PermissionEditorValidateDialogComponent } from './components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component'; +import { PermissionsManagementComponent } from './components/permissions-management/permissions-management.component'; +import { PermissionEditLineComponent } from '@components/permissions-management/permission-edit-line/permission-edit-line.component'; +import {MatSlideToggleModule} from '@angular/material/slide-toggle'; +import { UserPermissionsComponent } from './components/user-management/user-detail/user-permissions/user-permissions.component'; +import {MatAutocompleteModule} from "@angular/material/autocomplete"; +import {PathAutoCompleteComponent} from './components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component'; +import {FilterCompletePipe} from './components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe'; +import { AddPermissionLineComponent } from './components/permissions-management/add-permission-line/add-permission-line.component'; +import { MethodButtonComponent } from './components/permissions-management/method-button/method-button.component'; +import { ActionButtonComponent } from './components/permissions-management/action-button/action-button.component'; +import { DeletePermissionDialogComponent } from './components/permissions-management/delete-permission-dialog/delete-permission-dialog.component'; +import { AddRoleToGroupComponent } from './components/group-details/add-role-to-group/add-role-to-group.component'; +import {MatFormFieldModule} from "@angular/material/form-field"; +import { PermissionsFilterPipe } from './components/permissions-management/permissions-filter.pipe'; +import { DisplayPathPipe } from './components/permissions-management/display-path.pipe'; +import {RolePermissionsComponent} from "@components/role-management/role-detail/role-permissions/role-permissions.component"; +import { ChangeUserPasswordComponent } from './components/user-management/user-detail/change-user-password/change-user-password.component'; +import {MatMenuModule} from "@angular/material/menu"; +import { ImageManagerComponent } from './components/image-manager/image-manager.component'; +import { AddImageDialogComponent } from './components/image-manager/add-image-dialog/add-image-dialog.component'; +import { DeleteAllImageFilesDialogComponent } from './components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component'; +import { UploadingProcessbarComponent } from './common/uploading-processbar/uploading-processbar.component'; +import { ExportPortableProjectComponent } from './components/export-portable-project/export-portable-project.component'; +import { NodesMenuConfirmationDialogComponent } from './components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component'; +import { ConfirmationDeleteAllProjectsComponent } from './components/projects/confirmation-delete-all-projects/confirmation-delete-all-projects.component'; +import { ProjectMapLockConfirmationDialogComponent } from './components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component'; @NgModule({ - declarations: [ - AppComponent, - ProjectMapComponent, - ServersComponent, - AddServerDialogComponent, - CreateSnapshotDialogComponent, - SnapshotMenuItemComponent, - ProjectsComponent, - AddBlankProjectDialogComponent, - ImportProjectDialogComponent, - ConfirmationDialogComponent, - DefaultLayoutComponent, - ProgressDialogComponent, - ContextMenuComponent, - ContextConsoleMenuComponent, - StartNodeActionComponent, - StopNodeActionComponent, - TemplateComponent, - TemplateListDialogComponent, - MoveLayerDownActionComponent, - MoveLayerUpActionComponent, - EditStyleActionComponent, - EditTextActionComponent, - DeleteActionComponent, - DuplicateActionComponent, - PacketFiltersActionComponent, - StartCaptureActionComponent, - StopCaptureActionComponent, - ResumeLinkActionComponent, - SuspendLinkActionComponent, - SettingsComponent, - PreferencesComponent, - BundledServerFinderComponent, - ProgressComponent, - ServerDiscoveryComponent, - NodeSelectInterfaceComponent, - DrawLinkToolComponent, - InstalledSoftwareComponent, - DrawingAddedComponent, - DrawingResizedComponent, - TextAddedComponent, - TextEditedComponent, - NodeDraggedComponent, - NodeLabelDraggedComponent, - DrawingDraggedComponent, - LinkCreatedComponent, - InterfaceLabelDraggedComponent, - InstallSoftwareComponent, - StyleEditorDialogComponent, - TextEditorDialogComponent, - PacketFiltersDialogComponent, - QemuPreferencesComponent, - QemuVmTemplatesComponent, - AddQemuVmTemplateComponent, - QemuVmTemplateDetailsComponent, - GeneralPreferencesComponent, - VpcsPreferencesComponent, - VpcsTemplatesComponent, - AddVpcsTemplateComponent, - VpcsTemplateDetailsComponent, - VirtualBoxPreferencesComponent, - VirtualBoxTemplatesComponent, - VirtualBoxTemplateDetailsComponent, - AddVirtualBoxTemplateComponent, - BuiltInPreferencesComponent, - EthernetHubsTemplatesComponent, - EthernetHubsAddTemplateComponent, - EthernetHubsTemplateDetailsComponent, - CloudNodesTemplatesComponent, - CloudNodesAddTemplateComponent, - CloudNodesTemplateDetailsComponent, - EthernetSwitchesTemplatesComponent, - EthernetSwitchesAddTemplateComponent, - EthernetSwitchesTemplateDetailsComponent, - DynamipsPreferencesComponent, - IosTemplatesComponent, - IosTemplateDetailsComponent, - AddIosTemplateComponent, - SymbolsComponent, - VmwarePreferencesComponent, - VmwareTemplatesComponent, - VmwareTemplateDetailsComponent, - AddVmwareTemplateComponent, - DeleteConfirmationDialogComponent, - HelpDialogComponent, - StartCaptureDialogComponent, - DeleteTemplateComponent, - DockerTemplatesComponent, - AddDockerTemplateComponent, - DockerTemplateDetailsComponent, - IouTemplatesComponent, - AddIouTemplateComponent, - IouTemplateDetailsComponent, - CopyQemuVmTemplateComponent, - CopyIosTemplateComponent, - CopyIouTemplateComponent, - CopyDockerTemplateComponent, - EmptyTemplatesListComponent, - SymbolsMenuComponent, - SearchFilter, - DateFilter, - NameFilter, - DataSourceFilter, - TemplateFilter, - ProjectsFilter, - ListOfSnapshotsComponent, - CustomAdaptersComponent, - NodesMenuComponent, - AdbutlerComponent, - ConsoleDeviceActionComponent, - ShowNodeActionComponent, - ConsoleComponent, - NodesMenuComponent, - ProjectMapMenuComponent, - HelpComponent, - ConfigEditorDialogComponent, - EditConfigActionComponent, - LogConsoleComponent, - SaveProjectDialogComponent, - TopologySummaryComponent, - InfoDialogComponent, - BringToFrontActionComponent, - ExportConfigActionComponent, - ImportConfigActionComponent, - ConsoleDeviceActionBrowserComponent, - ChangeSymbolDialogComponent, - ChangeSymbolActionComponent, - EditProjectDialogComponent, - ReloadNodeActionComponent, - SuspendNodeActionComponent, - ConfigActionComponent, - ConfiguratorDialogVpcsComponent, - ConfiguratorDialogEthernetHubComponent, - ConfiguratorDialogEthernetSwitchComponent, - PortsComponent, - ConfiguratorDialogSwitchComponent, - ConfiguratorDialogVirtualBoxComponent, - CustomAdaptersTableComponent, - ConfiguratorDialogQemuComponent, - ConfiguratorDialogCloudComponent, - UdpTunnelsComponent, - ConfiguratorDialogAtmSwitchComponent, - ConfiguratorDialogVmwareComponent, - ConfiguratorDialogIouComponent, - ConfiguratorDialogIosComponent, - ConfiguratorDialogDockerComponent, - ConfiguratorDialogNatComponent, - ConfiguratorDialogTracengComponent, - AddTracengTemplateComponent, - TracengPreferencesComponent, - TracengTemplatesComponent, - TracengTemplateDetailsComponent, - QemuImageCreatorComponent, - ChooseNameDialogComponent, - StartCaptureOnStartedLinkActionComponent, - LockActionComponent, - NavigationDialogComponent, - ScreenshotDialogComponent, - PageNotFoundComponent, - AlignHorizontallyActionComponent, - AlignVerticallyActionComponent, - ConfirmationBottomSheetComponent, - ConfigDialogComponent, - Gns3vmComponent, - ConfigureGns3VMDialogComponent, - ImportApplianceComponent, - DirectLinkComponent, - SystemStatusComponent, - StatusInfoComponent, - StatusChartComponent, - OpenFileExplorerActionComponent, - HttpConsoleActionComponent, - WebConsoleComponent, - ConsoleWrapperComponent, - HttpConsoleNewTabActionComponent, - WebConsoleFullWindowComponent, - NewTemplateDialogComponent, - ChangeHostnameActionComponent, - ChangeHostnameDialogComponent, - ApplianceInfoDialogComponent, - InformationDialogComponent, - TemplateNameDialogComponent, - ConfigureCustomAdaptersDialogComponent, - EditNetworkConfigurationDialogComponent - ], - imports: [ - BrowserModule, - HttpClientModule, - AppRoutingModule, - FormsModule, - ReactiveFormsModule, - BrowserAnimationsModule, - CdkTableModule, - CartographyModule, - NgxElectronModule, - FileUploadModule, - MatSidenavModule, - ResizableModule, - DragAndDropModule, - DragDropModule, - NgxChildProcessModule, - MATERIAL_IMPORTS, - NgCircleProgressModule.forRoot(), - OverlayModule, - ], - providers: [ - SettingsService, - { provide: ErrorHandler, useClass: ToasterErrorHandler }, - D3Service, - VersionService, - ProjectService, - SymbolService, - ServerService, - TemplateService, - NodeService, - LinkService, - DrawingService, - HttpServer, - SnapshotService, - ProgressDialogService, - ToasterService, - ProgressService, - ProjectWebServiceHandler, - LinksDataSource, - NodesDataSource, - SymbolsDataSource, - LogEventsDataSource, - SelectionManager, - InRectangleHelper, - DrawingsDataSource, - ServerErrorHandler, - ServerDatabase, - ProjectNameValidator, - ToolsService, - ServerSettingsService, - QemuService, - VpcsService, - TemplateMocksService, - VirtualBoxService, - BuiltInTemplatesService, - IosService, - InstalledSoftwareService, - ExternalSoftwareDefinitionService, - PlatformService, - IosConfigurationService, - QemuConfigurationService, - VirtualBoxConfigurationService, - VpcsConfigurationService, - BuiltInTemplatesConfigurationService, - VmwareService, - VmwareConfigurationService, - DockerService, - DockerConfigurationService, - IouService, - IouConfigurationService, - RecentlyOpenedProjectService, - ServerManagementService, - MapScaleService, - ConsoleService, - DefaultConsoleService, - NodeCreatedLabelStylesFixer, - NonNegativeValidator, - RotationValidator, - MapSettingsService, - InfoService, - ComputeService, - TracengService, - PacketCaptureService, - NotificationService, - Gns3vmService, - ThemeService, - GoogleAnalyticsService, - NodeConsoleService, - ServerResolve, - ConsoleGuard, - Title, - ApplianceService, - UpdatesService, - ], - entryComponents: [ - AddServerDialogComponent, - CreateSnapshotDialogComponent, - ProgressDialogComponent, - TemplateListDialogComponent, - AddBlankProjectDialogComponent, - ImportProjectDialogComponent, - ConfirmationDialogComponent, - StyleEditorDialogComponent, - PacketFiltersDialogComponent, - TextEditorDialogComponent, - SymbolsComponent, - DeleteConfirmationDialogComponent, - HelpDialogComponent, - StartCaptureDialogComponent, - ConfigEditorDialogComponent, - SaveProjectDialogComponent, - InfoDialogComponent, - ChangeSymbolDialogComponent, - EditProjectDialogComponent, - ConfigureGns3VMDialogComponent, - ConfiguratorDialogVpcsComponent, - ConfiguratorDialogEthernetHubComponent, - ConfiguratorDialogEthernetSwitchComponent, - ConfiguratorDialogSwitchComponent, - ConfiguratorDialogVirtualBoxComponent, - ConfiguratorDialogQemuComponent, - ConfiguratorDialogCloudComponent, - ConfiguratorDialogAtmSwitchComponent, - ConfiguratorDialogVmwareComponent, - ConfiguratorDialogIouComponent, - ConfiguratorDialogIosComponent, - ConfiguratorDialogDockerComponent, - ConfiguratorDialogNatComponent, - ConfiguratorDialogTracengComponent, - QemuImageCreatorComponent, - ChooseNameDialogComponent, - NavigationDialogComponent, - ScreenshotDialogComponent, - ConfirmationBottomSheetComponent, - ConfigDialogComponent, - AdbutlerComponent, - NewTemplateDialogComponent, - ChangeHostnameDialogComponent, - ApplianceInfoDialogComponent, - ConfigureCustomAdaptersDialogComponent, - EditNetworkConfigurationDialogComponent, - ], - bootstrap: [AppComponent], + declarations: [ + AppComponent, + LoggedUserComponent, + ProjectMapComponent, + LoginComponent, + ControllersComponent, + AddControllerDialogComponent, + CreateSnapshotDialogComponent, + SnapshotMenuItemComponent, + ProjectsComponent, + AddBlankProjectDialogComponent, + ImportProjectDialogComponent, + ConfirmationDialogComponent, + DefaultLayoutComponent, + ProgressDialogComponent, + ContextMenuComponent, + ContextConsoleMenuComponent, + StartNodeActionComponent, + IsolateNodeActionComponent, + UnisolateNodeActionComponent, + StopNodeActionComponent, + TemplateComponent, + TemplateListDialogComponent, + MoveLayerDownActionComponent, + MoveLayerUpActionComponent, + EditStyleActionComponent, + EditLinkStyleActionComponent, + EditTextActionComponent, + DeleteActionComponent, + DuplicateActionComponent, + PacketFiltersActionComponent, + StartCaptureActionComponent, + StopCaptureActionComponent, + ResumeLinkActionComponent, + SuspendLinkActionComponent, + SettingsComponent, + PreferencesComponent, + BundledControllerFinderComponent, + ProgressComponent, + ControllerDiscoveryComponent, + NodeSelectInterfaceComponent, + DrawLinkToolComponent, + InstalledSoftwareComponent, + DrawingAddedComponent, + DrawingResizedComponent, + TextAddedComponent, + TextEditedComponent, + NodeDraggedComponent, + NodeLabelDraggedComponent, + DrawingDraggedComponent, + LinkCreatedComponent, + InterfaceLabelDraggedComponent, + InstallSoftwareComponent, + StyleEditorDialogComponent, + LinkStyleEditorDialogComponent, + TextEditorDialogComponent, + PacketFiltersDialogComponent, + QemuPreferencesComponent, + QemuVmTemplatesComponent, + AddQemuVmTemplateComponent, + QemuVmTemplateDetailsComponent, + GeneralPreferencesComponent, + VpcsPreferencesComponent, + VpcsTemplatesComponent, + AddVpcsTemplateComponent, + VpcsTemplateDetailsComponent, + VirtualBoxPreferencesComponent, + VirtualBoxTemplatesComponent, + VirtualBoxTemplateDetailsComponent, + AddVirtualBoxTemplateComponent, + BuiltInPreferencesComponent, + EthernetHubsTemplatesComponent, + EthernetHubsAddTemplateComponent, + EthernetHubsTemplateDetailsComponent, + CloudNodesTemplatesComponent, + CloudNodesAddTemplateComponent, + CloudNodesTemplateDetailsComponent, + EthernetSwitchesTemplatesComponent, + EthernetSwitchesAddTemplateComponent, + EthernetSwitchesTemplateDetailsComponent, + DynamipsPreferencesComponent, + IosTemplatesComponent, + IosTemplateDetailsComponent, + AddIosTemplateComponent, + SymbolsComponent, + VmwarePreferencesComponent, + VmwareTemplatesComponent, + VmwareTemplateDetailsComponent, + AddVmwareTemplateComponent, + DeleteConfirmationDialogComponent, + HelpDialogComponent, + StartCaptureDialogComponent, + DeleteTemplateComponent, + DockerTemplatesComponent, + AddDockerTemplateComponent, + DockerTemplateDetailsComponent, + IouTemplatesComponent, + AddIouTemplateComponent, + IouTemplateDetailsComponent, + CopyQemuVmTemplateComponent, + CopyIosTemplateComponent, + CopyIouTemplateComponent, + CopyDockerTemplateComponent, + EmptyTemplatesListComponent, + SymbolsMenuComponent, + SearchFilter, + DateFilter, + NameFilter, + DataSourceFilter, + TemplateFilter, + ProjectsFilter, + AuthImageFilter, + ListOfSnapshotsComponent, + CustomAdaptersComponent, + NodesMenuComponent, + AdbutlerComponent, + ConsoleDeviceActionComponent, + ShowNodeActionComponent, + ConsoleComponent, + NodesMenuComponent, + ProjectMapMenuComponent, + HelpComponent, + ConfigEditorDialogComponent, + EditConfigActionComponent, + LogConsoleComponent, + SaveProjectDialogComponent, + TopologySummaryComponent, + InfoDialogComponent, + BringToFrontActionComponent, + ExportConfigActionComponent, + ImportConfigActionComponent, + ConsoleDeviceActionBrowserComponent, + ChangeSymbolDialogComponent, + ChangeSymbolActionComponent, + EditProjectDialogComponent, + ReloadNodeActionComponent, + SuspendNodeActionComponent, + ConfigActionComponent, + ConfiguratorDialogVpcsComponent, + ConfiguratorDialogEthernetHubComponent, + ConfiguratorDialogEthernetSwitchComponent, + PortsComponent, + ConfiguratorDialogSwitchComponent, + ConfiguratorDialogVirtualBoxComponent, + CustomAdaptersTableComponent, + ConfiguratorDialogQemuComponent, + ConfiguratorDialogCloudComponent, + UdpTunnelsComponent, + ConfiguratorDialogAtmSwitchComponent, + ConfiguratorDialogVmwareComponent, + ConfiguratorDialogIouComponent, + ConfiguratorDialogIosComponent, + ConfiguratorDialogDockerComponent, + ConfiguratorDialogNatComponent, + QemuImageCreatorComponent, + ChooseNameDialogComponent, + StartCaptureOnStartedLinkActionComponent, + LockActionComponent, + NavigationDialogComponent, + ScreenshotDialogComponent, + PageNotFoundComponent, + AlignHorizontallyActionComponent, + AlignVerticallyActionComponent, + ConfirmationBottomSheetComponent, + ConfigDialogComponent, + ImportApplianceComponent, + DirectLinkComponent, + SystemStatusComponent, + StatusInfoComponent, + StatusChartComponent, + OpenFileExplorerActionComponent, + HttpConsoleActionComponent, + WebConsoleComponent, + ConsoleWrapperComponent, + HttpConsoleNewTabActionComponent, + WebConsoleFullWindowComponent, + NewTemplateDialogComponent, + ChangeHostnameActionComponent, + ChangeHostnameDialogComponent, + ApplianceInfoDialogComponent, + ReadmeEditorComponent, + MarkedDirective, + InformationDialogComponent, + TemplateNameDialogComponent, + ConfigureCustomAdaptersDialogComponent, + EditNetworkConfigurationDialogComponent, + UserManagementComponent, + ProjectReadmeComponent, + AddGroupDialogComponent, + GroupFilterPipe, + GroupManagementComponent, + AddUserDialogComponent, + UserFilterPipe, + DeleteGroupDialogComponent, + DeleteUserDialogComponent, + GroupDetailsComponent, + UserDetailComponent, + AddUserToGroupDialogComponent, + RemoveToGroupDialogComponent, + PaginatorPipe, + MembersFilterPipe, + ManagementComponent, + RoleManagementComponent, + RoleFilterPipe, + AddRoleDialogComponent, + DeleteRoleDialogComponent, + RoleDetailComponent, + PermissionEditorComponent, + EditablePermissionComponent, + PermissionEditorValidateDialogComponent, + RemoveToGroupDialogComponent, + PermissionsManagementComponent, + AddRoleToGroupComponent, + PermissionEditLineComponent, + AddPermissionLineComponent, + MethodButtonComponent, + ActionButtonComponent, + DeletePermissionDialogComponent, + PathAutoCompleteComponent, + FilterCompletePipe, + UserPermissionsComponent, + PermissionsFilterPipe, + RolePermissionsComponent, + DisplayPathPipe, + ChangeUserPasswordComponent, + FilterCompletePipe, + DisplayPathPipe, + ChangeUserPasswordComponent, + ProjectReadmeComponent, + ImageManagerComponent, + AddImageDialogComponent, + DeleteAllImageFilesDialogComponent, + UploadingProcessbarComponent, + ExportPortableProjectComponent, + NodesMenuConfirmationDialogComponent, + ConfirmationDeleteAllProjectsComponent, + ProjectMapLockConfirmationDialogComponent, + ], + imports: [ + BrowserModule, + HttpClientModule, + AppRoutingModule, + FormsModule, + ReactiveFormsModule, + BrowserAnimationsModule, + CdkTableModule, + CartographyModule, + NgxElectronModule, + FileUploadModule, + MatSidenavModule, + MatFormFieldModule, + MatMenuModule, + ResizableModule, + DragAndDropModule, + DragDropModule, + NgxChildProcessModule, + MATERIAL_IMPORTS, + NgCircleProgressModule.forRoot(), + OverlayModule, + MatSlideToggleModule, + MatCheckboxModule, + MatAutocompleteModule, + ], + providers: [ + SettingsService, + { provide: ErrorHandler, useClass: ToasterErrorHandler }, + { provide: HTTP_INTERCEPTORS, useClass: HttpRequestsInterceptor, multi: true }, + VersionService, + D3Service, + ProjectService, + SymbolService, + ControllerService, + TemplateService, + NodeService, + LinkService, + DrawingService, + HttpController, + SnapshotService, + ProgressDialogService, + ToasterService, + ProgressService, + ProjectWebServiceHandler, + LinksDataSource, + NodesDataSource, + SymbolsDataSource, + LogEventsDataSource, + SelectionManager, + InRectangleHelper, + DrawingsDataSource, + ControllerErrorHandler, + ControllerDatabase, + ProjectNameValidator, + ToolsService, + ControllerSettingsService, + QemuService, + VpcsService, + TemplateMocksService, + VirtualBoxService, + BuiltInTemplatesService, + IosService, + InstalledSoftwareService, + ExternalSoftwareDefinitionService, + PlatformService, + IosConfigurationService, + QemuConfigurationService, + VirtualBoxConfigurationService, + VpcsConfigurationService, + BuiltInTemplatesConfigurationService, + VmwareService, + VmwareConfigurationService, + DockerService, + DockerConfigurationService, + IouService, + IouConfigurationService, + RecentlyOpenedProjectService, + ControllerManagementService, + MapScaleService, + ConsoleService, + DefaultConsoleService, + NodeCreatedLabelStylesFixer, + NonNegativeValidator, + RotationValidator, + MapSettingsService, + InfoService, + ComputeService, + PacketCaptureService, + NotificationService, + ThemeService, + GoogleAnalyticsService, + NodeConsoleService, + ControllerResolve, + LoginGuard, + ConsoleGuard, + Title, + ApplianceService, + UpdatesService, + LoginService, + UserService + ], + bootstrap: [AppComponent] }) export class AppModule { constructor(protected _googleAnalyticsService: GoogleAnalyticsService) {} diff --git a/src/app/cartography/cartography.module.ts b/src/app/cartography/cartography.module.ts index 7d7c813df..a900548fb 100644 --- a/src/app/cartography/cartography.module.ts +++ b/src/app/cartography/cartography.module.ts @@ -5,6 +5,7 @@ import { MatMenuModule } from '@angular/material/menu'; import { ANGULAR_MAP_DECLARATIONS } from './angular-map.imports'; import { D3MapComponent } from './components/d3-map/d3-map.component'; import { DraggableSelectionComponent } from './components/draggable-selection/draggable-selection.component'; +import { LinkEditingComponent } from './components/link-editing/link-editing.component'; import { DrawingAddingComponent } from './components/drawing-adding/drawing-adding.component'; import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component'; import { ExperimentalMapComponent } from './components/experimental-map/experimental-map.component'; @@ -73,6 +74,7 @@ import { SerialLinkWidget } from './widgets/links/serial-link'; SelectionControlComponent, SelectionSelectComponent, DraggableSelectionComponent, + LinkEditingComponent, MovingCanvasDirective, ZoomingCanvasDirective, ], diff --git a/src/app/cartography/components/d3-map/d3-map.component.html b/src/app/cartography/components/d3-map/d3-map.component.html index e166c6976..ee3a26dd2 100644 --- a/src/app/cartography/components/d3-map/d3-map.component.html +++ b/src/app/cartography/components/d3-map/d3-map.component.html @@ -44,5 +44,6 @@ - + + diff --git a/src/app/cartography/components/d3-map/d3-map.component.spec.ts b/src/app/cartography/components/d3-map/d3-map.component.spec.ts index 007b05f2b..4868aa12f 100644 --- a/src/app/cartography/components/d3-map/d3-map.component.spec.ts +++ b/src/app/cartography/components/d3-map/d3-map.component.spec.ts @@ -1,23 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { D3MapComponent } from './d3-map.component'; describe('D3MapComponent', () => { let component: D3MapComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [D3MapComponent], }).compileComponents(); - })); + }); - // beforeEach(() => { - // fixture = TestBed.createComponent(MapComponent); - // component = fixture.componentInstance; - // fixture.detectChanges(); - // }); - // - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component) + }); }); diff --git a/src/app/cartography/components/d3-map/d3-map.component.ts b/src/app/cartography/components/d3-map/d3-map.component.ts index b79b3bbe7..b0c0f9504 100644 --- a/src/app/cartography/components/d3-map/d3-map.component.ts +++ b/src/app/cartography/components/d3-map/d3-map.component.ts @@ -13,7 +13,7 @@ import { select, Selection } from 'd3-selection'; import { Subscription } from 'rxjs'; import { Link } from '../../../models/link'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import { Controller } from '../../../models/controller'; import { Symbol } from '../../../models/symbol'; import { MapScaleService } from '../../../services/mapScale.service'; import { MapSettingsService } from '../../../services/mapsettings.service'; @@ -43,7 +43,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy { @Input() drawings: Drawing[] = []; @Input() symbols: Symbol[] = []; @Input() project: Project; - @Input() server: Server; + @Input() controller: Controller; @Input() width = 1500; @Input() height = 600; diff --git a/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts b/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts index 21a994dca..8e3011698 100644 --- a/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts +++ b/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts @@ -42,7 +42,7 @@ describe('DraggableSelectionComponent', () => { let interfaceLabelDragEventEmitter: EventEmitter>; let interfaceLabelEndEventEmitter: EventEmitter>; - beforeEach(async(() => { + beforeEach(async () => { mockedGraphDataManager = new MockedGraphDataManager(); nodesStartEventEmitter = new EventEmitter>(); @@ -110,7 +110,7 @@ describe('DraggableSelectionComponent', () => { interfaceDragged: { emit: () => {} }, }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ providers: [ { provide: NodesWidget, useValue: nodesWidgetStub }, { provide: DrawingsWidget, useValue: drawingsWidgetStub }, @@ -126,7 +126,7 @@ describe('DraggableSelectionComponent', () => { ], declarations: [DraggableSelectionComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DraggableSelectionComponent); diff --git a/src/app/cartography/components/drawing-adding/drawing-adding.component.spec.ts b/src/app/cartography/components/drawing-adding/drawing-adding.component.spec.ts index ea508b706..9eefc3c83 100644 --- a/src/app/cartography/components/drawing-adding/drawing-adding.component.spec.ts +++ b/src/app/cartography/components/drawing-adding/drawing-adding.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DrawingsEventSource } from '../../events/drawings-event-source'; import { Context } from '../../models/context'; @@ -9,8 +9,8 @@ describe('DrawingAddingComponent', () => { let fixture: ComponentFixture; let drawingsEventSource = new DrawingsEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [NoopAnimationsModule], providers: [ { provide: DrawingsEventSource, useValue: drawingsEventSource }, @@ -18,7 +18,7 @@ describe('DrawingAddingComponent', () => { ], declarations: [DrawingAddingComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingAddingComponent); diff --git a/src/app/cartography/components/drawing-resizing/drawing-resizing.component.spec.ts b/src/app/cartography/components/drawing-resizing/drawing-resizing.component.spec.ts index 7cd3fac28..63eccbdbb 100644 --- a/src/app/cartography/components/drawing-resizing/drawing-resizing.component.spec.ts +++ b/src/app/cartography/components/drawing-resizing/drawing-resizing.component.spec.ts @@ -1,5 +1,5 @@ import { EventEmitter } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DrawingsEventSource } from '../../events/drawings-event-source'; import { ResizingEnd } from '../../events/resizing'; @@ -30,8 +30,8 @@ describe('DrawingResizingComponent', () => { let drawingsWidgetMock = new DrawingWidgetMock(); let drawingsEventSource = new DrawingsEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [NoopAnimationsModule], providers: [ { provide: DrawingsWidget, useValue: drawingsWidgetMock }, @@ -39,7 +39,7 @@ describe('DrawingResizingComponent', () => { ], declarations: [DrawingResizingComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingResizingComponent); diff --git a/src/app/cartography/components/experimental-map/draggable/draggable.component.spec.ts b/src/app/cartography/components/experimental-map/draggable/draggable.component.spec.ts index 3182c040a..80794246f 100644 --- a/src/app/cartography/components/experimental-map/draggable/draggable.component.spec.ts +++ b/src/app/cartography/components/experimental-map/draggable/draggable.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DraggableComponent } from './draggable.component'; describe('DraggableComponent', () => { let component: DraggableComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async() => { TestBed.configureTestingModule({ declarations: [DraggableComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DraggableComponent); @@ -17,7 +17,7 @@ describe('DraggableComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.html b/src/app/cartography/components/experimental-map/drawing/drawing.component.html index d22484796..9410b885a 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawing.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.html @@ -5,13 +5,13 @@ (dragging)="OnDragging($event)" (dragged)="OnDragged($event)" > - + - + - + - + - + diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts index b07d4b9fe..191d84280 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts @@ -1,15 +1,18 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed } from '@angular/core/testing'; +import { DrawingsEventSource } from 'app/cartography/events/drawings-event-source'; +import { SvgToDrawingConverter } from 'app/cartography/helpers/svg-to-drawing-converter'; import { DrawingComponent } from './drawing.component'; describe('DrawingComponent', () => { let component: DrawingComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [DrawingComponent], + providers:[SvgToDrawingConverter,DrawingsEventSource] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingComponent); @@ -17,7 +20,7 @@ describe('DrawingComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.ts b/src/app/cartography/components/experimental-map/drawing/drawing.component.ts index 724f61e52..ade50af6a 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawing.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.ts @@ -21,17 +21,17 @@ export class DrawingComponent implements OnInit { private svgToDrawingConverter: SvgToDrawingConverter, private drawingsEventSource: DrawingsEventSource, private cd: ChangeDetectorRef - ) {} + ) { } ngOnInit() { try { this.drawing.element = this.svgToDrawingConverter.convert(this.drawing.svg); - } catch (error) {} + } catch (error) { } } OnDragging(evt) { - this.drawing.x = evt.x; - this.drawing.y = evt.y; + this.drawing.x = evt ? evt.x : ''; + this.drawing.y = evt ? evt.y : ''; this.cd.detectChanges(); } @@ -64,6 +64,8 @@ export class DrawingComponent implements OnInit { } get transformation() { - return `translate(${this.drawing.x},${this.drawing.y}) rotate(${this.drawing.rotation})`; + if (this.drawing) { + return `translate(${this.drawing.x},${this.drawing.y}) rotate(${this.drawing.rotation})`; + } } } diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html index 64bae406c..ba88c2d21 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html @@ -1,12 +1,12 @@ diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts index 1e8c38d85..58815067a 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts @@ -1,15 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { QtDasharrayFixer } from 'app/cartography/helpers/qt-dasharray-fixer'; import { EllipseComponent } from './ellipse.component'; describe('EllipseComponent', () => { let component: EllipseComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [EllipseComponent], + providers:[QtDasharrayFixer] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(EllipseComponent); @@ -17,7 +19,7 @@ describe('EllipseComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts index 74b3f11ee..609bde452 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts @@ -15,21 +15,21 @@ export class EllipseComponent implements OnInit { ngOnInit() {} get fill_opacity() { - if (isFinite(this.ellipse.fill_opacity)) { + if (this.ellipse && isFinite(this.ellipse.fill_opacity)) { return this.ellipse.fill_opacity; } return null; } get stroke_width() { - if (isFinite(this.ellipse.stroke_width)) { + if (this.ellipse && isFinite(this.ellipse.stroke_width)) { return this.ellipse.stroke_width; } return null; } get stroke_dasharray() { - if (this.ellipse.stroke_dasharray) { + if (this.ellipse && this.ellipse.stroke_dasharray) { return this.qtDasharrayFixer.fix(this.ellipse.stroke_dasharray); } return null; diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html index 2be30057d..919b12d22 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts index 65bf99599..c91c17d1f 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ImageComponent } from './image.component'; describe('ImageComponent', () => { let component: ImageComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [ImageComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ImageComponent); @@ -17,7 +17,7 @@ describe('ImageComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts index b8151e683..b299dd24f 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts @@ -8,6 +8,7 @@ import { ImageElement } from '../../../../../models/drawings/image-element'; }) export class ImageComponent implements OnInit { @Input('app-image') image: ImageElement; + data:any constructor() {} diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html index b9516dafc..09e23fd44 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html @@ -1,10 +1,10 @@ diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts index c6cfb82ae..53b850e04 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts @@ -1,15 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed } from '@angular/core/testing'; +import { QtDasharrayFixer } from 'app/cartography/helpers/qt-dasharray-fixer'; import { LineComponent } from './line.component'; describe('LineComponent', () => { let component: LineComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async() => { TestBed.configureTestingModule({ declarations: [LineComponent], + providers:[QtDasharrayFixer] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(LineComponent); @@ -17,7 +19,7 @@ describe('LineComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts index 175d66a43..709770bff 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts @@ -15,14 +15,14 @@ export class LineComponent implements OnInit { ngOnInit() {} get stroke_width() { - if (isFinite(this.line.stroke_width)) { + if (this.line && isFinite(this.line.stroke_width)) { return this.line.stroke_width; } return null; } get stroke_dasharray() { - if (this.line.stroke_dasharray) { + if ( this.line && this.line.stroke_dasharray) { return this.qtDasharrayFixer.fix(this.line.stroke_dasharray); } return null; diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html index ed00003c8..7c6fdb2e8 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html @@ -1,10 +1,10 @@ diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts index 17c35d335..b0a1e7883 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts @@ -1,15 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed } from '@angular/core/testing'; +import { QtDasharrayFixer } from 'app/cartography/helpers/qt-dasharray-fixer'; import { RectComponent } from './rect.component'; describe('RectComponent', () => { let component: RectComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [RectComponent], + providers:[QtDasharrayFixer] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(RectComponent); @@ -17,7 +19,7 @@ describe('RectComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts index 3fc17a267..b3596f4bb 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts @@ -15,21 +15,21 @@ export class RectComponent implements OnInit { ngOnInit() {} get fill_opacity() { - if (isFinite(this.rect.fill_opacity)) { - return this.rect.fill_opacity; + if (this.rect && isFinite(this.rect.fill_opacity)) { + return this.rect.fill_opacity ? this.rect.fill_opacity : null; } return null; } get stroke_width() { - if (isFinite(this.rect.stroke_width)) { - return this.rect.stroke_width; + if (this.rect && isFinite(this.rect.stroke_width)) { + return this.rect.stroke_width ? this.rect.stroke_width : null; } return null; } get stroke_dasharray() { - if (this.rect.stroke_dasharray) { + if (this.rect && this.rect.stroke_dasharray) { return this.qtDasharrayFixer.fix(this.rect.stroke_dasharray); } return null; diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html index 42f87e3d4..fe864fe40 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html +++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html @@ -3,7 +3,7 @@ class="text_element noselect" [attr.style]="style" [attr.text-decoration]="textDecoration" - [attr.fill]="text.fill" + [attr.fill]="text?.fill" [attr.transform]="transformation" > diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts index 5dfb1368f..32557aae8 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts @@ -1,15 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FontFixer } from 'app/cartography/helpers/font-fixer'; import { TextComponent } from './text.component'; describe('TextComponent', () => { let component: TextComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [TextComponent], + providers:[FontFixer] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(TextComponent); @@ -17,7 +19,7 @@ describe('TextComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts index 2292278b9..4e03742d8 100644 --- a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts +++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts @@ -19,10 +19,12 @@ export class TextComponent implements OnInit, DoCheck { transformation = ''; - constructor(private fontFixer: FontFixer, private sanitizer: DomSanitizer) {} + constructor(private fontFixer: FontFixer, private sanitizer: DomSanitizer) { } ngOnInit() { - this.lines = this.getLines(this.text.text); + if (this.text) { + this.lines = this.getLines(this.text.text); + } } ngDoCheck() { @@ -30,32 +32,38 @@ export class TextComponent implements OnInit, DoCheck { } get style() { - const font = this.fontFixer.fix(this.text); + if (this.text) { + const font = this.fontFixer.fix(this.text); - const styles: string[] = []; - if (font.font_family) { - styles.push(`font-family: "${this.text.font_family}"`); - } - if (font.font_size) { - styles.push(`font-size: ${this.text.font_size}pt`); + const styles: string[] = []; + if (font.font_family) { + styles.push(`font-family: "${this.text.font_family}"`); + } + if (font.font_size) { + styles.push(`font-size: ${this.text.font_size}pt`); + } + if (font.font_weight) { + styles.push(`font-weight: ${this.text.font_weight}`); + } + return this.sanitizer.bypassSecurityTrustStyle(styles.join('; ')); } - if (font.font_weight) { - styles.push(`font-weight: ${this.text.font_weight}`); - } - return this.sanitizer.bypassSecurityTrustStyle(styles.join('; ')); } get textDecoration() { - return this.text.text_decoration; + if (this.text) { + return this.text.text_decoration; + } } calculateTransformation() { - const tspans = this.textRef.nativeElement.getElementsByTagName('tspan'); - if (tspans.length > 0) { - const height = this.textRef.nativeElement.getBBox().height / tspans.length; - return `translate(${TextComponent.MARGIN}, ${height - TextComponent.MARGIN})`; + if (this.textRef != undefined) { + const tspans = this.textRef.nativeElement.getElementsByTagName('tspan'); + if (tspans.length > 0) { + const height = this.textRef.nativeElement.getBBox().height / tspans.length; + return `translate(${TextComponent.MARGIN}, ${height - TextComponent.MARGIN})`; + } + return ''; } - return ''; } getLines(text: string) { diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts index 70e8d3780..9f68960da 100644 --- a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts +++ b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts @@ -1,15 +1,28 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectorRef, ElementRef, Injectable } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { CssFixer } from 'app/cartography/helpers/css-fixer'; import { InterfaceLabelComponent } from './interface-label.component'; -describe('InterfaceLabelComponent', () => { +export class MockElementRef extends ElementRef { + constructor() { super(null || undefined); } + nativeElement={} +} + + +xdescribe('InterfaceLabelComponent', () => { let component: InterfaceLabelComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [InterfaceLabelComponent], + providers: [ + CssFixer, + ChangeDetectorRef, + { provide: ElementRef, useValue: new MockElementRef() }, + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(InterfaceLabelComponent); @@ -17,7 +30,7 @@ describe('InterfaceLabelComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy() + }); }); diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts index cd316ec9d..a451698e3 100644 --- a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts +++ b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts @@ -30,9 +30,9 @@ export class InterfaceLabelComponent implements OnInit { private ref: ChangeDetectorRef, private sanitizer: DomSanitizer, private cssFixer: CssFixer - ) {} + ) { } - ngOnInit() {} + ngOnInit() { } @Input('x') set x(value) { @@ -89,9 +89,11 @@ export class InterfaceLabelComponent implements OnInit { } get transform() { - const bbox = this.elementRef.nativeElement.getBBox(); - const x = this.label.x; - const y = this.label.y + bbox.height; - return `translate(${x}, ${y}) rotate(${this.label.rotation}, ${x}, ${y})`; + if (this.elementRef.nativeElement.getBBox) { + const bbox = this.elementRef.nativeElement.getBBox() + const x = this.label.x; + const y = this.label.y + bbox.height; + return `translate(${x}, ${y}) rotate(${this.label.rotation}, ${x}, ${y})`; + } } } diff --git a/src/app/cartography/components/experimental-map/link/link.component.html b/src/app/cartography/components/experimental-map/link/link.component.html index ec46886aa..d13044ce5 100644 --- a/src/app/cartography/components/experimental-map/link/link.component.html +++ b/src/app/cartography/components/experimental-map/link/link.component.html @@ -1,13 +1,13 @@ - + - + diff --git a/src/app/cartography/components/experimental-map/link/link.component.spec.ts b/src/app/cartography/components/experimental-map/link/link.component.spec.ts index f1e1960b4..5eaa34c77 100644 --- a/src/app/cartography/components/experimental-map/link/link.component.spec.ts +++ b/src/app/cartography/components/experimental-map/link/link.component.spec.ts @@ -1,15 +1,18 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MultiLinkCalculatorHelper } from 'app/cartography/helpers/multi-link-calculator-helper'; import { LinkComponent } from './link.component'; describe('LinkComponent', () => { let component: LinkComponent; let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [LinkComponent], + providers: [ + { provide: MultiLinkCalculatorHelper, useValue: {} } + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(LinkComponent); @@ -17,7 +20,7 @@ describe('LinkComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/link/link.component.ts b/src/app/cartography/components/experimental-map/link/link.component.ts index 80069d941..394bb9151 100644 --- a/src/app/cartography/components/experimental-map/link/link.component.ts +++ b/src/app/cartography/components/experimental-map/link/link.component.ts @@ -33,7 +33,7 @@ export class LinkComponent implements OnInit, OnDestroy { private nodeChangedSubscription: Subscription; - constructor(private multiLinkCalculatorHelper: MultiLinkCalculatorHelper, private ref: ChangeDetectorRef) {} + constructor(private multiLinkCalculatorHelper: MultiLinkCalculatorHelper, private ref: ChangeDetectorRef) { } ngOnInit() { this.ref.detectChanges(); @@ -49,19 +49,21 @@ export class LinkComponent implements OnInit, OnDestroy { } get strategy(): LinkStrategy { - if (this.link.linkType === 'serial') { + if (this.link && this.link != undefined && this.link.linkType === 'serial') { return this.serialLinkStrategy; } return this.ethernetLinkStrategy; } get transform() { - const translation = this.multiLinkCalculatorHelper.linkTranslation( - this.link.distance, - this.link.source, - this.link.target - ); - return `translate (${translation.dx}, ${translation.dy})`; + if (this.link) { + const translation = this.multiLinkCalculatorHelper.linkTranslation( + this.link.distance, + this.link.source, + this.link.target + ); + return `translate (${translation.dx}, ${translation.dy})`; + } } get d() { diff --git a/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts b/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts index 98d2d1ba8..c04891766 100644 --- a/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts +++ b/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts @@ -5,8 +5,9 @@ import { LinkStrategy } from './link-strategy'; export class EthernetLinkStrategy implements LinkStrategy { public d(link: MapLink): string { const points = [ - [link.source.x + link.source.width / 2, link.source.y + link.source.height / 2], - [link.target.x + link.target.width / 2, link.target.y + link.target.height / 2], + + [link?.source?.x + link?.source?.width / 2, link?.source.y + link?.source?.height / 2], + [link?.target?.x + link?.target?.width / 2, link?.target?.y + link?.target?.height / 2], ]; const line_generator = path(); diff --git a/src/app/cartography/components/experimental-map/node/node.component.html b/src/app/cartography/components/experimental-map/node/node.component.html index 6a3c7529a..6fd282222 100644 --- a/src/app/cartography/components/experimental-map/node/node.component.html +++ b/src/app/cartography/components/experimental-map/node/node.component.html @@ -1,8 +1,8 @@ - + - {{ node.label.text }} + {{ node?.label?.text }} diff --git a/src/app/cartography/components/experimental-map/node/node.component.spec.ts b/src/app/cartography/components/experimental-map/node/node.component.spec.ts index c35dda52f..1d5367171 100644 --- a/src/app/cartography/components/experimental-map/node/node.component.spec.ts +++ b/src/app/cartography/components/experimental-map/node/node.component.spec.ts @@ -1,15 +1,23 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { NodesEventSource } from 'app/cartography/events/nodes-event-source'; +import { CssFixer } from 'app/cartography/helpers/css-fixer'; +import { FontFixer } from 'app/cartography/helpers/font-fixer'; import { NodeComponent } from './node.component'; describe('NodeComponent', () => { let component: NodeComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [NodeComponent], + providers:[ + CssFixer, + FontFixer, + NodesEventSource, + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(NodeComponent); @@ -17,7 +25,7 @@ describe('NodeComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/node/node.component.ts b/src/app/cartography/components/experimental-map/node/node.component.ts index cea785f2e..d86aeefbe 100644 --- a/src/app/cartography/components/experimental-map/node/node.component.ts +++ b/src/app/cartography/components/experimental-map/node/node.component.ts @@ -49,7 +49,7 @@ export class NodeComponent implements OnInit, OnDestroy, OnChanges, AfterViewIni protected element: ElementRef, private cd: ChangeDetectorRef, private nodesEventSource: NodesEventSource - ) {} + ) { } ngOnInit() { // this.nodeChangedSubscription = this.nodeChanged.subscribe((node: Node) => { @@ -85,42 +85,52 @@ export class NodeComponent implements OnInit, OnDestroy, OnChanges, AfterViewIni } get symbol(): string { - const symbol = this.symbols.find((s: Symbol) => s.symbol_id === this.node.symbol); - if (symbol) { - return 'data:image/svg+xml;base64,' + btoa(symbol.raw); + if (this.symbols) { + const symbol = this.symbols.find((s: Symbol) => s.symbol_id === this.node.symbol); + if (symbol) { + return 'data:image/svg+xml;base64,' + btoa(symbol.raw); + } + // @todo; we need to have default image + return 'data:image/svg+xml;base64,none'; } - // @todo; we need to have default image - return 'data:image/svg+xml;base64,none'; } get label_style() { - let styles = this.cssFixer.fix(this.node.label.style); - styles = this.fontFixer.fixStyles(styles); - return this.sanitizer.bypassSecurityTrustStyle(styles); + if (this.node != undefined) { + let styles = this.cssFixer.fix(this.node.label.style); + styles = this.fontFixer.fixStyles(styles); + return this.sanitizer.bypassSecurityTrustStyle(styles); + } } get label_x(): number { - if (this.node.label.x === null) { - // center - const bbox = this.label.nativeElement.getBBox(); - - return -bbox.width / 2; + if (this.node != undefined) { + if (this.node.label.x === null) { + // center + const bbox = this.label.nativeElement.getBBox(); + + return -bbox.width / 2; + } + return this.node.label.x + NodeComponent.NODE_LABEL_MARGIN; } - return this.node.label.x + NodeComponent.NODE_LABEL_MARGIN; } get label_y(): number { this.labelHeight = this.getLabelHeight(); - if (this.node.label.x === null) { - // center - return -this.node.height / 2 - this.labelHeight; + if (this.node != undefined) { + if (this.node.label.x === null) { + // center + return -this.node.height / 2 - this.labelHeight; + } + return this.node.label.y + this.labelHeight - NodeComponent.NODE_LABEL_MARGIN; } - return this.node.label.y + this.labelHeight - NodeComponent.NODE_LABEL_MARGIN; } private getLabelHeight() { - const bbox = this.label.nativeElement.getBBox(); - return bbox.height; + if (this.label != undefined) { + const bbox = this.label.nativeElement.getBBox(); + return bbox.height; + } } } diff --git a/src/app/cartography/components/experimental-map/selection/selection.component.spec.ts b/src/app/cartography/components/experimental-map/selection/selection.component.spec.ts index 94c95763b..b6d556d51 100644 --- a/src/app/cartography/components/experimental-map/selection/selection.component.spec.ts +++ b/src/app/cartography/components/experimental-map/selection/selection.component.spec.ts @@ -1,23 +1,24 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SelectionComponent } from './selection.component'; describe('SelectionComponent', () => { let component: SelectionComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ declarations: [SelectionComponent], }).compileComponents(); - })); - - beforeEach(() => { fixture = TestBed.createComponent(SelectionComponent); component = fixture.componentInstance; fixture.detectChanges(); }); + afterEach(() => { + fixture.destroy() + }) - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/experimental-map/selection/selection.component.ts b/src/app/cartography/components/experimental-map/selection/selection.component.ts index f2d915a45..ffc634460 100644 --- a/src/app/cartography/components/experimental-map/selection/selection.component.ts +++ b/src/app/cartography/components/experimental-map/selection/selection.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Observable, Subscription } from 'rxjs'; +import { Observable, Subscription} from 'rxjs'; import { Rectangle } from '../../../models/rectangle'; @Component({ @@ -28,15 +28,14 @@ export class SelectionComponent implements OnInit, AfterViewInit { ngAfterViewInit() { const down = Observable.fromEvent(this.svg, 'mousedown').do((e: MouseEvent) => e.preventDefault()); - down.subscribe((e: MouseEvent) => { if (e.target !== this.svg) { return; } this.started = true; - this.startX = e.clientX + window.scrollX; - this.startY = e.clientY + window.scrollY; + this.startX = e?.clientX + window?.scrollX; + this.startY = e?.clientY + window?.scrollY; this.width = 0; this.height = 0; this.visible = true; @@ -51,7 +50,7 @@ export class SelectionComponent implements OnInit, AfterViewInit { const scrollWindow = Observable.fromEvent(document, 'scroll').startWith({}); - const move = Observable.combineLatest(mouseMove, scrollWindow); + const move = Observable.combineLatest([mouseMove, scrollWindow]); const drag = down.mergeMap((md: MouseEvent) => { return move @@ -76,11 +75,11 @@ export class SelectionComponent implements OnInit, AfterViewInit { this.visible = false; this.started = false; + this.width = e.clientX - this.startX + window.scrollX; this.height = e.clientY - this.startY + window.scrollY; this.ref.detectChanges(); - this.selectedEvent([this.startX, this.startY], [this.width, this.height]); }) ) diff --git a/src/app/cartography/components/experimental-map/status/status.component.spec.ts b/src/app/cartography/components/experimental-map/status/status.component.spec.ts index 51032287c..2a32141f1 100644 --- a/src/app/cartography/components/experimental-map/status/status.component.spec.ts +++ b/src/app/cartography/components/experimental-map/status/status.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { StatusComponent } from './status.component'; describe('StatusComponent', () => { let component: StatusComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [StatusComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(StatusComponent); diff --git a/src/app/components/bundled-server-finder/bundled-server-finder.component.scss b/src/app/cartography/components/link-editing/link-editing.component.html similarity index 100% rename from src/app/components/bundled-server-finder/bundled-server-finder.component.scss rename to src/app/cartography/components/link-editing/link-editing.component.html diff --git a/src/app/components/preferences/gns3vm/gns3vm.component.spec.ts b/src/app/cartography/components/link-editing/link-editing.component.scss similarity index 100% rename from src/app/components/preferences/gns3vm/gns3vm.component.spec.ts rename to src/app/cartography/components/link-editing/link-editing.component.scss diff --git a/src/app/cartography/components/link-editing/link-editing.component.ts b/src/app/cartography/components/link-editing/link-editing.component.ts new file mode 100644 index 000000000..65eb2e90e --- /dev/null +++ b/src/app/cartography/components/link-editing/link-editing.component.ts @@ -0,0 +1,31 @@ +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { select } from 'd3-selection'; +import { Subscription } from 'rxjs'; +import { LinksEventSource } from '../../events/links-event-source'; +import { MapLink } from '../../models/map/map-link'; +import { LinksWidget } from '../../widgets/links'; + +@Component({ + selector: 'app-link-editing', + templateUrl: './link-editing.component.html', + styleUrls: ['./link-editing.component.scss'], +}) +export class LinkEditingComponent implements OnInit, OnDestroy { + private linkEditedSubscription: Subscription; + @Input('svg') svg: SVGSVGElement; + + constructor( + private linksWidget: LinksWidget, + private linksEventSource: LinksEventSource ) {} + + ngOnInit() { + const svg = select(this.svg); + this.linkEditedSubscription = this.linksEventSource.edited.subscribe((link: MapLink) => { + this.linksWidget.redrawLink(svg, link); + }); + } + + ngOnDestroy() { + this.linkEditedSubscription.unsubscribe(); + } +} diff --git a/src/app/cartography/components/selection-select/selection-select.component.spec.ts b/src/app/cartography/components/selection-select/selection-select.component.spec.ts index f819be272..362f95d00 100644 --- a/src/app/cartography/components/selection-select/selection-select.component.spec.ts +++ b/src/app/cartography/components/selection-select/selection-select.component.spec.ts @@ -1,15 +1,18 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SelectionManager } from 'app/cartography/managers/selection-manager'; +import { MapChangeDetectorRef } from 'app/cartography/services/map-change-detector-ref'; import { SelectionSelectComponent } from './selection-select.component'; describe('SelectionSelectComponent', () => { let component: SelectionSelectComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async () => { TestBed.configureTestingModule({ declarations: [SelectionSelectComponent], + providers: [MapChangeDetectorRef,SelectionManager] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(SelectionSelectComponent); @@ -17,7 +20,7 @@ describe('SelectionSelectComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/cartography/components/text-editor/text-editor.component.spec.ts b/src/app/cartography/components/text-editor/text-editor.component.spec.ts index 7619b5c0c..19b186cb8 100644 --- a/src/app/cartography/components/text-editor/text-editor.component.spec.ts +++ b/src/app/cartography/components/text-editor/text-editor.component.spec.ts @@ -1,5 +1,5 @@ import { Renderer2 } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MockedLinkService } from '../../../components/project-map/project-map.component.spec'; import { LinkService } from '../../../services/link.service'; @@ -18,7 +18,7 @@ describe('TextEditorComponent', () => { let fixture: ComponentFixture; let mockedLinkService: MockedLinkService = new MockedLinkService(); - beforeEach(async(() => { + beforeEach(async() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], providers: [ @@ -35,7 +35,7 @@ describe('TextEditorComponent', () => { ], declarations: [TextEditorComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(TextEditorComponent); diff --git a/src/app/cartography/components/text-editor/text-editor.component.ts b/src/app/cartography/components/text-editor/text-editor.component.ts index 70f690a59..ef7eff1a6 100644 --- a/src/app/cartography/components/text-editor/text-editor.component.ts +++ b/src/app/cartography/components/text-editor/text-editor.component.ts @@ -13,7 +13,7 @@ import { select } from 'd3-selection'; import { Subscription } from 'rxjs'; import { StyleProperty } from '../../../components/project-map/drawings-editors/text-editor/text-editor.component'; import { Link } from '../../../models/link'; -import { Server } from '../../../models/server'; +import { Controller } from '../../../models/controller'; import { LinkService } from '../../../services/link.service'; import { MapScaleService } from '../../../services/mapScale.service'; import { ToolsService } from '../../../services/tools.service'; @@ -37,7 +37,7 @@ import { Node } from '../../models/node'; export class TextEditorComponent implements OnInit, OnDestroy { @ViewChild('temporaryTextElement') temporaryTextElement: ElementRef; @Input('svg') svg: SVGSVGElement; - @Input('server') server: Server; + @Input('controller') controller: Controller; leftPosition: string = '0px'; topPosition: string = '0px'; @@ -185,7 +185,7 @@ export class TextEditorComponent implements OnInit, OnDestroy { let link: Link = this.linksDataSource.get(this.editedLink.linkId); link.nodes.find((n) => n.node_id === this.editedNode.node_id).label.text = innerText; - this.linkService.updateLink(this.server, link).subscribe((link: Link) => { + this.linkService.updateLink(this.controller, link).subscribe((link: Link) => { rootElement .selectAll('text.editingMode') .attr('visibility', 'visible') diff --git a/src/app/cartography/converters/map/link-to-map-link-converter.ts b/src/app/cartography/converters/map/link-to-map-link-converter.ts index 28ecf2c8f..14fd38270 100644 --- a/src/app/cartography/converters/map/link-to-map-link-converter.ts +++ b/src/app/cartography/converters/map/link-to-map-link-converter.ts @@ -15,6 +15,7 @@ export class LinkToMapLinkConverter implements Converter { mapLink.captureFilePath = link.capture_file_path; mapLink.capturing = link.capturing; mapLink.filters = link.filters; + mapLink.link_style = link.link_style; mapLink.linkType = link.link_type; mapLink.nodes = link.nodes.map((linkNode) => this.linkNodeToMapLinkNode.convert(linkNode, { link_id: link.link_id }) diff --git a/src/app/cartography/converters/map/map-drawing-to-svg-converter.ts b/src/app/cartography/converters/map/map-drawing-to-svg-converter.ts index e54664835..bd76c68cf 100644 --- a/src/app/cartography/converters/map/map-drawing-to-svg-converter.ts +++ b/src/app/cartography/converters/map/map-drawing-to-svg-converter.ts @@ -14,11 +14,11 @@ export class MapDrawingToSvgConverter implements Converter { let elem = ``; if (mapDrawing.element instanceof RectElement) { - elem = ``; + elem = `${mapDrawing.element.stroke_dasharray == '' ? `` :``}`; } else if (mapDrawing.element instanceof EllipseElement) { - elem = ``; + elem = `${mapDrawing.element.stroke_dasharray == '' ? `` :``}`; } else if (mapDrawing.element instanceof LineElement) { - elem = ``; + elem = ``; } else if (mapDrawing.element instanceof TextElement) { elem = `${mapDrawing.element.text}`; } else return ''; diff --git a/src/app/cartography/converters/map/map-link-to-link-converter.ts b/src/app/cartography/converters/map/map-link-to-link-converter.ts index ae269a420..6cc8be8b6 100644 --- a/src/app/cartography/converters/map/map-link-to-link-converter.ts +++ b/src/app/cartography/converters/map/map-link-to-link-converter.ts @@ -16,6 +16,7 @@ export class MapLinkToLinkConverter implements Converter { link.capturing = mapLink.capturing; link.filters = mapLink.filters; link.link_type = mapLink.linkType; + link.link_style = mapLink.link_style; link.nodes = mapLink.nodes.map((mapLinkNode) => this.mapLinkNodeToMapLinkNode.convert(mapLinkNode)); link.project_id = mapLink.projectId; link.suspend = mapLink.suspend; diff --git a/src/app/cartography/directives/moving-canvas.directive.spec.ts b/src/app/cartography/directives/moving-canvas.directive.spec.ts index 0a9cda7dc..1a51e86cb 100644 --- a/src/app/cartography/directives/moving-canvas.directive.spec.ts +++ b/src/app/cartography/directives/moving-canvas.directive.spec.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MovingEventSource } from '../events/moving-event-source'; import { Context } from '../models/context'; @@ -19,8 +19,8 @@ describe('MovingCanvasDirective', () => { let fixture: ComponentFixture; let movingEventSource = new MovingEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [NoopAnimationsModule], providers: [ { provide: MovingEventSource, useValue: movingEventSource }, @@ -28,7 +28,7 @@ describe('MovingCanvasDirective', () => { ], declarations: [DummyComponent, MovingCanvasDirective], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DummyComponent); diff --git a/src/app/cartography/directives/zooming-canvas.directive.spec.ts b/src/app/cartography/directives/zooming-canvas.directive.spec.ts index 3407eaefd..91c0536bc 100644 --- a/src/app/cartography/directives/zooming-canvas.directive.spec.ts +++ b/src/app/cartography/directives/zooming-canvas.directive.spec.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MapScaleService } from '../../services/mapScale.service'; import { MovingEventSource } from '../events/moving-event-source'; @@ -20,8 +20,8 @@ describe('ZoomingCanvasDirective', () => { let fixture: ComponentFixture; let movingEventSource = new MovingEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [NoopAnimationsModule], providers: [ { provide: MovingEventSource, useValue: movingEventSource }, @@ -30,7 +30,7 @@ describe('ZoomingCanvasDirective', () => { ], declarations: [DummyComponent, ZoomingCanvasDirective], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DummyComponent); diff --git a/src/app/cartography/events/links-event-source.ts b/src/app/cartography/events/links-event-source.ts index 53341290d..7c831aa03 100644 --- a/src/app/cartography/events/links-event-source.ts +++ b/src/app/cartography/events/links-event-source.ts @@ -1,4 +1,5 @@ import { EventEmitter, Injectable } from '@angular/core'; +import { MapLink } from '../models/map/map-link'; import { MapLinkNode } from '../models/map/map-link-node'; import { DraggedDataEvent } from './event-source'; import { MapLinkCreated } from './links'; @@ -6,5 +7,6 @@ import { MapLinkCreated } from './links'; @Injectable() export class LinksEventSource { public created = new EventEmitter(); + public edited = new EventEmitter(); public interfaceDragged = new EventEmitter>(); } diff --git a/src/app/cartography/helpers/font-fixer.spec.ts b/src/app/cartography/helpers/font-fixer.spec.ts index 31615a44a..28d4d68fe 100644 --- a/src/app/cartography/helpers/font-fixer.spec.ts +++ b/src/app/cartography/helpers/font-fixer.spec.ts @@ -8,43 +8,47 @@ describe('FontFixer', () => { fixer = new FontFixer(); }); - it('should fix TypeWriter font and 10px size', () => { + it("should fix TypeWriter font and 10px size", () => { const font: Font = { - font_family: 'TypeWriter', + font_family: "TypeWriter", font_size: 10, - font_weight: 'bold', + font_weight: "bold", }; expect(fixer.fix(font)).toEqual({ - font_family: 'Arial', - font_size: 12, - font_weight: 'bold', + font_family: "Noto Sans", + font_size: 11, + font_weight: "bold", }); }); - it('should not fix other fonts', () => { + it("should not fix other fonts", () => { const font: Font = { - font_family: 'OtherFont', + font_family: "OtherFont", font_size: 11, - font_weight: 'bold', + font_weight: "bold", }; expect(fixer.fix(font)).toEqual({ - font_family: 'OtherFont', + font_family: "OtherFont", font_size: 11, - font_weight: 'bold', + font_weight: "bold", }); }); it('should fix TypeWriter font and 10px size in styles', () => { - const styles = 'font-family: TypeWriter; font-size: 10px; font-weight: bold'; + let typeWriter = "TypeWriter"; + let notoSans = "Noto Sans"; + const styles = `font-family:${typeWriter} ; font-size: 10px; font-weight: bold`; - expect(fixer.fixStyles(styles)).toEqual('font-family:Arial;font-size:12px;font-weight:bold'); + expect(fixer.fixStyles(styles)).toEqual(`font-family:${notoSans};font-size:11px;font-weight:bold`); }); - it('should fix TypeWriter font and 10px size in styles with quotes', () => { - const styles = 'font-family: "TypeWriter"; font-size: 10px; font-weight: bold'; + it("should fix TypeWriter font and 10px size in styles with quotes", () => { + let typeWriter = "TypeWriter"; + let notoSans = "Noto Sans"; + const styles = `font-family:${typeWriter}; font-size: 10px; font-weight: bold`; - expect(fixer.fixStyles(styles)).toEqual('font-family:Arial;font-size:12px;font-weight:bold'); + expect(fixer.fixStyles(styles)).toEqual(`font-family:${notoSans};font-size:11px;font-weight:bold`); }); }); diff --git a/src/app/cartography/helpers/font-fixer.ts b/src/app/cartography/helpers/font-fixer.ts index f566ba512..f038ca8a9 100644 --- a/src/app/cartography/helpers/font-fixer.ts +++ b/src/app/cartography/helpers/font-fixer.ts @@ -9,8 +9,8 @@ import { Font } from '../models/font'; export class FontFixer { static DEFAULT_FONT = 'TypeWriter'; static DEFAULT_SIZE = 10; - static REPLACE_BY_FONT = 'Arial'; - static REPLACE_BY_SIZE = 12; + static REPLACE_BY_FONT = 'Noto Sans'; + static REPLACE_BY_SIZE = 11; public fix(font: Font): Font { if (font.font_family === FontFixer.DEFAULT_FONT && font.font_size === FontFixer.DEFAULT_SIZE) { diff --git a/src/app/cartography/helpers/qt-dasharray-fixer.ts b/src/app/cartography/helpers/qt-dasharray-fixer.ts index 31e2a7c2c..95bb82264 100644 --- a/src/app/cartography/helpers/qt-dasharray-fixer.ts +++ b/src/app/cartography/helpers/qt-dasharray-fixer.ts @@ -7,16 +7,18 @@ import { Injectable } from '@angular/core'; @Injectable() export class QtDasharrayFixer { static MAPPING = { - '25, 25': '10, 2', - '5, 25': '4, 2', - '5, 25, 25': '5, 5, 1, 5', - '25, 25, 5, 25, 5': '5, 2, 5, 2, 5', + '25, 25': '10, 2', // Dash + '5, 25': '4, 2', // Dot + '5, 25, 25': '12, 3, 5, 3', // Dash Dot + '25, 25, 5, 25, 5': '12, 3, 5, 3, 5, 3', // Dash Dot Dot }; public fix(dasharray: string): string { + if(dasharray || dasharray == '' ){ if (dasharray in QtDasharrayFixer.MAPPING) { return QtDasharrayFixer.MAPPING[dasharray]; } return dasharray; } } +} diff --git a/src/app/cartography/managers/graph-data-manager.ts b/src/app/cartography/managers/graph-data-manager.ts index 278e96a08..a84693c2d 100644 --- a/src/app/cartography/managers/graph-data-manager.ts +++ b/src/app/cartography/managers/graph-data-manager.ts @@ -45,6 +45,7 @@ export class GraphDataManager { public setLinks(links: Link[]) { if (links) { + console.log("from set links"); const mapLinks = links.map((l) => this.linkToMapLink.convert(l)); this.mapLinksDataSource.set(mapLinks); @@ -88,6 +89,7 @@ export class GraphDataManager { private onDataUpdate() { this.layersManager.clear(); this.layersManager.setNodes(this.getNodes()); + console.log(this.getLinks()); this.layersManager.setLinks(this.getLinks()); this.layersManager.setDrawings(this.getDrawings()); } diff --git a/src/app/cartography/managers/layers-manager.ts b/src/app/cartography/managers/layers-manager.ts index f0e6007b1..afb2e13ee 100644 --- a/src/app/cartography/managers/layers-manager.ts +++ b/src/app/cartography/managers/layers-manager.ts @@ -38,6 +38,7 @@ export class LayersManager { } public setLinks(links: MapLink[]) { + console.log('from set links 2'); links .filter((link: MapLink) => link.source && link.target) .forEach((link: MapLink) => { diff --git a/src/app/cartography/models/map/map-link.ts b/src/app/cartography/models/map/map-link.ts index 57bac994d..aebfac0d0 100644 --- a/src/app/cartography/models/map/map-link.ts +++ b/src/app/cartography/models/map/map-link.ts @@ -2,6 +2,7 @@ import { Filter } from '../../../models/filter'; import { Indexed } from '../../datasources/map-datasource'; import { MapLinkNode } from './map-link-node'; import { MapNode } from './map-node'; +import { LinkStyle } from '../../../models/link-style'; export class MapLink implements Indexed { id: string; @@ -13,14 +14,15 @@ export class MapLink implements Indexed { nodes: MapLinkNode[]; projectId: string; suspend: boolean; + link_style?: LinkStyle; - distance: number; // this is not from server - length: number; // this is not from server - source: MapNode; // this is not from server - target: MapNode; // this is not from server + distance: number; // this is not from controller + length: number; // this is not from controller + source: MapNode; // this is not from controller + target: MapNode; // this is not from controller - isSelected = false; // this is not from server - isMultiplied = false; // this is not from server - x: number; // this is not from server - y: number; // this is not from server + isSelected = false; // this is not from controller + isMultiplied = false; // this is not from controller + x: number; // this is not from controller + y: number; // this is not from controller } diff --git a/src/app/cartography/models/node.ts b/src/app/cartography/models/node.ts index b92c8fbab..f3800453b 100644 --- a/src/app/cartography/models/node.ts +++ b/src/app/cartography/models/node.ts @@ -45,7 +45,6 @@ export class Properties { kernel_command_line: string; kernel_image: string; kernel_image_md5sum?: any; - legacy_networking: boolean; mac_address: string; options: string; platform: string; @@ -53,9 +52,10 @@ export class Properties { qemu_path: string; environment: string; extra_hosts: string; - extra_volumes: string[]; replicate_network_connection_state: boolean; + memory: number; tpm: boolean; + uefi: boolean; } export class Node { diff --git a/src/app/cartography/services/map-change-detector-ref.ts b/src/app/cartography/services/map-change-detector-ref.ts index c97c0df19..59c79171f 100644 --- a/src/app/cartography/services/map-change-detector-ref.ts +++ b/src/app/cartography/services/map-change-detector-ref.ts @@ -7,6 +7,7 @@ export class MapChangeDetectorRef { public hasBeenDrawn = false; public detectChanges() { + console.log('from map change detector'); this.changesDetected.emit(true); } } diff --git a/src/app/cartography/widgets/drawings/text-drawing.spec.ts b/src/app/cartography/widgets/drawings/text-drawing.spec.ts index ab6fae127..f4b427332 100644 --- a/src/app/cartography/widgets/drawings/text-drawing.spec.ts +++ b/src/app/cartography/widgets/drawings/text-drawing.spec.ts @@ -42,7 +42,7 @@ describe('TextDrawingWidget', () => { const text_element = drew.nodes()[0]; expect(text_element.innerHTML).toEqual('THIS IS TEXT'); expect(text_element.getAttribute('fill')).toEqual('#000000'); - expect(text_element.getAttribute('style')).toEqual('font-family: "Arial"; font-size: 12pt; font-weight: bold'); + expect(text_element.getAttribute('style')).toEqual('font-family: "Noto Sans"; font-size: 11pt; font-weight: bold'); expect(text_element.getAttribute('text-decoration')).toEqual('line-through'); }); diff --git a/src/app/cartography/widgets/interface-status.ts b/src/app/cartography/widgets/interface-status.ts index 0e6fc0967..6ed0e8dcc 100644 --- a/src/app/cartography/widgets/interface-status.ts +++ b/src/app/cartography/widgets/interface-status.ts @@ -52,13 +52,13 @@ export class InterfaceStatusWidget implements Widget { new LinkStatus( start_point.x, start_point.y, - l.capturing && l.suspend ? 'suspended' : l.source.status, + (( !l.capturing && l.suspend) || ( l.capturing && l.suspend)) ? 'suspended' : l.source.status, sourcePort ), new LinkStatus( end_point.x, end_point.y, - l.capturing && l.suspend ? 'suspended' : l.target.status, + (( !l.capturing && l.suspend) || ( l.capturing && l.suspend)) ? 'suspended' : l.target.status, destinationPort ), ]; @@ -97,9 +97,9 @@ export class InterfaceStatusWidget implements Widget { .attr('y', (ls: LinkStatus) => ls.y - 10) .attr('rx', 8) .attr('ry', 8) - .style('fill', '#c7ffdf') + .style('fill', 'white') .attr('stroke', '#2ecc71') - .attr('stroke-width', 2); + .attr('stroke-width', 3); status_started.exit().remove(); const status_started_label = link_group .selectAll('text.status_started_label') @@ -111,7 +111,7 @@ export class InterfaceStatusWidget implements Widget { .text((ls: LinkStatus) => ls.port) .attr('x', (ls: LinkStatus) => ls.x - 25) .attr('y', (ls: LinkStatus) => ls.y + 5) - .attr('fill', `#0e9647`); + .attr('fill', `black`); status_started_label.exit().remove(); const status_stopped = link_group @@ -129,9 +129,9 @@ export class InterfaceStatusWidget implements Widget { .attr('y', (ls: LinkStatus) => ls.y - 10) .attr('rx', 8) .attr('ry', 8) - .style('fill', '#ffe3e3') + .style('fill', 'white') .attr('stroke', 'red') - .attr('stroke-width', 2); + .attr('stroke-width', 3); status_stopped.exit().remove(); const status_stopped_label = link_group .selectAll('text.status_stopped_label') @@ -143,7 +143,7 @@ export class InterfaceStatusWidget implements Widget { .text((ls: LinkStatus) => ls.port) .attr('x', (ls: LinkStatus) => ls.x - 25) .attr('y', (ls: LinkStatus) => ls.y + 5) - .attr('fill', `red`); + .attr('fill', `black`); status_stopped_label.exit().remove(); const status_suspended = link_group @@ -162,8 +162,8 @@ export class InterfaceStatusWidget implements Widget { .attr('rx', 8) .attr('ry', 8) .style('fill', 'white') - .attr('stroke', '#fffbc3') - .attr('stroke-width', 2); + .attr('stroke', '#FFFF00') + .attr('stroke-width', 3); status_suspended.exit().remove(); const status_suspended_label = link_group .selectAll('text.status_suspended_label') @@ -175,7 +175,7 @@ export class InterfaceStatusWidget implements Widget { .text((ls: LinkStatus) => ls.port) .attr('x', (ls: LinkStatus) => ls.x - 25) .attr('y', (ls: LinkStatus) => ls.y + 5) - .attr('fill', `#6b5633`); + .attr('fill', `black`); status_suspended_label.exit().remove(); } else { const status_started = link_group diff --git a/src/app/cartography/widgets/link.ts b/src/app/cartography/widgets/link.ts index 0bef6c18c..2a9421ec0 100644 --- a/src/app/cartography/widgets/link.ts +++ b/src/app/cartography/widgets/link.ts @@ -22,14 +22,15 @@ export class LinkWidget implements Widget { private selectionManager: SelectionManager, private ethernetLinkWidget: EthernetLinkWidget, private serialLinkWidget: SerialLinkWidget - ) {} + ) { } public draw(view: SVGSelection) { const link_body = view.selectAll('g.link_body').data((l) => [l]); const link_body_enter = link_body.enter().append('g').attr('class', 'link_body'); - const link_body_merge = link_body.merge(link_body_enter).attr('transform', (link) => { + const link_body_merge = link_body.merge(link_body_enter) + .attr('transform', (link) => { const translation = this.multiLinkCalculatorHelper.linkTranslation(link.distance, link.source, link.target); return `translate (${translation.dx}, ${translation.dy})`; }); @@ -50,9 +51,8 @@ export class LinkWidget implements Widget { }) .attr('class', 'capture-icon') .attr('transform', (link) => { - return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${ - (link.source.y + link.target.y) / 2 + 24 - }) scale(0.5)`; + return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${(link.source.y + link.target.y) / 2 + 24 + }) scale(0.5)`; }) .attr('viewBox', '0 0 20 20') .append('image') @@ -74,9 +74,8 @@ export class LinkWidget implements Widget { }) .attr('class', 'filter-capture-icon') .attr('transform', (link) => { - return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${ - (link.source.y + link.target.y) / 2 + 24 - }) scale(0.5)`; + return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${(link.source.y + link.target.y) / 2 + 24 + }) scale(0.5)`; }) .attr('viewBox', '0 0 20 20') .append('image') @@ -100,9 +99,8 @@ export class LinkWidget implements Widget { .attr('width', '48px') .attr('height', '48px') .attr('transform', (link) => { - return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${ - (link.source.y + link.target.y) / 2 + 24 - }) scale(0.5)`; + return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${(link.source.y + link.target.y) / 2 + 24 + }) scale(0.5)`; }) .attr('viewBox', '0 0 20 20') .append('image') @@ -124,9 +122,8 @@ export class LinkWidget implements Widget { }) .attr('class', 'pause-icon') .attr('transform', (link) => { - return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${ - (link.source.y + link.target.y) / 2 + 24 - }) scale(0.5)`; + return `translate (${(link.source.x + link.target.x) / 2 + 24}, ${(link.source.y + link.target.y) / 2 + 24 + }) scale(0.5)`; }) .attr('viewBox', '0 0 20 20') .append('image') diff --git a/src/app/cartography/widgets/links.ts b/src/app/cartography/widgets/links.ts index f6eecce65..59addeeca 100644 --- a/src/app/cartography/widgets/links.ts +++ b/src/app/cartography/widgets/links.ts @@ -11,6 +11,7 @@ export class LinksWidget implements Widget { constructor(private multiLinkCalculatorHelper: MultiLinkCalculatorHelper, private linkWidget: LinkWidget) {} public redrawLink(view: SVGSelection, link: MapLink) { + console.log('redraw called'); this.linkWidget.draw(this.selectLink(view, link)); } diff --git a/src/app/cartography/widgets/links/ethernet-link.ts b/src/app/cartography/widgets/links/ethernet-link.ts index 3de741e03..18eafa0f7 100644 --- a/src/app/cartography/widgets/links/ethernet-link.ts +++ b/src/app/cartography/widgets/links/ethernet-link.ts @@ -4,21 +4,29 @@ import { LinkContextMenu } from '../../events/event-source'; import { MapLink } from '../../models/map/map-link'; import { SVGSelection } from '../../models/types'; import { Widget } from '../widget'; +import { LinkStyle } from '../../../models/link-style'; +import { StyleTranslator} from './style-translator'; class EthernetLinkPath { - constructor(public source: [number, number], public target: [number, number]) {} + constructor(public source: [number, number], public target: [number, number], public style: LinkStyle) {} } @Injectable() export class EthernetLinkWidget implements Widget { public onContextMenu = new EventEmitter(); + private defaultEthernetLinkStyle : LinkStyle = { + color: "#000", + width: 2, + type: 0 + }; constructor() {} private linktoEthernetLink(link: MapLink) { return new EthernetLinkPath( [link.source.x + link.source.width / 2, link.source.y + link.source.height / 2], - [link.target.x + link.target.width / 2, link.target.y + link.target.height / 2] + [link.target.x + link.target.width / 2, link.target.y + link.target.height / 2], + link.link_style.color ? link.link_style : this.defaultEthernetLinkStyle ); } @@ -38,15 +46,15 @@ export class EthernetLinkWidget implements Widget { let link: MapLink = (datum as unknown) as MapLink; const evt = event; this.onContextMenu.emit(new LinkContextMenu(evt, link)); - }); - - link_enter - .attr('stroke', '#000') - .attr('stroke-width', '2') - .on('contextmenu', (datum) => { - let link: MapLink = (datum as unknown) as MapLink; - const evt = event; - this.onContextMenu.emit(new LinkContextMenu(evt, link)); + }) + .attr('stroke', (datum) => { + return datum.style.color; + }) + .attr('stroke-width', (datum) => { + return datum.style.width; + }) + .attr('stroke-dasharray', (datum) => { + return StyleTranslator.getLinkStyle(datum.style); }); const link_merge = link.merge(link_enter); diff --git a/src/app/cartography/widgets/links/serial-link.ts b/src/app/cartography/widgets/links/serial-link.ts index 9fc0e9217..49e8c509c 100644 --- a/src/app/cartography/widgets/links/serial-link.ts +++ b/src/app/cartography/widgets/links/serial-link.ts @@ -4,19 +4,27 @@ import { LinkContextMenu } from '../../events/event-source'; import { MapLink } from '../../models/map/map-link'; import { SVGSelection } from '../../models/types'; import { Widget } from '../widget'; +import { LinkStyle } from '../../../models/link-style'; +import { StyleTranslator} from './style-translator'; class SerialLinkPath { constructor( public source: [number, number], public source_angle: [number, number], public target_angle: [number, number], - public target: [number, number] + public target: [number, number], + public style: LinkStyle ) {} } @Injectable() export class SerialLinkWidget implements Widget { public onContextMenu = new EventEmitter(); + private defaultSerialLinkStyle : LinkStyle = { + color: "#B22222", + width: 2, + type: 0 + }; constructor() {} @@ -47,7 +55,12 @@ export class SerialLinkWidget implements Widget { target.y - dy / 2.0 - 15 * vect_rot[1], ]; - return new SerialLinkPath([source.x, source.y], angle_source, angle_target, [target.x, target.y]); + return new SerialLinkPath( + [source.x, source.y], + angle_source, + angle_target, + [target.x, target.y], + link.link_style.color ? link.link_style : this.defaultSerialLinkStyle); } public draw(view: SVGSelection) { @@ -68,7 +81,16 @@ export class SerialLinkWidget implements Widget { this.onContextMenu.emit(new LinkContextMenu(evt, link)); }); - link_enter.attr('stroke', '#B22222').attr('fill', 'none').attr('stroke-width', '2'); + link_enter + .attr('stroke', (datum) => { + return datum.style.color; + }) + .attr('stroke-width', (datum) => { + return datum.style.width; + }) + .attr('stroke-dasharray', (datum) => { + return StyleTranslator.getLinkStyle(datum.style); + }); const link_merge = link.merge(link_enter); diff --git a/src/app/cartography/widgets/links/style-translator.ts b/src/app/cartography/widgets/links/style-translator.ts new file mode 100644 index 000000000..34762529c --- /dev/null +++ b/src/app/cartography/widgets/links/style-translator.ts @@ -0,0 +1,16 @@ +import { LinkStyle } from '../../../models/link-style'; + +export class StyleTranslator { + static getLinkStyle(linkStyle: LinkStyle) { + if (linkStyle.type == 1) { + return `10, 10` + } + if (linkStyle.type == 2) { + return `${linkStyle.width}, ${linkStyle.width}` + } + if (linkStyle.type == 3) { + return `20, 10, ${linkStyle.width}, ${linkStyle.width}, ${linkStyle.width}, 10` + } + return `0, 0` + } +} diff --git a/src/app/cartography/widgets/node.spec.ts b/src/app/cartography/widgets/node.spec.ts index f8e669e17..e4069d70f 100644 --- a/src/app/cartography/widgets/node.spec.ts +++ b/src/app/cartography/widgets/node.spec.ts @@ -31,19 +31,21 @@ describe('NodesWidget', () => { const drew = svg.canvas.selectAll('g.node'); const drewNode = drew.nodes()[0]; - drewNode.dispatchEvent( - new MouseEvent('mousedown', { - clientX: 150, - clientY: 250, - relatedTarget: drewNode, - screenY: 1024, - screenX: 1024, - view: window, - }) - ); + if (drewNode != undefined && drewNode != null) { + drewNode.dispatchEvent( + new MouseEvent('mousedown', { + clientX: 150, + clientY: 250, + relatedTarget: drewNode, + screenY: 1024, + screenX: 1024, + view: window, + }) + ); - window.dispatchEvent(new MouseEvent('mousemove', { clientX: 300, clientY: 300 })); - window.dispatchEvent(new MouseEvent('mouseup', { clientX: 300, clientY: 300, view: window })); + window.dispatchEvent(new MouseEvent('mousemove', { clientX: 300, clientY: 300 })); + window.dispatchEvent(new MouseEvent('mouseup', { clientX: 300, clientY: 300, view: window })); + } }; beforeEach(() => { @@ -54,6 +56,9 @@ describe('NodesWidget', () => { node.height = 100; node.label = new MapLabel(); }); + it('draggable behaviour', () => { + tryToDrag() + }) // it('should be draggable when enabled', () => { // widget.setDraggingEnabled(true); diff --git a/src/app/cartography/widgets/node.ts b/src/app/cartography/widgets/node.ts index fc217f858..0273169b5 100644 --- a/src/app/cartography/widgets/node.ts +++ b/src/app/cartography/widgets/node.ts @@ -4,7 +4,6 @@ import { MapSettingsService } from '../../services/mapsettings.service'; import { ClickedDataEvent } from '../events/event-source'; import { NodeClicked, NodeContextMenu } from '../events/nodes'; import { NodesEventSource } from '../events/nodes-event-source'; -import { GraphDataManager } from '../managers/graph-data-manager'; import { SelectionManager } from '../managers/selection-manager'; import { MapNode } from '../models/map/map-node'; import { SVGSelection } from '../models/types'; @@ -18,7 +17,6 @@ export class NodeWidget implements Widget { public onNodeClicked = new EventEmitter(); constructor( - private graphDataManager: GraphDataManager, private selectionManager: SelectionManager, private labelWidget: LabelWidget, private nodesEventSource: NodesEventSource, diff --git a/src/app/cartography/widgets/nodes.spec.ts b/src/app/cartography/widgets/nodes.spec.ts index f0445712e..3857155ff 100644 --- a/src/app/cartography/widgets/nodes.spec.ts +++ b/src/app/cartography/widgets/nodes.spec.ts @@ -14,8 +14,12 @@ describe('NodesWidget', () => { nodeWidget = instance(mock(NodeWidget)); widget = new NodesWidget(nodeWidget, new MapSettingsManager()); }); + it('draggable behaviour', () => { + + }) afterEach(() => { svg.destroy(); }); + }); diff --git a/src/app/common/error-handlers/toaster-error-handler.spec.ts b/src/app/common/error-handlers/toaster-error-handler.spec.ts index aaaf02e7d..bcc62ee53 100644 --- a/src/app/common/error-handlers/toaster-error-handler.spec.ts +++ b/src/app/common/error-handlers/toaster-error-handler.spec.ts @@ -18,8 +18,8 @@ describe('ToasterErrorHandler', () => { let toasterService: MockedToasterService; let settingsService: SettingsService; - beforeEach(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: ToasterService, useClass: MockedToasterService }, { provide: SettingsService}, diff --git a/src/app/common/progress-dialog/progress-dialog.component.spec.ts b/src/app/common/progress-dialog/progress-dialog.component.spec.ts index cf08db74a..17da7790a 100644 --- a/src/app/common/progress-dialog/progress-dialog.component.spec.ts +++ b/src/app/common/progress-dialog/progress-dialog.component.spec.ts @@ -1,15 +1,31 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatToolbarModule } from '@angular/material/toolbar'; import { ProgressDialogComponent } from './progress-dialog.component'; describe('ProgressDialogComponent', () => { let component: ProgressDialogComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [ProgressDialogComponent], + imports:[ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule + ], + providers:[ + { provide: MatDialogRef, useValue: {}}, + { provide: MAT_DIALOG_DATA, useValue: {}}, + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ProgressDialogComponent); @@ -17,7 +33,7 @@ describe('ProgressDialogComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/common/progress-dialog/progress-dialog.service.spec.ts b/src/app/common/progress-dialog/progress-dialog.service.spec.ts index 86b6ba0f8..067a9bf08 100644 --- a/src/app/common/progress-dialog/progress-dialog.service.spec.ts +++ b/src/app/common/progress-dialog/progress-dialog.service.spec.ts @@ -1,14 +1,21 @@ -import { TestBed } from '@angular/core/testing'; +import { inject, TestBed } from '@angular/core/testing'; +import { MatDialog } from '@angular/material/dialog'; +import { MockedProgressService } from 'app/components/project-map/project-map.component.spec'; import { ProgressDialogService } from './progress-dialog.service'; describe('ProgressDialogService', () => { + let mockedProgressService : MockedProgressService beforeEach(() => { TestBed.configureTestingModule({ - providers: [ProgressDialogService], + // imports:[ProgressDialogService], + providers: [ + { provide: MatDialog, useValue: {} }, + { provide: ProgressDialogService, useClass:MockedProgressService }, + ], }); }); - // it('should be created', inject([ProgressDialogService], (service: ProgressDialogService) => { - // expect(service).toBeTruthy(); - // })); + it('should be created', inject([ProgressDialogService], (service: ProgressDialogService) => { + expect(service).toBeTruthy(); + })); }); diff --git a/src/app/common/progress/progress.component.spec.ts b/src/app/common/progress/progress.component.spec.ts index 368de1e85..ee2ab95c0 100644 --- a/src/app/common/progress/progress.component.spec.ts +++ b/src/app/common/progress/progress.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { Router } from '@angular/router'; @@ -23,8 +23,8 @@ describe('ProgressComponent', () => { let progressService: ProgressService; let router: MockedRouter = new MockedRouter(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [RouterTestingModule, MatProgressSpinnerModule, MatIconModule], providers: [ProgressService, { provide: Router, useValue: router }], declarations: [ProgressComponent], @@ -32,7 +32,7 @@ describe('ProgressComponent', () => { progressService = TestBed.get(ProgressService); router = TestBed.get(Router); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ProgressComponent); diff --git a/src/app/common/uploading-processbar/upload-service.service.spec.ts b/src/app/common/uploading-processbar/upload-service.service.spec.ts new file mode 100644 index 000000000..76686182b --- /dev/null +++ b/src/app/common/uploading-processbar/upload-service.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UploadServiceService } from './upload-service.service'; + +describe('UploadServiceService', () => { + let service: UploadServiceService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UploadServiceService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/common/uploading-processbar/upload-service.service.ts b/src/app/common/uploading-processbar/upload-service.service.ts new file mode 100644 index 000000000..71efc849b --- /dev/null +++ b/src/app/common/uploading-processbar/upload-service.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Subject } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class UploadServiceService { + + private countSource = new Subject(); + currentCount = this.countSource.asObservable(); + private cancelItem = new Subject(); + currentCancelItemDetails = this.cancelItem.asObservable(); + + constructor() { } + + processBarCount(processCount:number) { + this.countSource.next(processCount) + } + cancelFileUploading(isCancel){ + this.cancelItem.next(isCancel) + } + +} diff --git a/src/app/common/uploading-processbar/uploading-processbar.component.html b/src/app/common/uploading-processbar/uploading-processbar.component.html new file mode 100644 index 000000000..4229bb768 --- /dev/null +++ b/src/app/common/uploading-processbar/uploading-processbar.component.html @@ -0,0 +1,10 @@ +

{{upload_file_type}} Uploading please wait .... {{uploadProgress}}%

+
+
+ + +
+
+ +
+
diff --git a/src/app/common/uploading-processbar/uploading-processbar.component.scss b/src/app/common/uploading-processbar/uploading-processbar.component.scss new file mode 100644 index 000000000..b05df9a6a --- /dev/null +++ b/src/app/common/uploading-processbar/uploading-processbar.component.scss @@ -0,0 +1,11 @@ + +.mat-snack-bar-container{ + min-width: 450px !important; +} + +.proccessBar-row{ + display: flex; +} +.proccessBar-col{ + margin: auto; +} diff --git a/src/app/common/uploading-processbar/uploading-processbar.component.spec.ts b/src/app/common/uploading-processbar/uploading-processbar.component.spec.ts new file mode 100644 index 000000000..c38f0b4a9 --- /dev/null +++ b/src/app/common/uploading-processbar/uploading-processbar.component.spec.ts @@ -0,0 +1,34 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatSnackBarModule, MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar'; +import { UploadServiceService } from './upload-service.service'; + +import { UploadingProcessbarComponent } from './uploading-processbar.component'; + +describe('UploadingProcessbarComponent', () => { + let component: UploadingProcessbarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [UploadingProcessbarComponent], + imports:[MatSnackBarModule], + providers: [ + { provide: MAT_SNACK_BAR_DATA, useValue: {} }, + { provide: MatSnackBarRef, useValue: {} }, + { provide: UploadServiceService, useClass: UploadServiceService }, + + ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UploadingProcessbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/common/uploading-processbar/uploading-processbar.component.ts b/src/app/common/uploading-processbar/uploading-processbar.component.ts new file mode 100644 index 000000000..f4fcee467 --- /dev/null +++ b/src/app/common/uploading-processbar/uploading-processbar.component.ts @@ -0,0 +1,45 @@ +import { Component, Inject, OnInit, Renderer2, ViewEncapsulation } from '@angular/core'; +import { MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar'; +import { Subscription } from 'rxjs'; +import { UploadServiceService } from './upload-service.service'; + +@Component({ + selector: 'app-uploading-processbar', + templateUrl: './uploading-processbar.component.html', + styleUrls: ['./uploading-processbar.component.scss'], + encapsulation: ViewEncapsulation.None, + +}) +export class UploadingProcessbarComponent implements OnInit { + uploadProgress: number = 0 + subscription: Subscription; + upload_file_type:string + constructor( + @Inject(MAT_SNACK_BAR_DATA) public data, + private _snackRef: MatSnackBarRef, + private _US: UploadServiceService + ) { } + + ngOnInit() { + this.upload_file_type = this.data.upload_file_type + this.subscription = this._US.currentCount.subscribe((count:number) => { + this.uploadProgress = count; + if (this.uploadProgress === 100 || this.uploadProgress == null ) { + this.dismiss() + } + }) + } + + + + dismiss() { + this._snackRef.dismiss(); + } + cancelItem() { + this._US.cancelFileUploading(true) + } + ngOnDestroy() { + this.subscription.unsubscribe(); + } + +} diff --git a/src/app/components/adbutler/adbutler.component.spec.ts b/src/app/components/adbutler/adbutler.component.spec.ts index 15ff30f30..95c86ea7e 100644 --- a/src/app/components/adbutler/adbutler.component.spec.ts +++ b/src/app/components/adbutler/adbutler.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AdbutlerComponent } from './adbutler.component'; xdescribe('AdbutlerComponent', () => { let component: AdbutlerComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [AdbutlerComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AdbutlerComponent); diff --git a/src/app/components/bundled-server-finder/bundled-server-finder.component.html b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.html similarity index 100% rename from src/app/components/bundled-server-finder/bundled-server-finder.component.html rename to src/app/components/bundled-controller-finder/bundled-controller-finder.component.html diff --git a/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.scss b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.scss similarity index 100% rename from src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.scss rename to src/app/components/bundled-controller-finder/bundled-controller-finder.component.scss diff --git a/src/app/components/bundled-controller-finder/bundled-controller-finder.component.spec.ts b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.spec.ts new file mode 100644 index 000000000..9dec69cfc --- /dev/null +++ b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.spec.ts @@ -0,0 +1,64 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ProgressService } from '../../common/progress/progress.service'; +import{ Controller } from '../../models/controller'; +import { ControllerService } from '../../services/controller.service'; +import { MockedControllerService } from '../../services/controller.service.spec'; +import { MockedProgressService } from '../project-map/project-map.component.spec'; +import { BundledControllerFinderComponent } from './bundled-controller-finder.component'; + +describe('BundledControllerFinderComponent', () => { + let component: BundledControllerFinderComponent; + let fixture: ComponentFixture; + let router: any; + let service: ControllerService; + let progressService: MockedProgressService = new MockedProgressService(); + let controllerServiceMock: jasmine.SpyObj; + + + beforeEach(async () => { + router = { + navigate: jasmine.createSpy('navigate'), + }; + + + + controllerServiceMock = jasmine.createSpyObj([ + "getLocalController" + ]); + + + await TestBed.configureTestingModule({ + providers: [ + { provide: Router, useValue: router }, + { provide: ControllerService, useValue: controllerServiceMock }, + { provide: ProgressService, useValue: progressService }, + ], + declarations: [BundledControllerFinderComponent], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + + fixture = TestBed.createComponent(BundledControllerFinderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create and redirect to controller', fakeAsync(() => { + const controller = new Controller (); + controller.id = 99; + controllerServiceMock.getLocalController.and.returnValue( + Promise.resolve(controller) + ); + expect(component).toBeTruthy(); + tick(101) + fixture.detectChanges() + fixture.whenStable().then(() => { + expect(controllerServiceMock.getLocalController).toHaveBeenCalledWith('vps3.gns3.net',3000); + expect(router.navigate).toHaveBeenCalledWith(['/controller', 99, 'projects']); + }) + service = TestBed.inject(ControllerService); + })); +}); diff --git a/src/app/components/bundled-server-finder/bundled-server-finder.component.ts b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.ts similarity index 56% rename from src/app/components/bundled-server-finder/bundled-server-finder.component.ts rename to src/app/components/bundled-controller-finder/bundled-controller-finder.component.ts index 39b9904c8..cfa332b01 100644 --- a/src/app/components/bundled-server-finder/bundled-server-finder.component.ts +++ b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.ts @@ -2,18 +2,18 @@ import { DOCUMENT } from '@angular/common'; import { Component, Inject, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { ProgressService } from '../../common/progress/progress.service'; -import { Server } from '../../models/server'; -import { ServerService } from '../../services/server.service'; +import{ Controller } from '../../models/controller'; +import { ControllerService } from '../../services/controller.service'; @Component({ - selector: 'app-bundled-server-finder', - templateUrl: './bundled-server-finder.component.html', - styleUrls: ['./bundled-server-finder.component.scss'], + selector: 'app-bundled-controller-finder', + templateUrl: './bundled-controller-finder.component.html', + styleUrls: ['./bundled-controller-finder.component.scss'], }) -export class BundledServerFinderComponent implements OnInit { +export class BundledControllerFinderComponent implements OnInit { constructor( private router: Router, - private serverService: ServerService, + private controllerService: ControllerService, private progressService: ProgressService, @Inject(DOCUMENT) private document ) {} @@ -31,9 +31,9 @@ export class BundledServerFinderComponent implements OnInit { port = 80; } - this.serverService.getLocalServer(this.document.location.hostname, port).then((server: Server) => { + this.controllerService.getLocalController(this.document.location.hostname, port).then((controller:Controller ) => { + this.router.navigate(['/controller', controller.id, 'projects']); this.progressService.deactivate(); - this.router.navigate(['/server', server.id, 'projects']); }); }, 100); } diff --git a/src/app/components/bundled-server-finder/bundled-server-finder.component.spec.ts b/src/app/components/bundled-server-finder/bundled-server-finder.component.spec.ts deleted file mode 100644 index 8d4d16de9..000000000 --- a/src/app/components/bundled-server-finder/bundled-server-finder.component.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { Router } from '@angular/router'; -import { ProgressService } from '../../common/progress/progress.service'; -import { Server } from '../../models/server'; -import { ServerService } from '../../services/server.service'; -import { MockedServerService } from '../../services/server.service.spec'; -import { MockedProgressService } from '../project-map/project-map.component.spec'; -import { BundledServerFinderComponent } from './bundled-server-finder.component'; - -describe('BundledServerFinderComponent', () => { - let component: BundledServerFinderComponent; - let fixture: ComponentFixture; - let router: any; - let serverService: any; - let progressService: MockedProgressService = new MockedProgressService(); - - beforeEach(async(() => { - router = { - navigate: jasmine.createSpy('navigate'), - }; - - const server = new Server(); - server.id = 99; - - serverService = new MockedServerService(); - spyOn(serverService, 'getLocalServer').and.returnValue(Promise.resolve(server)); - - TestBed.configureTestingModule({ - providers: [ - { provide: Router, useValue: router }, - { provide: ServerService, useValue: serverService }, - { provide: ProgressService, useValue: progressService }, - ], - declarations: [BundledServerFinderComponent], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(BundledServerFinderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - })); - - it('should create and redirect to server', fakeAsync(() => { - expect(component).toBeTruthy(); - expect(serverService.getLocalServer).toHaveBeenCalled(); - tick(); - expect(router.navigate).toHaveBeenCalledWith(['/server', 99, 'projects']); - })); -}); diff --git a/src/app/components/servers/add-server-dialog/add-server-dialog.component.html b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.html similarity index 53% rename from src/app/components/servers/add-server-dialog/add-server-dialog.component.html rename to src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.html index 51a9545d9..7c806c014 100644 --- a/src/app/components/servers/add-server-dialog/add-server-dialog.component.html +++ b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.html @@ -1,24 +1,24 @@ -

Add server

-
+

Add controller

+
- You must enter a value + You must enter a value - + - - + @@ -33,20 +33,6 @@

Add server

{{ protocol.name }}
- - - - {{ auth.name }} - - - - - - - - - -
diff --git a/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.scss b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.scss similarity index 100% rename from src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.scss rename to src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.scss diff --git a/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts new file mode 100644 index 000000000..42b9ae19b --- /dev/null +++ b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts @@ -0,0 +1,147 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ElectronService } from 'ngx-electron'; +import { Controller } from '../../../models/controller'; +import { ControllerService } from '../../../services/controller.service'; +import { ToasterService } from '../../../services/toaster.service'; + +@Component({ + selector: 'app-add-controller-dialog', + templateUrl: 'add-controller-dialog.component.html', +}) +export class AddControllerDialogComponent implements OnInit { + protocols = [ + { key: 'http:', name: 'HTTP' }, + { key: 'https:', name: 'HTTPS' }, + ]; + locations = []; + + controllerForm = new UntypedFormGroup({ + name: new UntypedFormControl('', [Validators.required]), + location: new UntypedFormControl(''), + path: new UntypedFormControl(''), + ubridge_path: new UntypedFormControl(''), + host: new UntypedFormControl('', [Validators.required]), + port: new UntypedFormControl('', [Validators.required, Validators.min(1)]), + protocol: new UntypedFormControl('http:') + }); + + constructor( + public dialogRef: MatDialogRef, + private electronService: ElectronService, + private controllerService: ControllerService, + private toasterService: ToasterService, + @Inject(MAT_DIALOG_DATA) public data: any + ) {} + + async getLocations() { + const localControllers = await this.numberOfLocalControllers(); + + let locations = []; + if (this.electronService.isElectronApp && localControllers === 0) { + locations.push({ key: 'local', name: 'Local' }); + } + locations.push({ key: 'remote', name: 'Remote' }); + return locations; + } + + async getDefaultLocation() { + const localControllers = await this.numberOfLocalControllers(); + if (this.electronService.isElectronApp && localControllers === 0) { + return 'local'; + } + return 'remote'; + } + + async numberOfLocalControllers() { + const controllers = await this.controllerService.findAll(); + + return controllers.filter((controller) => controller.location === 'local').length; + } + + getDefaultHost() { + return '127.0.0.1'; + } + + getDefaultPort() { + return 3080; + } + + async getDefaultLocalControllerPath() { + if (this.electronService.isElectronApp) { + return await this.electronService.remote.require('./local-controller.js').getLocalControllerPath(); + } + return; + } + + async getDefaultUbridgePath() { + if (this.electronService.isElectronApp) { + return await this.electronService.remote.require('./local-controller.js').getUbridgePath(); + } + return; + } + + async ngOnInit() { + this.locations = await this.getLocations(); + + const defaultLocalControllerPath = await this.getDefaultLocalControllerPath(); + const defaultUbridgePath = await this.getDefaultUbridgePath(); + + this.controllerForm.get('location').valueChanges.subscribe((location: string) => { + const pathControl = this.controllerForm.get('path'); + const ubridgePathControl = this.controllerForm.get('ubridge_path'); + + if (location === 'local') { + pathControl.setValue(defaultLocalControllerPath); + pathControl.setValidators([Validators.required]); + + ubridgePathControl.setValue(defaultUbridgePath); + ubridgePathControl.setValidators([Validators.required]); + } else { + pathControl.setValue(''); + pathControl.clearValidators(); + + ubridgePathControl.setValue(''); + ubridgePathControl.clearValidators(); + } + + [pathControl, ubridgePathControl].forEach((control) => { + control.updateValueAndValidity({ + onlySelf: true, + }); + }); + }); + + const defaultLocation = await this.getDefaultLocation(); + this.controllerForm.get('location').setValue(defaultLocation); + this.controllerForm.get('host').setValue(this.getDefaultHost()); + this.controllerForm.get('port').setValue(this.getDefaultPort()); + } + + onAddClick(): void { + if (!this.controllerForm.valid) { + return; + } + + const controller:Controller = Object.assign({}, this.controllerForm.value); + this.controllerService.checkControllerVersion(controller).subscribe( + (controllerInfo) => { + if (controllerInfo.version.split('.')[0] >= 3) { + this.dialogRef.close(controller); + this.toasterService.success(`Controller ${controller.name} added.`); + } else { + this.dialogRef.close(); + this.toasterService.error(`Controller version is not supported.`); + } + }, + (error) => { + this.toasterService.error('Cannot connect to the controller: ' + error); + } + ); + } + + onNoClick(): void { + this.dialogRef.close(); + } +} diff --git a/src/app/components/controllers/controller-discovery/controller-discovery.component.html b/src/app/components/controllers/controller-discovery/controller-discovery.component.html new file mode 100644 index 000000000..37d5a8fcb --- /dev/null +++ b/src/app/components/controllers/controller-discovery/controller-discovery.component.html @@ -0,0 +1,12 @@ + + + We've discovered GNS3 controller on {{ discoveredController?.host }}:{{ discoveredController?.port }}, would you like to add to the list? + + + + + + + + diff --git a/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.scss b/src/app/components/controllers/controller-discovery/controller-discovery.component.scss similarity index 100% rename from src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.scss rename to src/app/components/controllers/controller-discovery/controller-discovery.component.scss diff --git a/src/app/components/controllers/controller-discovery/controller-discovery.component.spec.ts b/src/app/components/controllers/controller-discovery/controller-discovery.component.spec.ts new file mode 100644 index 000000000..ddd845b4b --- /dev/null +++ b/src/app/components/controllers/controller-discovery/controller-discovery.component.spec.ts @@ -0,0 +1,171 @@ +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { MatCardModule } from '@angular/material/card'; +import { MatDividerModule } from '@angular/material/divider'; +import { Observable } from 'rxjs/Rx'; +import{ Controller } from '../../../models/controller'; +import { Version } from '../../../models/version'; +import { ControllerDatabase } from '../../../services/controller.database'; +import { ControllerService } from '../../../services/controller.service'; +import { MockedControllerService } from '../../../services/controller.service.spec'; +import { VersionService } from '../../../services/version.service'; +import { MockedVersionService } from '../../../services/version.service.spec'; +import { ControllerDiscoveryComponent } from './controller-discovery.component'; + +xdescribe('ControllerDiscoveryComponent', () => { + let component: ControllerDiscoveryComponent; + let fixture: ComponentFixture; + let mockedVersionService: MockedVersionService; + let mockedControllerService: MockedControllerService; + + beforeEach(async () => { + mockedControllerService = new MockedControllerService(); + mockedVersionService = new MockedVersionService(); + await TestBed.configureTestingModule({ + imports: [MatCardModule, MatDividerModule], + providers: [ + { provide: VersionService, useFactory: () => mockedVersionService }, + { provide: ControllerService, useFactory: () => mockedControllerService }, + ControllerDatabase, + ], + declarations: [ControllerDiscoveryComponent], + }).compileComponents(); + }); + +beforeEach(() => { + fixture = TestBed.createComponent(ControllerDiscoveryComponent); + + component = fixture.componentInstance; + + // we don't really want to run it during testing + spyOn(component, 'ngOnInit').and.returnValue(null); + + fixture.detectChanges(); +}); + +it('should create', () => { + expect(component).toBeTruthy(); +}); + +describe('isAvailable', () => { + it('should return controller object when controller is available', () => { + const version = new Version(); + version.version = '2.1.8'; + + const getVersionSpy = spyOn(mockedVersionService, 'get').and.returnValue(Observable.of(version)); + + component.isControllerAvailable('127.0.0.1', 3080).subscribe((s) => { + expect(s.host).toEqual('127.0.0.1'); + expect(s.port).toEqual(3080); + }); + + const controller = new Controller (); + controller.host = '127.0.0.1'; + controller.port = 3080; + + expect(getVersionSpy).toHaveBeenCalledWith(controller); + }); + + it('should throw error once controller is not available', () => { + const controller = new Controller (); + controller.host = '127.0.0.1'; + controller.port = 3080; + + const getVersionSpy = spyOn(mockedVersionService, 'get').and.returnValue( + Observable.throwError(new Error('controller is unavailable')) + ); + let hasExecuted = false; + + component.isControllerAvailable('127.0.0.1', 3080).subscribe( + (ver) => { }, + (err) => { + hasExecuted = true; + expect(err.toString()).toEqual('Error: controller is unavailable'); + } + ); + + expect(getVersionSpy).toHaveBeenCalledWith(controller); + expect(hasExecuted).toBeTruthy(); + }); +}); + +describe('discovery', () => { + it('should discovery all controllers available', (done) => { + const version = new Version(); + version.version = '2.1.8'; + + spyOn(component, 'isControllerAvailable').and.callFake((ip, port) => { + const controller = new Controller (); + controller.host = ip; + controller.port = port; + return Observable.of(controller); + }); + + component.discovery().subscribe((discovered) => { + expect(discovered[0].host).toEqual('127.0.0.1'); + expect(discovered[0].port).toEqual(3080); + + expect(discovered.length).toEqual(1); + + done(); + }); + }); +}); + +describe('discoverFirstAvailableController', () => { + let controller:Controller ; + + beforeEach(function () { + controller = new Controller (); + (controller.host = '199.111.111.1'), (controller.port = 3333); + + spyOn(component, 'discovery').and.callFake(() => { + return Observable.of([controller]); + }); + }); + + it('should get first controller from discovered and with no added before', fakeAsync(() => { + expect(component.discoveredController).toBeUndefined(); + component.discoverFirstAvailableController(); + tick(); + expect(component.discoveredController.host).toEqual('199.111.111.1'); + expect(component.discoveredController.port).toEqual(3333); + })); + + it('should get first controller from discovered and with already added', fakeAsync(() => { + mockedControllerService.controllers.push(controller); + + expect(component.discoveredController).toBeUndefined(); + component.discoverFirstAvailableController(); + tick(); + expect(component.discoveredController).toBeUndefined(); + })); +}); + +describe('accepting and ignoring found controller', () => { + let controller:Controller ; + beforeEach(() => { + controller = new Controller (); + (controller.host = '199.111.111.1'), (controller.port = 3333); + component.discoveredController = controller; + }); + + describe('accept', () => { + it('should add new controller', fakeAsync(() => { + component.accept(controller); + tick(); + expect(component.discoveredController).toBeNull(); + expect(mockedControllerService.controllers[0].host).toEqual('199.111.111.1'); + expect(mockedControllerService.controllers[0].name).toEqual('199.111.111.1'); + expect(mockedControllerService.controllers[0].location).toEqual('remote'); + })); + }); + + describe('ignore', () => { + it('should reject controller', fakeAsync(() => { + component.ignore(controller); + tick(); + expect(component.discoveredController).toBeNull(); + })); + }); +}); +}); diff --git a/src/app/components/controllers/controller-discovery/controller-discovery.component.ts b/src/app/components/controllers/controller-discovery/controller-discovery.component.ts new file mode 100644 index 000000000..4488a1200 --- /dev/null +++ b/src/app/components/controllers/controller-discovery/controller-discovery.component.ts @@ -0,0 +1,132 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { forkJoin, from } from 'rxjs'; +import { map } from 'rxjs//operators'; +import { Observable } from 'rxjs/Rx'; +import { Controller, ControllerProtocol } from '../../../models/controller'; +import { Version } from '../../../models/version'; +import { ControllerDatabase } from '../../../services/controller.database'; +import { ControllerService } from '../../../services/controller.service'; +import { VersionService } from '../../../services/version.service'; + +@Component({ + selector: 'app-controller-discovery', + templateUrl: './controller-discovery.component.html', + styleUrls: ['./controller-discovery.component.scss'], +}) +export class ControllerDiscoveryComponent implements OnInit { + private defaultControllers = [ + { + host: '127.0.0.1', + port: 3080, + }, + ]; + + discoveredController: Controller; + + constructor( + private versionService: VersionService, + private controllerService: ControllerService, + private controllerDatabase: ControllerDatabase, + private route: ActivatedRoute + ) {} + + ngOnInit() { + if (this.controllerService.isServiceInitialized) this.discoverFirstController(); + this.controllerService.serviceInitialized.subscribe(async (value: boolean) => { + if (value) { + this.discoverFirstController(); + } + }); + } + + async discoverFirstController() { + let discovered = await this.discoverControllers(); + let local = await this.controllerService.findAll(); + + local.forEach((added) => { + discovered = discovered.filter((controller) => { + return !(controller.host == added.host && controller.port == added.port); + }); + }); + + if (discovered.length > 0) { + this.discoveredController = discovered.shift(); + } + } + + async discoverControllers() { + let discoveredControllers: Controller[] = []; + this.defaultControllers.forEach(async (testController) => { + const controller = new Controller(); + controller.host = testController.host; + controller.port = testController.port; + let version = await this.versionService + .get(controller) + .toPromise() + .catch((error) => null); + if (version) discoveredControllers.push(controller); + }); + return discoveredControllers; + } + + discoverFirstAvailableController() { + forkJoin([from(this.controllerService.findAll()).pipe(map((s: Controller[]) => s)), this.discovery()]).subscribe( + ([local, discovered]) => { + local.forEach((added) => { + discovered = discovered.filter((controller) => { + return !(controller.host == added.host && controller.port == added.port); + }); + }); + if (discovered.length > 0) { + this.discoveredController = discovered.shift(); + } + }, + (error) => {} + ); + } + + discovery(): Observable { + const queries: Observable[] = []; + + this.defaultControllers.forEach((testController) => { + queries.push( + this.isControllerAvailable(testController.host, testController.port).catch((err) => { + return Observable.of(null); + }) + ); + }); + + return new Observable((observer) => { + forkJoin(queries).subscribe((discoveredControllers) => { + observer.next(discoveredControllers.filter((s) => s != null)); + observer.complete(); + }); + }); + } + + isControllerAvailable(ip: string, port: number): Observable { + const controller = new Controller(); + controller.host = ip; + controller.port = port; + return this.versionService.get(controller).flatMap((version: Version) => Observable.of(controller)); + } + + ignore(controller: Controller) { + this.discoveredController = null; + } + + accept(controller: Controller) { + if (controller.name == null) { + controller.name = controller.host; + } + + controller.location = 'remote'; + controller.protocol = location.protocol as ControllerProtocol; + + this.controllerService.create(controller).then((created: Controller) => { + this.controllerDatabase.addController(created); + this.discoveredController = null; + }); + } +} diff --git a/src/app/components/servers/servers.component.html b/src/app/components/controllers/controllers.component.html similarity index 66% rename from src/app/components/servers/servers.component.html rename to src/app/components/controllers/controllers.component.html index 178a1b2ef..67fdb29bc 100644 --- a/src/app/components/servers/servers.component.html +++ b/src/app/components/controllers/controllers.component.html @@ -1,7 +1,7 @@
-

Servers

+

Controllers

- +
@@ -14,13 +14,13 @@ Name {{ row.name }} {{ row.name }} @@ -49,43 +49,43 @@ matTooltip="Go to projects" matTooltipClass="custom-tooltip" (click)="openProjects(row)" - *ngIf="getServerStatus(row) === 'running' || row.location === 'remote' || row.location === 'bundled'" + *ngIf="getControllerStatus(row) === 'running' || row.location === 'remote' || row.location === 'bundled'" > arrow_forward @@ -96,10 +96,10 @@
- - +
diff --git a/src/app/components/controllers/controllers.component.scss b/src/app/components/controllers/controllers.component.scss new file mode 100644 index 000000000..06283dbb3 --- /dev/null +++ b/src/app/components/controllers/controllers.component.scss @@ -0,0 +1,14 @@ +.buttons-bar { + padding-top: 0px; +} + +.button { + margin: 20px !important; +} +table { + width: 100%; +} + +mat-header-cell, mat-cell { + justify-content: center; +} \ No newline at end of file diff --git a/src/app/components/controllers/controllers.component.spec.ts b/src/app/components/controllers/controllers.component.spec.ts new file mode 100644 index 000000000..5efb12a3f --- /dev/null +++ b/src/app/components/controllers/controllers.component.spec.ts @@ -0,0 +1,59 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { ControllerDatabase } from '../../services/controller.database'; +import { ControllerService } from '../../services/controller.service'; +import { MockedControllerService } from 'app/services/controller.service.spec'; +import { ControllersComponent } from './controllers.component'; +import { ControllerManagementService } from '../../services/controller-management.service'; +import { ElectronService } from 'ngx-electron'; +import { ChildProcessService } from 'ngx-childprocess'; +import { MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet'; +import { ActivatedRoute, Router } from '@angular/router'; +import { MockedActivatedRoute } from '../snapshots/list-of-snapshots/list-of-snaphshots.component.spec'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ChangeDetectorRef } from '@angular/core'; +import { MockedRouter } from 'app/common/progress/progress.component.spec'; + +describe('ControllersComponent', () => { + let component: ControllersComponent; + let fixture: ComponentFixture; + let controllerMockedService: MockedControllerService + let mockedActivatedRoute: MockedActivatedRoute + let mockedRouter : MockedRouter + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ControllersComponent], + imports: [ + MatDialogModule, + RouterTestingModule, + MatBottomSheetModule + ], + providers: [ + MatDialog, + ControllerDatabase, + ControllerManagementService, + ElectronService, + MatBottomSheet, + ChildProcessService, + ChangeDetectorRef, + { provide: ControllerService, useValue: controllerMockedService }, + { provide: ActivatedRoute, useValue: mockedActivatedRoute }, + { provide: Router, useValue: mockedRouter }, + ] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ControllersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/controllers/controllers.component.ts b/src/app/components/controllers/controllers.component.ts new file mode 100644 index 000000000..9bae27f18 --- /dev/null +++ b/src/app/components/controllers/controllers.component.ts @@ -0,0 +1,177 @@ +import { DataSource } from '@angular/cdk/collections'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { MatBottomSheet } from '@angular/material/bottom-sheet'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ChildProcessService } from 'ngx-childprocess'; +import { ElectronService } from 'ngx-electron'; +import { merge, Observable, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; +import {Controller , ControllerProtocol } from '../../models/controller'; +import { ControllerManagementService } from '../../services/controller-management.service'; +import { ControllerDatabase } from '../../services/controller.database'; +import { ControllerService } from '../../services/controller.service'; +import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component'; +import { AddControllerDialogComponent } from './add-controller-dialog/add-controller-dialog.component'; + +@Component({ + selector: 'app-controller-list', + templateUrl: './controllers.component.html', + styleUrls: ['./controllers.component.scss'], +}) +export class ControllersComponent implements OnInit, OnDestroy { + dataSource: ControllerDataSource; + displayedColumns = ['id', 'name', 'location', 'ip', 'port', 'actions']; + controllerStatusSubscription: Subscription; + isElectronApp: boolean = false; + + constructor( + private dialog: MatDialog, + private controllerService: ControllerService, + private controllerDatabase: ControllerDatabase, + private controllerManagement: ControllerManagementService, + private changeDetector: ChangeDetectorRef, + private electronService: ElectronService, + private childProcessService: ChildProcessService, + private bottomSheet: MatBottomSheet, + private route: ActivatedRoute, + private router: Router + ) { } + + getControllers() { + const runningControllerNames = this.controllerManagement.getRunningControllers(); + + this.controllerService.findAll().then((controllers:Controller []) => { + controllers.forEach((controller) => { + const controllerIndex = runningControllerNames.findIndex((controllerName) => controller.name === controllerName); + if (controllerIndex >= 0) { + controller.status = 'running'; + } + }); + + controllers.forEach((controller) => { + this.controllerService.checkControllerVersion(controller).subscribe( + (controllerInfo) => { + if (controllerInfo.version.split('.')[0] >= 3) { + if (!controller.protocol) controller.protocol = location.protocol as ControllerProtocol; + if (!this.controllerDatabase.find(controller.name)) this.controllerDatabase.addController(controller); + } + }, + (error) => { } + ); + }); + }); + } + + ngOnInit() { + this.isElectronApp = this.electronService.isElectronApp; + + if (this.controllerService && this.controllerService.isServiceInitialized) this.getControllers(); + + if (this.controllerService && this.controllerService.isServiceInitialized) { + this.controllerService.serviceInitialized.subscribe(async (value: boolean) => { + if (value) { + this.getControllers(); + } + }); + } + + this.dataSource = new ControllerDataSource(this.controllerDatabase); + + this.controllerStatusSubscription = this.controllerManagement.controllerStatusChanged.subscribe((controllerStatus) => { + const controller = this.controllerDatabase.find(controllerStatus.controllerName); + if (!controller) { + return; + } + if (controllerStatus.status === 'starting') { + controller.status = 'starting'; + } + if (controllerStatus.status === 'stopped') { + controller.status = 'stopped'; + } + if (controllerStatus.status === 'errored') { + controller.status = 'stopped'; + } + if (controllerStatus.status === 'started') { + controller.status = 'running'; + } + this.controllerDatabase.update(controller); + this.changeDetector.detectChanges(); + }); + } + + ngOnDestroy() { + this.controllerStatusSubscription.unsubscribe(); + } + + startLocalController() { + const controller = this.controllerDatabase.data.find((n) => n.location === 'bundled' || 'local'); + this.startController(controller); + } + + openProjects(controller) { + this.router.navigate(['/controller', controller.id, 'projects']); + } + + createModal() { + const dialogRef = this.dialog.open(AddControllerDialogComponent, { + width: '350px', + autoFocus: false, + disableClose: true, + }); + + dialogRef.afterClosed().subscribe((controller) => { + if (controller) { + this.controllerService.create(controller).then((created:Controller ) => { + this.controllerDatabase.addController(created); + }); + } + }); + } + + getControllerStatus(controller:Controller ) { + if (controller.location === 'local') { + if (controller.status === undefined) { + return 'stopped'; + } + return controller.status; + } + } + + deleteController(controller:Controller ) { + this.bottomSheet.open(ConfirmationBottomSheetComponent); + let bottomSheetRef = this.bottomSheet._openedBottomSheetRef; + bottomSheetRef.instance.message = 'Do you want to delete the controller?'; + const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { + if (result) { + this.controllerService.delete(controller).then(() => { + this.controllerDatabase.remove(controller); + }); + } + }); + } + + async startController(controller:Controller ) { + await this.controllerManagement.start(controller); + } + + async stopController(controller:Controller ) { + await this.controllerManagement.stop(controller); + } +} + +export class ControllerDataSource extends DataSource { + constructor(private controllerDatabase: ControllerDatabase) { + super(); + } + + connect(): Observable< Controller[] > { + return merge(this.controllerDatabase.dataChange).pipe( + map(() => { + return this.controllerDatabase.data; + }) + ); + } + + disconnect() { } +} diff --git a/src/app/components/direct-link/direct-link.component.html b/src/app/components/direct-link/direct-link.component.html index 227ff1ef0..a591ab367 100644 --- a/src/app/components/direct-link/direct-link.component.html +++ b/src/app/components/direct-link/direct-link.component.html @@ -1,46 +1,32 @@ -
+
-

Add new server

+

Add new controller

- + - You must enter a value + You must enter a value - + {{ location.name }} - + {{ protocol.name }} - - - - {{ auth.name }} - - - - - - - - - -
- +
diff --git a/src/app/components/direct-link/direct-link.component.ts b/src/app/components/direct-link/direct-link.component.ts index 6476d749a..088034c70 100644 --- a/src/app/components/direct-link/direct-link.component.ts +++ b/src/app/components/direct-link/direct-link.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../models/server'; -import { ServerDatabase } from '../../services/server.database'; -import { ServerService } from '../../services/server.service'; +import{ Controller } from '../../models/controller'; +import { ControllerDatabase } from '../../services/controller.database'; +import { ControllerService } from '../../services/controller.service'; import { ToasterService } from '../../services/toaster.service'; @Component({ @@ -13,15 +13,11 @@ import { ToasterService } from '../../services/toaster.service'; encapsulation: ViewEncapsulation.None, }) export class DirectLinkComponent implements OnInit { - public serverOptionsVisibility = false; - public serverIp; - public serverPort; + public controllerOptionsVisibility = false; + public controllerIp; + public controllerPort; public projectId; - authorizations = [ - { key: 'none', name: 'No authorization' }, - { key: 'basic', name: 'Basic authorization' }, - ]; protocols = [ { key: 'http:', name: 'HTTP' }, { key: 'https:', name: 'HTTPS' }, @@ -31,72 +27,61 @@ export class DirectLinkComponent implements OnInit { { key: 'remote', name: 'Remote' }, ]; - serverForm = new FormGroup({ - name: new FormControl('', [Validators.required]), - location: new FormControl(''), - protocol: new FormControl('http:'), - authorization: new FormControl('none'), - login: new FormControl(''), - password: new FormControl(''), + controllerForm = new UntypedFormGroup({ + name: new UntypedFormControl('', [Validators.required]), + location: new UntypedFormControl(''), + protocol: new UntypedFormControl('http:') }); constructor( - private serverService: ServerService, - private serverDatabase: ServerDatabase, + private controllerService: ControllerService, + private controllerDatabase: ControllerDatabase, private route: ActivatedRoute, private router: Router, private toasterService: ToasterService ) {} async ngOnInit() { - if (this.serverService.isServiceInitialized) this.getServers(); + if (this.controllerService.isServiceInitialized) this.getControllers(); - this.serverService.serviceInitialized.subscribe(async (value: boolean) => { + this.controllerService.serviceInitialized.subscribe(async (value: boolean) => { if (value) { - this.getServers(); + this.getControllers(); } }); } - private async getServers() { - this.serverIp = this.route.snapshot.paramMap.get('server_ip'); - this.serverPort = +this.route.snapshot.paramMap.get('server_port'); + private async getControllers() { + this.controllerIp = this.route.snapshot.paramMap.get('controller_ip'); + this.controllerPort = +this.route.snapshot.paramMap.get('controller_port'); this.projectId = this.route.snapshot.paramMap.get('project_id'); - const servers = await this.serverService.findAll(); - const server = servers.filter((server) => server.host === this.serverIp && server.port === this.serverPort)[0]; + const controllers = await this.controllerService.findAll(); + const controller = controllers.filter((controller) => controller.host === this.controllerIp && controller.port === this.controllerPort)[0]; - if (server) { - this.router.navigate(['/server', server.id, 'project', this.projectId]); + if (controller) { + this.router.navigate(['/controller', controller.id, 'project', this.projectId]); } else { - this.serverOptionsVisibility = true; + this.controllerOptionsVisibility = true; } } - public createServer() { - if (!this.serverForm.get('name').hasError && !this.serverForm.get('location').hasError && !this.serverForm.get('protocol').hasError) { - this.toasterService.error('Please use correct values'); - return; - } - - if (this.serverForm.get('authorization').value === 'basic' && !this.serverForm.get('login').value && !this.serverForm.get('password').value) { + public createController() { + if (!this.controllerForm.get('name').hasError && !this.controllerForm.get('location').hasError && !this.controllerForm.get('protocol').hasError) { this.toasterService.error('Please use correct values'); return; } - let serverToAdd: Server = new Server(); - serverToAdd.host = this.serverIp; - serverToAdd.port = this.serverPort; + let controllerToAdd:Controller = new Controller (); + controllerToAdd.host = this.controllerIp; + controllerToAdd.port = this.controllerPort; - serverToAdd.name = this.serverForm.get('name').value; - serverToAdd.location = this.serverForm.get('location').value; - serverToAdd.protocol = this.serverForm.get('protocol').value; - serverToAdd.authorization = this.serverForm.get('authorization').value; - serverToAdd.login = this.serverForm.get('login').value; - serverToAdd.password = this.serverForm.get('password').value; + controllerToAdd.name = this.controllerForm.get('name').value; + controllerToAdd.location = this.controllerForm.get('location').value; + controllerToAdd.protocol = this.controllerForm.get('protocol').value; - this.serverService.create(serverToAdd).then((addedServer: Server) => { - this.router.navigate(['/server', addedServer.id, 'project', this.projectId]); + this.controllerService.create(controllerToAdd).then((addedController:Controller ) => { + this.router.navigate(['/controller', addedController.id, 'project', this.projectId]); }); } } diff --git a/src/app/components/drawings-listeners/drawing-added/drawing-added.component.spec.ts b/src/app/components/drawings-listeners/drawing-added/drawing-added.component.spec.ts index a5069bedc..cafb9250e 100644 --- a/src/app/components/drawings-listeners/drawing-added/drawing-added.component.spec.ts +++ b/src/app/components/drawings-listeners/drawing-added/drawing-added.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { MapDrawingToSvgConverter } from '../../../cartography/converters/map/map-drawing-to-svg-converter'; import { DrawingsDataSource } from '../../../cartography/datasources/drawings-datasource'; @@ -27,8 +27,8 @@ describe('DrawingAddedComponent', () => { new LineElementFactory() ); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: DrawingService, useValue: mockedDrawingService }, { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, @@ -38,7 +38,7 @@ describe('DrawingAddedComponent', () => { ], declarations: [DrawingAddedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingAddedComponent); diff --git a/src/app/components/drawings-listeners/drawing-added/drawing-added.component.ts b/src/app/components/drawings-listeners/drawing-added/drawing-added.component.ts index f43c825f1..fd0dfb33b 100644 --- a/src/app/components/drawings-listeners/drawing-added/drawing-added.component.ts +++ b/src/app/components/drawings-listeners/drawing-added/drawing-added.component.ts @@ -7,7 +7,7 @@ import { AddedDataEvent } from '../../../cartography/events/event-source'; import { DefaultDrawingsFactory } from '../../../cartography/helpers/default-drawings-factory'; import { Drawing } from '../../../cartography/models/drawing'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DrawingService } from '../../../services/drawing.service'; @Component({ @@ -16,7 +16,7 @@ import { DrawingService } from '../../../services/drawing.service'; styleUrls: ['./drawing-added.component.scss'], }) export class DrawingAddedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller: Controller @Input() project: Project; @Input() selectedDrawing: string; @Output() drawingSaved = new EventEmitter(); @@ -49,9 +49,9 @@ export class DrawingAddedComponent implements OnInit, OnDestroy { let svgText = this.mapDrawingToSvgConverter.convert(drawing); this.drawingService - .add(this.server, this.project.project_id, evt.x, evt.y, svgText) - .subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.add(serverDrawing); + .add(this.controller, this.project.project_id, evt.x, evt.y, svgText) + .subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.add(controllerDrawing); this.drawingSaved.emit(true); }); } diff --git a/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.spec.ts b/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.spec.ts index 4f9e1edc2..a9657d74c 100644 --- a/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.spec.ts +++ b/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { DrawingsDataSource } from '../../../cartography/datasources/drawings-datasource'; import { DrawingsEventSource } from '../../../cartography/events/drawings-event-source'; @@ -16,8 +16,8 @@ describe('DrawingDraggedComponent', () => { let mockedDrawingsDataSource = new MockedDrawingsDataSource(); let mockedDrawingsEventSource = new DrawingsEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: DrawingService, useValue: mockedDrawingService }, { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, @@ -25,7 +25,7 @@ describe('DrawingDraggedComponent', () => { ], declarations: [DrawingDraggedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingDraggedComponent); diff --git a/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.ts b/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.ts index dc33b8fa0..8954e944e 100644 --- a/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.ts +++ b/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.ts @@ -6,7 +6,7 @@ import { DraggedDataEvent } from '../../../cartography/events/event-source'; import { Drawing } from '../../../cartography/models/drawing'; import { MapDrawing } from '../../../cartography/models/map/map-drawing'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DrawingService } from '../../../services/drawing.service'; @Component({ @@ -15,7 +15,7 @@ import { DrawingService } from '../../../services/drawing.service'; styleUrls: ['./drawing-dragged.component.scss'], }) export class DrawingDraggedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; private drawingDragged: Subscription; @@ -35,9 +35,9 @@ export class DrawingDraggedComponent implements OnInit, OnDestroy { drawing.y += draggedEvent.dy; this.drawingService - .updatePosition(this.server, this.project, drawing, drawing.x, drawing.y) - .subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.update(serverDrawing); + .updatePosition(this.controller, this.project, drawing, drawing.x, drawing.y) + .subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.update(controllerDrawing); }); } diff --git a/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.spec.ts b/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.spec.ts index fa084caee..528fbede6 100644 --- a/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.spec.ts +++ b/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.spec.ts @@ -18,8 +18,8 @@ describe('DrawingResizedComponent', () => { let mockedDrawingsEventSource = new DrawingsEventSource(); let mockedMapDrawingToSvgConverter = new MapDrawingToSvgConverter(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: DrawingService, useValue: mockedDrawingService }, { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, @@ -28,7 +28,7 @@ describe('DrawingResizedComponent', () => { ], declarations: [DrawingResizedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawingResizedComponent); diff --git a/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.ts b/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.ts index ef8fc2030..1bfabf809 100644 --- a/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.ts +++ b/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.ts @@ -6,7 +6,7 @@ import { DrawingsEventSource } from '../../../cartography/events/drawings-event- import { ResizedDataEvent } from '../../../cartography/events/event-source'; import { Drawing } from '../../../cartography/models/drawing'; import { MapDrawing } from '../../../cartography/models/map/map-drawing'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DrawingService } from '../../../services/drawing.service'; @Component({ @@ -15,7 +15,7 @@ import { DrawingService } from '../../../services/drawing.service'; styleUrls: ['./drawing-resized.component.scss'], }) export class DrawingResizedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; private drawingResized: Subscription; constructor( @@ -34,9 +34,9 @@ export class DrawingResizedComponent implements OnInit, OnDestroy { let svgString = this.mapDrawingToSvgConverter.convert(resizedEvent.datum); this.drawingService - .updateSizeAndPosition(this.server, drawing, resizedEvent.x, resizedEvent.y, svgString) - .subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.update(serverDrawing); + .updateSizeAndPosition(this.controller, drawing, resizedEvent.x, resizedEvent.y, svgString) + .subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.update(controllerDrawing); }); } diff --git a/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.spec.ts b/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.spec.ts index 54cc07ffd..5381a17c2 100644 --- a/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.spec.ts +++ b/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { LinksDataSource } from '../../../cartography/datasources/links-datasource'; import { DraggedDataEvent } from '../../../cartography/events/event-source'; @@ -18,8 +18,8 @@ describe('InterfaceLabelDraggedComponent', () => { let mockedLinksEventSource = new LinksEventSource(); let mockedLinksDataSource = new LinksDataSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: LinkService, useValue: mockedLinkService }, { provide: LinksDataSource, useValue: mockedLinksDataSource }, @@ -27,7 +27,7 @@ describe('InterfaceLabelDraggedComponent', () => { ], declarations: [InterfaceLabelDraggedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(InterfaceLabelDraggedComponent); diff --git a/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.ts b/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.ts index 124674eaa..0e82d8669 100644 --- a/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.ts +++ b/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.ts @@ -5,7 +5,7 @@ import { DraggedDataEvent } from '../../../cartography/events/event-source'; import { LinksEventSource } from '../../../cartography/events/links-event-source'; import { MapLinkNode } from '../../../cartography/models/map/map-link-node'; import { Link } from '../../../models/link'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { LinkService } from '../../../services/link.service'; @Component({ @@ -14,7 +14,7 @@ import { LinkService } from '../../../services/link.service'; styleUrls: ['./interface-label-dragged.component.scss'], }) export class InterfaceLabelDraggedComponent { - @Input() server: Server; + @Input() controller:Controller ; private interfaceDragged: Subscription; constructor( @@ -40,8 +40,8 @@ export class InterfaceLabelDraggedComponent { link.nodes[1].label.y += draggedEvent.dy; } - this.linkService.updateNodes(this.server, link, link.nodes).subscribe((serverLink: Link) => { - this.linksDataSource.update(serverLink); + this.linkService.updateNodes(this.controller, link, link.nodes).subscribe((controllerLink: Link) => { + this.linksDataSource.update(controllerLink); }); } diff --git a/src/app/components/drawings-listeners/link-created/link-created.component.spec.ts b/src/app/components/drawings-listeners/link-created/link-created.component.spec.ts index ba97514b4..22c5bb319 100644 --- a/src/app/components/drawings-listeners/link-created/link-created.component.spec.ts +++ b/src/app/components/drawings-listeners/link-created/link-created.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { MapLabelToLabelConverter } from '../../../cartography/converters/map/map-label-to-label-converter'; import { MapNodeToNodeConverter } from '../../../cartography/converters/map/map-node-to-node-converter'; @@ -30,8 +30,8 @@ describe('LinkCreatedComponent', () => { let mockedLinksEventSource = new LinksEventSource(); let project = new Project(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: ProjectService, useClass: MockedProjectService }, { provide: LinkService, useValue: mockedLinkService }, @@ -42,7 +42,7 @@ describe('LinkCreatedComponent', () => { ], declarations: [LinkCreatedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(LinkCreatedComponent); diff --git a/src/app/components/drawings-listeners/link-created/link-created.component.ts b/src/app/components/drawings-listeners/link-created/link-created.component.ts index f115ca908..a5c027c67 100644 --- a/src/app/components/drawings-listeners/link-created/link-created.component.ts +++ b/src/app/components/drawings-listeners/link-created/link-created.component.ts @@ -7,7 +7,7 @@ import { MapLinkCreated } from '../../../cartography/events/links'; import { LinksEventSource } from '../../../cartography/events/links-event-source'; import { Link } from '../../../models/link'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { LinkService } from '../../../services/link.service'; import { ProjectService } from '../../../services/project.service'; @@ -17,7 +17,7 @@ import { ProjectService } from '../../../services/project.service'; styleUrls: ['./link-created.component.scss'], }) export class LinkCreatedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; private linkCreated: Subscription; @@ -87,7 +87,7 @@ export class LinkCreatedComponent implements OnInit, OnDestroy { this.linkService .createLink( - this.server, + this.controller, sourceNode, sourcePort, targetNode, @@ -98,7 +98,7 @@ export class LinkCreatedComponent implements OnInit, OnDestroy { yLabelTargetNode ) .subscribe(() => { - this.projectService.links(this.server, this.project.project_id).subscribe((links: Link[]) => { + this.projectService.links(this.controller, this.project.project_id).subscribe((links: Link[]) => { this.linksDataSource.set(links); }); }); diff --git a/src/app/components/drawings-listeners/node-dragged/node-dragged.component.spec.ts b/src/app/components/drawings-listeners/node-dragged/node-dragged.component.spec.ts index 0b69c34f8..770dd990c 100644 --- a/src/app/components/drawings-listeners/node-dragged/node-dragged.component.spec.ts +++ b/src/app/components/drawings-listeners/node-dragged/node-dragged.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { DraggedDataEvent } from '../../../cartography/events/event-source'; @@ -16,8 +16,8 @@ describe('NodeDraggedComponent', () => { let mockedNodeService = new MockedNodeService(); let mockedNodesEventSource = new NodesEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: NodesDataSource, useValue: mockedNodesDataSource }, { provide: NodeService, useValue: mockedNodeService }, @@ -25,7 +25,7 @@ describe('NodeDraggedComponent', () => { ], declarations: [NodeDraggedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(NodeDraggedComponent); diff --git a/src/app/components/drawings-listeners/node-dragged/node-dragged.component.ts b/src/app/components/drawings-listeners/node-dragged/node-dragged.component.ts index 7730d4b29..f651e94cc 100644 --- a/src/app/components/drawings-listeners/node-dragged/node-dragged.component.ts +++ b/src/app/components/drawings-listeners/node-dragged/node-dragged.component.ts @@ -6,7 +6,7 @@ import { NodesEventSource } from '../../../cartography/events/nodes-event-source import { MapNode } from '../../../cartography/models/map/map-node'; import { Node } from '../../../cartography/models/node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { NodeService } from '../../../services/node.service'; @Component({ @@ -15,7 +15,7 @@ import { NodeService } from '../../../services/node.service'; styleUrls: ['./node-dragged.component.scss'], }) export class NodeDraggedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; private nodeDragged: Subscription; @@ -34,8 +34,8 @@ export class NodeDraggedComponent implements OnInit, OnDestroy { node.x += draggedEvent.dx; node.y += draggedEvent.dy; - this.nodeService.updatePosition(this.server, this.project, node, node.x, node.y).subscribe((serverNode: Node) => { - this.nodesDataSource.update(serverNode); + this.nodeService.updatePosition(this.controller, this.project, node, node.x, node.y).subscribe((controllerNode: Node) => { + this.nodesDataSource.update(controllerNode); }); } diff --git a/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.spec.ts b/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.spec.ts index 2767728c2..e1a976285 100644 --- a/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.spec.ts +++ b/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { MapLabelToLabelConverter } from '../../../cartography/converters/map/map-label-to-label-converter'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; @@ -24,8 +24,8 @@ describe('NodeLabelDraggedComponent', () => { new FontFixer() ); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: NodesDataSource, useValue: mockedNodesDataSource }, { provide: NodeService, useValue: mockedNodeService }, @@ -34,7 +34,7 @@ describe('NodeLabelDraggedComponent', () => { ], declarations: [NodeLabelDraggedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(NodeLabelDraggedComponent); diff --git a/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.ts b/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.ts index 9a3bcc47b..4f8780327 100644 --- a/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.ts +++ b/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.ts @@ -6,7 +6,7 @@ import { DraggedDataEvent } from '../../../cartography/events/event-source'; import { NodesEventSource } from '../../../cartography/events/nodes-event-source'; import { MapLabel } from '../../../cartography/models/map/map-label'; import { Node } from '../../../cartography/models/node'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { NodeService } from '../../../services/node.service'; @Component({ @@ -15,7 +15,7 @@ import { NodeService } from '../../../services/node.service'; styleUrls: ['./node-label-dragged.component.scss'], }) export class NodeLabelDraggedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; private nodeLabelDragged: Subscription; constructor( @@ -38,8 +38,8 @@ export class NodeLabelDraggedComponent implements OnInit, OnDestroy { const label = this.mapLabelToLabel.convert(mapLabel); node.label = label; - this.nodeService.updateLabel(this.server, node, node.label).subscribe((serverNode: Node) => { - this.nodesDataSource.update(serverNode); + this.nodeService.updateLabel(this.controller, node, node.label).subscribe((controllerNode: Node) => { + this.nodesDataSource.update(controllerNode); }); } diff --git a/src/app/components/drawings-listeners/text-added/text-added.component.spec.ts b/src/app/components/drawings-listeners/text-added/text-added.component.spec.ts index 8f9f32d33..3d2e69f6e 100644 --- a/src/app/components/drawings-listeners/text-added/text-added.component.spec.ts +++ b/src/app/components/drawings-listeners/text-added/text-added.component.spec.ts @@ -28,8 +28,8 @@ describe('TextAddedComponent', () => { new LineElementFactory() ); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: DrawingService, useValue: mockedDrawingService }, { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, @@ -40,7 +40,7 @@ describe('TextAddedComponent', () => { ], declarations: [TextAddedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(TextAddedComponent); diff --git a/src/app/components/drawings-listeners/text-added/text-added.component.ts b/src/app/components/drawings-listeners/text-added/text-added.component.ts index d14311ee6..dfd050382 100644 --- a/src/app/components/drawings-listeners/text-added/text-added.component.ts +++ b/src/app/components/drawings-listeners/text-added/text-added.component.ts @@ -9,7 +9,7 @@ import { Context } from '../../../cartography/models/context'; import { Drawing } from '../../../cartography/models/drawing'; import { TextElement } from '../../../cartography/models/drawings/text-element'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DrawingService } from '../../../services/drawing.service'; @Component({ @@ -18,7 +18,7 @@ import { DrawingService } from '../../../services/drawing.service'; styleUrls: ['./text-added.component.scss'], }) export class TextAddedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller: Controller; @Input() project: Project; @Output() drawingSaved = new EventEmitter(); private textAdded: Subscription; @@ -43,7 +43,7 @@ export class TextAddedComponent implements OnInit, OnDestroy { this.drawingService .add( - this.server, + this.controller, this.project.project_id, (evt.x - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x)) / this.context.transformation.k, @@ -51,8 +51,8 @@ export class TextAddedComponent implements OnInit, OnDestroy { this.context.transformation.k, svgText ) - .subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.add(serverDrawing); + .subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.add(controllerDrawing); this.drawingSaved.emit(true); }); } diff --git a/src/app/components/drawings-listeners/text-edited/text-edited.component.spec.ts b/src/app/components/drawings-listeners/text-edited/text-edited.component.spec.ts index ed0fae2dc..009a273ae 100644 --- a/src/app/components/drawings-listeners/text-edited/text-edited.component.spec.ts +++ b/src/app/components/drawings-listeners/text-edited/text-edited.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs'; import { MapDrawingToSvgConverter } from '../../../cartography/converters/map/map-drawing-to-svg-converter'; import { DrawingsDataSource } from '../../../cartography/datasources/drawings-datasource'; @@ -16,8 +16,8 @@ describe('TextEditedComponent', () => { let mockedDrawingsDataSource = new MockedDrawingsDataSource(); let mockedDrawingsEventSource = new DrawingsEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: DrawingService, useValue: mockedDrawingService }, { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, @@ -26,7 +26,7 @@ describe('TextEditedComponent', () => { ], declarations: [TextEditedComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(TextEditedComponent); diff --git a/src/app/components/drawings-listeners/text-edited/text-edited.component.ts b/src/app/components/drawings-listeners/text-edited/text-edited.component.ts index d5d5eaec8..32a138e5d 100644 --- a/src/app/components/drawings-listeners/text-edited/text-edited.component.ts +++ b/src/app/components/drawings-listeners/text-edited/text-edited.component.ts @@ -7,7 +7,7 @@ import { TextEditedDataEvent } from '../../../cartography/events/event-source'; import { Drawing } from '../../../cartography/models/drawing'; import { TextElement } from '../../../cartography/models/drawings/text-element'; import { MapDrawing } from '../../../cartography/models/map/map-drawing'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DrawingService } from '../../../services/drawing.service'; @Component({ @@ -16,7 +16,7 @@ import { DrawingService } from '../../../services/drawing.service'; styleUrls: ['./text-edited.component.scss'], }) export class TextEditedComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller: Controller; private textEdited: Subscription; constructor( @@ -38,8 +38,8 @@ export class TextEditedComponent implements OnInit, OnDestroy { let drawing = this.drawingsDataSource.get(evt.textDrawingId); - this.drawingService.updateText(this.server, drawing, svgString).subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.update(serverDrawing); + this.drawingService.updateText(this.controller, drawing, svgString).subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.update(controllerDrawing); this.drawingsEventSource.textSaved.emit(true); }); } diff --git a/src/app/components/export-portable-project/export-portable-project.component.html b/src/app/components/export-portable-project/export-portable-project.component.html new file mode 100644 index 000000000..de20ebe80 --- /dev/null +++ b/src/app/components/export-portable-project/export-portable-project.component.html @@ -0,0 +1,73 @@ +
+
+
+

Export Project

+
+
+ +
+
+ + +
+
+
Compression:
+
+ + + {{ + compressionValue?.name + }} + + +
+
+
+
Compression level:
+
+ + + {{ + compressionLevel + }} + + +
+
+
+
+
+ Include base images +
+
+
+
+
+
+ Include snapshots +
+
+
+
+
+
+ Reset MAC addresses +
+
+
+
+ +
+
+
+ + +
+
+
+
diff --git a/src/app/components/export-portable-project/export-portable-project.component.scss b/src/app/components/export-portable-project/export-portable-project.component.scss new file mode 100644 index 000000000..3f4278959 --- /dev/null +++ b/src/app/components/export-portable-project/export-portable-project.component.scss @@ -0,0 +1,39 @@ +.mat-dialog-title { + margin: 0 0 0px; + display: block; +} +.mat-dialog-container { + padding: 14px 14px 5px 14px !important; +} +.checkBox-section { + display: flex; + align-content: center; + align-items: center; + height: 35px; +} + +.checkBox-margin { + margin: 0 10px; +} +.txt-align { + text-align: end; +} +.close-btn { + margin: 0 0 20px 40px; +} +.mat-data { + margin: 15px 0 15px 0; +} + + +.input-full-width { + width: 100%; +} +.col-data { + text-align: left; + align-self: self-end; + margin-bottom: 20px; +} +.checkbox-row{ + margin-top: 5px 0 5px 0; +} diff --git a/src/app/components/export-portable-project/export-portable-project.component.spec.ts b/src/app/components/export-portable-project/export-portable-project.component.spec.ts new file mode 100644 index 000000000..169f9689f --- /dev/null +++ b/src/app/components/export-portable-project/export-portable-project.component.spec.ts @@ -0,0 +1,59 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ProjectService } from '../../services/project.service'; +import { MockedProjectService } from '../../services/project.service.spec'; +import { ToasterService } from '../../services/toaster.service'; +import { MockedToasterService } from '../../services/toaster.service.spec'; +import { ExportPortableProjectComponent } from './export-portable-project.component'; + +describe('ExportPortableProjectComponent', () => { + let component: ExportPortableProjectComponent; + let fixture: ComponentFixture; + let mockedToasterService = new MockedToasterService(); + let mockedProjectService = new MockedProjectService(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ExportPortableProjectComponent], + imports: [ + MatDialogModule, + ReactiveFormsModule, + FormsModule, + MatSelectModule, + MatCheckboxModule, + MatFormFieldModule, + MatInputModule, + BrowserAnimationsModule, + ], + providers: [ + { provide: MatDialogRef, useValue: {} }, + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: ToasterService, useValue: mockedToasterService }, + { provide: ProjectService, useValue: mockedProjectService }, + ], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ExportPortableProjectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + let compression_methods_Value = mockedProjectService.getCompression; + let compression_level_value = mockedProjectService.getCompressionLevel; + component.compression_methods = compression_methods_Value[4]; + component.compression_level = compression_level_value; + component.selectCompression(component.compression_methods); + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/export-portable-project/export-portable-project.component.ts b/src/app/components/export-portable-project/export-portable-project.component.ts new file mode 100644 index 000000000..90b3c06ec --- /dev/null +++ b/src/app/components/export-portable-project/export-portable-project.component.ts @@ -0,0 +1,73 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Project } from '../../models/project'; +import{ Controller } from '../../models/controller'; +import { ProjectService } from '../../services/project.service'; + +@Component({ + selector: 'app-export-portable-project', + templateUrl: './export-portable-project.component.html', + styleUrls: ['./export-portable-project.component.scss'], +}) +export class ExportPortableProjectComponent implements OnInit { + export_project_form: UntypedFormGroup; + chosenImage: string = ''; + compression_methods: any = []; + compression_level: any = []; + compression_filter_value: any = []; + controller:Controller ; + project: Project; + index: number = 4; + fileName: string; + isExport: boolean = false; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + private projectService: ProjectService, + private _fb: UntypedFormBuilder + ) {} + + async ngOnInit() { + this.controller = this.data.controllerDetails; + this.project = this.data.projectDetails; + if( this.project){ + this.fileName = this.project.name + '.gns3project'; + } + await this.formControls(); + this.compression_methods = this.projectService.getCompression(); + this.compression_level = this.projectService.getCompressionLevel(); + this.selectCompression({ value: this.compression_methods[this.index] }); + this.export_project_form.get('compression').setValue(this.compression_methods[this.index]); + } + + formControls() { + this.export_project_form = this._fb.group({ + compression: ['', Validators.required], + compression_level: [''], + include_base_image: [false, Validators.required], + include_snapshots: [false, Validators.required], + reset_mac_address: [false, Validators.required], + }); + this.export_project_form.valueChanges.subscribe(() => {}); + } + + selectCompression(event) { + if (this.compression_level.length > 0) { + this.compression_level.map((_) => { + if (event.value.value === _.name) { + this.export_project_form.get('compression_level').setValue(_.value); + this.compression_filter_value = _.selectionValues; + } + }); + } + } + + exportPortableProject() { + this.isExport = true; + this.export_project_form.value.compression = this.export_project_form.value.compression.value ?? 'zstd'; + window.location.assign(this.projectService.getexportPortableProjectPath(this.controller, this.project.project_id, this.export_project_form.value)) + this.dialogRef.close(); + } +} diff --git a/src/app/components/group-details/add-role-to-group/add-role-to-group.component.html b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.html new file mode 100644 index 000000000..dff5bcd00 --- /dev/null +++ b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.html @@ -0,0 +1,15 @@ +
+

Add Role To group: {{data.group.name}}

+
+
+ + Search user + + +
+ +
+
{{role.name}}
+ add + +
diff --git a/src/app/components/group-details/add-role-to-group/add-role-to-group.component.scss b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.scss new file mode 100644 index 000000000..01cd6a622 --- /dev/null +++ b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.scss @@ -0,0 +1,35 @@ +:host { + display: flex; + flex-direction: column; + width: 100%; +} + +.title { + width: 100%; + text-align: center; +} + +.filter { + display: flex; + width: 600px; + justify-content: center; + margin-bottom: 50px; +} + +mat-form-field { + width: 600px; +} + +input { + width: 100%; +} + +.userList { + display: flex; + justify-content: space-between; + margin-bottom: 10px; +} + +mat-spinner { + width: 36px; +} diff --git a/src/app/components/servers/add-server-dialog/add-server-dialog.component.scss b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.spec.ts similarity index 100% rename from src/app/components/servers/add-server-dialog/add-server-dialog.component.scss rename to src/app/components/group-details/add-role-to-group/add-role-to-group.component.spec.ts diff --git a/src/app/components/group-details/add-role-to-group/add-role-to-group.component.ts b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.ts new file mode 100644 index 000000000..e6bf83503 --- /dev/null +++ b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.ts @@ -0,0 +1,90 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {BehaviorSubject, forkJoin, timer} from "rxjs"; +import {User} from "@models/users/user"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {Controller} from "@models/controller"; +import {Group} from "@models/groups/group"; +import {UserService} from "@services/user.service"; +import {GroupService} from "@services/group.service"; +import {ToasterService} from "@services/toaster.service"; +import {Role} from "@models/api/role"; +import {RoleService} from "@services/role.service"; + +@Component({ + selector: 'app-add-role-to-group', + templateUrl: './add-role-to-group.component.html', + styleUrls: ['./add-role-to-group.component.scss'] +}) +export class AddRoleToGroupComponent implements OnInit { + roles = new BehaviorSubject([]); + displayedRoles = new BehaviorSubject([]); + + searchText: string; + loading = false; + + constructor(private dialog: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { controller: Controller; group: Group }, + private groupService: GroupService, + private roleService: RoleService, + private toastService: ToasterService) { + } + + ngOnInit(): void { + this.getRoles(); + } + + onSearch() { + timer(500) + .subscribe(() => { + const displayedUsers = this.roles.value.filter((roles: Role) => { + return roles.name.includes(this.searchText); + }); + + this.displayedRoles.next(displayedUsers); + }); + } + + getRoles() { + forkJoin([ + this.roleService.get(this.data.controller), + this.groupService.getGroupRole(this.data.controller, this.data.group.user_group_id) + ]).subscribe((results) => { + const [globalRoles, groupRoles] = results; + const roles = globalRoles.filter((role: Role) => { + return !groupRoles.find((r: Role) => r.role_id === role.role_id); + }); + + this.roles.next(roles); + this.displayedRoles.next(roles); + + }); + + } + + addRole(role: Role) { + this.loading = true; + this.groupService + .addRoleToGroup(this.data.controller, this.data.group, role) + .subscribe(() => { + this.toastService.success(`role ${role.name} was added`); + this.getRoles(); + this.loading = false; + }, (err) => { + console.log(err); + this.toastService.error(`error while adding role ${role.name} to group ${this.data.group.name}`); + this.loading = false; + }); + } +} diff --git a/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.html b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.html new file mode 100644 index 000000000..5c3974731 --- /dev/null +++ b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.html @@ -0,0 +1,16 @@ +
+

Add User To group: {{data.group.name}}

+
+
+ + Search user + + +
+ +
+
{{user.username}}
+
{{user.email}}
+ add + +
diff --git a/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.scss b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.scss new file mode 100644 index 000000000..01cd6a622 --- /dev/null +++ b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.scss @@ -0,0 +1,35 @@ +:host { + display: flex; + flex-direction: column; + width: 100%; +} + +.title { + width: 100%; + text-align: center; +} + +.filter { + display: flex; + width: 600px; + justify-content: center; + margin-bottom: 50px; +} + +mat-form-field { + width: 600px; +} + +input { + width: 100%; +} + +.userList { + display: flex; + justify-content: space-between; + margin-bottom: 10px; +} + +mat-spinner { + width: 36px; +} diff --git a/src/app/components/servers/configure-gns3vm-dialog/configure-gns3vm-dialog.component.scss b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.spec.ts similarity index 100% rename from src/app/components/servers/configure-gns3vm-dialog/configure-gns3vm-dialog.component.scss rename to src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.spec.ts diff --git a/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.ts b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.ts new file mode 100644 index 000000000..4aac22930 --- /dev/null +++ b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.ts @@ -0,0 +1,91 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {UserService} from "@services/user.service"; +import {Controller} from "@models/controller"; +import {BehaviorSubject, forkJoin, observable, Observable, timer} from "rxjs"; +import {User} from "@models/users/user"; +import {GroupService} from "@services/group.service"; +import {Group} from "@models/groups/group"; +import {tap} from "rxjs/operators"; +import {ToasterService} from "@services/toaster.service"; + +@Component({ + selector: 'app-add-user-to-group-dialog', + templateUrl: './add-user-to-group-dialog.component.html', + styleUrls: ['./add-user-to-group-dialog.component.scss'] +}) +export class AddUserToGroupDialogComponent implements OnInit { + users = new BehaviorSubject([]); + displayedUsers = new BehaviorSubject([]); + + searchText: string; + loading = false; + + constructor(private dialog: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { controller: Controller; group: Group }, + private userService: UserService, + private groupService: GroupService, + private toastService: ToasterService) { + } + + ngOnInit(): void { + this.getUsers(); + } + + onSearch() { + timer(500) + .subscribe(() => { + const displayedUsers = this.users.value.filter((user: User) => { + return user.username.includes(this.searchText) || user.email?.includes(this.searchText); + }); + + this.displayedUsers.next(displayedUsers); + }); + } + + getUsers() { + forkJoin([ + this.userService.list(this.data.controller), + this.groupService.getGroupMember(this.data.controller, this.data.group.user_group_id) + ]).subscribe((results) => { + const [userList, members] = results; + const users = userList.filter((user: User) => { + return !members.find((u: User) => u.user_id === user.user_id); + }); + + this.users.next(users); + this.displayedUsers.next(users); + + }); + + } + + addUser(user: User) { + this.loading = true; + this.groupService + .addMemberToGroup(this.data.controller, this.data.group, user) + .subscribe(() => { + this.toastService.success(`user ${user.username} was added`); + this.getUsers(); + this.loading = false; + }, (err) => { + console.log(err); + this.toastService.error(`error while adding user ${user.username} to group ${this.data.group.name}`); + this.loading = false; + }); + + + } +} diff --git a/src/app/components/group-details/group-details.component.html b/src/app/components/group-details/group-details.component.html new file mode 100644 index 000000000..9bec7a3ab --- /dev/null +++ b/src/app/components/group-details/group-details.component.html @@ -0,0 +1,72 @@ +
+
+
+ + keyboard_arrow_left + +

Groups {{group.name}} details

+
+ + +
+
+ + Group name: + + +
+ +
+ Is build in +
+
+ +
+
+
+
Creation date: {{group.created_at}}
+
Last update Date: {{group.updated_at}}
+
UUID: {{group.user_group_id}}
+
+
+ +
+
+ person_add +
+ + + +
+
+ +
+
+
{{role.name}}
+
+ +
+
+
+
+
+
diff --git a/src/app/components/group-details/group-details.component.scss b/src/app/components/group-details/group-details.component.scss new file mode 100644 index 000000000..e8417eab1 --- /dev/null +++ b/src/app/components/group-details/group-details.component.scss @@ -0,0 +1,51 @@ +.main { + display: flex; + justify-content: space-around; +} + +.details { + display: flex; + flex-direction: column; + justify-content: center; +} + +.members { + display: flex; + flex-direction: column; + justify-content: stretch; +} + +.members > div { + display: flex; + flex-direction: row; + justify-content: space-between; + margin-bottom: 5px; +} + +.clickable { + cursor: pointer; +} + +.details > div { + margin-bottom: 20px; +} + +.button-div { + float: right; +} + +.members > .search { + display: flex; + flex-direction: row; + justify-content: stretch; + width: 100%; +} +mat-form-field { + width: 100%; +} + +.roles { + display: flex; + flex-direction: row; + justify-content: space-between; +} diff --git a/src/app/components/servers/server-discovery/server-discovery.component.scss b/src/app/components/group-details/group-details.component.spec.ts similarity index 100% rename from src/app/components/servers/server-discovery/server-discovery.component.scss rename to src/app/components/group-details/group-details.component.spec.ts diff --git a/src/app/components/group-details/group-details.component.ts b/src/app/components/group-details/group-details.component.ts new file mode 100644 index 000000000..eb0eb4756 --- /dev/null +++ b/src/app/components/group-details/group-details.component.ts @@ -0,0 +1,152 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from "@angular/router"; +import {Controller} from "@models/controller"; +import {Group} from "@models/groups/group"; +import {User} from "@models/users/user"; +import {UntypedFormControl, UntypedFormGroup} from "@angular/forms"; +import {MatDialog} from "@angular/material/dialog"; +import {AddUserToGroupDialogComponent} from "@components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component"; +import {RemoveToGroupDialogComponent} from "@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component"; +import {GroupService} from "@services/group.service"; +import {ToasterService} from "@services/toaster.service"; +import {PageEvent} from "@angular/material/paginator"; +import {Role} from "@models/api/role"; +import {AddRoleToGroupComponent} from "@components/group-details/add-role-to-group/add-role-to-group.component"; + +@Component({ + selector: 'app-group-details', + templateUrl: './group-details.component.html', + styleUrls: ['./group-details.component.scss'] +}) +export class GroupDetailsComponent implements OnInit { + controller: Controller; + group: Group; + members: User[]; + editGroupForm: UntypedFormGroup; + pageEvent: PageEvent | undefined; + searchMembers: string; + roles: Role[]; + + constructor(private route: ActivatedRoute, + private dialog: MatDialog, + private groupService: GroupService, + private toastService: ToasterService) { + + this.editGroupForm = new UntypedFormGroup({ + groupname: new UntypedFormControl(''), + }); + + this.route.data.subscribe((d: { controller: Controller; group: Group, members: User[], roles: Role[] }) => { + + this.controller = d.controller; + this.group = d.group; + this.roles = d.roles; + this.members = d.members.sort((a: User, b: User) => a.username.toLowerCase().localeCompare(b.username.toLowerCase())); + this.editGroupForm.setValue({groupname: this.group.name}); + }); + } + + ngOnInit(): void { + + } + + onUpdate() { + this.groupService.update(this.controller, this.group) + .subscribe(() => { + this.toastService.success(`group updated`); + }, (error) => { + this.toastService.error('Error: Cannot update group'); + console.log(error); + }); + } + + openAddRoleDialog() { + this.dialog + .open(AddRoleToGroupComponent, + { + width: '700px', height: '500px', + data: {controller: this.controller, group: this.group} + }) + .afterClosed() + .subscribe(() => { + this.reloadRoles(); + }); + } + openAddUserDialog() { + this.dialog + .open(AddUserToGroupDialogComponent, + { + width: '700px', height: '500px', + data: {controller: this.controller, group: this.group} + }) + .afterClosed() + .subscribe(() => { + this.reloadMembers(); + }); + } + + openRemoveUserDialog(user: User) { + this.dialog.open(RemoveToGroupDialogComponent, + {width: '500px', height: '200px', data: {name: user.username}}) + .afterClosed() + .subscribe((confirm: boolean) => { + if (confirm) { + this.groupService.removeUser(this.controller, this.group, user) + .subscribe(() => { + this.toastService.success(`User ${user.username} was removed`); + this.reloadMembers(); + }, + (error) => { + this.toastService.error(`Error while removing user ${user.username} from ${this.group.name}`); + console.log(error); + }); + } + }); + } + + + openRemoveRoleDialog(role: Role) { + this.dialog.open(RemoveToGroupDialogComponent, + {width: '500px', height: '200px', data: {name: role.name}}) + .afterClosed() + .subscribe((confirm: string) => { + if (confirm) { + this.groupService.removeRole(this.controller, this.group, role) + .subscribe(() => { + this.toastService.success(`Role ${role.name} was removed`); + this.reloadRoles(); + }, + (error) => { + this.toastService.error(`Error while removing role ${role.name} from ${this.group.name}`); + console.log(error); + }); + } + }); + } + + reloadMembers() { + this.groupService.getGroupMember(this.controller, this.group.user_group_id) + .subscribe((members: User[]) => { + this.members = members; + }); + } + + reloadRoles() { + this.groupService.getGroupRole(this.controller, this.group.user_group_id) + .subscribe((roles: Role[]) => { + this.roles = roles; + }); + } +} diff --git a/src/app/services/traceng.service.spec.ts b/src/app/components/group-details/members-filter.pipe.spec.ts similarity index 100% rename from src/app/services/traceng.service.spec.ts rename to src/app/components/group-details/members-filter.pipe.spec.ts diff --git a/src/app/components/group-details/members-filter.pipe.ts b/src/app/components/group-details/members-filter.pipe.ts new file mode 100644 index 000000000..570a1456f --- /dev/null +++ b/src/app/components/group-details/members-filter.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Pipe, PipeTransform} from '@angular/core'; +import {User} from "@models/users/user"; + +@Pipe({ + name: 'membersFilter' +}) +export class MembersFilterPipe implements PipeTransform { + + transform(members: User[], filterText: string): User[] { + if (!members) { + return []; + } + if (filterText === undefined || filterText === '') { + return members; + } + + return members.filter((member: User) => member.username.toLowerCase().includes(filterText.toLowerCase())); + } + +} diff --git a/src/app/components/group-details/paginator.pipe.spec.ts b/src/app/components/group-details/paginator.pipe.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/group-details/paginator.pipe.ts b/src/app/components/group-details/paginator.pipe.ts new file mode 100644 index 000000000..7bc694241 --- /dev/null +++ b/src/app/components/group-details/paginator.pipe.ts @@ -0,0 +1,41 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Pipe, PipeTransform} from '@angular/core'; +import {User} from "@models/users/user"; +import {PageEvent} from "@angular/material/paginator"; + +@Pipe({ + name: 'paginator' +}) +export class PaginatorPipe implements PipeTransform { + + transform(elements: T[] | undefined, paginatorEvent: PageEvent | undefined): T[] { + if (!elements) { + return []; + } + + if (!paginatorEvent) { + paginatorEvent = { + length: elements.length, + pageIndex: 0, + pageSize: 5 + }; + } + + + return elements.slice( + paginatorEvent.pageIndex * paginatorEvent.pageSize, + (paginatorEvent.pageIndex + 1) * paginatorEvent.pageSize); + } + +} diff --git a/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.html b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.html new file mode 100644 index 000000000..e5811dad9 --- /dev/null +++ b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.html @@ -0,0 +1,9 @@ +
+
Confirm ?
+
Removing: {{data.name}}
+
+
+ + +
+ diff --git a/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.scss b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.scss new file mode 100644 index 000000000..8ebc2b8a4 --- /dev/null +++ b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.scss @@ -0,0 +1,20 @@ +:host { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; +} + +.header { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + margin-bottom: 20px; +} + +.button { + display: flex; + flex-direction: row; + justify-content: space-evenly; +} diff --git a/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.spec.ts b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.ts b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.ts new file mode 100644 index 000000000..2e86af2ee --- /dev/null +++ b/src/app/components/group-details/remove-to-group-dialog/remove-to-group-dialog.component.ts @@ -0,0 +1,37 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {User} from "@models/users/user"; + +@Component({ + selector: 'app-remove-user-to-group-dialog', + templateUrl: './remove-to-group-dialog.component.html', + styleUrls: ['./remove-to-group-dialog.component.scss'] +}) +export class RemoveToGroupDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { name: string }) { } + + ngOnInit(): void { + } + + onCancel() { + this.dialogRef.close(false); + } + + onConfirm() { + this.dialogRef.close(true); + } +} diff --git a/src/app/components/group-details/remove-user-to-group-dialog/remove-user-to-group-dialog.component.ts b/src/app/components/group-details/remove-user-to-group-dialog/remove-user-to-group-dialog.component.ts new file mode 100644 index 000000000..ef70a89fe --- /dev/null +++ b/src/app/components/group-details/remove-user-to-group-dialog/remove-user-to-group-dialog.component.ts @@ -0,0 +1,37 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {User} from "@models/users/user"; + +@Component({ + selector: 'app-remove-user-to-group-dialog', + templateUrl: './remove-user-to-group-dialog.component.html', + styleUrls: ['./remove-user-to-group-dialog.component.scss'] +}) +export class RemoveUserToGroupDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { user: User }) { } + + ngOnInit(): void { + } + + onCancel() { + this.dialogRef.close(); + } + + onConfirm() { + this.dialogRef.close(this.data.user); + } +} diff --git a/src/app/components/group-management/add-group-dialog/GroupNameValidator.ts b/src/app/components/group-management/add-group-dialog/GroupNameValidator.ts new file mode 100644 index 000000000..09b9cda8b --- /dev/null +++ b/src/app/components/group-management/add-group-dialog/GroupNameValidator.ts @@ -0,0 +1,26 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Injectable } from '@angular/core'; + +@Injectable() +export class GroupNameValidator { + get(groupName) { + const pattern = new RegExp(/[~`!#$%\^&*+=\[\]\\';,/{}|\\":<>\?]/); + + if (!pattern.test(groupName.value)) { + return null; + } + + return { invalidName: true }; + } +} diff --git a/src/app/components/group-management/add-group-dialog/add-group-dialog.component.html b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.html new file mode 100644 index 000000000..8bb21d51b --- /dev/null +++ b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.html @@ -0,0 +1,57 @@ +

Create new group

+
+ + + Group name is required + Group name is incorrect + Group with this name exists + +
+ +
Add users to group:
+ + Users + + + + {{user.username}} - {{user.email}} + + + + +
+
+
+
{{user.username}}
+
{{user.email}}
+ delete +
+
+
+ + + + +
+ + +
+ diff --git a/src/app/components/group-management/add-group-dialog/add-group-dialog.component.scss b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.scss new file mode 100644 index 000000000..0ab6fbfb1 --- /dev/null +++ b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.scss @@ -0,0 +1,25 @@ +.file-name-form-field { + width: 100%; +} + +.project-snackbar { + background: #2196f3; +} + +.userList { + display: flex; + margin: 10px; + justify-content: space-between; + flex: 1 1 auto; +} + +.users { + display: flex; + height: 180px; + overflow: auto; + flex-direction: column; +} + +.button-div { + float: right; +} diff --git a/src/app/components/group-management/add-group-dialog/add-group-dialog.component.spec.ts b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/group-management/add-group-dialog/add-group-dialog.component.ts b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.ts new file mode 100644 index 000000000..ea5c6215c --- /dev/null +++ b/src/app/components/group-management/add-group-dialog/add-group-dialog.component.ts @@ -0,0 +1,137 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators} from "@angular/forms"; +import {groupNameAsyncValidator} from "@components/group-management/add-group-dialog/groupNameAsyncValidator"; +import {GroupNameValidator} from "@components/group-management/add-group-dialog/GroupNameValidator"; +import {GroupService} from "../../../services/group.service"; +import {Controller} from "../../../models/controller"; +import {BehaviorSubject, forkJoin, timer} from "rxjs"; +import {User} from "@models/users/user"; +import {UserService} from "@services/user.service"; +import {ToasterService} from "@services/toaster.service"; +import {PageEvent} from "@angular/material/paginator"; +import {Observable} from "rxjs/Rx"; +import {Group} from "@models/groups/group"; +import {map, startWith} from "rxjs/operators"; + +@Component({ + selector: 'app-add-group-dialog', + templateUrl: './add-group-dialog.component.html', + styleUrls: ['./add-group-dialog.component.scss'], + providers: [GroupNameValidator] +}) +export class AddGroupDialogComponent implements OnInit { + + groupNameForm: UntypedFormGroup; + controller: Controller; + + users: User[]; + usersToAdd: Set = new Set([]); + filteredUsers: Observable + loading = false; + autocompleteControl = new UntypedFormControl(); + + + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { controller: Controller }, + private formBuilder: UntypedFormBuilder, + private groupNameValidator: GroupNameValidator, + private groupService: GroupService, + private userService: UserService, + private toasterService: ToasterService) { + } + + ngOnInit(): void { + this.controller = this.data.controller; + this.groupNameForm = this.formBuilder.group({ + groupName: new UntypedFormControl( + null, + [Validators.required, this.groupNameValidator.get], + [groupNameAsyncValidator(this.data.controller, this.groupService)] + ), + }); + this.userService.list(this.controller) + .subscribe((users: User[]) => { + this.users = users; + this.filteredUsers = this.autocompleteControl.valueChanges.pipe( + startWith(''), + map(value => this._filter(value)), + ); + }) + } + + onKeyDown(event) { + if (event.key === 'Enter') { + this.onAddClick(); + } + } + + get form() { + return this.groupNameForm.controls; + } + + onAddClick() { + if (this.groupNameForm.invalid) { + return; + } + const groupName = this.groupNameForm.controls['groupName'].value; + const toAdd = Array.from(this.usersToAdd.values()); + + + this.groupService.addGroup(this.controller, groupName) + .subscribe((group) => { + toAdd.forEach((user: User) => { + this.groupService.addMemberToGroup(this.controller, group, user) + .subscribe(() => { + this.toasterService.success(`user ${user.username} was added`); + }, + (error) => { + this.toasterService.error(`An error occur while trying to add user ${user.username} to group ${groupName}`); + }) + }) + this.dialogRef.close(true); + }, (error) => { + this.toasterService.error(`An error occur while trying to create new group ${groupName}`); + this.dialogRef.close(false); + }); + } + + onNoClick() { + this.dialogRef.close(); + } + + selectedUser(user: User) { + this.usersToAdd.add(user); + } + + delUser(user: User) { + this.usersToAdd.delete(user); + } + + private _filter(value: string): User[] { + if (typeof value === 'string') { + const filterValue = value.toLowerCase(); + + return this.users.filter(option => option.username.toLowerCase().includes(filterValue) + || (option.email?.toLowerCase().includes(filterValue))); + } + } + + displayFn(value): string { + return value && value.username ? value.username : ''; + } + +} diff --git a/src/app/components/group-management/add-group-dialog/groupNameAsyncValidator.ts b/src/app/components/group-management/add-group-dialog/groupNameAsyncValidator.ts new file mode 100644 index 000000000..cfe724a8f --- /dev/null +++ b/src/app/components/group-management/add-group-dialog/groupNameAsyncValidator.ts @@ -0,0 +1,29 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { UntypedFormControl } from '@angular/forms'; +import { timer } from 'rxjs'; +import { map, switchMap, tap } from 'rxjs/operators'; +import { Controller } from "../../../models/controller"; +import { GroupService } from "../../../services/group.service"; + +export const groupNameAsyncValidator = (controller: Controller, groupService: GroupService) => { + return (control: UntypedFormControl) => { + return timer(500).pipe( + switchMap(() => groupService.getGroups(controller)), + map((response) => { + console.log(response); + return (response.find((n) => n.name === control.value) ? { projectExist: true } : null); + }) + ); + }; +}; diff --git a/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.html b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.html new file mode 100644 index 000000000..4ab223672 --- /dev/null +++ b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.html @@ -0,0 +1,8 @@ +

Are you sure to delete group named:

+

{{group.name}}

+
+ + +
diff --git a/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.scss b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.scss new file mode 100644 index 000000000..1b0fdabd0 --- /dev/null +++ b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.scss @@ -0,0 +1,6 @@ +:host { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.spec.ts b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.ts b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.ts new file mode 100644 index 000000000..b4af6d154 --- /dev/null +++ b/src/app/components/group-management/delete-group-dialog/delete-group-dialog.component.ts @@ -0,0 +1,37 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {Group} from "@models/groups/group"; + +@Component({ + selector: 'app-delete-group-dialog', + templateUrl: './delete-group-dialog.component.html', + styleUrls: ['./delete-group-dialog.component.scss'] +}) +export class DeleteGroupDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { groups: Group[] }) { } + + ngOnInit(): void { + } + + onCancel() { + this.dialogRef.close(); + } + + onDelete() { + this.dialogRef.close(true); + } +} diff --git a/src/app/components/group-management/group-management.component.html b/src/app/components/group-management/group-management.component.html new file mode 100644 index 000000000..5773ec49e --- /dev/null +++ b/src/app/components/group-management/group-management.component.html @@ -0,0 +1,81 @@ +
+
+
+

Groups management

+ + +
+
+ +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + Name{{element.name}} Creation date {{element.created_at}} Last update {{element.updated_at}} is build in {{element.is_builtin}}
+ + +
+
+ +
+ +
+
diff --git a/src/app/components/group-management/group-management.component.scss b/src/app/components/group-management/group-management.component.scss new file mode 100644 index 000000000..2b5547abf --- /dev/null +++ b/src/app/components/group-management/group-management.component.scss @@ -0,0 +1,26 @@ +table { + width: 100%; +} + +.full-width { + width: 940px; + margin-left: -470px; + left: 50%; +} + +.add-group-button { + height: 40px; + width: 160px; + margin: 20px; +} + +.loader { + position: absolute; + margin: auto; + height: 175px; + bottom: 0; + left: 0; + right: 0; + top: 0; + width: 175px; +} diff --git a/src/app/components/group-management/group-management.component.spec.ts b/src/app/components/group-management/group-management.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/group-management/group-management.component.ts b/src/app/components/group-management/group-management.component.ts new file mode 100644 index 000000000..6a459b5e8 --- /dev/null +++ b/src/app/components/group-management/group-management.component.ts @@ -0,0 +1,133 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core'; +import {ActivatedRoute, Router} from "@angular/router"; +import {ControllerService} from "../../services/controller.service"; +import {ToasterService} from "../../services/toaster.service"; +import {GroupService} from "../../services/group.service"; +import {Controller} from "../../models/controller"; +import {Group} from "../../models/groups/group"; +import {MatSort, Sort} from "@angular/material/sort"; +import {MatDialog} from "@angular/material/dialog"; +import {AddGroupDialogComponent} from "@components/group-management/add-group-dialog/add-group-dialog.component"; +import {DeleteGroupDialogComponent} from "@components/group-management/delete-group-dialog/delete-group-dialog.component"; +import {SelectionModel} from "@angular/cdk/collections"; +import {forkJoin} from "rxjs"; +import {MatPaginator} from "@angular/material/paginator"; +import {MatTableDataSource} from "@angular/material/table"; + + +@Component({ + selector: 'app-group-management', + templateUrl: './group-management.component.html', + styleUrls: ['./group-management.component.scss'] +}) +export class GroupManagementComponent implements OnInit { + controller: Controller; + + @ViewChildren('groupsPaginator') groupsPaginator: QueryList; + @ViewChildren('groupsSort') groupsSort: QueryList; + + public displayedColumns = ['select', 'name', 'created_at', 'updated_at', 'is_builtin', 'delete']; + selection = new SelectionModel(true, []); + groups: Group[]; + dataSource = new MatTableDataSource(); + searchText: string; + isReady = false; + + constructor( + private route: ActivatedRoute, + private controllerService: ControllerService, + private toasterService: ToasterService, + public groupService: GroupService, + public dialog: MatDialog + ) { + } + + + ngOnInit(): void { + const controllerId = this.route.parent.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.controller = controller; + this.refresh(); + }); + } + + ngAfterViewInit() { + this.groupsPaginator.changes.subscribe((comps: QueryList ) => + { + this.dataSource.paginator = comps.first; + }); + this.groupsSort.changes.subscribe((comps: QueryList) => { + this.dataSource.sort = comps.first; + }); + this.dataSource.sortingDataAccessor = (item, property) => { + switch (property) { + case 'name': + return item[property] ? item[property].toLowerCase() : ''; + default: + return item[property]; + } + }; + } + + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.groups.length; + return numSelected === numRows; + } + + masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.groups.forEach(row => this.selection.select(row)); + } + + addGroup() { + this.dialog + .open(AddGroupDialogComponent, {width: '600px', height: '500px', data: {controller: this.controller}}) + .afterClosed() + .subscribe((added: boolean) => { + if (added) { + this.refresh(); + } + }); + } + + refresh() { + this.groupService.getGroups(this.controller).subscribe((groups: Group[]) => { + this.isReady = true; + this.groups = groups; + this.dataSource.data = groups; + this.selection.clear(); + }); + } + + onDelete(groupsToDelete: Group[]) { + this.dialog + .open(DeleteGroupDialogComponent, {width: '500px', height: '250px', data: {groups: groupsToDelete}}) + .afterClosed() + .subscribe((isDeletedConfirm) => { + if (isDeletedConfirm) { + const observables = groupsToDelete.map((group: Group) => this.groupService.delete(this.controller, group.user_group_id)); + forkJoin(observables) + .subscribe(() => { + this.refresh(); + }, + (error) => { + this.toasterService.error(`An error occur while trying to delete group`); + }); + } + }); + } +} diff --git a/src/app/components/help/help.component.html b/src/app/components/help/help.component.html index d6f11ce53..85b7edd6c 100644 --- a/src/app/components/help/help.component.html +++ b/src/app/components/help/help.component.html @@ -21,7 +21,8 @@ Third party components -
+ +
diff --git a/src/app/components/help/help.component.scss b/src/app/components/help/help.component.scss index 6e0e106ff..a74bf1261 100644 --- a/src/app/components/help/help.component.scss +++ b/src/app/components/help/help.component.scss @@ -2,3 +2,10 @@ width: 100%; margin-top: 20px; } +a { + color: #f8f9fa; + font-family: Roboto, "Helvetica Neue", sans-serif; + font-size: 14px; + font-weight: 400; + text-decoration: none; +} diff --git a/src/app/components/help/help.component.ts b/src/app/components/help/help.component.ts index 57d9d1b2b..285fed877 100644 --- a/src/app/components/help/help.component.ts +++ b/src/app/components/help/help.component.ts @@ -19,7 +19,7 @@ export class HelpComponent implements OnInit { }, (error) => { if (error.status === 404) { - this.thirdpartylicenses = 'File not found'; + this.thirdpartylicenses = 'Download Solar-PuTTY'; } } ); diff --git a/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.html b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.html new file mode 100644 index 000000000..6d9034084 --- /dev/null +++ b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.html @@ -0,0 +1,105 @@ +
+
+
+
Would you like to automatically install appliances for this image?
+
+
+ +
+
+ +
+ + + Yes + + + No + + +
+
+ +
+
+ +
+
+
+
Please Select image
+

Uploaded image details

+
+
+ + +
+
+ +
+
+ + +
+
+ + {{ i + 1 }}. {{ img.isError ? 'Image ' : '' }} {{ img?.some?.name }} + {{ img.isError ? ' already exists' : '' }} + +
+
+ + + +
+
+ {{ uploadProgress.progress + ' %' }} +
+
+ {{ '0 %' }} +
+
+
+ +
+
diff --git a/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.scss b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.scss new file mode 100644 index 000000000..2e50dcab8 --- /dev/null +++ b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.scss @@ -0,0 +1,84 @@ +.progress-bar { + padding: 0; + } + .progress { + width: 50px; + background-color: #263238; + height: 28px; + margin-left: 13px; + } + .mat-input-element { + font-size: medium; + font-weight: 200; + } + #fileInput { + position: absolute; + cursor: pointer; + z-index: 10; + opacity: 0; + height: 100%; + left: 0px; + top: 0px; + } + .mat-toolbar-single-row { + height: auto; + background: transparent; + padding: 0; + } + .mat-toolbar-single-row button { + width: 100px; + } + .mat-form-field { + width: 100%; + } + .message { + background-color: #ddd; + padding: 15px; + color: #333; + border: #aaa solid 1px; + border-radius: 4px; + margin: 15px 0; + } + .preview { + max-width: 200px; + vertical-align: middle; + } + .list-card { + margin-top: 20px; + } + .list-item { + margin-bottom: 20px; + } + + .non-visible { + display: none; + } + + mat-progress-bar{ + margin-top: 10px; + } + .txt-align{ + text-align: end; + } + .uploaded-text{ + color: #0ca8c7; + font-size: 17px; + } + .uploaded-error-text{ + color: #d52435; + font-weight: 600; + } + + .choose-instal-appliance { + display: flex; + flex-direction: row; + margin: 15px 0px 11px 0px; + align-items: flex-start; + } + + .instal-appliances-button { + margin: 11px; + } + + + \ No newline at end of file diff --git a/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.spec.ts b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.spec.ts new file mode 100644 index 000000000..0e3190414 --- /dev/null +++ b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.spec.ts @@ -0,0 +1,66 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialog, MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { ImageManagerService } from 'app/services/image-manager.service'; +import { ControllerService } from '../../../services/controller.service'; +import { MockedControllerService } from '../../../services/controller.service.spec'; +import { of } from 'rxjs'; +import{ Controller } from '../../../models/controller'; + +import { AddImageDialogComponent } from './add-image-dialog.component'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ToasterService } from 'app/services/toaster.service'; +import { MockedToasterService } from 'app/services/toaster.service.spec'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; + +export class MockedImageManagerService { + public getImages(controller:Controller ) { + return of(); + } + +} + +describe('AddImageDialogComponent', () => { + let component: AddImageDialogComponent; + let fixture: ComponentFixture; + + let mockedControllerService = new MockedControllerService(); + let mockedImageManagerService = new MockedImageManagerService() + let mockedToasterService = new MockedToasterService() + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports:[ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule, + MatSnackBarModule + ], + providers: [ + { provide: ControllerService, useValue: mockedControllerService }, + { provide: ImageManagerService, useValue: mockedImageManagerService }, + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: MatDialogRef, useValue: {} }, + { provide: ToasterService, useValue: mockedToasterService }, + ], + declarations: [ AddImageDialogComponent ], + schemas: [NO_ERRORS_SCHEMA], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AddImageDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.ts b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.ts new file mode 100644 index 000000000..392e60639 --- /dev/null +++ b/src/app/components/image-manager/add-image-dialog/add-image-dialog.component.ts @@ -0,0 +1,111 @@ +import { animate, state, style, transition, trigger } from '@angular/animations'; +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { UploadServiceService } from 'app/common/uploading-processbar/upload-service.service'; +import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; +import{ Controller } from '../../../models/controller'; +import { ImageManagerService } from '../../../services/image-manager.service'; +import { ToasterService } from '../../../services/toaster.service'; + +@Component({ + selector: 'app-add-image-dialog', + templateUrl: './add-image-dialog.component.html', + styleUrls: ['./add-image-dialog.component.scss'], + animations: [ + trigger('detailExpand', [ + state('collapsed', style({ height: '0px', minHeight: '0', visibility: 'hidden' })), + state('expanded', style({ height: '*', visibility: 'visible' })), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ], +}) +export class AddImageDialogComponent implements OnInit { + controller:Controller ; + isInstallAppliance: boolean = false; + install_appliance: boolean = false; + selectFile: any = []; + uploaderImage: FileUploader; + uploadProgress: number = 0; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: any, + public dialogRef: MatDialogRef, + private imageService: ImageManagerService, + private toasterService: ToasterService, + private uploadServiceService: UploadServiceService + ) {} + + public ngOnInit() { + this.controller = this.data; + + this.uploaderImage = new FileUploader({url: ''}); + this.uploaderImage.onAfterAddingFile = (file) => { + file.withCredentials = false; + }; + + this.uploaderImage.onErrorItem = ( + item: FileItem, + response: string, + status: number, + headers: ParsedResponseHeaders + ) => { + let responseData = { + name: item.file.name, + message: JSON.parse(response), + }; + this.toasterService.error(responseData?.message.message); + }; + + this.uploaderImage.onSuccessItem = ( + item: FileItem, + response: string, + status: number, + headers: ParsedResponseHeaders + ) => { + let responseData = { + filename: item.file.name, + message: JSON.parse(response), + }; + this.toasterService.success('Image ' + responseData?.message.filename + ' imported succesfully' ); + }; + this.uploaderImage.onProgressItem = (progress: any) => { + this.uploadProgress = progress; + }; + } + + cancelUploading() { + this.uploaderImage.clearQueue(); + this.dialogRef.close(); + this.uploadServiceService.processBarCount(null); + this.toasterService.warning('Image file Uploading canceled'); + } + + selectInstallApplianceOption(ev) { + this.install_appliance = ev.value; + } + + async uploadImageFile(event) { + for (let imgFile of event) { + this.selectFile.push(imgFile); + } + await this.importImageFile(); + } + + // files uploading + importImageFile() { + this.selectFile.forEach((event, i) => { + let fileName = event.name; + let file = event; + let fileReader: FileReader = new FileReader(); + fileReader.onloadend = () => { + const url = this.imageService.getImagePath(this.controller, this.install_appliance, fileName); + const itemToUpload = this.uploaderImage.queue[i]; + itemToUpload.url = url; + if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; + (itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.controller.authToken }]; + this.uploaderImage.uploadItem(itemToUpload); + }; + fileReader.readAsText(file); + }); + } +} diff --git a/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.html b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.html new file mode 100644 index 000000000..72a4d605c --- /dev/null +++ b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.html @@ -0,0 +1,34 @@ +
+

Do you want delete all files ?.

+
+

Your selected files

+

{{i+1}}. {{file?.filename}}

+
+
+ + +
+
+
+

Please wait.

+ +
+ + +
+
+ +
+
+
+
Images can't be deleted because image used in one or more template.
+

{{i+1}}. {{message?.error?.message}}

+
+
+
{{fileNotDeleted.length}} Images deleted successfully.
+
+
+
+ +
+
\ No newline at end of file diff --git a/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.scss b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.scss new file mode 100644 index 000000000..f962e55b7 --- /dev/null +++ b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.scss @@ -0,0 +1,11 @@ +.delete-text{ + color: #0ca8c7; + font-size: 17px; + } + +.deleted-error-text{ + color: #d52435; + font-weight: 600; +} + + \ No newline at end of file diff --git a/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.spec.ts b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.spec.ts new file mode 100644 index 000000000..eeb3a8d92 --- /dev/null +++ b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.spec.ts @@ -0,0 +1,65 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { ToasterService } from 'app/services/toaster.service'; +import { MockedToasterService } from 'app/services/toaster.service.spec'; +import { Server } from 'http'; +import { of } from 'rxjs'; +import { ImageManagerService } from '../../../services/image-manager.service'; +import { ControllerService } from '../../../services/controller.service'; +import { MockedControllerService } from '../../../services/controller.service.spec'; +import { ImageManagerComponent } from '../image-manager.component'; + +import { DeleteAllImageFilesDialogComponent } from './deleteallfiles-dialog.component'; + +export class MockedImageManagerService { + public deleteALLFile(controller:Server , image_path) { + return of(); + } +} + + describe('DeleteAllImageFilesDialogComponent', () => { + let component: DeleteAllImageFilesDialogComponent; + let fixture: ComponentFixture; + let mockedControllerService = new MockedControllerService(); + let mockedImageManagerService = new MockedImageManagerService() + let mockedToasterService = new MockedToasterService() + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule, + ], + providers: [ + { provide: ControllerService, useValue: mockedControllerService }, + { provide: ImageManagerService, useValue: mockedImageManagerService }, + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: MatDialogRef, useValue: {} }, + { provide: ToasterService, useValue: mockedToasterService }, + + ], + declarations: [DeleteAllImageFilesDialogComponent, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DeleteAllImageFilesDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.ts b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.ts new file mode 100644 index 000000000..99077c720 --- /dev/null +++ b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.ts @@ -0,0 +1,50 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ImageManagerService } from '../../../services/image-manager.service'; +import { ToasterService } from '../../../services/toaster.service'; +import { Observable, of } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { ImageData } from '../../../models/images'; + +@Component({ + selector: 'app-deleteallfiles-dialog', + templateUrl: './deleteallfiles-dialog.component.html', + styleUrls: ['./deleteallfiles-dialog.component.scss'] +}) +export class DeleteAllImageFilesDialogComponent implements OnInit { + isDelete: boolean = false; + isUsedFiles: boolean = false; + deleteFliesDetails: ImageData = [] + fileNotDeleted: ImageData = [] + + constructor( + @Inject(MAT_DIALOG_DATA) public deleteData: any, + public dialogRef: MatDialogRef, + private imageService: ImageManagerService, + private toasterService: ToasterService + ) { } + + ngOnInit(): void { + } + + async deleteAll() { + this.isDelete = true + await this.deleteFile() + } + + deleteFile() { + const calls = []; + this.deleteData.deleteFilesPaths.forEach(pathElement => { + calls.push(this.imageService.deleteFile(this.deleteData.controller, pathElement.filename).pipe(catchError(error => of(error)))) + }); + Observable.forkJoin(calls).subscribe(responses => { + this.deleteFliesDetails = responses.filter(x => x !== null) + this.fileNotDeleted = responses.filter(x => x === null) + this.isUsedFiles = true; + this.isDelete = true + }); + + } + + +} diff --git a/src/app/components/image-manager/image-database-file.ts b/src/app/components/image-manager/image-database-file.ts new file mode 100644 index 000000000..d328229ae --- /dev/null +++ b/src/app/components/image-manager/image-database-file.ts @@ -0,0 +1,36 @@ + + +import { DataSource, SelectionModel } from '@angular/cdk/collections'; +import { MatSort } from '@angular/material/sort'; +import { BehaviorSubject, Observable, Subscription, merge } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Image } from '../../models/images'; + + +export class imageDatabase { + dataChange: BehaviorSubject = new BehaviorSubject([]); + get data(): Image[] { + return this.dataChange.value; + } + + public addImages(fileData: Image[]) { + this.dataChange.next(fileData); + } + +} + +export class imageDataSource extends DataSource { + constructor(private controllerDatabase: imageDatabase) { + super(); + } + + connect(): Observable { + return merge(this.controllerDatabase.dataChange).pipe( + map(() => { + return this.controllerDatabase.data; + }) + ); + } + + disconnect() { } +} diff --git a/src/app/components/image-manager/image-manager.component.html b/src/app/components/image-manager/image-manager.component.html new file mode 100644 index 000000000..daad9e157 --- /dev/null +++ b/src/app/components/image-manager/image-manager.component.html @@ -0,0 +1,70 @@ +
+
+
+
+

Image Manager

+
+
+ +
+
+ + +
+
+ + +
+ + + + + + + + + + + + + + + File Name + + {{ row.filename }} + + + + + Image Type + {{ row.image_type }} + + + + Image Size + {{ (row.image_size/1000000).toFixed()}} MB + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/src/app/components/image-manager/image-manager.component.scss b/src/app/components/image-manager/image-manager.component.scss new file mode 100644 index 000000000..6eb9f60fa --- /dev/null +++ b/src/app/components/image-manager/image-manager.component.scss @@ -0,0 +1,24 @@ +.non-visible { + display: none; + } + +.img-btn{ + margin: auto; + } +.btn-box{ + display: flex; + margin-top: 10px; +} + +mat-header-cell, mat-cell { + justify-content: center; +} +mat-cell, mat-header-cell, mat-footer-cell { + flex: 1; + display: flex; + align-items: center; + overflow: initial; + min-height: inherit; +} + + \ No newline at end of file diff --git a/src/app/components/image-manager/image-manager.component.spec.ts b/src/app/components/image-manager/image-manager.component.spec.ts new file mode 100644 index 000000000..4d1d9e868 --- /dev/null +++ b/src/app/components/image-manager/image-manager.component.spec.ts @@ -0,0 +1,96 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { ImageManagerService } from 'app/services/image-manager.service'; +import { ControllerService } from 'app/services/controller.service'; +import { MockedControllerService } from 'app/services/controller.service.spec'; +import { of } from 'rxjs'; +import{ Controller } from '../../models/controller'; + +import { ImageManagerComponent } from './image-manager.component'; +import { Image } from '../../models/images'; +import { ProgressService } from 'app/common/progress/progress.service'; +import { MockedProgressService } from '../project-map/project-map.component.spec'; +import { MockedActivatedRoute } from '../preferences/preferences.component.spec'; +import { ActivatedRoute } from '@angular/router'; +import { MockedVersionService } from '../../services/version.service.spec'; +import { VersionService } from 'app/services/version.service'; +import { ToasterService } from 'app/services/toaster.service'; +import { MockedToasterService } from 'app/services/toaster.service.spec'; + +export class MockedImageManagerService { + public getImages(controller:Controller ) { + return of(); + } + + public deleteFile(controller:Controller , image_path) { + return of(); + } + +} + +describe('ImageManagerComponent', () => { + let component: ImageManagerComponent; + let fixture: ComponentFixture; + + let mockedControllerService = new MockedControllerService(); + let mockedImageManagerService = new MockedImageManagerService() + let mockedProgressService = new MockedProgressService() + let mockedVersionService = new MockedVersionService() + let mockedToasterService = new MockedToasterService() + let activatedRoute = new MockedActivatedRoute().get(); + + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule + ], + providers: [ + { + provide: ActivatedRoute, + useValue: activatedRoute, + }, + { provide: ControllerService, useValue: mockedControllerService }, + { provide: ImageManagerService, useValue: mockedImageManagerService }, + { provide: ProgressService, useValue: mockedProgressService }, + { provide: VersionService, useValue: mockedVersionService }, + { provide: ToasterService, useValue: mockedToasterService }, + ], + declarations: [ImageManagerComponent], + schemas: [NO_ERRORS_SCHEMA], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImageManagerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + + it('should call save images', () => { + spyOn(mockedImageManagerService, 'getImages').and.returnValue(of({} as Image)); + component.getImages() + expect(mockedImageManagerService.getImages).toHaveBeenCalled(); + }); + + it('should delete image', () => { + spyOn(mockedImageManagerService, 'deleteFile').and.returnValue(of({} as Image)); + component.deleteFile('image_path') + expect(mockedImageManagerService.deleteFile).toHaveBeenCalled(); + }); +}); diff --git a/src/app/components/image-manager/image-manager.component.ts b/src/app/components/image-manager/image-manager.component.ts new file mode 100644 index 000000000..7ccd3d31f --- /dev/null +++ b/src/app/components/image-manager/image-manager.component.ts @@ -0,0 +1,149 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ControllerService } from '../../services/controller.service'; +import { VersionService } from '../../services/version.service'; +import { ProgressService } from 'app/common/progress/progress.service'; +import { Image } from '../../models/images'; +import{ Controller } from '../../models/controller'; +import { ImageManagerService } from "../../services/image-manager.service"; +import { DataSource, SelectionModel } from '@angular/cdk/collections'; +import { AddImageDialogComponent } from './add-image-dialog/add-image-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { ToasterService } from '../../services/toaster.service'; +import { DeleteAllImageFilesDialogComponent } from './deleteallfiles-dialog/deleteallfiles-dialog.component'; +import { imageDataSource, imageDatabase } from "./image-database-file"; + +@Component({ + selector: 'app-image-manager', + templateUrl: './image-manager.component.html', + styleUrls: ['./image-manager.component.scss'] +}) +export class ImageManagerComponent implements OnInit { + controller:Controller ; + public version: string; + dataSource: imageDataSource; + imageDatabase = new imageDatabase(); + isAllDelete: boolean = false + selection = new SelectionModel(true, []); + + displayedColumns = ['select', 'filename', 'image_type', 'image_size','delete']; + + constructor( + private imageService: ImageManagerService, + private progressService: ProgressService, + private route: ActivatedRoute, + private controllerService: ControllerService, + private versionService: VersionService, + private dialog: MatDialog, + private toasterService: ToasterService, + + ) { } + + ngOnInit(): void { + let controller_id = parseInt(this.route.snapshot.paramMap.get('controller_id')); + this.controllerService.get(controller_id).then((controller:Controller ) => { + this.controller = controller; + if (controller.authToken) { + this.getImages() + } + // this.versionService.get(this.controller).subscribe((version: Version) => { + // this.version = version.version; + // }); + }); + this.dataSource = new imageDataSource(this.imageDatabase); + } + + getImages() { + this.imageService.getImages(this.controller).subscribe( + (images: Image[]) => { + this.imageDatabase.addImages(images) + }, + (error) => { + this.toasterService.error(error.error.message) + + } + ); + } + + deleteFile(path) { + this.imageService.deleteFile(this.controller, path).subscribe( + (res) => { + this.getImages() + this.unChecked() + this.toasterService.success('File deleted'); + }, + (error) => { + this.getImages() + this.unChecked() + this.toasterService.error(error.error.message) + } + ); + } + + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.imageDatabase.data.length; + return numSelected === numRows; + } + + selectAllImages() { + this.isAllSelected() ? this.unChecked() : this.allChecked() + } + + unChecked() { + this.selection.clear() + this.isAllDelete = false + } + + allChecked() { + this.imageDatabase.data.forEach(row => this.selection.select(row)) + this.isAllDelete = true; + } + + public addImageDialog() { + const dialogRef = this.dialog.open(AddImageDialogComponent, { + width: '600px', + maxHeight: '550px', + autoFocus: false, + disableClose: true, + data: this.controller + }); + + dialogRef.afterClosed().subscribe((isAddes: boolean) => { + if (isAddes) { + this.getImages() + this.unChecked() + } else { + this.getImages() + this.unChecked() + return false; + } + }); + } + + deleteAllFiles() { + const dialogRef = this.dialog.open(DeleteAllImageFilesDialogComponent, { + width: '550px', + maxHeight: '650px', + autoFocus: false, + disableClose: true, + data: { + controller: this.controller, + deleteFilesPaths: this.selection.selected + } + }); + + dialogRef.afterClosed().subscribe((isAllfilesdeleted: boolean) => { + if (isAllfilesdeleted) { + this.unChecked() + this.getImages() + this.toasterService.success('All files deleted'); + } else { + this.unChecked() + this.getImages() + return false; + } + }); + } +} + diff --git a/src/app/components/installed-software/install-software/install-software.component.spec.ts b/src/app/components/installed-software/install-software/install-software.component.spec.ts index 9d88320ef..d40cd123e 100644 --- a/src/app/components/installed-software/install-software/install-software.component.spec.ts +++ b/src/app/components/installed-software/install-software/install-software.component.spec.ts @@ -1,15 +1,19 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ElectronService, ElectronServiceRef } from 'ngx-electron'; import { InstallSoftwareComponent } from './install-software.component'; describe('InstallSoftwareComponent', () => { let component: InstallSoftwareComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async () => { TestBed.configureTestingModule({ declarations: [InstallSoftwareComponent], + providers: [ + { provide: ElectronService, useValue: {} }, + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(InstallSoftwareComponent); @@ -17,7 +21,7 @@ describe('InstallSoftwareComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/installed-software/install-software/install-software.component.ts b/src/app/components/installed-software/install-software/install-software.component.ts index 7e1cd18ac..01bd1df64 100644 --- a/src/app/components/installed-software/install-software/install-software.component.ts +++ b/src/app/components/installed-software/install-software/install-software.component.ts @@ -17,17 +17,21 @@ export class InstallSoftwareComponent implements OnInit, OnDestroy, OnChanges { public readyToInstall = true; public buttonText: string; - constructor(private electronService: ElectronService) {} + constructor(private electronService: ElectronService) { } ngOnInit() { - this.electronService.ipcRenderer.on(this.responseChannel, (event, data) => { - this.updateButton(); - this.installedChanged.emit(data); - }); + if (this.electronService && this.electronService.ipcRenderer) { + this.electronService.ipcRenderer.on(this.responseChannel, (event, data) => { + this.updateButton(); + this.installedChanged.emit(data); + }); + } } ngOnDestroy() { - this.electronService.ipcRenderer.removeAllListeners(this.responseChannel); + if (this.electronService && this.electronService.ipcRenderer) { + this.electronService.ipcRenderer.removeAllListeners(this.responseChannel); + } } ngOnChanges() { diff --git a/src/app/components/installed-software/installed-software.component.spec.ts b/src/app/components/installed-software/installed-software.component.spec.ts index d1c8d2ea1..9d11cf61e 100644 --- a/src/app/components/installed-software/installed-software.component.spec.ts +++ b/src/app/components/installed-software/installed-software.component.spec.ts @@ -1,15 +1,26 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ExternalSoftwareDefinitionService } from 'app/services/external-software-definition.service'; +import { InstalledSoftwareService } from 'app/services/installed-software.service'; +import { PlatformService } from 'app/services/platform.service'; +import { ElectronService } from 'ngx-electron'; import { InstalledSoftwareComponent } from './installed-software.component'; describe('InstalledSoftwareComponent', () => { let component: InstalledSoftwareComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [InstalledSoftwareComponent], + providers: [ + InstalledSoftwareService, + ElectronService, + ExternalSoftwareDefinitionService, + PlatformService + ], + }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(InstalledSoftwareComponent); @@ -17,7 +28,7 @@ describe('InstalledSoftwareComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/login/login.component.html b/src/app/components/login/login.component.html new file mode 100644 index 000000000..430357732 --- /dev/null +++ b/src/app/components/login/login.component.html @@ -0,0 +1,42 @@ +
+
+ +
+
+ + +
+

GNS3

+
v{{ version }}
+
+
+
+ +
+ + + You must enter username + + + + You must enter password + +
+ Remember me +
+ +
+
+ +
+ Authentication was unsuccessful +
+
+
diff --git a/src/app/components/login/login.component.scss b/src/app/components/login/login.component.scss new file mode 100644 index 000000000..dbdd4dd70 --- /dev/null +++ b/src/app/components/login/login.component.scss @@ -0,0 +1,41 @@ +mat-form-field { + width: 100%; +} + +.wrapper { + display: flex; + justify-content: center; +} + +.loginCard { + width: 540px; +} + +.mat-icon-login { + height: 100px !important; + width: 100px !important; +} + +.loginTitle { + display: flex; + justify-content: center; +} + +.loginIcon { + display: flex; + align-items: center; +} + +.loginButton { + width: 100%; +} + +.errorMessage { + display: flex; + justify-content: center; + margin-top: 20px; +} + +.margin-left { + margin-left: 5px; +} \ No newline at end of file diff --git a/src/app/components/login/login.component.spec.ts b/src/app/components/login/login.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts new file mode 100644 index 000000000..7f012ee39 --- /dev/null +++ b/src/app/components/login/login.component.ts @@ -0,0 +1,123 @@ +import { Component, DoCheck, OnInit, ViewEncapsulation } from '@angular/core'; +import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { AuthResponse } from '../../models/authResponse'; +import{ Controller } from '../../models/controller'; +import { Version } from '../../models/version'; +import { LoginService } from '../../services/login.service'; +import { ControllerDatabase } from '../../services/controller.database'; +import { ControllerService } from '../../services/controller.service'; +import { ThemeService } from '../../services/theme.service'; +import { ToasterService } from '../../services/toaster.service'; +import { VersionService } from '../../services/version.service'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'], + encapsulation: ViewEncapsulation.None, +}) +export class LoginComponent implements OnInit, DoCheck { + private controller:Controller ; + public version: string; + public isLightThemeEnabled: boolean = false; + public loginError: boolean = false; + public returnUrl: string = ''; + public isRememberMe: boolean = false; + public isRememberMeCheked: boolean = false; + + loginForm = new UntypedFormGroup({ + username: new UntypedFormControl('', [Validators.required]), + password: new UntypedFormControl('', [Validators.required]), + }); + + constructor( + private loginService: LoginService, + private controllerService: ControllerService, + private controllerDatabase: ControllerDatabase, + private route: ActivatedRoute, + private router: Router, + private toasterService: ToasterService, + private versionService: VersionService, + private themeService: ThemeService + ) {} + + async ngOnInit() { + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/'; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; + + if (controller.authToken) { + this.router.navigate(['/controller', this.controller.id, 'projects']); + } + + this.versionService.get(this.controller).subscribe((version: Version) => { + this.version = version.version; + }); + }); + + this.themeService.getActualTheme() === 'light' + ? (this.isLightThemeEnabled = true) + : (this.isLightThemeEnabled = false); + + let getCurrentUser = JSON.parse(localStorage.getItem(`isRememberMe`)) ?? null; + if (getCurrentUser && getCurrentUser.isRememberMe) { + this.loginForm.get('username').setValue(getCurrentUser.username); + this.loginForm.get('password').setValue(getCurrentUser.password); + this.isRememberMeCheked = getCurrentUser.isRememberMe; + } + } + + public login() { + if (this.loginForm.get('username').invalid || this.loginForm.get('password').invalid) { + this.toasterService.error('Please enter username and password'); + return; + } + + let username = this.loginForm.get('username').value; + let password = this.loginForm.get('password').value; + + this.loginService.login(this.controller, username, password).subscribe( + async (response: AuthResponse) => { + let controller = this.controller; + controller.authToken = response.access_token; + controller.username = username; + controller.password = password; + controller.tokenExpired = false; + await this.controllerService.update(controller); + + if (this.returnUrl.length <= 1) { + this.router.navigate(['/controller', this.controller.id, 'projects']); + } else { + this.router.navigateByUrl(this.returnUrl); + } + }, + (error) => { + this.loginError = true; + } + ); + } + + rememberMe(ev) { + if (ev.checked) { + let curren_user = { + username: this.loginForm.get('username').value, + password: this.loginForm.get('password').value, + isRememberMe: ev.checked, + }; + this.isRememberMeCheked = ev.checked; + localStorage.setItem(`isRememberMe`, JSON.stringify(curren_user)); + } else { + localStorage.removeItem(`isRememberMe`); + this.loginForm.reset(); + this.isRememberMe = ev.checked; + } + } + + ngDoCheck() { + if (this.loginForm.get('username').valid && this.loginForm.get('password').valid) { + this.isRememberMe = true; + } + } +} diff --git a/src/app/components/management/management.component.html b/src/app/components/management/management.component.html new file mode 100644 index 000000000..24f7e2ede --- /dev/null +++ b/src/app/components/management/management.component.html @@ -0,0 +1,9 @@ + + diff --git a/src/app/components/management/management.component.scss b/src/app/components/management/management.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/management/management.component.spec.ts b/src/app/components/management/management.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/management/management.component.ts b/src/app/components/management/management.component.ts new file mode 100644 index 000000000..8bb190e62 --- /dev/null +++ b/src/app/components/management/management.component.ts @@ -0,0 +1,40 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Component, OnInit } from '@angular/core'; +import {ActivatedRoute, Router} from "@angular/router"; +import {Controller} from "@models/controller"; +import {ControllerService} from "@services/controller.service"; + +@Component({ + selector: 'app-management', + templateUrl: './management.component.html', + styleUrls: ['./management.component.scss'] +}) +export class ManagementComponent implements OnInit { + + controller: Controller; + links = ['users', 'groups', 'roles', 'permissions']; + activeLink: string = this.links[0]; + + constructor( + private route: ActivatedRoute, + public router: Router, + private controllerService: ControllerService) { } + + ngOnInit(): void { + const controllerId = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.controller = controller; + }); + } +} diff --git a/src/app/components/page-not-found/page-not-found.component.html b/src/app/components/page-not-found/page-not-found.component.html index d4b33a2dc..22598e3ca 100644 --- a/src/app/components/page-not-found/page-not-found.component.html +++ b/src/app/components/page-not-found/page-not-found.component.html @@ -2,6 +2,6 @@

404 Page not found

- +
diff --git a/src/app/components/permissions-management/action-button/action-button.component.html b/src/app/components/permissions-management/action-button/action-button.component.html new file mode 100644 index 000000000..cac087407 --- /dev/null +++ b/src/app/components/permissions-management/action-button/action-button.component.html @@ -0,0 +1,6 @@ + diff --git a/src/app/components/permissions-management/action-button/action-button.component.scss b/src/app/components/permissions-management/action-button/action-button.component.scss new file mode 100644 index 000000000..fe2111dce --- /dev/null +++ b/src/app/components/permissions-management/action-button/action-button.component.scss @@ -0,0 +1,8 @@ +.allow { + background-color: green; + border-radius: unset !important; +} + +.deny { + background-color: darkred; +} diff --git a/src/app/components/permissions-management/action-button/action-button.component.spec.ts b/src/app/components/permissions-management/action-button/action-button.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/permissions-management/action-button/action-button.component.ts b/src/app/components/permissions-management/action-button/action-button.component.ts new file mode 100644 index 000000000..9cf23619b --- /dev/null +++ b/src/app/components/permissions-management/action-button/action-button.component.ts @@ -0,0 +1,38 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {PermissionActions} from "@models/api/permission"; + +@Component({ + selector: 'app-action-button', + templateUrl: './action-button.component.html', + styleUrls: ['./action-button.component.scss'] +}) +export class ActionButtonComponent implements OnInit { + + readonly DENY = 'DENY'; + readonly ALLOW = 'ALLOW'; + @Input() action: PermissionActions; + @Input() disabled = true; + @Output() update = new EventEmitter(); + + constructor() { } + + ngOnInit(): void { + } + + change() { + this.action === PermissionActions.DENY ? this.action = PermissionActions.ALLOW : this.action = PermissionActions.DENY; + this.update.emit(this.action); + } +} diff --git a/src/app/components/permissions-management/add-permission-line/add-permission-line.component.html b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.html new file mode 100644 index 000000000..4a743b78c --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.html @@ -0,0 +1,48 @@ +
+
+
+
+
+ +
+
+ +
+ +
+
+ + + +
+
+
+
+ + +
+
+
+ +
+ +
+
+
diff --git a/src/app/components/permissions-management/add-permission-line/add-permission-line.component.scss b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.scss new file mode 100644 index 000000000..aed624daf --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.scss @@ -0,0 +1,49 @@ +.box-border { + width: 100%; + margin-top: 20px; + border-bottom: 1px solid; +} + +.edit-mode { + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.information-box { + margin-left: 10px; + width: 100%; +} + +.information-box > div { + margin-bottom: 10px; +} + +.methods { + display: flex; + flex-direction: row; + align-items: center; +} + +.button-box { + display: flex; + flex-direction: column; + justify-content: space-around; +} + +.description { + width: 100%; + margin-left: 10px; + margin-right: 10px; +} + +.description > mat-form-field { + width: 100%; +} + +.not-edit { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; +} diff --git a/src/app/components/permissions-management/add-permission-line/add-permission-line.component.spec.ts b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.spec.ts new file mode 100644 index 000000000..bea06b2ba --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.spec.ts @@ -0,0 +1,132 @@ +/* tslint:disable:no-shadowed-variable */ +import {fakeAsync, TestBed, tick} from "@angular/core/testing"; +import {AddPermissionLineComponent} from "@components/permissions-management/add-permission-line/add-permission-line.component"; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {PermissionsService} from "@services/permissions.service"; +import {ToasterService} from "@services/toaster.service"; +import {Methods, Permission, PermissionActions} from "@models/api/permission"; +import {Controller} from "@models/controller"; +import {Observable, of, throwError} from "rxjs"; +import {HttpErrorResponse} from "@angular/common/http"; + +class MockApiInformationService { + +} + +class MockPermissionService { +} + +class MockToasterService { + +} + + +describe('AddPermissionLineComponent', () => { + beforeEach(async () => { + TestBed.configureTestingModule({ + providers: [ + AddPermissionLineComponent, + {provide: ApiInformationService, useClass: MockApiInformationService}, + {provide: PermissionsService, useClass: MockPermissionService}, + {provide: ToasterService, useClass: MockToasterService} + ] + }); + }); + + it('Should add GET method to method list', () => { + const comp = TestBed.inject(AddPermissionLineComponent); + comp.updateMethod({name: Methods.GET, enable: true}); + expect(comp.permission.methods).toContain(Methods.GET); + }); + + it('Should remove GET Method from list', () => { + const comp = TestBed.inject(AddPermissionLineComponent); + comp.permission.methods = [Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]; + comp.updateMethod({name: Methods.GET, enable: false}); + + expect(comp.permission.methods).not.toContain(Methods.GET); + }); + + it('Should not add same GET method a second time', () => { + const comp = TestBed.inject(AddPermissionLineComponent); + comp.permission.methods = [Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]; + comp.updateMethod({name: Methods.GET, enable: true}); + + expect(comp.permission.methods).toEqual([Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]); + }); + + it('Should reset permission values', () => { + const comp = TestBed.inject(AddPermissionLineComponent); + comp.permission.methods = [Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]; + comp.permission.path = "/test/path"; + comp.permission.action = PermissionActions.DENY; + comp.permission.description = "john doe is here"; + + comp.reset(); + const p = comp.permission; + + expect(p.methods).toEqual([]); + expect(p.action).toEqual(PermissionActions.ALLOW); + expect(p.description).toEqual(''); + }); + + it('Should save permission with success', fakeAsync(() => { + const comp = TestBed.inject(AddPermissionLineComponent); + const permissionService = TestBed.inject(PermissionsService); + const toasterService = TestBed.inject(ToasterService); + comp.permission.methods = [Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]; + comp.permission.path = "/test/path"; + comp.permission.action = PermissionActions.DENY; + comp.permission.description = "john doe is here"; + + permissionService.add = (controller: Controller, permission: Permission): Observable => { + return of(permission); + }; + + let message: string; + + toasterService.success = (m: string) => { + message = m; + }; + + comp.save(); + const p = comp.permission; + + tick(); + expect(message).toBeTruthy(); + expect(p.methods).toEqual([]); + expect(p.action).toEqual(PermissionActions.ALLOW); + expect(p.description).toEqual(''); + + })); + + it('Should throw error on rejected permission', fakeAsync(() => { + const comp = TestBed.inject(AddPermissionLineComponent); + const permissionService = TestBed.inject(PermissionsService); + const toasterService = TestBed.inject(ToasterService); + comp.permission.methods = [Methods.GET, Methods.PUT, Methods.POST, Methods.DELETE]; + comp.permission.path = "/test/path"; + comp.permission.action = PermissionActions.DENY; + comp.permission.description = "john doe is here"; + + let errorMessage: string; + + permissionService.add = (controller: Controller, permission: Permission): Observable => { + const error = new HttpErrorResponse({ + error: new Error("An error occur"), + headers: undefined, + status: 500, + statusText: 'error from controller' + }); + return throwError(error); + }; + + toasterService.error = (message: string) => { + errorMessage = message; + }; + + comp.save(); + tick(); + expect(errorMessage).toBeTruthy(); + })); +}); diff --git a/src/app/components/permissions-management/add-permission-line/add-permission-line.component.ts b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.ts new file mode 100644 index 000000000..5e6436fda --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/add-permission-line.component.ts @@ -0,0 +1,82 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {Controller} from "@models/controller"; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {Methods, Permission, PermissionActions} from "@models/api/permission"; +import {PermissionsService} from "@services/permissions.service"; +import {ToasterService} from "@services/toaster.service"; +import {HttpErrorResponse} from "@angular/common/http"; + +@Component({ + selector: 'app-add-permission-line', + templateUrl: './add-permission-line.component.html', + styleUrls: ['./add-permission-line.component.scss'] +}) +export class AddPermissionLineComponent implements OnInit { + + @Input() controller: Controller; + @Output() addPermissionEvent = new EventEmitter(); + permission: Permission = { + action: PermissionActions.ALLOW, + description: "", + methods: [], + path: "/" + }; + edit = false; + + constructor(public apiInformation: ApiInformationService, + private permissionService: PermissionsService, + private toasterService: ToasterService) { + + } + + ngOnInit(): void { + + } + + + updateMethod(data: { name: Methods; enable: boolean }) { + const set = new Set(this.permission.methods); + if (data.enable) { + set.add(data.name); + } else { + set.delete(data.name); + } + + this.permission.methods = Array.from(set); + } + + reset() { + this.permission = { + action: PermissionActions.ALLOW, + description: "", + methods: [], + path: "/", + }; + + this.edit = false; + } + + save() { + this.permissionService.add(this.controller, this.permission) + .subscribe(() => { + this.toasterService.success(`permission was created`); + this.reset(); + }, (error: HttpErrorResponse) => { + this.toasterService.error(` + ${error.message} + ${error.error.message}`); + }); + } +} diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.spec.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.spec.ts new file mode 100644 index 000000000..9c1f35fbd --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.spec.ts @@ -0,0 +1,82 @@ +import {PermissionPath} from "@components/permissions-management/add-permission-line/path-auto-complete/PermissionPath"; +import {SubPath} from "@components/permissions-management/add-permission-line/path-auto-complete/SubPath"; + +describe('PermissionPath', () => { + + it('Should add subPath to path', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + + expect(path.getPath()).toEqual(['projects', '1111-2222-3333-4444']); + }); + + it('Should return display path', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + + expect(path.getDisplayPath()).toEqual(['projects', 'my project']); + }); + + it('Should remove last element', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + path.add(new SubPath('nodes', 'nodes')); + path.add(new SubPath('6666-7777-8888-9999', 'myFirstNode', 'node_id')); + + path.removeLast(); + expect(path.getPath()).toEqual(['projects', '1111-2222-3333-4444', 'nodes']); + }); + + it('Should return path variables', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + path.add(new SubPath('nodes', 'nodes')); + path.add(new SubPath('6666-7777-8888-9999', 'myFirstNode', 'node_id')); + + expect(path.getVariables()) + .toEqual([{key: 'project_id', value: '1111-2222-3333-4444'}, { key: 'node_id', value: '6666-7777-8888-9999'}]); + }); + + + it('Should return true if subPath contain *', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + path.add(new SubPath('nodes', 'nodes')); + path.add(new SubPath('*', 'myFirstNode', 'node_id')); + + expect(path.containStar()).toBeTruthy(); + }); + + it('Should return false if subPath does not contain *', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + path.add(new SubPath('nodes', 'nodes')); + path.add(new SubPath('6666-7777-8888-999', 'myFirstNode', 'node_id')); + + expect(path.containStar()).toBeFalsy(); + }); + + + it('Should return true if path is empty', () => { + const path = new PermissionPath(); + expect(path.isEmpty()).toBeTruthy(); + }); + + + it('Should return false if path is not empty', () => { + const path = new PermissionPath(); + path.add(new SubPath('projects', 'projects', undefined)); + path.add(new SubPath('1111-2222-3333-4444', 'my project', 'project_id')); + path.add(new SubPath('nodes', 'nodes')); + path.add(new SubPath('6666-7777-8888-999', 'myFirstNode', 'node_id')); + + expect(path.isEmpty()).toBeFalsy(); + }); + +}); diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.ts new file mode 100644 index 000000000..5e84941b7 --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/PermissionPath.ts @@ -0,0 +1,56 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {SubPath} from "./SubPath"; + +export class PermissionPath { + private subPath: SubPath[] = []; + + constructor() { + } + + add(subPath: SubPath) { + this.subPath.push(subPath); + } + + getDisplayPath() { + return this.subPath + .map((subPath) => subPath.displayValue); + } + + removeLast() { + this.subPath.pop(); + } + + getPath() { + return this.subPath.map((subPath) => subPath.value); + } + + isEmpty() { + return this.subPath.length === 0; + } + + getVariables(): { key: string; value: string }[] { + return this.subPath + .filter((path) => path.key) + .map((path) => { + return {key: path.key, value: path.value}; + }); + } + + + containStar() { + return this.subPath + .map(subPath => subPath.value === '*') + .reduce((previous, next) => previous || next, false); + } +} diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/SubPath.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/SubPath.ts new file mode 100644 index 000000000..11fe2675c --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/SubPath.ts @@ -0,0 +1,24 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +export class SubPath { + + /** + * @param {value} original subPath value from gns3 api + * @param {displayValue} displayed value can replace a UUID from original URL + * @param {key} associate key ex: 'project_id' + */ + constructor(public value: string, + public displayValue: string, + public key?: string) { + } +} diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.spec.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.spec.ts new file mode 100644 index 000000000..fb5e7afa7 --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.spec.ts @@ -0,0 +1,37 @@ +import {FilterCompletePipe} from "@components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +describe('FilterCompletePipe', () => { + it('should remove items which not match searchText', function () { + const filter = new FilterCompletePipe(); + + const items: IGenericApiObject[] = [ + {id: 'b2afe0da-b83e-42a8-bcb6-e46ca1bd1747', name: 'test project 1'}, + {id: '698d35c1-9fd0-4b89-86dc-336a958b1f70', name: 'test project 2'}, + {id: '4bbd57e6-bf99-4387-8948-7e7d8e96de9b', name: 'test project 3'}, + {id: '29e9ddb6-1ba0-422d-b767-92592821f011', name: 'test project 4'}, + {id: '5a522134-0bfd-4864-b8b3-520bcecd4fc9', name: 'test project 5'}, + {id: '7e27f67a-2b63-4d00-936b-e3d8c7e2b751', name: 'test project 6'}, + ]; + + expect(filter.transform(items, 'test project 6')) + .toEqual([{id: '7e27f67a-2b63-4d00-936b-e3d8c7e2b751', name: 'test project 6'}]); + }); + + + it('should return entire list if searchText is empty', function () { + const filter = new FilterCompletePipe(); + + const items: IGenericApiObject[] = [ + {id: 'b2afe0da-b83e-42a8-bcb6-e46ca1bd1747', name: 'test project 1'}, + {id: '698d35c1-9fd0-4b89-86dc-336a958b1f70', name: 'test project 2'}, + {id: '4bbd57e6-bf99-4387-8948-7e7d8e96de9b', name: 'test project 3'}, + {id: '29e9ddb6-1ba0-422d-b767-92592821f011', name: 'test project 4'}, + {id: '5a522134-0bfd-4864-b8b3-520bcecd4fc9', name: 'test project 5'}, + {id: '7e27f67a-2b63-4d00-936b-e3d8c7e2b751', name: 'test project 6'}, + ]; + + expect(filter.transform(items, '')).toEqual(items); + expect(filter.transform(items, undefined)).toEqual(items); + }); +}); diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts new file mode 100644 index 000000000..9fcf0be06 --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Pipe, PipeTransform } from '@angular/core'; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +/** + * Pipe to filter autocomplete proposals + */ +@Pipe({ + name: 'filterComplete' +}) +export class FilterCompletePipe implements PipeTransform { + + transform(value: IGenericApiObject[], searchText: string): IGenericApiObject[] { + if (!searchText || searchText === '') { return value; } + + return value.filter((v) => { + return v.name.includes(searchText) || v.id.includes(searchText); + }); + } + +} diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.html b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.html new file mode 100644 index 000000000..b4297c5e5 --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.html @@ -0,0 +1,37 @@ +
+
Path: /
+
{{p}}/
+
+
+
+ + {{value}} + +
+
+ + + * + + {{data.name}} + + +
+
+
+ cancel + add_circle_outline + check_circle + +
+
+
diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.scss b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.scss new file mode 100644 index 000000000..2720f01ea --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.scss @@ -0,0 +1,22 @@ +.path { + display: flex; + flex-direction: row; + justify-content: flex-start; +} + +mat-select { + width: 150px; +} + +.edit-area { + border: 1px solid; +} + +.command-button { + margin-left: 5px; +} + +.path-edit-line { + display: flex; + flex-direction: row; +} diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.spec.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts new file mode 100644 index 000000000..c7441b3f1 --- /dev/null +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts @@ -0,0 +1,98 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {Controller} from "@models/controller"; +import {PermissionPath} from "@components/permissions-management/add-permission-line/path-auto-complete/PermissionPath"; +import {SubPath} from "@components/permissions-management/add-permission-line/path-auto-complete/SubPath"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +@Component({ + selector: 'app-path-auto-complete', + templateUrl: './path-auto-complete.component.html', + styleUrls: ['./path-auto-complete.component.scss'] +}) +export class PathAutoCompleteComponent implements OnInit { + + + @Output() update = new EventEmitter(); + @Input() controller: Controller; + path: PermissionPath = new PermissionPath(); + values: string[] = []; + private completeData: { data: IGenericApiObject[]; key: string }; + public mode: 'SELECT' | 'COMPLETE' | undefined; + completeField: string; + + constructor(private apiInformationService: ApiInformationService) { + + } + + updatePath(name: string, value: string, key?: string) { + this.path.add(new SubPath(name, value, key)); + this.update.emit('/' + this.path.getPath().join("/")); + } + + popPath() { + this.path.removeLast(); + this.update.emit('/' + this.path.getPath().join("/")); + } + + ngOnInit(): void { + } + + getNext() { + this.apiInformationService + .getPathNextElement(this.path.getPath()) + .subscribe((next: string[]) => { + if (this.path.containStar()) { + next = next.filter(item => !item.match(this.apiInformationService.bracketIdRegex)); + } + this.values = next; + this.mode = 'SELECT'; + }); + } + + removePrevious() { + if (this.mode) { + return this.mode = undefined; + } + if (!this.path.isEmpty()) { + return this.popPath(); + } + } + + valueChanged(value: string) { + if (value.match(this.apiInformationService.bracketIdRegex) && !this.path.containStar()) { + this.apiInformationService.getListByObjectId(this.controller, value, undefined, this.path.getVariables()) + .subscribe((data) => { + this.mode = 'COMPLETE'; + this.completeData = {data, key: value}; + }); + + } else { + this.updatePath(value, value); + this.mode = undefined; + } + } + + validComplete() { + if (this.completeField === '*') { + this.updatePath('*', '*'); + } else { + const data = this.completeData.data.find((d) => this.completeField === d.name); + this.updatePath(data.id, data.name, this.completeData.key); + } + this.mode = undefined; + this.completeField = undefined; + } +} diff --git a/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.html b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.html new file mode 100644 index 000000000..1983ebb8d --- /dev/null +++ b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.html @@ -0,0 +1,12 @@ +
+
confirm deleting permission:
+
{{data.permission_id}}
+
{{data.path}}
+
{{data.methods.join(',')}}
+
{{data.action}}
+
{{data.description}}
+
+
+ + +
diff --git a/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.scss b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.scss new file mode 100644 index 000000000..51a317947 --- /dev/null +++ b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.scss @@ -0,0 +1,18 @@ +.description { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + margin-top: 20px; +} + +.description > div { + margin-bottom: 10px; +} + +.button { + display: flex; + flex-direction: row; + justify-content: space-around; + margin-top: 20px; +} diff --git a/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.spec.ts b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.ts b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.ts new file mode 100644 index 000000000..cc1a149c0 --- /dev/null +++ b/src/app/components/permissions-management/delete-permission-dialog/delete-permission-dialog.component.ts @@ -0,0 +1,37 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {Permission} from "@models/api/permission"; + +@Component({ + selector: 'app-delete-permission-dialog', + templateUrl: './delete-permission-dialog.component.html', + styleUrls: ['./delete-permission-dialog.component.scss'] +}) +export class DeletePermissionDialogComponent implements OnInit { + + constructor(private dialog: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: Permission) { } + + ngOnInit(): void { + } + + cancel() { + this.dialog.close(false); + } + + confirm() { + this.dialog.close(true); + } +} diff --git a/src/app/components/permissions-management/display-path.pipe.spec.ts b/src/app/components/permissions-management/display-path.pipe.spec.ts new file mode 100644 index 000000000..d72a85168 --- /dev/null +++ b/src/app/components/permissions-management/display-path.pipe.spec.ts @@ -0,0 +1,57 @@ +import {async, fakeAsync, TestBed, tick} from "@angular/core/testing"; +import {DisplayPathPipe} from "@components/permissions-management/display-path.pipe"; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {Controller} from "@models/controller"; +import {Observable, of} from "rxjs"; +import {IExtraParams} from "@services/ApiInformation/IExtraParams"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +class MockApiInformationService { + +} + + +describe('DisplayPathPipe', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + providers: [ + DisplayPathPipe, + {provide: ApiInformationService, useClass: MockApiInformationService}] + }); + })); + + it('Should display human readable path', fakeAsync(() => { + const comp = TestBed.inject(DisplayPathPipe); + const apiService = TestBed.inject(ApiInformationService); + + apiService.getKeysForPath = (path: string): Observable<{ key: string; value: string }[]> => { + return of([ + {key: 'project_id', value: '1111-2222-3333'}, + {key: 'node_id', value: '2222-2222-2222'} + ]); + }; + + apiService + .getListByObjectId = (controller: Controller, key: string, value?: string, extraParams?: IExtraParams[]): Observable => { + if (key === 'project_id') { + return of([{id: '1111-2222-3333', name: 'myProject'}]); + } + if (key === 'node_id') { + return of([{id: '2222-2222-2222', name: 'node1'}]); + } + }; + + let result: string; + + const controller = new Controller(); + comp + .transform('/project/1111-2222-3333/nodes/2222-2222-2222', controller) + .subscribe((res: string) => { + result = res; + }); + + tick(); + expect(result).toEqual('/project/myProject/nodes/node1'); + })); +}); diff --git a/src/app/components/permissions-management/display-path.pipe.ts b/src/app/components/permissions-management/display-path.pipe.ts new file mode 100644 index 000000000..c7abac9fb --- /dev/null +++ b/src/app/components/permissions-management/display-path.pipe.ts @@ -0,0 +1,54 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Pipe, PipeTransform} from '@angular/core'; +import {map, switchMap} from "rxjs/operators"; +import {forkJoin, Observable, of} from "rxjs"; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {Controller} from "@models/controller"; + +@Pipe({ + name: 'displayPath' +}) +export class DisplayPathPipe implements PipeTransform { + + constructor(private apiInformation: ApiInformationService) { + } + + transform(originalPath: string, controller: Controller): Observable { + if (!controller) { + return of(originalPath); + } + return this.apiInformation + .getKeysForPath(originalPath) + .pipe(switchMap((values) => { + if (values.length === 0) { + return of([]); + } + const obs = values.map((k) => this.apiInformation.getListByObjectId(controller, k.key, k.value, values)); + return forkJoin(obs); + }), + map((values: { id: string; name: string }[][]) => { + let displayPath = `${originalPath}`; + values.forEach((value) => { + if (value[0].id && value[0].name) { + displayPath = displayPath.replace(value[0].id, value[0].name); + } else { + } + + }); + return displayPath; + }) + ); + } + +} diff --git a/src/app/components/permissions-management/method-button/method-button.component.html b/src/app/components/permissions-management/method-button/method-button.component.html new file mode 100644 index 000000000..4e4a10cc9 --- /dev/null +++ b/src/app/components/permissions-management/method-button/method-button.component.html @@ -0,0 +1,7 @@ + diff --git a/src/app/components/permissions-management/method-button/method-button.component.scss b/src/app/components/permissions-management/method-button/method-button.component.scss new file mode 100644 index 000000000..cc1b1778e --- /dev/null +++ b/src/app/components/permissions-management/method-button/method-button.component.scss @@ -0,0 +1,10 @@ +:host { + padding: unset !important; +} + +.enable { + color: green !important; +} +.disabled { + color: dimgrey; +} diff --git a/src/app/components/permissions-management/method-button/method-button.component.spec.ts b/src/app/components/permissions-management/method-button/method-button.component.spec.ts new file mode 100644 index 000000000..087ced034 --- /dev/null +++ b/src/app/components/permissions-management/method-button/method-button.component.spec.ts @@ -0,0 +1,53 @@ +import {async, fakeAsync, TestBed} from "@angular/core/testing"; +import {MethodButtonComponent} from "@components/permissions-management/method-button/method-button.component"; +import {Methods} from "@models/api/permission"; + +describe('MethodButtonComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({declarations: [MethodButtonComponent]}); + })); + + it('Should set text color to green when button is enable', fakeAsync(() => { + const fixture = TestBed.createComponent(MethodButtonComponent); + const component = fixture.componentInstance; + const debugElement = fixture.debugElement; + + component.enable = true; + + fixture.detectChanges(); + + expect(debugElement.nativeElement.querySelector('button').classList).toContain('enable'); + + })); + + it('Should switch to enable on button click', (() => { + const fixture = TestBed.createComponent(MethodButtonComponent); + const component = fixture.componentInstance; + fixture.detectChanges(); + + component.enable = false; + component.change(); + + expect(component.enable).toEqual(true); + + })); + + + it('Should emit event enable on button click', (() => { + const fixture = TestBed.createComponent(MethodButtonComponent); + const component = fixture.componentInstance; + fixture.detectChanges(); + + component.update.subscribe((data) => { + expect(data.enable).toEqual(true); + expect(data.name).toEqual(Methods.GET); + }); + + component.name = Methods.GET; + component.enable = false; + component.change(); + + })); + + +}); diff --git a/src/app/components/permissions-management/method-button/method-button.component.ts b/src/app/components/permissions-management/method-button/method-button.component.ts new file mode 100644 index 000000000..b9a2c3738 --- /dev/null +++ b/src/app/components/permissions-management/method-button/method-button.component.ts @@ -0,0 +1,38 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {Methods} from "@models/api/permission"; + +@Component({ + selector: 'app-method-button', + templateUrl: './method-button.component.html', + styleUrls: ['./method-button.component.scss'] +}) +export class MethodButtonComponent implements OnInit { + + @Input() enable = false; + @Input() name: Methods; + @Input() disabled = true; + + @Output() update = new EventEmitter<{name: Methods; enable: boolean}>(); + + constructor() { } + + ngOnInit(): void { + } + + change() { + this.enable = !this.enable; + this.update.emit({name: this.name, enable: this.enable}); + } +} diff --git a/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.html b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.html new file mode 100644 index 000000000..b2a58b23f --- /dev/null +++ b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.html @@ -0,0 +1,57 @@ +
+
+
+ +
+
+
+ +
+
+
+
+
+ {{permission.path | displayPath: controller | async}} +
+
+
+ + + +
+ +
+
+ + +
+
+ + +
+
+
diff --git a/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.scss b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.scss new file mode 100644 index 000000000..8d6e5890d --- /dev/null +++ b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.scss @@ -0,0 +1,28 @@ +.permission { + display: flex; + flex-direction: row; + justify-content: space-between; + border-bottom: solid 1px; + margin-top: 10px; + align-items: center; +} + +.action-button-bar { + display: flex; + flex-direction: row; +} + +.methods { + display: flex; + flex-direction: row; + border: 1px solid; +} + +.permission-input { + width: 300px; +} + +.button-bar > div > button { + padding: unset !important; +} + diff --git a/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.spec.ts b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.ts b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.ts new file mode 100644 index 000000000..df2fa8570 --- /dev/null +++ b/src/app/components/permissions-management/permission-edit-line/permission-edit-line.component.ts @@ -0,0 +1,81 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {Methods, Permission} from "@models/api/permission"; +import {Controller} from '@models/controller'; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {PermissionsService} from "@services/permissions.service"; +import {ToasterService} from "@services/toaster.service"; +import {MatDialog} from "@angular/material/dialog"; +import {DeletePermissionDialogComponent} from "@components/permissions-management/delete-permission-dialog/delete-permission-dialog.component"; + +@Component({ + selector: 'app-permission-add-edit-line', + templateUrl: './permission-edit-line.component.html', + styleUrls: ['./permission-edit-line.component.scss'] +}) +export class PermissionEditLineComponent { + @Input() permission: Permission; + @Input() controller: Controller; + + isEditable = false; + @Output() update = new EventEmitter(); + + constructor(public apiInformation: ApiInformationService, + private permissionService: PermissionsService, + private toasterService: ToasterService, + private dialog: MatDialog) { + } + + + onDelete() { + this.dialog.open(DeletePermissionDialogComponent, + {width: '700px', height: '500px', data: this.permission}) + .afterClosed() + .subscribe((confirm: boolean) => { + if (confirm) { + this.permissionService.delete(this.controller, this.permission.permission_id) + .subscribe(() => { + this.toasterService.success(`Permission was deleted`); + this.update.emit(); + }, (e) => { + this.toasterService.error(e); + this.update.emit(); + }); + } + }); + + } + + onSave() { + this.permissionService.update(this.controller, this.permission) + .subscribe(() => { + this.toasterService.success(`Permission was updated`); + this.update.emit(); + }, (e) => { + this.toasterService.error(e); + this.update.emit(); + }); + } + + onCancel() { + this.update.emit(); + } + + + onMethodUpdate(event: { name: Methods; enable: boolean }) { + const set = new Set(this.permission.methods); + event.enable ? set.add(event.name) : set.delete(event.name); + this.permission.methods = Array.from(set); + } +} diff --git a/src/app/components/permissions-management/permissions-filter.pipe.spec.ts b/src/app/components/permissions-management/permissions-filter.pipe.spec.ts new file mode 100644 index 000000000..418028175 --- /dev/null +++ b/src/app/components/permissions-management/permissions-filter.pipe.spec.ts @@ -0,0 +1,57 @@ +import {PermissionsFilterPipe} from './permissions-filter.pipe'; +import {Methods, Permission, PermissionActions} from "../../models/api/permission"; + +const testPermissions: Permission[] = [ + { + methods: [Methods.GET, Methods.PUT], + path: '/projects/projet-test', + action: PermissionActions.ALLOW, + description: 'description of permission 1', + created_at: "2022-03-15T09:45:36.531Z", + updated_at: "2022-03-15T09:45:36.531Z", + permission_id: '1' + }, + { + methods: [Methods.GET, Methods.PUT], + path: '/projects/projet-test/nodes', + action: PermissionActions.ALLOW, + description: 'permission on projet-test nodes', + created_at: "2022-03-15T09:45:36.531Z", + updated_at: "2022-03-15T09:45:36.531Z", + permission_id: '2' + }, + { + methods: [Methods.GET, Methods.PUT], + path: '/projects/projet-bidule', + action: PermissionActions.ALLOW, + description: 'permission on biduler project', + created_at: "2022-03-15T09:45:36.531Z", + updated_at: "2022-03-15T09:45:36.531Z", + permission_id: '3' + } +] + +describe('PermissionsFilterPipe', () => { + const pipe = new PermissionsFilterPipe(); + + it('create an instance', () => { + expect(pipe).toBeTruthy(); + }); + + it('Should return all test permissions', () => { + const res = pipe.transform(testPermissions, ''); + expect(res.length).toBe(3); + }); + + it('Should return both permissions concerning project projet-test', () => { + const res = pipe.transform(testPermissions, 'test'); + expect(res.length).toBe(2); + expect(res).toContain(testPermissions[0]); + expect(res).toContain(testPermissions[1]); + }); + + it('Should return no permissions', () => { + const res = pipe.transform(testPermissions, 'aaaaaa'); + expect(res.length).toBe(0); + }); +}); diff --git a/src/app/components/permissions-management/permissions-filter.pipe.ts b/src/app/components/permissions-management/permissions-filter.pipe.ts new file mode 100644 index 000000000..71b4e75f3 --- /dev/null +++ b/src/app/components/permissions-management/permissions-filter.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Pipe, PipeTransform } from '@angular/core'; +import {Permission} from "@models/api/permission"; + +@Pipe({ + name: 'permissionsFilter' +}) +export class PermissionsFilterPipe implements PipeTransform { + + transform(permissions: Permission[], filterText: string): Permission[] { + if (!permissions) { + return []; + } + if (filterText === undefined || filterText === null || filterText === '') { + return permissions; + } + + return permissions.filter((permissions: Permission) => permissions.path.toLowerCase().includes(filterText.toLowerCase())); + } + +} diff --git a/src/app/components/permissions-management/permissions-management.component.html b/src/app/components/permissions-management/permissions-management.component.html new file mode 100644 index 000000000..e0ae94c11 --- /dev/null +++ b/src/app/components/permissions-management/permissions-management.component.html @@ -0,0 +1,36 @@ +
+
+ +
+
+ + + + {{option.name}} + + + +
+ +
+ +
+
+ +
+ +
+
diff --git a/src/app/components/permissions-management/permissions-management.component.scss b/src/app/components/permissions-management/permissions-management.component.scss new file mode 100644 index 000000000..e7b3efa56 --- /dev/null +++ b/src/app/components/permissions-management/permissions-management.component.scss @@ -0,0 +1,36 @@ +.permission-content { + max-width: 1400px; +} + +.add-button { + height: 40px; + width: 160px; + margin: 20px; +} + +.loader { + position: absolute; + margin: auto; + height: 175px; + bottom: 0; + left: 0; + right: 0; + top: 0; + width: 175px; +} + +.add { + /* display: flex; + flex-direction: row; + justify-content: flex-end; + padding-right: 20px; + padding-bottom: 20px; + border-bottom: 1px solid; + align-items: center;*/ +} + +.permission-filter { + border-bottom: 1px solid; + margin: 5px; + border-bottom-color: #b0bec5; +} diff --git a/src/app/components/permissions-management/permissions-management.component.spec.ts b/src/app/components/permissions-management/permissions-management.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/permissions-management/permissions-management.component.ts b/src/app/components/permissions-management/permissions-management.component.ts new file mode 100644 index 000000000..b62f708d7 --- /dev/null +++ b/src/app/components/permissions-management/permissions-management.component.ts @@ -0,0 +1,80 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import {Component, ComponentFactoryResolver, OnInit, ViewChild, ViewContainerRef} from '@angular/core'; +import {ActivatedRoute, Router} from "@angular/router"; +import {Controller} from "@models/controller"; +import {PermissionsService} from "@services/permissions.service"; +import {ProgressService} from "../../common/progress/progress.service"; +import {Permission} from "@models/api/permission"; +import {AddPermissionLineComponent} from "@components/permissions-management/add-permission-line/add-permission-line.component"; +import {ControllerService} from "@services/controller.service"; +import {PageEvent} from "@angular/material/paginator"; +import {ApiInformationService} from "@services/ApiInformation/api-information.service"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +@Component({ + selector: 'app-permissions-management', + templateUrl: './permissions-management.component.html', + styleUrls: ['./permissions-management.component.scss'] +}) +export class PermissionsManagementComponent implements OnInit { + controller: Controller; + permissions: Permission[]; + addPermissionLineComp = AddPermissionLineComponent; + newPermissionEdit = false; + searchPermissions: any; + pageEvent: PageEvent | undefined; + filteredOptions: IGenericApiObject[]; + options: string[] = []; + + @ViewChild('dynamic', { + read: ViewContainerRef + }) viewContainerRef: ViewContainerRef; + isReady = false; + + constructor(private route: ActivatedRoute, + private router: Router, + private permissionService: PermissionsService, + private progressService: ProgressService, + private controllerService: ControllerService, + private apiInformationService: ApiInformationService) { } + + ngOnInit(): void { + const controllerId = this.route.parent.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.controller = controller; + this.refresh(); + }); + } + + refresh() { + this.permissionService.list(this.controller).subscribe( + (permissions: Permission[]) => { + this.permissions = permissions; + this.isReady = true; + }, + (error) => { + this.progressService.setError(error); + } + ); + } + + displayFn(value): string { + return value && value.name ? value.name : ''; + } + + changeAutocomplete(inputText) { + this.filteredOptions = this.apiInformationService.getIdByObjNameFromCache(inputText); + } + +} diff --git a/src/app/components/permissions-management/permissions-type-filter.pipe.ts b/src/app/components/permissions-management/permissions-type-filter.pipe.ts new file mode 100644 index 000000000..a5ce9fe0b --- /dev/null +++ b/src/app/components/permissions-management/permissions-type-filter.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Pipe, PipeTransform } from '@angular/core'; +import {Permission} from "@models/api/permission"; + +@Pipe({ + name: 'permissionsTypeFilter' +}) +export class PermissionsTypeFilterPipe implements PipeTransform { + + transform(permissions: Permission[], filterTypeText: string): Permission[] { + if (!permissions) { + return []; + } + if (filterTypeText === undefined || filterTypeText === null || filterTypeText === '') { + return permissions; + } + + return permissions.filter((permissions: Permission) => permissions.path.toLowerCase().includes(filterTypeText.toLowerCase())); + } + +} diff --git a/src/app/components/preferences/built-in/built-in-preferences.component.html b/src/app/components/preferences/built-in/built-in-preferences.component.html index 04a5bb218..af679bb8f 100644 --- a/src/app/components/preferences/built-in/built-in-preferences.component.html +++ b/src/app/components/preferences/built-in/built-in-preferences.component.html @@ -1,22 +1,26 @@
-

Built-in preferences

- +
+ +
+
+

Built-in templates

+
- - Ethernet hubs + + Ethernet hub templates - - Ethernet switches + + Ethernet switch templates - Cloud nodes + Cloud node templates
diff --git a/src/app/components/preferences/built-in/built-in-preferences.component.spec.ts b/src/app/components/preferences/built-in/built-in-preferences.component.spec.ts index 405029336..99b9e8da9 100644 --- a/src/app/components/preferences/built-in/built-in-preferences.component.spec.ts +++ b/src/app/components/preferences/built-in/built-in-preferences.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -16,8 +16,8 @@ describe('BuiltInPreferencesComponent', () => { let fixture: ComponentFixture; let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -36,7 +36,7 @@ describe('BuiltInPreferencesComponent', () => { declarations: [BuiltInPreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(BuiltInPreferencesComponent); @@ -48,7 +48,7 @@ describe('BuiltInPreferencesComponent', () => { expect(component).toBeTruthy(); }); - it('should set correct server id', () => { - expect(component.serverId).toBe('1'); + it('should set correct controller id', () => { + expect(component.controllerId).toBe('1'); }); }); diff --git a/src/app/components/preferences/built-in/built-in-preferences.component.ts b/src/app/components/preferences/built-in/built-in-preferences.component.ts index 7749d54f3..145b3a3e1 100644 --- a/src/app/components/preferences/built-in/built-in-preferences.component.ts +++ b/src/app/components/preferences/built-in/built-in-preferences.component.ts @@ -7,11 +7,11 @@ import { ActivatedRoute } from '@angular/router'; styleUrls: ['./built-in-preferences.component.scss', '../preferences.component.scss'], }) export class BuiltInPreferencesComponent implements OnInit { - public serverId: string = ''; + public controllerId: string = ''; constructor(private route: ActivatedRoute) {} ngOnInit() { - this.serverId = this.route.snapshot.paramMap.get('server_id'); + this.controllerId = this.route.snapshot.paramMap.get('controller_id'); } } diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.html b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.html index 89cf0f0ca..d750544ac 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.html +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.html @@ -1,22 +1,22 @@
-

New cloud node template

+
+ +
+
+

New cloud node template

+
- Run the cloud node locally - Run the cloud node on the GNS3 VM
diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.spec.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.spec.ts index 7c09abe42..f33ac462d 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.spec.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,12 +10,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; @@ -24,7 +24,7 @@ import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { CloudNodesAddTemplateComponent } from './cloud-nodes-add-template.component'; export class MockedBuiltInTemplatesService { - public addTemplate(server: Server, cloudTemplate: CloudTemplate) { + public addTemplate(controller:Controller , cloudTemplate: CloudTemplate) { return of(cloudTemplate); } } @@ -33,14 +33,14 @@ describe('CloudNodesAddTemplateComponent', () => { let component: CloudNodesAddTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let mockedComputeService = new MockedComputeService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -51,12 +51,12 @@ describe('CloudNodesAddTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/builtin/cloud-nodes', component: CloudNodesAddTemplateComponent }, + { path: 'controller/1/preferences/builtin/cloud-nodes', component: CloudNodesAddTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: ComputeService, useValue: mockedComputeService }, @@ -65,7 +65,7 @@ describe('CloudNodesAddTemplateComponent', () => { declarations: [CloudNodesAddTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(CloudNodesAddTemplateComponent); @@ -80,7 +80,7 @@ describe('CloudNodesAddTemplateComponent', () => { it('should call add template', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as CloudTemplate)); component.templateName = 'sample name'; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.formGroup.controls['templateName'].setValue('template name'); component.addTemplate(); @@ -92,7 +92,7 @@ describe('CloudNodesAddTemplateComponent', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as CloudTemplate)); spyOn(mockedToasterService, 'error'); component.templateName = ''; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.ts index 9910b72d5..c909b54e9 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-add-template/cloud-nodes-add-template.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../../models/compute'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -17,52 +17,41 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['./cloud-nodes-add-template.component.scss', '../../../preferences.component.scss'], }) export class CloudNodesAddTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; - formGroup: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + formGroup: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private router: Router, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private computeService: ComputeService ) { this.formGroup = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'cloud-nodes']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'cloud-nodes']); } addTemplate() { @@ -75,9 +64,9 @@ export class CloudNodesAddTemplateComponent implements OnInit { cloudTemplate.template_id = uuid(); cloudTemplate.name = this.formGroup.get('templateName').value; - cloudTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + cloudTemplate.compute_id = 'local'; - this.builtInTemplatesService.addTemplate(this.server, cloudTemplate).subscribe((cloudNodeTemplate) => { + this.builtInTemplatesService.addTemplate(this.controller, cloudTemplate).subscribe((cloudNodeTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.html b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.html index 7dbf5e78f..ce992fe5c 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.html +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.html @@ -3,135 +3,176 @@

Cloud configuration

-
-
- - - - General - - - - - - - - - - -

- - - - {{ category[0] }} - - - - - - - {{ type }} - - - - - - - - - - - - -
- - - Ethernet interfaces - -
-
{{ port.name }}
-

-
- - - - {{ type }} - - - - -
- - - TAP interfaces - -
-
{{ port.name }}
-

-
- - - - -
- - - UDP tunnels - - - - - - - - - - - - - - - - - - - - - +
+ + + + + General + + + + + + + + + + + +

+ + + + {{category[0]}} + + + + + + + {{type}} + + + + + + + + + + + + +
+ + + + Ethernet interfaces + + +
+
{{port.name}}


+
+ + + + {{type}} + + + + +
+ + + + TAP interfaces + + +
+
{{port.name}}


+
+ + + + +
+ + + + UDP tunnels + + +
Name{{ element.name }}Local port{{ element.rport }}Type{{ element.rhost }}Remote port{{ element.lport }}
+ + + + + + + + + + + + + + - - -
Name {{element.name}} Local port {{element.rport}} Type {{element.rhost}}
-
- - - - - - - - - - - - - -
-
+ + Remote port + {{element.lport}} + + + + + +
+ + + + + + + + + + + + + + + + + + Usage + + + + + + +

@@ -140,7 +181,7 @@

Cloud configuration

diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.spec.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.spec.ts index efb79a4ed..d5e2a0628 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.spec.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.spec.ts @@ -11,23 +11,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { CloudNodesTemplateDetailsComponent } from './cloud-nodes-template-details.component'; export class MockedBuiltInTemplatesService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({ ports_mapping: [] } as CloudTemplate); } - public saveTemplate(server: Server, cloudTemplate: CloudTemplate) { + public saveTemplate(controller:Controller , cloudTemplate: CloudTemplate) { return of(cloudTemplate); } } @@ -36,13 +36,13 @@ describe('CloudNodesTemplateDetailsComponent', () => { let component: CloudNodesTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -60,7 +60,7 @@ describe('CloudNodesTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }, @@ -68,7 +68,7 @@ describe('CloudNodesTemplateDetailsComponent', () => { declarations: [CloudNodesTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(CloudNodesTemplateDetailsComponent); diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.ts index e6877a490..72fd15293 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-template-details/cloud-nodes-template-details.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { ToasterService } from '../../../../../services/toaster.service'; @Component({ @@ -14,7 +14,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['./cloud-nodes-template-details.component.scss', '../../../preferences.component.scss'], }) export class CloudNodesTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; cloudNodeTemplate: CloudTemplate; isSymbolSelectionOpened: boolean = false; @@ -34,7 +34,7 @@ export class CloudNodesTemplateDetailsComponent implements OnInit { constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private toasterService: ToasterService, private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService, @@ -47,14 +47,14 @@ export class CloudNodesTemplateDetailsComponent implements OnInit { } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); this.builtInTemplatesService - .getTemplate(this.server, template_id) + .getTemplate(this.controller, template_id) .subscribe((cloudNodeTemplate: CloudTemplate) => { this.cloudNodeTemplate = cloudNodeTemplate; @@ -70,7 +70,7 @@ export class CloudNodesTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'cloud-nodes']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'cloud-nodes']); } getConfiguration() { @@ -114,7 +114,7 @@ export class CloudNodesTemplateDetailsComponent implements OnInit { this.cloudNodeTemplate.ports_mapping = [...this.portsMappingEthernet, ...this.portsMappingTap]; this.builtInTemplatesService - .saveTemplate(this.server, this.cloudNodeTemplate) + .saveTemplate(this.controller, this.cloudNodeTemplate) .subscribe((cloudNodeTemplate: CloudTemplate) => { this.toasterService.success('Changes saved'); }); diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.html b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.html index 22cfab266..4676a5a55 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.html +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.html @@ -1,31 +1,39 @@
-

Cloud nodes templates

- - +
+ +
+
+

Cloud nodes templates

+
+
+ +
+
- +
{{ template.name @@ -37,10 +45,13 @@

Cloud nodes templates

+
- + diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.spec.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.spec.ts index 05abbebee..bbc60d085 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.spec.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { CloudNodesTemplatesComponent } from './cloud-nodes-templates.component'; export class MockedBuiltInTemplatesService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as CloudTemplate]); } } @@ -27,12 +27,12 @@ describe('CloudNodesTemplatesComponent', () => { let component: CloudNodesTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,13 +47,13 @@ describe('CloudNodesTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, ], declarations: [CloudNodesTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(CloudNodesTemplatesComponent); diff --git a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.ts b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.ts index b6e03e13c..209142c43 100644 --- a/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.ts +++ b/src/app/components/preferences/built-in/cloud-nodes/cloud-nodes-templates/cloud-nodes-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { CloudTemplate } from '../../../../../models/templates/cloud-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,26 +12,26 @@ import { DeleteTemplateComponent } from '../../../common/delete-template-compone styleUrls: ['./cloud-nodes-templates.component.scss', '../../../preferences.component.scss'], }) export class CloudNodesTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; cloudNodesTemplates: CloudTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.builtInTemplatesService.getTemplates(this.server).subscribe((cloudNodesTemplates: CloudTemplate[]) => { + this.builtInTemplatesService.getTemplates(this.controller).subscribe((cloudNodesTemplates: CloudTemplate[]) => { this.cloudNodesTemplates = cloudNodesTemplates.filter((elem) => elem.template_type === 'cloud' && !elem.builtin); }); } diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.html b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.html index 0e90b602a..f2239c48e 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.html +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.html @@ -1,22 +1,29 @@
-

New Ethernet hub template

+
+ +
+
+

New Ethernet hub template

+ +
- Run the Ethernet Hub locally - Run the Ethernet Hub on the GNS3 VM diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.spec.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.spec.ts index 3b1749f29..bfb770686 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,12 +10,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; @@ -24,7 +24,7 @@ import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetHubsAddTemplateComponent } from './ethernet-hubs-add-template.component'; export class MockedBuiltInTemplatesService { - public addTemplate(server: Server, ethernetHubTemplate: EthernetHubTemplate) { + public addTemplate(controller:Controller , ethernetHubTemplate: EthernetHubTemplate) { return of(ethernetHubTemplate); } } @@ -33,14 +33,14 @@ describe('EthernetHubsAddTemplateComponent', () => { let component: EthernetHubsAddTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let mockedComputeService = new MockedComputeService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -51,7 +51,7 @@ describe('EthernetHubsAddTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/builtin/ethernet-hubs', component: EthernetHubsAddTemplateComponent }, + { path: 'controller/1/preferences/builtin/ethernet-hubs', component: EthernetHubsAddTemplateComponent }, ]), ], providers: [ @@ -59,7 +59,7 @@ describe('EthernetHubsAddTemplateComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: ComputeService, useValue: mockedComputeService }, @@ -68,7 +68,7 @@ describe('EthernetHubsAddTemplateComponent', () => { declarations: [EthernetHubsAddTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(EthernetHubsAddTemplateComponent); @@ -83,7 +83,7 @@ describe('EthernetHubsAddTemplateComponent', () => { it('should call add template', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate)); component.templateName = 'sample name'; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.formGroup.controls['templateName'].setValue('template name'); component.formGroup.controls['numberOfPorts'].setValue('1'); @@ -96,7 +96,7 @@ describe('EthernetHubsAddTemplateComponent', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate)); spyOn(mockedToasterService, 'error'); component.templateName = ''; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -108,7 +108,7 @@ describe('EthernetHubsAddTemplateComponent', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetHubTemplate)); spyOn(mockedToasterService, 'error'); component.templateName = 'sample name'; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.ts index 7a3d4da81..c2992dd9e 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-add-template/ethernet-hubs-add-template.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../../models/compute'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -17,53 +17,42 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['./ethernet-hubs-add-template.component.scss', '../../../preferences.component.scss'], }) export class EthernetHubsAddTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; - formGroup: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + formGroup: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private router: Router, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private computeService: ComputeService ) { this.formGroup = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - numberOfPorts: new FormControl(8, Validators.required), + templateName: new UntypedFormControl('', Validators.required), + numberOfPorts: new UntypedFormControl(8, Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-hubs']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'ethernet-hubs']); } addTemplate() { @@ -76,7 +65,7 @@ export class EthernetHubsAddTemplateComponent implements OnInit { ethernetHubTemplate.template_id = uuid(); ethernetHubTemplate.name = this.formGroup.get('templateName').value; - ethernetHubTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + ethernetHubTemplate.compute_id = 'local'; for (let i = 0; i < this.formGroup.get('numberOfPorts').value; i++) { ethernetHubTemplate.ports_mapping.push({ @@ -85,7 +74,7 @@ export class EthernetHubsAddTemplateComponent implements OnInit { }); } - this.builtInTemplatesService.addTemplate(this.server, ethernetHubTemplate).subscribe(() => { + this.builtInTemplatesService.addTemplate(this.controller, ethernetHubTemplate).subscribe(() => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.html b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.html index b33932f2e..b4e429507 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.html +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.html @@ -1,7 +1,20 @@
-

Ethernet hub settings

+
+ +
+
+

Ethernet hub settings

+
@@ -65,7 +78,7 @@

Ethernet hub settings

diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.spec.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.spec.ts index 28476feba..083bcbd6d 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -11,23 +11,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetHubsTemplateDetailsComponent } from './ethernet-hubs-template-details.component'; export class MockedBuiltInTemplatesService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({ ports_mapping: [] } as EthernetHubTemplate); } - public saveTemplate(server: Server, cloudTemplate: EthernetHubTemplate) { + public saveTemplate(controller:Controller , cloudTemplate: EthernetHubTemplate) { return of(cloudTemplate); } } @@ -36,13 +36,13 @@ describe('EthernetHubsTemplateDetailsComponent', () => { let component: EthernetHubsTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -60,7 +60,7 @@ describe('EthernetHubsTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }, @@ -68,7 +68,7 @@ describe('EthernetHubsTemplateDetailsComponent', () => { declarations: [EthernetHubsTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(EthernetHubsTemplateDetailsComponent); diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.ts index 146617b97..84f823b0b 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-template-details/ethernet-hubs-template-details.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { ToasterService } from '../../../../../services/toaster.service'; @Component({ @@ -14,39 +14,39 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['./ethernet-hubs-template-details.component.scss', '../../../preferences.component.scss'], }) export class EthernetHubsTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; ethernetHubTemplate: EthernetHubTemplate; numberOfPorts: number; - inputForm: FormGroup; + inputForm: UntypedFormGroup; isSymbolSelectionOpened: boolean = false; categories = []; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService, private router: Router ) { this.inputForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetHubs(); this.builtInTemplatesService - .getTemplate(this.server, template_id) + .getTemplate(this.controller, template_id) .subscribe((ethernetHubTemplate: EthernetHubTemplate) => { this.ethernetHubTemplate = ethernetHubTemplate; this.numberOfPorts = this.ethernetHubTemplate.ports_mapping.length; @@ -55,7 +55,7 @@ export class EthernetHubsTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-hubs']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'ethernet-hubs']); } onSave() { @@ -71,7 +71,7 @@ export class EthernetHubsTemplateDetailsComponent implements OnInit { } this.builtInTemplatesService - .saveTemplate(this.server, this.ethernetHubTemplate) + .saveTemplate(this.controller, this.ethernetHubTemplate) .subscribe((ethernetHubTemplate: EthernetHubTemplate) => { this.toasterService.success('Changes saved'); }); diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.html b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.html index f83b36a4e..13d202b6d 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.html +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.html @@ -1,31 +1,38 @@
-

Ethernet hubs templates

- - +
+ +
+
+

Ethernet hubs templates

+
+
+ +
- +
{{ template.name @@ -37,10 +44,13 @@

Ethernet hubs templates

+
- + diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.spec.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.spec.ts index 4fe7cd5fc..5fe651e30 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.spec.ts @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetHubsTemplatesComponent } from './ethernet-hubs-templates.component'; export class MockedBuiltInTemplatesService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as EthernetHubTemplate]); } } @@ -27,12 +27,12 @@ describe('EthernetHubsTemplatesComponent', () => { let component: EthernetHubsTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,21 +47,21 @@ describe('EthernetHubsTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, ], declarations: [EthernetHubsTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EthernetHubsTemplatesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); +beforeEach(() => { + fixture = TestBed.createComponent(EthernetHubsTemplatesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); +}); + +it('should create', () => { + expect(component).toBeTruthy(); +}); }); diff --git a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.ts b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.ts index 98eda9c02..fd7996983 100644 --- a/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.ts +++ b/src/app/components/preferences/built-in/ethernet-hubs/ethernet-hubs-templates/ethernet-hubs-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetHubTemplate } from '../../../../../models/templates/ethernet-hub-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,26 +12,26 @@ import { DeleteTemplateComponent } from '../../../common/delete-template-compone styleUrls: ['./ethernet-hubs-templates.component.scss', '../../../preferences.component.scss'], }) export class EthernetHubsTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; ethernetHubsTemplates: EthernetHubTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.builtInTemplatesService.getTemplates(this.server).subscribe((ethernetHubsTemplates: EthernetHubTemplate[]) => { + this.builtInTemplatesService.getTemplates(this.controller).subscribe((ethernetHubsTemplates: EthernetHubTemplate[]) => { this.ethernetHubsTemplates = ethernetHubsTemplates.filter( (elem) => elem.template_type === 'ethernet_hub' && !elem.builtin ); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.html b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.html index ca42cf470..db1712953 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.html +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.html @@ -1,22 +1,28 @@
+
+ +
+

New Ethernet switch template

+
- Run the Ethernet switch locally - Run the Ethernet switch on the GNS3 VM diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.spec.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.spec.ts index f2dffb928..99e18d907 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,12 +10,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; @@ -24,7 +24,7 @@ import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetSwitchesAddTemplateComponent } from './ethernet-switches-add-template.component'; export class MockedBuiltInTemplatesService { - public addTemplate(server: Server, ethernetHubTemplate: EthernetSwitchTemplate) { + public addTemplate(controller:Controller , ethernetHubTemplate: EthernetSwitchTemplate) { return of(ethernetHubTemplate); } } @@ -33,14 +33,14 @@ describe('EthernetSwitchesAddTemplateComponent', () => { let component: EthernetSwitchesAddTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let mockedComputeService = new MockedComputeService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -51,7 +51,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/builtin/ethernet-switches', component: EthernetSwitchesAddTemplateComponent }, + { path: 'controller/1/preferences/builtin/ethernet-switches', component: EthernetSwitchesAddTemplateComponent }, ]), ], providers: [ @@ -59,7 +59,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: ComputeService, useValue: mockedComputeService }, @@ -68,7 +68,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { declarations: [EthernetSwitchesAddTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(EthernetSwitchesAddTemplateComponent); @@ -83,7 +83,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { it('should call add template', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate)); component.templateName = 'sample name'; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.formGroup.controls['templateName'].setValue('template name'); component.formGroup.controls['numberOfPorts'].setValue('1'); @@ -96,7 +96,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate)); spyOn(mockedToasterService, 'error'); component.formGroup.controls['numberOfPorts'].setValue('1'); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -108,7 +108,7 @@ describe('EthernetSwitchesAddTemplateComponent', () => { spyOn(mockedBuiltInTemplatesService, 'addTemplate').and.returnValue(of({} as EthernetSwitchTemplate)); spyOn(mockedToasterService, 'error'); component.formGroup.controls['templateName'].setValue('template name'); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.ts index 4bfd638cb..a312786da 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-add-template/ethernet-switches-add-template.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../../models/compute'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { ComputeService } from '../../../../../services/compute.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { TemplateMocksService } from '../../../../../services/template-mocks.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -17,51 +17,40 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['./ethernet-switches-add-template.component.scss', '../../../preferences.component.scss'], }) export class EthernetSwitchesAddTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; - formGroup: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + formGroup: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private router: Router, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private computeService: ComputeService ) { this.formGroup = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - numberOfPorts: new FormControl(8, Validators.required), + templateName: new UntypedFormControl('', Validators.required), + numberOfPorts: new UntypedFormControl(8, Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-switches']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'ethernet-switches']); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } @@ -76,11 +65,11 @@ export class EthernetSwitchesAddTemplateComponent implements OnInit { ethernetSwitchTemplate.template_id = uuid(); ethernetSwitchTemplate.name = this.formGroup.get('templateName').value; - ethernetSwitchTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + ethernetSwitchTemplate.compute_id = 'local'; for (let i = 0; i < this.formGroup.get('numberOfPorts').value; i++) { ethernetSwitchTemplate.ports_mapping.push({ - ethertype: '', + ethertype: '0x8100', name: `Ethernet${i}`, port_number: i, type: 'access', @@ -89,7 +78,7 @@ export class EthernetSwitchesAddTemplateComponent implements OnInit { } this.builtInTemplatesService - .addTemplate(this.server, ethernetSwitchTemplate) + .addTemplate(this.controller, ethernetSwitchTemplate) .subscribe((ethernetSwitchTemplate) => { this.goBack(); }); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html index 1de6293c1..dcd41345b 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html @@ -1,7 +1,14 @@
-

Ethernet switch configuration

+
+ +
+
+

Ethernet switch configuration

+
@@ -78,7 +85,7 @@

Ethernet switch configuration

diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts index ab69568ae..4a006adaa 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -11,12 +11,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; import { PortsComponent } from '../../../common/ports/ports.component'; @@ -24,11 +24,11 @@ import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetSwitchesTemplateDetailsComponent } from './ethernet-switches-template-details.component'; export class MockedBuiltInTemplatesService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({ ports_mapping: [] } as EthernetSwitchTemplate); } - public saveTemplate(server: Server, cloudTemplate: EthernetSwitchTemplate) { + public saveTemplate(controller:Controller , cloudTemplate: EthernetSwitchTemplate) { return of(cloudTemplate); } } @@ -37,13 +37,13 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => { let component: EthernetSwitchesTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -61,7 +61,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: BuiltInTemplatesConfigurationService, useClass: BuiltInTemplatesConfigurationService }, @@ -69,7 +69,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => { declarations: [EthernetSwitchesTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(EthernetSwitchesTemplateDetailsComponent); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts index 8a68b1dac..d5d3893b3 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { PortsComponent } from '../../../common/ports/ports.component'; @@ -16,38 +16,38 @@ import { PortsComponent } from '../../../common/ports/ports.component'; }) export class EthernetSwitchesTemplateDetailsComponent implements OnInit { @ViewChild(PortsComponent) portsComponent: PortsComponent; - server: Server; + controller:Controller ; ethernetSwitchTemplate: EthernetSwitchTemplate; - inputForm: FormGroup; + inputForm: UntypedFormGroup; isSymbolSelectionOpened: boolean = false; categories = []; consoleTypes: string[] = []; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService, private router: Router ) { this.inputForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); this.builtInTemplatesService - .getTemplate(this.server, template_id) + .getTemplate(this.controller, template_id) .subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => { this.ethernetSwitchTemplate = ethernetSwitchTemplate; }); @@ -60,7 +60,7 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'builtin', 'ethernet-switches']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'builtin', 'ethernet-switches']); } onSave() { @@ -69,7 +69,7 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { } else { this.ethernetSwitchTemplate.ports_mapping = this.portsComponent.ethernetPorts; this.builtInTemplatesService - .saveTemplate(this.server, this.ethernetSwitchTemplate) + .saveTemplate(this.controller, this.ethernetSwitchTemplate) .subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => { this.toasterService.success('Changes saved'); }); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.html b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.html index 73017e631..f7b372456 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.html +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.html @@ -1,31 +1,39 @@
-

Ethernet switches templates

- - +
+ +
+
+

Ethernet switches templates

+
+
+ +
+
- +
{{ template.name @@ -37,10 +45,13 @@

Ethernet switches templates

+
- + diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.spec.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.spec.ts index abb9459bb..b4b67078b 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../../preferences.component.spec'; import { EthernetSwitchesTemplatesComponent } from './ethernet-switches-templates.component'; export class MockedBuiltInTemplatesService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as EthernetSwitchTemplate]); } } @@ -27,12 +27,12 @@ describe('EthernetSwitchesTemplatesComponent', () => { let component: EthernetSwitchesTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedBuiltInTemplatesService = new MockedBuiltInTemplatesService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,21 +47,21 @@ describe('EthernetSwitchesTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService }, ], declarations: [EthernetSwitchesTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EthernetSwitchesTemplatesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); +beforeEach(() => { + fixture = TestBed.createComponent(EthernetSwitchesTemplatesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); +}); + +it('should create', () => { + expect(component).toBeTruthy(); +}); }); diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.ts index 2c9fa9413..08cf3d76d 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-templates/ethernet-switches-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,27 +12,27 @@ import { DeleteTemplateComponent } from '../../../common/delete-template-compone styleUrls: ['./ethernet-switches-templates.component.scss', '../../../preferences.component.scss'], }) export class EthernetSwitchesTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; ethernetSwitchesTemplates: EthernetSwitchTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { this.builtInTemplatesService - .getTemplates(this.server) + .getTemplates(this.controller) .subscribe((ethernetSwitchesTemplates: EthernetSwitchTemplate[]) => { this.ethernetSwitchesTemplates = ethernetSwitchesTemplates.filter( (elem) => elem.template_type === 'ethernet_switch' && !elem.builtin diff --git a/src/app/components/preferences/common/custom-adapters-table/custom-adapters-table.component.html b/src/app/components/preferences/common/custom-adapters-table/custom-adapters-table.component.html index 7fecbe050..d1d000a61 100644 --- a/src/app/components/preferences/common/custom-adapters-table/custom-adapters-table.component.html +++ b/src/app/components/preferences/common/custom-adapters-table/custom-adapters-table.component.html @@ -13,8 +13,8 @@ Adapter type - - {{ type }} + + {{ type.name }} diff --git a/src/app/components/preferences/common/custom-adapters/custom-adapters.component.spec.ts b/src/app/components/preferences/common/custom-adapters/custom-adapters.component.spec.ts index 1bcd2b997..765875d16 100644 --- a/src/app/components/preferences/common/custom-adapters/custom-adapters.component.spec.ts +++ b/src/app/components/preferences/common/custom-adapters/custom-adapters.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -14,8 +14,8 @@ describe('Custom adapters component', () => { let component: CustomAdaptersComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatTableModule, MatIconModule, @@ -28,7 +28,7 @@ describe('Custom adapters component', () => { declarations: [CustomAdaptersComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(CustomAdaptersComponent); diff --git a/src/app/components/preferences/common/delete-template-component/delete-template.component.ts b/src/app/components/preferences/common/delete-template-component/delete-template.component.ts index e0299dc2f..ae222c573 100644 --- a/src/app/components/preferences/common/delete-template-component/delete-template.component.ts +++ b/src/app/components/preferences/common/delete-template-component/delete-template.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { TemplateService } from '../../../../services/template.service'; import { ToasterService } from '../../../../services/toaster.service'; import { DeleteConfirmationDialogComponent } from '../delete-confirmation-dialog/delete-confirmation-dialog.component'; @@ -11,7 +11,7 @@ import { DeleteConfirmationDialogComponent } from '../delete-confirmation-dialog styleUrls: ['./delete-template.component.scss'], }) export class DeleteTemplateComponent { - @Input() server: Server; + @Input() controller:Controller ; @Output() deleteEvent = new EventEmitter(); constructor( @@ -33,7 +33,7 @@ export class DeleteTemplateComponent { dialogRef.afterClosed().subscribe((answer: boolean) => { if (answer) { - this.templateService.deleteTemplate(this.server, templateId).subscribe((answer) => { + this.templateService.deleteTemplate(this.controller, templateId).subscribe((answer) => { this.deleteEvent.emit(templateId); this.toasterService.success(`Template ${templateName} deleted.`); }); diff --git a/src/app/components/preferences/common/symbols-menu/symbols-menu.component.html b/src/app/components/preferences/common/symbols-menu/symbols-menu.component.html index b727fa15e..646a26f97 100644 --- a/src/app/components/preferences/common/symbols-menu/symbols-menu.component.html +++ b/src/app/components/preferences/common/symbols-menu/symbols-menu.component.html @@ -7,6 +7,6 @@

Symbol selection

- +
diff --git a/src/app/components/preferences/common/symbols-menu/symbols-menu.component.ts b/src/app/components/preferences/common/symbols-menu/symbols-menu.component.ts index 15e6024b8..1db2a26ab 100644 --- a/src/app/components/preferences/common/symbols-menu/symbols-menu.component.ts +++ b/src/app/components/preferences/common/symbols-menu/symbols-menu.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; @Component({ selector: 'app-symbols-menu', @@ -7,7 +7,7 @@ import { Server } from '../../../../models/server'; styleUrls: ['./symbols-menu.component.scss', '../../preferences.component.scss'], }) export class SymbolsMenuComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() symbol: string; @Output() symbolChangedEmitter = new EventEmitter(); diff --git a/src/app/components/preferences/common/symbols/symbols.component.scss b/src/app/components/preferences/common/symbols/symbols.component.scss index 608fc79db..0e0cde8ca 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.scss +++ b/src/app/components/preferences/common/symbols/symbols.component.scss @@ -20,7 +20,6 @@ } .buttonSelected { - border-width: 3px; background: #0097a7 !important; } diff --git a/src/app/components/preferences/common/symbols/symbols.component.spec.ts b/src/app/components/preferences/common/symbols/symbols.component.spec.ts index 19cb0feae..858f7d716 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.spec.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.spec.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -28,7 +28,7 @@ describe('Symbols component', () => { let fixture: ComponentFixture; let mockedSymbolsService = new MockedSymbolService(); - beforeEach(async(() => { + beforeEach(async() => { TestBed.configureTestingModule({ imports: [ HttpClientModule, @@ -49,7 +49,7 @@ describe('Symbols component', () => { declarations: [SymbolsComponent, SearchFilter], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(SymbolsComponent); diff --git a/src/app/components/preferences/common/symbols/symbols.component.ts b/src/app/components/preferences/common/symbols/symbols.component.ts index 7dbbb5270..0e82e3240 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.ts @@ -1,5 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Server } from '../../../../models/server'; +import { environment } from 'environments/environment'; +import{ Controller } from '../../../../models/controller'; import { Symbol } from '../../../../models/symbol'; import { SymbolService } from '../../../../services/symbol.service'; @@ -9,7 +10,7 @@ import { SymbolService } from '../../../../services/symbol.service'; styleUrls: ['./symbols.component.scss'], }) export class SymbolsComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() symbol: string; @Output() symbolChanged = new EventEmitter(); @@ -41,7 +42,7 @@ export class SymbolsComponent implements OnInit { } loadSymbols() { - this.symbolService.list(this.server).subscribe((symbols: Symbol[]) => { + this.symbolService.list(this.controller).subscribe((symbols: Symbol[]) => { this.symbols = symbols; this.filteredSymbols = symbols; }); @@ -60,7 +61,7 @@ export class SymbolsComponent implements OnInit { fileReader.onloadend = () => { let image = fileReader.result; let svg = this.createSvgFileForImage(image, imageToUpload); - this.symbolService.add(this.server, fileName, svg).subscribe(() => { + this.symbolService.add(this.controller, fileName, svg).subscribe(() => { this.loadSymbols(); }); }; @@ -77,6 +78,6 @@ export class SymbolsComponent implements OnInit { } getImageSourceForTemplate(symbol: string) { - return `${this.server.protocol}//${this.server.host}:${this.server.port}/v2/symbols/${symbol}/raw`; + return `${this.controller.protocol}//${this.controller.host}:${this.controller.port}/${environment.current_version}/symbols/${symbol}/raw`; } } diff --git a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.html b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.html index 6742275e5..c59350f50 100644 --- a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.html +++ b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.html @@ -7,19 +7,12 @@

New Docker container template

- + - - Run this Docker container on a remote compute --> + Run this Docker container locally - Run this Docker container on the GNS3 VM diff --git a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.spec.ts b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.spec.ts index 879c8ae4a..2273b5567 100644 --- a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.spec.ts +++ b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AbstractControlDirective, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { AbstractControlDirective, UntypedFormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCommonModule } from '@angular/material/core'; @@ -18,12 +18,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerConfigurationService } from '../../../../services/docker-configuration.service'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -31,7 +31,7 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddDockerTemplateComponent } from './add-docker-template.component'; export class MockedDockerService { - public addTemplate(server: Server, dockerTemplate: DockerTemplate) { + public addTemplate(controller:Controller , dockerTemplate: DockerTemplate) { return of(dockerTemplate); } } @@ -41,13 +41,13 @@ xdescribe('AddDockerTemplateComponent', () => { let component: AddDockerTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedDockerService = new MockedDockerService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatStepperModule, MatAutocompleteModule, @@ -67,21 +67,21 @@ xdescribe('AddDockerTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/docker/templates', component: AddDockerTemplateComponent }, + { path: 'controller/1/preferences/docker/templates', component: AddDockerTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: DockerService, useValue: mockedDockerService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, { provide: DockerConfigurationService, useClass: DockerConfigurationService }, - { provide: AbstractControlDirective, useExisting: FormControl, useMulti: true }, + { provide: AbstractControlDirective, useExisting: UntypedFormControl, useMulti: true }, ], declarations: [AddDockerTemplateComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddDockerTemplateComponent); @@ -92,27 +92,27 @@ xdescribe('AddDockerTemplateComponent', () => { fixture.destroy(); }); - it('should open first step at start', async(() => { + it('should open first step at start', async () => { fixture.detectChanges(); - fixture.whenStable().then(() => { + await fixture.whenStable().then(() => { let stepperComponent = fixture.debugElement.query(By.css('mat-vertical-stepper')).componentInstance; expect(stepperComponent.selectedIndex).toBe(0); }); - })); + }); - it('should display correct label at start', async(() => { + it('should display correct label at start', async() => { fixture.detectChanges(); - fixture.whenStable().then(() => { + await fixture.whenStable().then(() => { let selectedLabel = fixture.nativeElement.querySelector('[aria-selected="true"]'); - expect(selectedLabel.textContent).toMatch('Server type'); + expect(selectedLabel.textContent).toMatch('Controller type'); }); - })); + }); - it('should not call add template when required fields are empty', async(() => { + it('should not call add template when required fields are empty', async() => { fixture.detectChanges(); - fixture.whenStable().then(() => { + await fixture.whenStable().then(() => { let addButton = fixture.debugElement.nativeElement.querySelector('.add-button'); spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate)); @@ -124,11 +124,11 @@ xdescribe('AddDockerTemplateComponent', () => { expect(mockedDockerService.addTemplate).not.toHaveBeenCalled(); }); - })); + }); - it('should call add template when required fields are filled', async(() => { + it('should call add template when required fields are filled', async () => { fixture.detectChanges(); - fixture.whenStable().then(() => { + await fixture.whenStable().then(() => { let stepperComponent = fixture.debugElement.query(By.css('mat-vertical-stepper')).componentInstance; stepperComponent.selectedIndex = 1; component.newImageSelected = true; @@ -197,5 +197,5 @@ xdescribe('AddDockerTemplateComponent', () => { }); }); }); - })); + }); }); diff --git a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.ts b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.ts index f7d0529d0..507d31727 100644 --- a/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.ts +++ b/src/app/components/preferences/docker/add-docker-template/add-docker-template.component.ts @@ -1,15 +1,15 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../models/compute'; import { DockerImage } from '../../../../models/docker/docker-image'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { ComputeService } from '../../../../services/compute.service'; import { DockerConfigurationService } from '../../../../services/docker-configuration.service'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -19,7 +19,7 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./add-docker-template.component.scss', '../../preferences.component.scss'], }) export class AddDockerTemplateComponent implements OnInit { - server: Server; + controller:Controller ; dockerTemplate: DockerTemplate; consoleTypes: string[] = []; isRemoteComputerChosen: boolean = false; @@ -27,21 +27,18 @@ export class AddDockerTemplateComponent implements OnInit { selectedImage: DockerImage; newImageSelected: boolean = false; - virtualMachineForm: FormGroup; - containerNameForm: FormGroup; - networkAdaptersForm: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + virtualMachineForm: UntypedFormGroup; + containerNameForm: UntypedFormGroup; + networkAdaptersForm: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private templateMocksService: TemplateMocksService, private configurationService: DockerConfigurationService, private computeService: ComputeService @@ -49,22 +46,22 @@ export class AddDockerTemplateComponent implements OnInit { this.dockerTemplate = new DockerTemplate(); this.virtualMachineForm = this.formBuilder.group({ - filename: new FormControl(null, Validators.required), + filename: new UntypedFormControl(null, Validators.required), }); this.containerNameForm = this.formBuilder.group({ - templateName: new FormControl(null, Validators.required), + templateName: new UntypedFormControl(null, Validators.required), }); this.networkAdaptersForm = this.formBuilder.group({ - adapters: new FormControl('1', Validators.required), + adapters: new UntypedFormControl('1', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.consoleTypes = this.configurationService.getConsoleTypes(); @@ -72,22 +69,14 @@ export class AddDockerTemplateComponent implements OnInit { this.dockerTemplate = dockerTemplate; }); - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); - - this.dockerService.getImages(server).subscribe((images) => { + this.dockerService.getImages(controller).subscribe((images) => { this.dockerImages = images; }); }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } @@ -97,7 +86,7 @@ export class AddDockerTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'docker', 'templates']); } addTemplate() { @@ -116,9 +105,9 @@ export class AddDockerTemplateComponent implements OnInit { this.dockerTemplate.name = this.containerNameForm.get('templateName').value; this.dockerTemplate.adapters = +this.networkAdaptersForm.get('adapters').value; - this.dockerTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + this.dockerTemplate.compute_id = 'local'; - this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => { + this.dockerService.addTemplate(this.controller, this.dockerTemplate).subscribe((template: DockerTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.html b/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.html index 3b2f0f93e..7bdf1e832 100644 --- a/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.html +++ b/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.html @@ -1,7 +1,14 @@
+
+ +
+

Copy Docker container template

+
diff --git a/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.ts b/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.ts index 6e8c13c87..723e47fec 100644 --- a/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.ts +++ b/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -14,31 +14,31 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./copy-docker-template.component.scss', '../../preferences.component.scss'], }) export class CopyDockerTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; dockerTemplate: DockerTemplate; - templateNameForm: FormGroup; + templateNameForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.dockerService.getTemplate(this.server, template_id).subscribe((dockerTemplate: DockerTemplate) => { + this.dockerService.getTemplate(this.controller, template_id).subscribe((dockerTemplate: DockerTemplate) => { this.dockerTemplate = dockerTemplate; this.templateName = `Copy of ${this.dockerTemplate.name}`; }); @@ -46,7 +46,7 @@ export class CopyDockerTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'docker', 'templates']); } addTemplate() { @@ -54,7 +54,7 @@ export class CopyDockerTemplateComponent implements OnInit { this.dockerTemplate.template_id = uuid(); this.dockerTemplate.name = this.templateName; - this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => { + this.dockerService.addTemplate(this.controller, this.dockerTemplate).subscribe((template: DockerTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.html b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.html index e36dccf03..300800eb4 100644 --- a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.html +++ b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.html @@ -1,7 +1,14 @@
-

Docker image configuration

+
+ +
+
+

Docker image configuration

+
@@ -143,7 +150,7 @@
Extra hosts
diff --git a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.spec.ts b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.spec.ts index 84ff735dd..8d134acdc 100644 --- a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.spec.ts +++ b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,23 +10,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerConfigurationService } from '../../../../services/docker-configuration.service'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { DockerTemplateDetailsComponent } from './docker-template-details.component'; export class MockedDockerService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as DockerTemplate); } - public saveTemplate(server: Server, dockerTemplate: DockerTemplate) { + public saveTemplate(controller:Controller , dockerTemplate: DockerTemplate) { return of(dockerTemplate); } } @@ -35,13 +35,13 @@ describe('DockerTemplateDetailsComponent', () => { let component: DockerTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedDockerService = new MockedDockerService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -58,7 +58,7 @@ describe('DockerTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: DockerService, useValue: mockedDockerService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: DockerConfigurationService, useClass: DockerConfigurationService }, @@ -66,7 +66,7 @@ describe('DockerTemplateDetailsComponent', () => { declarations: [DockerTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DockerTemplateDetailsComponent); diff --git a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.ts b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.ts index 3c57a696b..9e101a622 100644 --- a/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.ts +++ b/src/app/components/preferences/docker/docker-template-details/docker-template-details.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerConfigurationService } from '../../../../services/docker-configuration.service'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -15,7 +15,7 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./docker-template-details.component.scss', '../../preferences.component.scss'], }) export class DockerTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; dockerTemplate: DockerTemplate; isSymbolSelectionOpened: boolean = false; @@ -26,33 +26,33 @@ export class DockerTemplateDetailsComponent implements OnInit { adapters: CustomAdapter[] = []; displayedColumns: string[] = ['adapter_number', 'port_name']; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private configurationService: DockerConfigurationService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private router: Router ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - adapter: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + adapter: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.dockerService.getTemplate(this.server, template_id).subscribe((dockerTemplate: DockerTemplate) => { + this.dockerService.getTemplate(this.controller, template_id).subscribe((dockerTemplate: DockerTemplate) => { this.dockerTemplate = dockerTemplate; }); }); @@ -65,14 +65,14 @@ export class DockerTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'docker', 'templates']); } onSave() { if (this.generalSettingsForm.invalid) { this.toasterService.error(`Fill all required fields`); } else { - this.dockerService.saveTemplate(this.server, this.dockerTemplate).subscribe((savedTemplate: DockerTemplate) => { + this.dockerService.saveTemplate(this.controller, this.dockerTemplate).subscribe((savedTemplate: DockerTemplate) => { this.toasterService.success('Changes saved'); }); } diff --git a/src/app/components/preferences/docker/docker-templates/docker-templates.component.html b/src/app/components/preferences/docker/docker-templates/docker-templates.component.html index 72227b93a..63ce6675c 100644 --- a/src/app/components/preferences/docker/docker-templates/docker-templates.component.html +++ b/src/app/components/preferences/docker/docker-templates/docker-templates.component.html @@ -1,31 +1,39 @@
-

Docker container templates

- - +
+ +
+
+

Docker container templates

+
+
+ +
+
- +
{{ template.name @@ -34,16 +42,19 @@

Docker container templates

more_vert - +
- + diff --git a/src/app/components/preferences/docker/docker-templates/docker-templates.component.spec.ts b/src/app/components/preferences/docker/docker-templates/docker-templates.component.spec.ts index 7a89634b2..962f79ce4 100644 --- a/src/app/components/preferences/docker/docker-templates/docker-templates.component.spec.ts +++ b/src/app/components/preferences/docker/docker-templates/docker-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { DockerTemplatesComponent } from './docker-templates.component'; export class MockedDockerService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as DockerTemplate]); } } @@ -27,12 +27,12 @@ describe('DockerTemplatesComponent', () => { let component: DockerTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedDockerService = new MockedDockerService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -44,13 +44,13 @@ describe('DockerTemplatesComponent', () => { ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: DockerService, useValue: mockedDockerService }, ], declarations: [DockerTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DockerTemplatesComponent); diff --git a/src/app/components/preferences/docker/docker-templates/docker-templates.component.ts b/src/app/components/preferences/docker/docker-templates/docker-templates.component.ts index e44688a0a..dd176d414 100644 --- a/src/app/components/preferences/docker/docker-templates/docker-templates.component.ts +++ b/src/app/components/preferences/docker/docker-templates/docker-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DockerTemplate } from '../../../../models/templates/docker-template'; import { DockerService } from '../../../../services/docker.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,27 +12,27 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./docker-templates.component.scss', '../../preferences.component.scss'], }) export class DockerTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; dockerTemplates: DockerTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private router: Router ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.dockerService.getTemplates(this.server).subscribe((dockerTemplates: DockerTemplate[]) => { + this.dockerService.getTemplates(this.controller).subscribe((dockerTemplates: DockerTemplate[]) => { this.dockerTemplates = dockerTemplates.filter((elem) => elem.template_type === 'docker' && !elem.builtin); }); } @@ -47,8 +47,8 @@ export class DockerTemplatesComponent implements OnInit { copyTemplate(template: DockerTemplate) { this.router.navigate([ - '/server', - this.server.id, + '/controller', + this.controller.id, 'preferences', 'docker', 'templates', diff --git a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.html b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.html index 1b41b9699..10e77a28d 100644 --- a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.html +++ b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.html @@ -1,24 +1,30 @@
-

New IOS router template

+
+ +
+
+

New IOS router template

+
- + - Run this IOS router locally - Run this IOS router on the GNS3 VM diff --git a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.spec.ts b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.spec.ts index 98db342b4..b329a8ffa 100644 --- a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.spec.ts +++ b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -16,12 +16,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { IosConfigurationService } from '../../../../services/ios-configuration.service'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -29,7 +29,7 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddIosTemplateComponent } from './add-ios-template.component'; export class MockedIosService { - public addTemplate(server: Server, iosTemplate: IosTemplate) { + public addTemplate(controller:Controller , iosTemplate: IosTemplate) { return of(iosTemplate); } } @@ -39,13 +39,13 @@ xdescribe('AddIosTemplateComponent', () => { let component: AddIosTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIosService = new MockedIosService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatStepperModule, FormsModule, @@ -62,12 +62,12 @@ xdescribe('AddIosTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/dynamips/templates', component: AddIosTemplateComponent }, + { path: 'controller/1/preferences/dynamips/templates', component: AddIosTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IosService, useValue: mockedIosService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, @@ -76,7 +76,7 @@ xdescribe('AddIosTemplateComponent', () => { declarations: [AddIosTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddIosTemplateComponent); @@ -95,7 +95,7 @@ xdescribe('AddIosTemplateComponent', () => { component.iosNameForm.controls['platform'].setValue('platform'); component.iosNameForm.controls['chassis'].setValue('chassis'); component.iosMemoryForm.controls['memory'].setValue(0); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -109,7 +109,7 @@ xdescribe('AddIosTemplateComponent', () => { component.iosNameForm.controls['platform'].setValue('platform'); component.iosNameForm.controls['chassis'].setValue('chassis'); component.iosMemoryForm.controls['memory'].setValue(0); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -122,7 +122,7 @@ xdescribe('AddIosTemplateComponent', () => { component.iosNameForm.controls['platform'].setValue('platform'); component.iosNameForm.controls['chassis'].setValue('chassis'); component.iosMemoryForm.controls['memory'].setValue(0); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -135,7 +135,7 @@ xdescribe('AddIosTemplateComponent', () => { component.iosNameForm.controls['templateName'].setValue('template name'); component.iosNameForm.controls['platform'].setValue('platform'); component.iosNameForm.controls['chassis'].setValue('chassis'); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.ts b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.ts index f420859a8..54713c33a 100644 --- a/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.ts +++ b/src/app/components/preferences/dynamips/add-ios-template/add-ios-template.component.ts @@ -1,16 +1,21 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Location } from '@angular/common'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; +import { UploadServiceService } from 'app/common/uploading-processbar/upload-service.service'; +import { UploadingProcessbarComponent } from 'app/common/uploading-processbar/uploading-processbar.component'; import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; +import { Subscription } from 'rxjs'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../models/compute'; import { IosImage } from '../../../../models/images/ios-image'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { ComputeService } from '../../../../services/compute.service'; import { IosConfigurationService } from '../../../../services/ios-configuration.service'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -19,14 +24,14 @@ import { ToasterService } from '../../../../services/toaster.service'; templateUrl: './add-ios-template.component.html', styleUrls: ['./add-ios-template.component.scss', '../../preferences.component.scss'], }) -export class AddIosTemplateComponent implements OnInit { - server: Server; +export class AddIosTemplateComponent implements OnInit, OnDestroy { + controller:Controller ; iosTemplate: IosTemplate; isEtherSwitchRouter: boolean = false; - iosImageForm: FormGroup; - iosNameForm: FormGroup; - iosMemoryForm: FormGroup; + iosImageForm: UntypedFormGroup; + iosNameForm: UntypedFormGroup; + iosMemoryForm: UntypedFormGroup; selectedPlatform: string; networkAdaptersForTemplate: string[] = []; @@ -45,41 +50,42 @@ export class AddIosTemplateComponent implements OnInit { ciscoUrl: string = 'https://cfn.cloudapps.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp'; uploader: FileUploader; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; isLocalComputerChosen: boolean = true; + uploadProgress:number = 0; + subscription: Subscription; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iosService: IosService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private router: Router, private templateMocksService: TemplateMocksService, private iosConfigurationService: IosConfigurationService, - private computeService: ComputeService + private computeService: ComputeService, + private uploadServiceService: UploadServiceService, + private snackBar : MatSnackBar, ) { this.iosTemplate = new IosTemplate(); this.iosImageForm = this.formBuilder.group({ - imageName: new FormControl(null, [Validators.required]), + imageName: new UntypedFormControl(null, [Validators.required]), }); this.iosNameForm = this.formBuilder.group({ - templateName: new FormControl(null, [Validators.required]), - platform: new FormControl(null, [Validators.required]), - chassis: new FormControl(null, [Validators.required]), + templateName: new UntypedFormControl(null, [Validators.required]), + platform: new UntypedFormControl(null, [Validators.required]), + chassis: new UntypedFormControl(null, [Validators.required]), }); this.iosMemoryForm = this.formBuilder.group({ - memory: new FormControl(null, [Validators.required]), + memory: new UntypedFormControl(null, [Validators.required]), }); } ngOnInit() { - this.uploader = new FileUploader({}); + this.uploader = new FileUploader({url: ''}); this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; }; @@ -95,10 +101,20 @@ export class AddIosTemplateComponent implements OnInit { this.getImages(); this.toasterService.success('Image uploaded'); }; + this.uploader.onProgressItem = (progress: any) => { + this.uploadProgress = progress['progress']; + this.uploadServiceService.processBarCount(this.uploadProgress) + }; + this.subscription = this.uploadServiceService.currentCancelItemDetails.subscribe((isCancel) => { + if (isCancel) { + this.cancelUploading() + } + + }) - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getImages(); @@ -114,25 +130,17 @@ export class AddIosTemplateComponent implements OnInit { this.chassis = this.iosConfigurationService.getChassis(); this.defaultRam = this.iosConfigurationService.getDefaultRamSettings(); }); - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } getImages() { - this.iosService.getImages(this.server).subscribe((images: IosImage[]) => { + this.iosService.getImages(this.controller).subscribe((images: IosImage[]) => { this.iosImages = images; }); } @@ -142,13 +150,16 @@ export class AddIosTemplateComponent implements OnInit { this.iosNameForm.controls['templateName'].setValue(name); let fileName = event.target.files[0].name; - const url = this.iosService.getImagePath(this.server, fileName); + const url = this.iosService.getImagePath(this.controller, fileName); this.uploader.queue.forEach((elem) => (elem.url = url)); const itemToUpload = this.uploader.queue[0]; - (itemToUpload as any).options.disableMultipart = true; - + if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.controller.authToken }]) this.uploader.uploadItem(itemToUpload); + this.snackBar.openFromComponent(UploadingProcessbarComponent, { + panelClass: 'uplaoding-file-snackabar', + data:{upload_file_type:'Image'} + }); } addTemplate() { @@ -168,16 +179,15 @@ export class AddIosTemplateComponent implements OnInit { this.iosTemplate.ram = this.iosMemoryForm.get('memory').value; if (this.isEtherSwitchRouter) { - this.iosTemplate.symbol = ':/symbols/multilayer_switch.svg'; + this.iosTemplate.symbol = 'multilayer_switch'; this.iosTemplate.category = 'switch'; } if (this.networkAdaptersForTemplate.length > 0) this.completeAdaptersData(); if (this.networkModulesForTemplate.length > 0) this.completeModulesData(); + this.iosTemplate.compute_id = 'local'; - this.iosTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; - - this.iosService.addTemplate(this.server, this.iosTemplate).subscribe((template: IosTemplate) => { + this.iosService.addTemplate(this.controller, this.iosTemplate).subscribe((template: IosTemplate) => { this.goBack(); }); } else { @@ -227,7 +237,7 @@ export class AddIosTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'dynamips', 'templates']); } onImageChosen() { @@ -262,4 +272,16 @@ export class AddIosTemplateComponent implements OnInit { onChassisChosen() { this.networkAdaptersForTemplate = []; } + + cancelUploading() { + this.uploader.clearQueue(); + this.uploadServiceService.processBarCount(null) + this.toasterService.warning('File upload cancelled'); + // this.uploadServiceService.cancelFileUploading(false) + // window.location.reload() + + } + ngOnDestroy() { + this.subscription.unsubscribe(); + } } diff --git a/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.html b/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.html index 3aa2a9535..ccf5ee7a1 100644 --- a/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.html +++ b/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.html @@ -1,7 +1,14 @@
-

Copy IOS router template

+
+ +
+
+

Copy IOS router template

+
diff --git a/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.ts b/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.ts index eb1dd44de..5a8717e7b 100644 --- a/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.ts +++ b/src/app/components/preferences/dynamips/copy-ios-template/copy-ios-template.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -14,31 +14,31 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./copy-ios-template.component.scss', '../../preferences.component.scss'], }) export class CopyIosTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; iosTemplate: IosTemplate; - formGroup: FormGroup; + formGroup: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iosService: IosService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.formGroup = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.iosService.getTemplate(this.server, template_id).subscribe((iosTemplate: IosTemplate) => { + this.iosService.getTemplate(this.controller, template_id).subscribe((iosTemplate: IosTemplate) => { this.iosTemplate = iosTemplate; this.templateName = `Copy of ${this.iosTemplate.name}`; }); @@ -46,7 +46,7 @@ export class CopyIosTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'dynamips', 'templates']); } addTemplate() { @@ -54,7 +54,7 @@ export class CopyIosTemplateComponent implements OnInit { this.iosTemplate.template_id = uuid(); this.iosTemplate.name = this.templateName; - this.iosService.addTemplate(this.server, this.iosTemplate).subscribe((template: IosTemplate) => { + this.iosService.addTemplate(this.controller, this.iosTemplate).subscribe((template: IosTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.spec.ts b/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.spec.ts index 1cf24f9d8..f708bf602 100644 --- a/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.spec.ts +++ b/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.spec.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,10 +9,10 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { ServerSettingsService } from '../../../../services/server-settings.service'; -import { MockedServerSettingsService } from '../../../../services/server-settings.service.spec'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerSettingsService } from '../../../../services/controller-settings.service'; +import { MockedControllerSettingsService } from '../../../../services/controller-settings.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; @@ -22,13 +22,13 @@ describe('DynamipsPreferencesComponent', () => { let component: DynamipsPreferencesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let activatedRoute = new MockedActivatedRoute().get(); - let mockedServerSettingsService = new MockedServerSettingsService(); + let mockedControllerSettingsService = new MockedControllerSettingsService(); let mockedToasterService = new MockedToasterService(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ HttpClientModule, MatIconModule, @@ -44,14 +44,14 @@ describe('DynamipsPreferencesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, - { provide: ServerSettingsService, useValue: mockedServerSettingsService }, + { provide: ControllerService, useValue: mockedControllerService }, + { provide: ControllerSettingsService, useValue: mockedControllerSettingsService }, { provide: ToasterService, useValue: mockedToasterService }, ], declarations: [DynamipsPreferencesComponent], - schemas: [NO_ERRORS_SCHEMA], + schemas: [NO_ERRORS_SCHEMA,CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DynamipsPreferencesComponent); diff --git a/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.ts b/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.ts index a81262864..9a76977c6 100644 --- a/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.ts +++ b/src/app/components/preferences/dynamips/dynamips-preferences/dynamips-preferences.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { ServerSettingsService } from '../../../../services/server-settings.service'; -import { ServerService } from '../../../../services/server.service'; +import{ Controller } from '../../../../models/controller'; +import { ControllerSettingsService } from '../../../../services/controller-settings.service'; +import { ControllerService } from '../../../../services/controller.service'; @Component({ selector: 'app-dynamips-preferences', @@ -10,19 +10,19 @@ import { ServerService } from '../../../../services/server.service'; styleUrls: ['./dynamips-preferences.component.scss'], }) export class DynamipsPreferencesComponent implements OnInit { - server: Server; + controller:Controller ; dynamipsPath: string; constructor( private route: ActivatedRoute, - private serverService: ServerService, - private serverSettingsService: ServerSettingsService + private controllerService: ControllerService, + private controllerSettingsService: ControllerSettingsService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } diff --git a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.html b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.html index 8c3f8c83c..ee1401c20 100644 --- a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.html +++ b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.html @@ -282,7 +282,7 @@
WICs
diff --git a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.spec.ts b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.spec.ts index e7413abd3..883efa132 100644 --- a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.spec.ts +++ b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,23 +10,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { IosConfigurationService } from '../../../../services/ios-configuration.service'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { IosTemplateDetailsComponent } from './ios-template-details.component'; export class MockedIosService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as IosTemplate); } - public saveTemplate(server: Server, iosTemplate: IosTemplate) { + public saveTemplate(controller:Controller , iosTemplate: IosTemplate) { return of(iosTemplate); } } @@ -35,13 +35,13 @@ describe('IosTemplateDetailsComponent', () => { let component: IosTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIosService = new MockedIosService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -58,7 +58,7 @@ describe('IosTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IosService, useValue: mockedIosService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: IosConfigurationService, useClass: IosConfigurationService }, @@ -66,7 +66,7 @@ describe('IosTemplateDetailsComponent', () => { declarations: [IosTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(IosTemplateDetailsComponent); diff --git a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.ts b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.ts index 750b9231c..8dfae1aaf 100644 --- a/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.ts +++ b/src/app/components/preferences/dynamips/ios-template-details/ios-template-details.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { IosConfigurationService } from '../../../../services/ios-configuration.service'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -14,7 +14,7 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./ios-template-details.component.scss', '../../preferences.component.scss'], }) export class IosTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; iosTemplate: IosTemplate; isSymbolSelectionOpened: boolean = false; @@ -31,51 +31,51 @@ export class IosTemplateDetailsComponent implements OnInit { networkAdaptersForPlatform = {}; networkModules = {}; - generalSettingsForm: FormGroup; - memoryForm: FormGroup; - advancedForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + memoryForm: UntypedFormGroup; + advancedForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iosService: IosService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private iosConfigurationService: IosConfigurationService, private router: Router ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), - path: new FormControl('', Validators.required), - initialConfig: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), + path: new UntypedFormControl('', Validators.required), + initialConfig: new UntypedFormControl('', Validators.required), }); this.memoryForm = this.formBuilder.group({ - ram: new FormControl('', Validators.required), - nvram: new FormControl('', Validators.required), - iomemory: new FormControl('', Validators.required), - disk0: new FormControl('', Validators.required), - disk1: new FormControl('', Validators.required), + ram: new UntypedFormControl('', Validators.required), + nvram: new UntypedFormControl('', Validators.required), + iomemory: new UntypedFormControl('', Validators.required), + disk0: new UntypedFormControl('', Validators.required), + disk1: new UntypedFormControl('', Validators.required), }); this.advancedForm = this.formBuilder.group({ - systemId: new FormControl('', Validators.required), - idlemax: new FormControl('', Validators.required), - idlesleep: new FormControl('', Validators.required), - execarea: new FormControl('', Validators.required), + systemId: new UntypedFormControl('', Validators.required), + idlemax: new UntypedFormControl('', Validators.required), + idlesleep: new UntypedFormControl('', Validators.required), + execarea: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.iosService.getTemplate(this.server, template_id).subscribe((iosTemplate: IosTemplate) => { + this.iosService.getTemplate(this.controller, template_id).subscribe((iosTemplate: IosTemplate) => { this.iosTemplate = iosTemplate; this.fillAdaptersData(); @@ -123,14 +123,14 @@ export class IosTemplateDetailsComponent implements OnInit { } else { this.completeAdaptersData(); - this.iosService.saveTemplate(this.server, this.iosTemplate).subscribe((iosTemplate: IosTemplate) => { + this.iosService.saveTemplate(this.controller, this.iosTemplate).subscribe((iosTemplate: IosTemplate) => { this.toasterService.success('Changes saved'); }); } } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'dynamips', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'dynamips', 'templates']); } chooseSymbol() { diff --git a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.html b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.html index d522abb86..0320cac6b 100644 --- a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.html +++ b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.html @@ -1,31 +1,38 @@
-

IOS router templates

- - +
+ +
+
+

IOS router templates

+
+
+ +
- +
{{ template.name @@ -40,10 +47,13 @@

IOS router templates

+
- + diff --git a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.spec.ts b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.spec.ts index 62bb84f76..df49bc652 100644 --- a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.spec.ts +++ b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { IosTemplatesComponent } from './ios-templates.component'; export class MockedIosService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as IosTemplate]); } } @@ -27,12 +27,12 @@ describe('IosTemplatesComponent', () => { let component: IosTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIosService = new MockedIosService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,13 +47,13 @@ describe('IosTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IosService, useValue: mockedIosService }, ], declarations: [IosTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(IosTemplatesComponent); diff --git a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.ts b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.ts index 2cc9a6b40..029585275 100644 --- a/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.ts +++ b/src/app/components/preferences/dynamips/ios-templates/ios-templates.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IosTemplate } from '../../../../models/templates/ios-template'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; import { IosService } from '../../../../services/ios.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @Component({ @@ -13,27 +13,27 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./ios-templates.component.scss', '../../preferences.component.scss'], }) export class IosTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; iosTemplates: IosTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iosService: IosService, private router: Router ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.iosService.getTemplates(this.server).subscribe((templates: IosTemplate[]) => { + this.iosService.getTemplates(this.controller).subscribe((templates: IosTemplate[]) => { this.iosTemplates = templates.filter((elem) => elem.template_type === 'dynamips' && !elem.builtin); }); } @@ -48,8 +48,8 @@ export class IosTemplatesComponent implements OnInit { copyTemplate(template: IosTemplate) { this.router.navigate([ - '/server', - this.server.id, + '/controller', + this.controller.id, 'preferences', 'dynamips', 'templates', diff --git a/src/app/components/preferences/general/general-preferences.component.spec.ts b/src/app/components/preferences/general/general-preferences.component.spec.ts index 4cfd7d570..a8b27f5dd 100644 --- a/src/app/components/preferences/general/general-preferences.component.spec.ts +++ b/src/app/components/preferences/general/general-preferences.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -16,8 +16,8 @@ describe('GeneralPreferencesComponent', () => { let fixture: ComponentFixture; let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -36,7 +36,7 @@ describe('GeneralPreferencesComponent', () => { declarations: [GeneralPreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(GeneralPreferencesComponent); @@ -48,7 +48,7 @@ describe('GeneralPreferencesComponent', () => { expect(component).toBeTruthy(); }); - it('should set correct server id', () => { - expect(component.serverId).toBe('1'); + it('should set correct controller id', () => { + expect(component.controllerId).toBe('1'); }); }); diff --git a/src/app/components/preferences/general/general-preferences.component.ts b/src/app/components/preferences/general/general-preferences.component.ts index e9f240132..22589912e 100644 --- a/src/app/components/preferences/general/general-preferences.component.ts +++ b/src/app/components/preferences/general/general-preferences.component.ts @@ -7,11 +7,11 @@ import { ActivatedRoute } from '@angular/router'; styleUrls: ['./general-preferences.component.scss'], }) export class GeneralPreferencesComponent implements OnInit { - public serverId: string = ''; + public controllerId: string = ''; constructor(private route: ActivatedRoute) {} ngOnInit() { - this.serverId = this.route.snapshot.paramMap.get('server_id'); + this.controllerId = this.route.snapshot.paramMap.get('controller_id'); } } diff --git a/src/app/components/preferences/gns3vm/gns3vm.component.html b/src/app/components/preferences/gns3vm/gns3vm.component.html deleted file mode 100644 index 8f14cd4f5..000000000 --- a/src/app/components/preferences/gns3vm/gns3vm.component.html +++ /dev/null @@ -1,66 +0,0 @@ -
-
-
-

GNS3 VM preferences

-
-
-
- - - Enable the GNS3 VM - - - - - {{ engine.name }} - - - - - - - {{ vm.vmname }} - - - - - Run the VM in headless mode - - - - - - - - MB - - - - - - - keep the GNS3 VM running - suspend the GNS3 VM - stop the GNS3 VM - - -
- - -
-
-
diff --git a/src/app/components/preferences/gns3vm/gns3vm.component.scss b/src/app/components/preferences/gns3vm/gns3vm.component.scss deleted file mode 100644 index d1ec18bf8..000000000 --- a/src/app/components/preferences/gns3vm/gns3vm.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -.form-field { - width: 100%; -} - -.select { - width: 100%; -} - -.radio-selection { - display: flex; - justify-content: space-between; -} diff --git a/src/app/components/preferences/gns3vm/gns3vm.component.ts b/src/app/components/preferences/gns3vm/gns3vm.component.ts deleted file mode 100644 index 422facdc0..000000000 --- a/src/app/components/preferences/gns3vm/gns3vm.component.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Gns3vm } from '../../../models/gns3vm/gns3vm'; -import { Gns3vmEngine } from '../../../models/gns3vm/gns3vmEngine'; -import { VM } from '../../../models/gns3vm/vm'; -import { Server } from '../../../models/server'; -import { Gns3vmService } from '../../../services/gns3vm.service'; -import { ServerService } from '../../../services/server.service'; -import { ToasterService } from '../../../services/toaster.service'; - -@Component({ - selector: 'app-gns3vm', - templateUrl: './gns3vm.component.html', - styleUrls: ['./gns3vm.component.scss'], -}) -export class Gns3vmComponent implements OnInit { - public server: Server; - public gns3vm: Gns3vm; - public vmEngines: Gns3vmEngine[]; - public vms: VM[] = []; - public vmForm: FormGroup; - public port: number; - - constructor( - private route: ActivatedRoute, - private serverService: ServerService, - private gns3vmService: Gns3vmService, - private router: Router, - private formBuilder: FormBuilder, - private toasterService: ToasterService - ) { - this.vmForm = this.formBuilder.group({ - ram: new FormControl(null, [Validators.required]), - vcpus: new FormControl(null, [Validators.required]), - }); - } - - ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - this.gns3vmService.getGns3vm(this.server).subscribe((vm: Gns3vm) => { - this.gns3vm = vm; - this.vmForm.controls['ram'].setValue(this.gns3vm.ram); - this.vmForm.controls['vcpus'].setValue(this.gns3vm.vcpus); - if (this.gns3vm.port) this.port = this.gns3vm.port; - this.gns3vmService.getGns3vmEngines(this.server).subscribe((vmEngines: Gns3vmEngine[]) => { - this.vmEngines = vmEngines; - }); - this.gns3vmService.getVms(this.server, this.gns3vm.engine).subscribe((vms: VM[]) => { - this.vms = vms; - }); - }); - }); - } - - goBack() { - this.router.navigate(['/server', this.server.id, 'preferences']); - } - - setCloseAction(action: string) { - this.gns3vm.when_exit = action; - } - - changeVmEngine(event) { - this.gns3vmService.getVms(this.server, event.value).subscribe( - (vms: VM[]) => { - this.vms = vms; - }, - (error) => {} - ); - } - - save() { - if ((this.vmForm.valid && this.gns3vm.vmname) || (this.gns3vm.engine === 'remote' && this.gns3vm.vmname)) { - this.gns3vm.ram = this.vmForm.get('ram').value; - this.gns3vm.vcpus = this.vmForm.get('vcpus').value; - if (this.port) this.gns3vm.port = this.port; - - this.gns3vmService.updateGns3vm(this.server, this.gns3vm).subscribe(() => { - this.toasterService.success('GNS3 VM updated.'); - }); - this.goBack(); - } else { - this.toasterService.error('Fill all required fields with correct values.'); - } - } -} diff --git a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.html b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.html index 28c738072..c9481a2dc 100644 --- a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.html +++ b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.html @@ -1,24 +1,30 @@
-

New IOU device template

+
+ +
+
+

New IOU device template

+
- + - Run this IOU device locally - Run this IOU device on the GNS3 VM diff --git a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.spec.ts b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.spec.ts index 04b9e29db..56c59af06 100644 --- a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.spec.ts +++ b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -16,12 +16,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouConfigurationService } from '../../../../services/iou-configuration.service'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -29,7 +29,7 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddIouTemplateComponent } from './add-iou-template.component'; export class MockedIouService { - public addTemplate(server: Server, iouTemplate: IouTemplate) { + public addTemplate(controller:Controller , iouTemplate: IouTemplate) { return of(iouTemplate); } } @@ -39,13 +39,13 @@ xdescribe('AddIouTemplateComponent', () => { let component: AddIouTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIouService = new MockedIouService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatStepperModule, FormsModule, @@ -62,12 +62,12 @@ xdescribe('AddIouTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/iou/templates', component: AddIouTemplateComponent }, + { path: 'controller/1/preferences/iou/templates', component: AddIouTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IouService, useValue: mockedIouService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, @@ -76,7 +76,7 @@ xdescribe('AddIouTemplateComponent', () => { declarations: [AddIouTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddIouTemplateComponent); @@ -93,7 +93,7 @@ xdescribe('AddIouTemplateComponent', () => { component.templateNameForm.controls['templateName'].setValue('sample name'); component.imageForm.controls['imageName'].setValue('sample name'); component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -104,7 +104,7 @@ xdescribe('AddIouTemplateComponent', () => { spyOn(mockedIouService, 'addTemplate').and.returnValue(of({} as IouTemplate)); component.imageForm.controls['imageName'].setValue('sample name'); component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -115,7 +115,7 @@ xdescribe('AddIouTemplateComponent', () => { spyOn(mockedIouService, 'addTemplate').and.returnValue(of({} as IouTemplate)); component.templateNameForm.controls['templateName'].setValue('sample name'); component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.ts b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.ts index 13a7568cd..5d167976c 100644 --- a/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.ts +++ b/src/app/components/preferences/ios-on-unix/add-iou-template/add-iou-template.component.ts @@ -1,15 +1,19 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; +import { UploadServiceService } from 'app/common/uploading-processbar/upload-service.service'; +import { UploadingProcessbarComponent } from 'app/common/uploading-processbar/uploading-processbar.component'; import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; +import { Subscription } from 'rxjs'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../models/compute'; import { IouImage } from '../../../../models/iou/iou-image'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { ComputeService } from '../../../../services/compute.service'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -18,8 +22,8 @@ import { ToasterService } from '../../../../services/toaster.service'; templateUrl: './add-iou-template.component.html', styleUrls: ['./add-iou-template.component.scss', '../../preferences.component.scss'], }) -export class AddIouTemplateComponent implements OnInit { - server: Server; +export class AddIouTemplateComponent implements OnInit, OnDestroy { + controller:Controller ; iouTemplate: IouTemplate; isRemoteComputerChosen: boolean = false; newImageSelected: boolean = false; @@ -28,42 +32,48 @@ export class AddIouTemplateComponent implements OnInit { iouImages: IouImage[] = []; uploader: FileUploader; - templateNameForm: FormGroup; - imageForm: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + templateNameForm: UntypedFormGroup; + imageForm: UntypedFormGroup; isLocalComputerChosen: boolean = true; + uploadProgress: number = 0 + subscription: Subscription; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iouService: IouService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private templateMocksService: TemplateMocksService, - private computeService: ComputeService + private computeService: ComputeService, + private uploadServiceService: UploadServiceService, + private snackBar: MatSnackBar ) { this.iouTemplate = new IouTemplate(); this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl(null, Validators.required), + templateName: new UntypedFormControl(null, Validators.required), }); this.imageForm = this.formBuilder.group({ - imageName: new FormControl('', Validators.required), + imageName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.uploader = new FileUploader({}); + this.uploader = new FileUploader({url: ''}); this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; }; this.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { this.toasterService.error('An error occured: ' + response); }; + this.uploader.onProgressItem = (progress: any) => { + this.uploadProgress = progress['progress']; + this.uploadServiceService.processBarCount(this.uploadProgress) + }; + this.uploader.onSuccessItem = ( item: FileItem, response: string, @@ -74,33 +84,31 @@ export class AddIouTemplateComponent implements OnInit { this.toasterService.success('Image uploaded'); }; - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getImages(); - this.templateMocksService.getIouTemplate().subscribe((iouTemplate: IouTemplate) => { this.iouTemplate = iouTemplate; }); - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); }); + this.subscription = this.uploadServiceService.currentCancelItemDetails.subscribe((isCancel) => { + if (isCancel) { + this.cancelUploading() + } + + }) + } getImages() { - this.iouService.getImages(this.server).subscribe((images: IouImage[]) => { + this.iouService.getImages(this.controller).subscribe((images: IouImage[]) => { this.iouImages = images; }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } @@ -113,17 +121,31 @@ export class AddIouTemplateComponent implements OnInit { let name = event.target.files[0].name; this.imageForm.controls['imageName'].setValue(name); - const url = this.iouService.getImagePath(this.server, name); + const url = this.iouService.getImagePath(this.controller, name); this.uploader.queue.forEach((elem) => (elem.url = url)); const itemToUpload = this.uploader.queue[0]; - (itemToUpload as any).options.disableMultipart = true; - + if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.controller.authToken }]) this.uploader.uploadItem(itemToUpload); + this.snackBar.openFromComponent(UploadingProcessbarComponent, { + panelClass: 'uplaoding-file-snackabar', + data:{upload_file_type:'Image'} + }); + + } + + cancelUploading() { + this.uploader.clearQueue(); + this.uploadServiceService.processBarCount(100) + this.toasterService.warning('File upload cancelled'); + // this.uploadServiceService.cancelFileUploading(false) + // window.location.reload() } + + goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'iou', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'iou', 'templates']); } addTemplate() { @@ -134,7 +156,7 @@ export class AddIouTemplateComponent implements OnInit { this.iouTemplate.template_id = uuid(); this.iouTemplate.name = this.templateNameForm.get('templateName').value; if (this.newImageSelected) this.iouTemplate.path = this.imageForm.get('imageName').value; - this.iouTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + this.iouTemplate.compute_id = 'local'; if (this.selectedType === 'L2 image') { this.iouTemplate.ethernet_adapters = 4; @@ -144,11 +166,15 @@ export class AddIouTemplateComponent implements OnInit { this.iouTemplate.serial_adapters = 2; } - this.iouService.addTemplate(this.server, this.iouTemplate).subscribe((template: IouTemplate) => { + this.iouService.addTemplate(this.controller, this.iouTemplate).subscribe((template: IouTemplate) => { this.goBack(); }); } else { this.toasterService.error(`Fill all required fields`); } } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } } diff --git a/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.html b/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.html index b9ca46692..9d097e10a 100644 --- a/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.html +++ b/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.html @@ -1,7 +1,20 @@
-

Copy IOU device template

+
+ +
+
+

Copy IOU device template

+
diff --git a/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.ts b/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.ts index 9bff80828..c4b67197a 100644 --- a/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.ts +++ b/src/app/components/preferences/ios-on-unix/copy-iou-template/copy-iou-template.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -14,31 +14,31 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./copy-iou-template.component.scss', '../../preferences.component.scss'], }) export class CopyIouTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; iouTemplate: IouTemplate; - templateNameForm: FormGroup; + templateNameForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private qemuService: IouService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.qemuService.getTemplate(this.server, template_id).subscribe((iouTemplate: IouTemplate) => { + this.qemuService.getTemplate(this.controller, template_id).subscribe((iouTemplate: IouTemplate) => { this.iouTemplate = iouTemplate; this.templateName = `Copy of ${this.iouTemplate.name}`; }); @@ -46,7 +46,7 @@ export class CopyIouTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'iou', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'iou', 'templates']); } addTemplate() { @@ -54,7 +54,7 @@ export class CopyIouTemplateComponent implements OnInit { this.iouTemplate.template_id = uuid(); this.iouTemplate.name = this.templateName; - this.qemuService.addTemplate(this.server, this.iouTemplate).subscribe((template: IouTemplate) => { + this.qemuService.addTemplate(this.controller, this.iouTemplate).subscribe((template: IouTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.html b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.html index 6d8cc52b4..5c0595bf7 100644 --- a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.html +++ b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.html @@ -1,7 +1,16 @@
-

IOU device configuration

+
+
+ +
+
+

IOU device configuration

+
+
@@ -150,7 +159,7 @@

IOU device configuration

diff --git a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.spec.ts b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.spec.ts index ddeae4496..04945f98f 100644 --- a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.spec.ts +++ b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,23 +10,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouConfigurationService } from '../../../../services/iou-configuration.service'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { IouTemplateDetailsComponent } from './iou-template-details.component'; export class MockedIouService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as IouTemplate); } - public saveTemplate(server: Server, iouTemplate: IouTemplate) { + public saveTemplate(controller:Controller , iouTemplate: IouTemplate) { return of(iouTemplate); } } @@ -35,13 +35,13 @@ describe('IouTemplateDetailsComponent', () => { let component: IouTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIouService = new MockedIouService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -55,7 +55,7 @@ describe('IouTemplateDetailsComponent', () => { ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IouService, useValue: mockedIouService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: IouConfigurationService, useClass: IouConfigurationService }, @@ -63,7 +63,7 @@ describe('IouTemplateDetailsComponent', () => { declarations: [IouTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(IouTemplateDetailsComponent); diff --git a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.ts b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.ts index e4a38306b..5d104ec2c 100644 --- a/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.ts +++ b/src/app/components/preferences/ios-on-unix/iou-template-details/iou-template-details.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouConfigurationService } from '../../../../services/iou-configuration.service'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -14,7 +14,7 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./iou-template-details.component.scss', '../../preferences.component.scss'], }) export class IouTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; iouTemplate: IouTemplate; isSymbolSelectionOpened: boolean = false; @@ -24,40 +24,40 @@ export class IouTemplateDetailsComponent implements OnInit { consoleResolutions: string[] = []; categories = []; - generalSettingsForm: FormGroup; - networkForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + networkForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iouService: IouService, private toasterService: ToasterService, private configurationService: IouConfigurationService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), - path: new FormControl('', Validators.required), - initialConfig: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), + path: new UntypedFormControl('', Validators.required), + initialConfig: new UntypedFormControl('', Validators.required), }); this.networkForm = this.formBuilder.group({ - ethernetAdapters: new FormControl('', Validators.required), - serialAdapters: new FormControl('', Validators.required), + ethernetAdapters: new UntypedFormControl('', Validators.required), + serialAdapters: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.iouService.getTemplate(this.server, template_id).subscribe((iouTemplate: IouTemplate) => { + this.iouService.getTemplate(this.controller, template_id).subscribe((iouTemplate: IouTemplate) => { this.iouTemplate = iouTemplate; }); }); @@ -69,14 +69,14 @@ export class IouTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'iou', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'iou', 'templates']); } onSave() { if (this.generalSettingsForm.invalid || this.networkForm.invalid) { this.toasterService.error(`Fill all required fields`); } else { - this.iouService.saveTemplate(this.server, this.iouTemplate).subscribe(() => { + this.iouService.saveTemplate(this.controller, this.iouTemplate).subscribe(() => { this.toasterService.success('Changes saved'); }); } diff --git a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.html b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.html index 72d551047..3408db33d 100644 --- a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.html +++ b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.html @@ -1,31 +1,37 @@
-

IOU device templates

- - +
+ +
+
+

IOU device templates

+
+
+ +
- +
{{ template.name @@ -40,10 +46,13 @@

IOU device templates

+
- + diff --git a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.spec.ts b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.spec.ts index 9c8ebfd0b..7b931f938 100644 --- a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.spec.ts +++ b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { IouTemplatesComponent } from './iou-templates.component'; export class MockedIouService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as IouTemplate]); } } @@ -27,12 +27,12 @@ describe('IouTemplatesComponent', () => { let component: IouTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedIouService = new MockedIouService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -44,13 +44,13 @@ describe('IouTemplatesComponent', () => { ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: IouService, useValue: mockedIouService }, ], declarations: [IouTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(IouTemplatesComponent); diff --git a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.ts b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.ts index 9f1400587..eed63fc89 100644 --- a/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.ts +++ b/src/app/components/preferences/ios-on-unix/iou-templates/iou-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { IouTemplate } from '../../../../models/templates/iou-template'; import { IouService } from '../../../../services/iou.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,27 +12,27 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./iou-templates.component.scss', '../../preferences.component.scss'], }) export class IouTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; iouTemplates: IouTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private iouService: IouService, private router: Router ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.iouService.getTemplates(this.server).subscribe((iouTemplates: IouTemplate[]) => { + this.iouService.getTemplates(this.controller).subscribe((iouTemplates: IouTemplate[]) => { this.iouTemplates = iouTemplates.filter((elem) => elem.template_type === 'iou' && !elem.builtin); }); } @@ -46,6 +46,6 @@ export class IouTemplatesComponent implements OnInit { } copyTemplate(template: IouTemplate) { - this.router.navigate(['/server', this.server.id, 'preferences', 'iou', 'templates', template.template_id, 'copy']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'iou', 'templates', template.template_id, 'copy']); } } diff --git a/src/app/components/preferences/preferences.component.html b/src/app/components/preferences/preferences.component.html index 8ca23a4be..ec9868e5b 100644 --- a/src/app/components/preferences/preferences.component.html +++ b/src/app/components/preferences/preferences.component.html @@ -1,24 +1,38 @@
-

Preferences

+
+ +
+
+

Template preferences

+
- GNS3 VM - Built-in - Dynamips - IOS on Unix - VPCS - QEMU - VirtualBox - VMware - Docker - + Built-in + + Dynamips + + + IOS on Unix + + VPCS + QEMU + + VirtualBox + + VMware + Docker
diff --git a/src/app/components/preferences/preferences.component.spec.ts b/src/app/components/preferences/preferences.component.spec.ts index 690b0c0cd..bfd98d207 100644 --- a/src/app/components/preferences/preferences.component.spec.ts +++ b/src/app/components/preferences/preferences.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -36,8 +36,8 @@ describe('PreferencesComponent', () => { let fixture: ComponentFixture; let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -56,7 +56,7 @@ describe('PreferencesComponent', () => { declarations: [PreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(PreferencesComponent); @@ -68,7 +68,7 @@ describe('PreferencesComponent', () => { expect(component).toBeTruthy(); }); - it('should save correct server id', () => { - expect(component.serverId).toBe('1'); + it('should save correct controller id', () => { + expect(component.controllerId).toBe('1'); }); }); diff --git a/src/app/components/preferences/preferences.component.ts b/src/app/components/preferences/preferences.component.ts index 42de52bab..98ab9840d 100644 --- a/src/app/components/preferences/preferences.component.ts +++ b/src/app/components/preferences/preferences.component.ts @@ -7,11 +7,11 @@ import { ActivatedRoute } from '@angular/router'; styleUrls: ['./preferences.component.scss'], }) export class PreferencesComponent implements OnInit { - public serverId: string = ''; + public controllerId: string = ''; constructor(private route: ActivatedRoute) {} ngOnInit() { - this.serverId = this.route.snapshot.paramMap.get('server_id'); + this.controllerId = this.route.snapshot.paramMap.get('controller_id'); } } diff --git a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.html b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.html index 9d2bf8dd3..521079aa6 100644 --- a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.html +++ b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.html @@ -1,24 +1,24 @@
-

New QEMU VM template

+
+ +
+
+

New QEMU VM template

+
- + - Run this QEMU VM locally - Run this QEMU VM on the GNS3 VM @@ -36,16 +36,12 @@

New QEMU VM template

- +
- - - {{ binary.path }} + + + {{ platform }}
@@ -110,9 +106,6 @@

New QEMU VM template

placeholder="Please enter name" /> -
- -
diff --git a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.spec.ts b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.spec.ts index 3e1927468..2543f5c9e 100644 --- a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.spec.ts +++ b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -15,12 +15,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuConfigurationService } from '../../../../services/qemu-configuration.service'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -28,15 +28,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddQemuVmTemplateComponent } from './add-qemu-vm-template.component'; export class MockedQemuService { - public addTemplate(server: Server, qemuTemplate: QemuTemplate) { + public addTemplate(controller:Controller , qemuTemplate: QemuTemplate) { return of(qemuTemplate); } - public getBinaries(server: Server) { - return of([]); - } - - public getImages(server: Server) { + public getImages(controller:Controller ) { return of([]); } } @@ -46,7 +42,7 @@ xdescribe('AddQemuVmTemplateComponent', () => { let component: AddQemuVmTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedQemuService = new MockedQemuService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); @@ -54,8 +50,8 @@ xdescribe('AddQemuVmTemplateComponent', () => { navigate: jasmine.createSpy('navigate'), }; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatStepperModule, FormsModule, @@ -71,13 +67,13 @@ xdescribe('AddQemuVmTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/qemu/templates', component: AddQemuVmTemplateComponent }, + { path: 'controller/1/preferences/qemu/templates', component: AddQemuVmTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, { provide: Router, useValue: router }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: QemuService, useValue: mockedQemuService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, @@ -86,7 +82,7 @@ xdescribe('AddQemuVmTemplateComponent', () => { declarations: [AddQemuVmTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddQemuVmTemplateComponent); @@ -105,12 +101,8 @@ xdescribe('AddQemuVmTemplateComponent', () => { component.memoryForm.controls['ramMemory'].setValue(0); component.diskForm.controls['fileName'].setValue('file name'); component.chosenImage = 'path'; - component.selectedBinary = { - path: 'path', - version: 'version', - }; component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -124,12 +116,8 @@ xdescribe('AddQemuVmTemplateComponent', () => { component.memoryForm.controls['ramMemory'].setValue(0); component.diskForm.controls['fileName'].setValue('file name'); component.chosenImage = 'path'; - component.selectedBinary = { - path: 'path', - version: 'version', - }; component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -142,12 +130,8 @@ xdescribe('AddQemuVmTemplateComponent', () => { component.memoryForm.controls['binary'].setValue('binary'); component.diskForm.controls['fileName'].setValue('file name'); component.chosenImage = 'path'; - component.selectedBinary = { - path: 'path', - version: 'version', - }; component.newImageSelected = true; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.ts b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.ts index 40db72802..cfdc1718a 100644 --- a/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.ts +++ b/src/app/components/preferences/qemu/add-qemu-vm-template/add-qemu-vm-template.component.ts @@ -1,17 +1,20 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; -import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; +import { UploadServiceService } from '../../../../common/uploading-processbar/upload-service.service'; +import { UploadingProcessbarComponent } from 'app/common/uploading-processbar/uploading-processbar.component'; +import { FileItem, FileUploader, FileUploaderOptions, ParsedResponseHeaders } from 'ng2-file-upload'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../models/compute'; import { QemuBinary } from '../../../../models/qemu/qemu-binary'; import { QemuImage } from '../../../../models/qemu/qemu-image'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { ComputeService } from '../../../../services/compute.service'; import { QemuConfigurationService } from '../../../../services/qemu-configuration.service'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -21,9 +24,9 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./add-qemu-vm-template.component.scss', '../../preferences.component.scss'], }) export class AddQemuVmTemplateComponent implements OnInit { - server: Server; - qemuBinaries: QemuBinary[] = []; - selectedBinary: QemuBinary; + controller:Controller ; + selectPlatform: string[] = []; + selectedPlatform: string; ramMemory: number; consoleTypes: string[] = []; newImageSelected: boolean = false; @@ -35,42 +38,42 @@ export class AddQemuVmTemplateComponent implements OnInit { uploadedFile: boolean = false; uploadProgress: number = 0; - nameForm: FormGroup; - memoryForm: FormGroup; - diskForm: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + nameForm: UntypedFormGroup; + memoryForm: UntypedFormGroup; + diskForm: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private qemuService: QemuService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private templateMocksService: TemplateMocksService, private configurationService: QemuConfigurationService, - private computeService: ComputeService + private computeService: ComputeService, + private snackBar : MatSnackBar, + private uploadServiceService : UploadServiceService ) { this.qemuTemplate = new QemuTemplate(); this.nameForm = this.formBuilder.group({ - templateName: new FormControl(null, Validators.required), + templateName: new UntypedFormControl(null, Validators.required), }); this.memoryForm = this.formBuilder.group({ - ramMemory: new FormControl('256', Validators.required), + ramMemory: new UntypedFormControl('256', Validators.required), }); this.diskForm = this.formBuilder.group({ - fileName: new FormControl('', Validators.required), + fileName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.uploader = new FileUploader({}); + this.uploader = new FileUploader({url: ''}); + this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; }; @@ -83,46 +86,47 @@ export class AddQemuVmTemplateComponent implements OnInit { status: number, headers: ParsedResponseHeaders ) => { - this.qemuService.getImages(this.server).subscribe((qemuImages: QemuImage[]) => { + this.qemuService.getImages(this.controller).subscribe((qemuImages: QemuImage[]) => { this.qemuImages = qemuImages; }); this.toasterService.success('Image uploaded'); }; + this.uploader.onProgressItem = (progress: any) => { this.uploadProgress = progress['progress']; + this.uploadServiceService.processBarCount(this.uploadProgress) + }; - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.templateMocksService.getQemuTemplate().subscribe((qemuTemplate: QemuTemplate) => { this.qemuTemplate = qemuTemplate; }); - this.qemuService.getBinaries(server).subscribe((qemuBinaries: QemuBinary[]) => { - this.qemuBinaries = qemuBinaries; - if (this.qemuBinaries[0]) this.selectedBinary = this.qemuBinaries[0]; - }); - - this.qemuService.getImages(server).subscribe((qemuImages: QemuImage[]) => { + this.qemuService.getImages(this.controller).subscribe((qemuImages: QemuImage[]) => { this.qemuImages = qemuImages; }); + this.selectPlatform = this.configurationService.getPlatform(); + this.selectedPlatform = this.selectPlatform[0]; this.consoleTypes = this.configurationService.getConsoleTypes(); - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); }); + + this.uploadServiceService.currentCancelItemDetails.subscribe((isCancel) => { + if (isCancel) { + this.cancelUploading() + } + + }) + + } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } @@ -132,27 +136,37 @@ export class AddQemuVmTemplateComponent implements OnInit { } uploadImageFile(event) { - this.uploadedFile = true; + + // this.uploadedFile = true; let name = event.target.files[0].name; this.diskForm.controls['fileName'].setValue(name); - const url = this.qemuService.getImagePath(this.server, name); + const url = this.qemuService.getImagePath(this.controller, name); this.uploader.queue.forEach((elem) => (elem.url = url)); const itemToUpload = this.uploader.queue[0]; - if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; + if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers =[{name:'Authorization',value:'Bearer ' + this.controller.authToken}]) this.uploader.uploadItem(itemToUpload); + this.snackBar.openFromComponent(UploadingProcessbarComponent,{panelClass: 'uplaoding-file-snackabar', data:{upload_file_type:'Image'}}); + } + + cancelUploading() { + this.uploader.clearQueue(); + this.uploadServiceService.processBarCount(null) + this.toasterService.warning('Image Uploading canceled'); + this.uploadServiceService.cancelFileUploading(false) + } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'qemu', 'templates']); } addTemplate() { if (!this.nameForm.invalid && !this.memoryForm.invalid && (this.selectedImage || this.chosenImage)) { this.qemuTemplate.ram = +this.memoryForm.get('ramMemory').value; - this.qemuTemplate.qemu_path = this.selectedBinary.path; + this.qemuTemplate.platform = this.selectedPlatform; if (this.newImageSelected) { this.qemuTemplate.hda_disk_image = this.diskForm.get('fileName').value; } else { @@ -160,13 +174,15 @@ export class AddQemuVmTemplateComponent implements OnInit { } this.qemuTemplate.template_id = uuid(); this.qemuTemplate.name = this.nameForm.get('templateName').value; - this.qemuTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'; + this.qemuTemplate.compute_id = 'local'; - this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => { + this.qemuService.addTemplate(this.controller, this.qemuTemplate).subscribe((template: QemuTemplate) => { this.goBack(); }); } else { this.toasterService.error(`Fill all required fields`); } } + + } diff --git a/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.html b/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.html index 6661ecaa3..c64470f4e 100644 --- a/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.html +++ b/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.html @@ -1,7 +1,14 @@
-

Copy QEMU VM template

+
+ +
+
+

Copy QEMU VM template

+
diff --git a/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.ts b/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.ts index 0c8eae00b..3a5883cda 100644 --- a/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.ts +++ b/src/app/components/preferences/qemu/copy-qemu-vm-template/copy-qemu-vm-template.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { QemuBinary } from '../../../../models/qemu/qemu-binary'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; @Component({ @@ -15,32 +15,31 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./copy-qemu-vm-template.component.scss', '../../preferences.component.scss'], }) export class CopyQemuVmTemplateComponent implements OnInit { - server: Server; - qemuBinaries: QemuBinary[] = []; + controller:Controller ; templateName: string = ''; qemuTemplate: QemuTemplate; - nameForm: FormGroup; + nameForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private qemuService: QemuService, private toasterService: ToasterService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.nameForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.qemuService.getTemplate(this.server, template_id).subscribe((qemuTemplate: QemuTemplate) => { + this.qemuService.getTemplate(this.controller, template_id).subscribe((qemuTemplate: QemuTemplate) => { this.qemuTemplate = qemuTemplate; this.templateName = `Copy of ${this.qemuTemplate.name}`; }); @@ -48,7 +47,7 @@ export class CopyQemuVmTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'qemu', 'templates']); } addTemplate() { @@ -56,7 +55,7 @@ export class CopyQemuVmTemplateComponent implements OnInit { this.qemuTemplate.template_id = uuid(); this.qemuTemplate.name = this.templateName; - this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => { + this.qemuService.addTemplate(this.controller, this.qemuTemplate).subscribe((template: QemuTemplate) => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/qemu/qemu-preferences/qemu-preferences.component.html b/src/app/components/preferences/qemu/qemu-preferences/qemu-preferences.component.html index cfc27c66c..9ce733b1b 100644 --- a/src/app/components/preferences/qemu/qemu-preferences/qemu-preferences.component.html +++ b/src/app/components/preferences/qemu/qemu-preferences/qemu-preferences.component.html @@ -3,9 +3,9 @@

QEMU preferences

+
+
+

QEMU VM configuration

+
@@ -47,6 +54,13 @@

QEMU VM configuration

+ + + + {{ platform }} + + + MB @@ -54,13 +68,7 @@

QEMU VM configuration

- - - - {{ binary.path }} - - - + @@ -186,13 +194,12 @@

QEMU VM configuration

- {{ type[1] }} ({{ type[0] }}) + {{type.name}} ({{type.value}})
- Use the legacy networking mode @@ -299,7 +306,7 @@

QEMU VM configuration

> diff --git a/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.spec.ts b/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.spec.ts index db001cb94..424ab9f94 100644 --- a/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.spec.ts +++ b/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.spec.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AbstractControlDirective, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AbstractControlDirective, UntypedFormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -11,31 +11,28 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuConfigurationService } from '../../../../services/qemu-configuration.service'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { QemuVmTemplateDetailsComponent } from './qemu-vm-template-details.component'; export class MockedQemuService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as QemuTemplate); } - public saveTemplate(server: Server, qemuTemplate: QemuTemplate) { + public saveTemplate(controller:Controller , qemuTemplate: QemuTemplate) { return of(qemuTemplate); } - public getBinaries(server: Server) { - return of([]); - } - public getImages(server: Server) { + public getImages(controller:Controller ) { return of([]); } } @@ -44,13 +41,13 @@ describe('QemuVmTemplateDetailsComponent', () => { let component: QemuVmTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedQemuService = new MockedQemuService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -65,16 +62,16 @@ describe('QemuVmTemplateDetailsComponent', () => { ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: QemuService, useValue: mockedQemuService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: QemuConfigurationService, useClass: QemuConfigurationService }, - { provide: AbstractControlDirective, useExisting: FormControl, useMulti: true }, + { provide: AbstractControlDirective, useExisting: UntypedFormControl, useMulti: true }, ], declarations: [QemuVmTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(QemuVmTemplateDetailsComponent); diff --git a/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.ts b/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.ts index 4d7e1ff45..ff0c939cc 100644 --- a/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.ts +++ b/src/app/components/preferences/qemu/qemu-vm-template-details/qemu-vm-template-details.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { QemuBinary } from '../../../../models/qemu/qemu-binary'; import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuConfigurationService } from '../../../../services/qemu-configuration.service'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-adapters.component'; @@ -17,7 +17,7 @@ import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-ada styleUrls: ['./qemu-vm-template-details.component.scss', '../../preferences.component.scss'], }) export class QemuVmTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; qemuTemplate: QemuTemplate; isSymbolSelectionOpened: boolean = false; consoleTypes: string[] = []; @@ -27,47 +27,47 @@ export class QemuVmTemplateDetailsComponent implements OnInit { onCloseOptions = []; categories = []; priorities: string[] = []; - binaries: QemuBinary[] = []; activateCpuThrottling: boolean = true; isConfiguratorOpened: boolean = false; displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions']; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + selectPlatform: string[] = []; + selectedPlatform: string; + @ViewChild('customAdaptersConfigurator') customAdaptersConfigurator: CustomAdaptersComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private qemuService: QemuService, private toasterService: ToasterService, private configurationService: QemuConfigurationService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private router: Router ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.qemuService.getTemplate(this.server, template_id).subscribe((qemuTemplate: QemuTemplate) => { + this.qemuService.getTemplate(this.controller, template_id).subscribe((qemuTemplate: QemuTemplate) => { this.qemuTemplate = qemuTemplate; this.fillCustomAdapters(); - - this.qemuService.getBinaries(server).subscribe((qemuBinaries: QemuBinary[]) => { - this.binaries = qemuBinaries; - }); }); }); + + this.selectPlatform = this.configurationService.getPlatform(); } getConfiguration() { @@ -134,7 +134,7 @@ export class QemuVmTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'qemu', 'templates']); } onSave() { @@ -146,7 +146,7 @@ export class QemuVmTemplateDetailsComponent implements OnInit { } this.fillCustomAdapters(); - this.qemuService.saveTemplate(this.server, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => { + this.qemuService.saveTemplate(this.controller, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => { this.toasterService.success('Changes saved'); }); } diff --git a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.html b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.html index 98e610e01..9731d9262 100644 --- a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.html +++ b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.html @@ -1,31 +1,39 @@
+
-

QEMU VM templates

- - +
+ +
+
+

QEMU VM templates

+
+
+ +
- +
{{ template.name @@ -34,16 +42,20 @@

QEMU VM templates

more_vert - + +
- + diff --git a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.spec.ts b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.spec.ts index a21a8006b..5a2d16c9c 100644 --- a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.spec.ts +++ b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.spec.ts @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { QemuVmTemplatesComponent } from './qemu-vm-templates.component'; export class MockedQemuService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as QemuTemplate]); } } @@ -27,12 +27,12 @@ describe('QemuTemplatesComponent', () => { let component: QemuVmTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedQemuService = new MockedQemuService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,13 +47,13 @@ describe('QemuTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: QemuService, useValue: mockedQemuService }, ], declarations: [QemuVmTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(QemuVmTemplatesComponent); diff --git a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.ts b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.ts index f5c08011b..5ae66b425 100644 --- a/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.ts +++ b/src/app/components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { QemuTemplate } from '../../../../models/templates/qemu-template'; import { QemuService } from '../../../../services/qemu.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @Component({ @@ -12,27 +12,27 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./qemu-vm-templates.component.scss', '../../preferences.component.scss'], }) export class QemuVmTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; qemuTemplates: QemuTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private qemuService: QemuService, private router: Router ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.qemuService.getTemplates(this.server).subscribe((qemuTemplates: QemuTemplate[]) => { + this.qemuService.getTemplates(this.controller).subscribe((qemuTemplates: QemuTemplate[]) => { this.qemuTemplates = qemuTemplates.filter((elem) => elem.template_type === 'qemu' && !elem.builtin); }); } @@ -46,6 +46,6 @@ export class QemuVmTemplatesComponent implements OnInit { } copyTemplate(template: QemuTemplate) { - this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates', template.template_id, 'copy']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'qemu', 'templates', template.template_id, 'copy']); } } diff --git a/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.html b/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.html deleted file mode 100644 index 4c7a9b2e3..000000000 --- a/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.html +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
-

New VPCS node template

-
-
-
- -
- - - - - - -
-
-
- - -
-
-
diff --git a/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.ts b/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.ts deleted file mode 100644 index a48a0a72a..000000000 --- a/src/app/components/preferences/traceng/add-traceng/add-traceng-template.component.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; -import { TracengTemplate } from '../../../../models/templates/traceng-template'; -import { ServerService } from '../../../../services/server.service'; -import { TemplateMocksService } from '../../../../services/template-mocks.service'; -import { ToasterService } from '../../../../services/toaster.service'; -import { TracengService } from '../../../../services/traceng.service'; - -@Component({ - selector: 'app-add-traceng-template', - templateUrl: './add-traceng-template.component.html', - styleUrls: ['./add-traceng-template.component.scss', '../../preferences.component.scss'], -}) -export class AddTracengTemplateComponent implements OnInit { - server: Server; - templateName: string = ''; - ipAddress: string = ''; - templateNameForm: FormGroup; - - constructor( - private route: ActivatedRoute, - private serverService: ServerService, - private tracengService: TracengService, - private router: Router, - private toasterService: ToasterService, - private templateMocksService: TemplateMocksService, - private formBuilder: FormBuilder - ) { - this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl(null, [Validators.required]), - ipAddress: new FormControl(null, [Validators.required]), - }); - } - - ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - }); - } - - goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'traceng', 'templates']); - } - - addTemplate() { - if (!this.templateNameForm.invalid) { - this.templateName = this.templateNameForm.get('templateName').value; - this.ipAddress = this.templateNameForm.get('ipAddress').value; - let tracengTemplate: TracengTemplate = this.templateMocksService.getTracengTemplate(); - - tracengTemplate.template_id = uuid(); - tracengTemplate.name = this.templateName; - tracengTemplate.ip_address = this.ipAddress; - - this.tracengService.addTemplate(this.server, tracengTemplate).subscribe(() => { - this.goBack(); - }); - } else { - this.toasterService.error(`Fill all required fields`); - } - } -} diff --git a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.html b/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.html deleted file mode 100644 index 20b262417..000000000 --- a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
-

TraceNG preferences

-
-
-
- - - -
-
diff --git a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.scss b/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.scss deleted file mode 100644 index 8aff6f5a5..000000000 --- a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.form-field { - width: 100%; -} diff --git a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.ts b/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.ts deleted file mode 100644 index d33bb9eae..000000000 --- a/src/app/components/preferences/traceng/traceng-preferences/traceng-preferences.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { ServerService } from '../../../../services/server.service'; - -@Component({ - selector: 'app-traceng-preferences', - templateUrl: './traceng-preferences.component.html', - styleUrls: ['./traceng-preferences.component.scss'], -}) -export class TracengPreferencesComponent implements OnInit { - server: Server; - tracengExecutable: string; - - constructor(private route: ActivatedRoute, private serverService: ServerService) {} - - ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - }); - } - - restoreDefaults() { - this.tracengExecutable = ''; - } -} diff --git a/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.html b/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.html deleted file mode 100644 index 2bd439292..000000000 --- a/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.html +++ /dev/null @@ -1,51 +0,0 @@ -
-
-
-

TraceNG device configuration

-
-
-
- -
- - - - - - - - - -

-
-
-
- - -
-
-
- diff --git a/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.ts b/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.ts deleted file mode 100644 index dd56acee1..000000000 --- a/src/app/components/preferences/traceng/traceng-template-details/traceng-template-details.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { TracengTemplate } from '../../../../models/templates/traceng-template'; -import { ServerService } from '../../../../services/server.service'; -import { ToasterService } from '../../../../services/toaster.service'; -import { TracengService } from '../../../../services/traceng.service'; - -@Component({ - selector: 'app-traceng-template-details', - templateUrl: './traceng-template-details.component.html', - styleUrls: ['./traceng-template-details.component.scss', '../../preferences.component.scss'], -}) -export class TracengTemplateDetailsComponent implements OnInit { - server: Server; - tracengTemplate: TracengTemplate; - inputForm: FormGroup; - isSymbolSelectionOpened: boolean = false; - - constructor( - private route: ActivatedRoute, - private serverService: ServerService, - private tracengService: TracengService, - private toasterService: ToasterService, - private formBuilder: FormBuilder, - private router: Router - ) { - this.inputForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), - }); - } - - ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - - this.tracengService.getTemplate(this.server, template_id).subscribe((tracengTemplate: TracengTemplate) => { - this.tracengTemplate = tracengTemplate; - }); - }); - } - - goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'traceng', 'templates']); - } - - onSave() { - if (this.inputForm.invalid) { - this.toasterService.error(`Fill all required fields`); - } else { - this.tracengService - .saveTemplate(this.server, this.tracengTemplate) - .subscribe((tracengTemplate: TracengTemplate) => { - this.toasterService.success('Changes saved'); - }); - } - } - - chooseSymbol() { - this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened; - } - - symbolChanged(chosenSymbol: string) { - this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened; - this.tracengTemplate.symbol = chosenSymbol; - } -} diff --git a/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.html b/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.html deleted file mode 100644 index 0932bb848..000000000 --- a/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.html +++ /dev/null @@ -1,46 +0,0 @@ -
-
-
-

TraceNG node templates

- - -
-
- -
-
- -
- {{ - template.name - }} - - - - -
-
-
-
-
- diff --git a/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.ts b/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.ts deleted file mode 100644 index 798229ca0..000000000 --- a/src/app/components/preferences/traceng/traceng-templates/traceng-templates.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { TracengTemplate } from '../../../../models/templates/traceng-template'; -import { ServerService } from '../../../../services/server.service'; -import { TracengService } from '../../../../services/traceng.service'; -import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; - -@Component({ - selector: 'app-traceng-templates', - templateUrl: './traceng-templates.component.html', - styleUrls: ['./traceng-templates.component.scss', '../../preferences.component.scss'], -}) -export class TracengTemplatesComponent implements OnInit { - server: Server; - tracengTemplates: TracengTemplate[] = []; - @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; - - constructor( - private route: ActivatedRoute, - private serverService: ServerService, - private tracengService: TracengService - ) {} - - ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - this.getTemplates(); - }); - } - - getTemplates() { - this.tracengService.getTemplates(this.server).subscribe((tracengTemplates: TracengTemplate[]) => { - this.tracengTemplates = tracengTemplates.filter((elem) => elem.template_type === 'traceng' && !elem.builtin); - }); - } - - deleteTemplate(template: TracengTemplate) { - this.deleteComponent.deleteItem(template.name, template.template_id); - } - - onDeleteEvent() { - this.getTemplates(); - } -} diff --git a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.html b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.html index 9e53678dc..eb52c5e4d 100644 --- a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.html +++ b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.html @@ -1,7 +1,20 @@
-

New VirtualBox VM template

+
+ +
+
+

New VirtualBox VM template

+
diff --git a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.spec.ts b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.spec.ts index 3dde837f3..416464466 100644 --- a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.spec.ts +++ b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.spec.ts @@ -10,10 +10,10 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -22,11 +22,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddVirtualBoxTemplateComponent } from './add-virtual-box-template.component'; export class MockedVirtualBoxService { - public addTemplate(server: Server, virtualBoxTemplate: VirtualBoxTemplate) { + public addTemplate(controller:Controller , virtualBoxTemplate: VirtualBoxTemplate) { return of(virtualBoxTemplate); } - public getVirtualMachines(server: Server) { + public getVirtualMachines(controller:Controller ) { return of([]); } } @@ -35,13 +35,13 @@ describe('AddVirtualBoxTemplateComponent', () => { let component: AddVirtualBoxTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVirtualBoxService = new MockedVirtualBoxService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -52,12 +52,12 @@ describe('AddVirtualBoxTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/virtualbox/templates', component: AddVirtualBoxTemplateComponent }, + { path: 'controller/1/preferences/virtualbox/templates', component: AddVirtualBoxTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VirtualBoxService, useValue: mockedVirtualBoxService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, @@ -65,7 +65,7 @@ describe('AddVirtualBoxTemplateComponent', () => { declarations: [AddVirtualBoxTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddVirtualBoxTemplateComponent); @@ -97,7 +97,7 @@ describe('AddVirtualBoxTemplateComponent', () => { port_name_format: 'Ethernet{0}', port_segment_size: 0, ram: 0, - symbol: ':/symbols/vbox_guest.svg', + symbol: 'vbox_guest', template_id: '', template_type: 'virtualbox', usage: '', @@ -106,7 +106,7 @@ describe('AddVirtualBoxTemplateComponent', () => { }; component.virtualBoxTemplate = {} as VirtualBoxTemplate; component.selectedVM = template; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.vmForm.controls['vm'].setValue('virtual machine'); component.addTemplate(); @@ -116,7 +116,7 @@ describe('AddVirtualBoxTemplateComponent', () => { it('should not call save template when virtual machine is not selected', () => { spyOn(mockedVirtualBoxService, 'addTemplate').and.returnValue(of({} as VirtualBoxTemplate)); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.ts b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.ts index 06108e20d..6d83f9067 100644 --- a/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.ts +++ b/src/app/components/preferences/virtual-box/add-virtual-box-template/add-virtual-box-template.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; import { VirtualBoxVm } from '../../../../models/virtualBox/virtual-box-vm'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VirtualBoxService } from '../../../../services/virtual-box.service'; @@ -16,32 +16,33 @@ import { VirtualBoxService } from '../../../../services/virtual-box.service'; styleUrls: ['./add-virtual-box-template.component.scss', '../../preferences.component.scss'], }) export class AddVirtualBoxTemplateComponent implements OnInit { - server: Server; + controller:Controller ; virtualMachines: VirtualBoxVm[]; selectedVM: VirtualBoxVm; virtualBoxTemplate: VirtualBoxTemplate; - vmForm: FormGroup; + vmForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private virtualBoxService: VirtualBoxService, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.vmForm = this.formBuilder.group({ - vm: new FormControl('', Validators.required), + vm: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.toasterService.error(`VirtualBox VM support is deprecated and will be removed in a future version, please use Qemu VMs instead`); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.virtualBoxService.getVirtualMachines(this.server).subscribe((virtualMachines: VirtualBoxVm[]) => { + this.virtualBoxService.getVirtualMachines(this.controller).subscribe((virtualMachines: VirtualBoxVm[]) => { this.virtualMachines = virtualMachines; this.templateMocksService.getVirtualBoxTemplate().subscribe((template: VirtualBoxTemplate) => { @@ -52,7 +53,7 @@ export class AddVirtualBoxTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'virtualbox', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'virtualbox', 'templates']); } addTemplate() { @@ -62,7 +63,7 @@ export class AddVirtualBoxTemplateComponent implements OnInit { this.virtualBoxTemplate.ram = this.selectedVM.ram; this.virtualBoxTemplate.template_id = uuid(); - this.virtualBoxService.addTemplate(this.server, this.virtualBoxTemplate).subscribe(() => { + this.virtualBoxService.addTemplate(this.controller, this.virtualBoxTemplate).subscribe(() => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component.ts b/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component.ts index 3041f9f4e..f18119d67 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-preferences.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { ServerService } from '../../../../services/server.service'; +import{ Controller } from '../../../../models/controller'; +import { ControllerService } from '../../../../services/controller.service'; @Component({ selector: 'app-virtual-box-preferences', @@ -9,15 +9,15 @@ import { ServerService } from '../../../../services/server.service'; styleUrls: ['./virtual-box-preferences.component.scss'], }) export class VirtualBoxPreferencesComponent implements OnInit { - server: Server; + controller:Controller ; vboxManagePath: string; - constructor(private route: ActivatedRoute, private serverService: ServerService) {} + constructor(private route: ActivatedRoute, private controllerService: ControllerService) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } diff --git a/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-prefernces.component.spec.ts b/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-prefernces.component.spec.ts index 1a1f8289d..8e0bfab7a 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-prefernces.component.spec.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-preferences/virtual-box-prefernces.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -8,8 +8,8 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VirtualBoxPreferencesComponent } from './virtual-box-preferences.component'; @@ -17,11 +17,11 @@ describe('VirtualBoxPreferencesComponent', () => { let component: VirtualBoxPreferencesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -36,12 +36,12 @@ describe('VirtualBoxPreferencesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, ], declarations: [VirtualBoxPreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VirtualBoxPreferencesComponent); diff --git a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.html b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.html index 7f0f6e19a..4c3873023 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.html +++ b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.html @@ -1,7 +1,14 @@
-

VirtualBox VM configuration

+
+ +
+
+

VirtualBox VM configuration

+
@@ -176,7 +183,7 @@

VirtualBox VM configuration

> diff --git a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.spec.ts b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.spec.ts index 86f07a5d3..8265a6f03 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.spec.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -11,10 +11,10 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { VirtualBoxConfigurationService } from '../../../../services/virtual-box-configuration.service'; @@ -23,11 +23,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VirtualBoxTemplateDetailsComponent } from './virtual-box-template-details.component'; export class MockedVirtualBoxService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as VirtualBoxTemplate); } - public saveTemplate(server: Server, virtualBoxTemplate: VirtualBoxTemplate) { + public saveTemplate(controller:Controller , virtualBoxTemplate: VirtualBoxTemplate) { return of(virtualBoxTemplate); } } @@ -36,13 +36,13 @@ describe('VirtualBoxTemplateDetailsComponent', () => { let component: VirtualBoxTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVirtualBoxService = new MockedVirtualBoxService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -60,7 +60,7 @@ describe('VirtualBoxTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VirtualBoxService, useValue: mockedVirtualBoxService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: VirtualBoxConfigurationService, useClass: VirtualBoxConfigurationService }, @@ -68,7 +68,7 @@ describe('VirtualBoxTemplateDetailsComponent', () => { declarations: [VirtualBoxTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VirtualBoxTemplateDetailsComponent); diff --git a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.ts b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.ts index d66ac506a..a91f60bcf 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-template-details/virtual-box-template-details.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VirtualBoxConfigurationService } from '../../../../services/virtual-box-configuration.service'; import { VirtualBoxService } from '../../../../services/virtual-box.service'; @@ -16,7 +16,7 @@ import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-ada styleUrls: ['./virtual-box-template-details.component.scss', '../../preferences.component.scss'], }) export class VirtualBoxTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; virtualBoxTemplate: VirtualBoxTemplate; isSymbolSelectionOpened: boolean = false; consoleTypes: string[] = []; @@ -25,44 +25,44 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit { networkTypes = []; displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions']; isConfiguratorOpened: boolean = false; - generalSettingsForm: FormGroup; - networkForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + networkForm: UntypedFormGroup; @ViewChild('customAdaptersConfigurator') customAdaptersConfigurator: CustomAdaptersComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private virtualBoxService: VirtualBoxService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private virtualBoxConfigurationService: VirtualBoxConfigurationService, private router: Router ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), - ram: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), + ram: new UntypedFormControl('', Validators.required), }); this.networkForm = this.formBuilder.group({ - adapters: new FormControl('', Validators.required), - nameFormat: new FormControl('', Validators.required), - size: new FormControl('', Validators.required), + adapters: new UntypedFormControl('', Validators.required), + nameFormat: new UntypedFormControl('', Validators.required), + size: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); this.virtualBoxService - .getTemplate(this.server, template_id) + .getTemplate(this.controller, template_id) .subscribe((virtualBoxTemplate: VirtualBoxTemplate) => { this.virtualBoxTemplate = virtualBoxTemplate; this.fillCustomAdapters(); @@ -115,7 +115,7 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'virtualbox', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'virtualbox', 'templates']); } onSave() { @@ -125,7 +125,7 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit { this.fillCustomAdapters(); this.virtualBoxService - .saveTemplate(this.server, this.virtualBoxTemplate) + .saveTemplate(this.controller, this.virtualBoxTemplate) .subscribe((virtualBoxTemplate: VirtualBoxTemplate) => { this.toasterService.success('Changes saved'); }); diff --git a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.html b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.html index e7018d187..3cfddb451 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.html +++ b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.html @@ -1,31 +1,39 @@
-

VirtualBox VM templates

- - +
+ +
+
+

VirtualBox VM templates

+
+
+ +
+
- +
{{ template.name @@ -43,4 +51,4 @@

VirtualBox VM templates

- + diff --git a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.spec.ts b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.spec.ts index dbdfc7290..96b38843c 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.spec.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { VirtualBoxService } from '../../../../services/virtual-box.service'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VirtualBoxTemplatesComponent } from './virtual-box-templates.component'; export class MockedVirtualBoxService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as VirtualBoxTemplate]); } } @@ -27,12 +27,12 @@ describe('VirtualBoxTemplatesComponent', () => { let component: VirtualBoxTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVirtualBoxService = new MockedVirtualBoxService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,13 +47,13 @@ describe('VirtualBoxTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VirtualBoxService, useValue: mockedVirtualBoxService }, ], declarations: [VirtualBoxTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VirtualBoxTemplatesComponent); diff --git a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.ts b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.ts index 93ddbee7f..ee5d14719 100644 --- a/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.ts +++ b/src/app/components/preferences/virtual-box/virtual-box-templates/virtual-box-templates.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { VirtualBoxService } from '../../../../services/virtual-box.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @@ -13,26 +13,26 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./virtual-box-templates.component.scss', '../../preferences.component.scss'], }) export class VirtualBoxTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; virtualBoxTemplates: VirtualBoxTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private virtualBoxService: VirtualBoxService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.virtualBoxService.getTemplates(this.server).subscribe((virtualBoxTemplates: VirtualBoxTemplate[]) => { + this.virtualBoxService.getTemplates(this.controller).subscribe((virtualBoxTemplates: VirtualBoxTemplate[]) => { this.virtualBoxTemplates = virtualBoxTemplates.filter( (elem) => elem.template_type === 'virtualbox' && !elem.builtin ); diff --git a/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.html b/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.html index 40261c2d9..ca5e608b1 100644 --- a/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.html +++ b/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.html @@ -1,7 +1,14 @@
-

New VMware VM template

+
+ +
+
+

New VMware VM template

+
diff --git a/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.ts b/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.ts index 3fa8c6943..d502b0048 100644 --- a/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.ts +++ b/src/app/components/preferences/vmware/add-vmware-template/add-vmware-template.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; import { VmwareVm } from '../../../../models/vmware/vmware-vm'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VmwareService } from '../../../../services/vmware.service'; @@ -16,32 +16,33 @@ import { VmwareService } from '../../../../services/vmware.service'; styleUrls: ['./add-vmware-template.component.scss', '../../preferences.component.scss'], }) export class AddVmwareTemplateComponent implements OnInit { - server: Server; + controller:Controller ; virtualMachines: VmwareVm[]; selectedVM: VmwareVm; vmwareTemplate: VmwareTemplate; - templateNameForm: FormGroup; + templateNameForm: UntypedFormGroup; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private vmwareService: VmwareService, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, private router: Router, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl(null, [Validators.required]), + templateName: new UntypedFormControl(null, [Validators.required]), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.toasterService.error(`VMware VM support is deprecated and will be removed in a future version, please use Qemu VMs instead`); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; - this.vmwareService.getVirtualMachines(this.server).subscribe((virtualMachines: VmwareVm[]) => { + this.vmwareService.getVirtualMachines(this.controller).subscribe((virtualMachines: VmwareVm[]) => { this.virtualMachines = virtualMachines; this.templateMocksService.getVmwareTemplate().subscribe((template: VmwareTemplate) => { @@ -52,7 +53,7 @@ export class AddVmwareTemplateComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'vmware', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'vmware', 'templates']); } addTemplate() { @@ -61,7 +62,7 @@ export class AddVmwareTemplateComponent implements OnInit { this.vmwareTemplate.vmx_path = this.selectedVM.vmx_path; this.vmwareTemplate.template_id = uuid(); - this.vmwareService.addTemplate(this.server, this.vmwareTemplate).subscribe(() => { + this.vmwareService.addTemplate(this.controller, this.vmwareTemplate).subscribe(() => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/vmware/add-vmware-template/add-vmware.component.template.spec.ts b/src/app/components/preferences/vmware/add-vmware-template/add-vmware.component.template.spec.ts index b707db8c2..8c5f3d4c3 100644 --- a/src/app/components/preferences/vmware/add-vmware-template/add-vmware.component.template.spec.ts +++ b/src/app/components/preferences/vmware/add-vmware-template/add-vmware.component.template.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,11 +10,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; import { VmwareVm } from '../../../../models/vmware/vmware-vm'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -23,11 +23,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddVmwareTemplateComponent } from './add-vmware-template.component'; export class MockedVmwareService { - public addTemplate(server: Server, vmwareTemplate: VmwareTemplate) { + public addTemplate(controller:Controller , vmwareTemplate: VmwareTemplate) { return of(vmwareTemplate); } - public getVirtualMachines(server: Server) { + public getVirtualMachines(controller:Controller ) { return of([]); } } @@ -36,13 +36,13 @@ describe('AddVmwareTemplateComponent', () => { let component: AddVmwareTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVmwareService = new MockedVmwareService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -53,12 +53,12 @@ describe('AddVmwareTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/vmware/templates', component: AddVmwareTemplateComponent }, + { path: 'controller/1/preferences/vmware/templates', component: AddVmwareTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VmwareService, useValue: mockedVmwareService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: TemplateMocksService, useClass: TemplateMocksService }, @@ -66,7 +66,7 @@ describe('AddVmwareTemplateComponent', () => { declarations: [AddVmwareTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddVmwareTemplateComponent); @@ -87,7 +87,7 @@ describe('AddVmwareTemplateComponent', () => { component.vmwareTemplate = {} as VmwareTemplate; component.selectedVM = template; - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.templateNameForm.controls['templateName'].setValue('template name'); component.addTemplate(); @@ -97,7 +97,7 @@ describe('AddVmwareTemplateComponent', () => { it('should not call save template when virtual machine is not selected', () => { spyOn(mockedVmwareService, 'addTemplate').and.returnValue(of({} as VmwareTemplate)); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.spec.ts b/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.spec.ts index 59c6e54e0..1ad992fd3 100644 --- a/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.spec.ts +++ b/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -8,8 +8,8 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VmwarePreferencesComponent } from './vmware-preferences.component'; @@ -17,11 +17,11 @@ describe('VmwarePreferencesComponent', () => { let component: VmwarePreferencesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -36,12 +36,12 @@ describe('VmwarePreferencesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, ], declarations: [VmwarePreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VmwarePreferencesComponent); diff --git a/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.ts b/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.ts index d8b16b60b..f424949d2 100644 --- a/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.ts +++ b/src/app/components/preferences/vmware/vmware-preferences/vmware-preferences.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { ServerService } from '../../../../services/server.service'; +import{ Controller } from '../../../../models/controller'; +import { ControllerService } from '../../../../services/controller.service'; @Component({ selector: 'app-vmware-preferences', @@ -9,16 +9,16 @@ import { ServerService } from '../../../../services/server.service'; styleUrls: ['./vmware-preferences.component.scss'], }) export class VmwarePreferencesComponent implements OnInit { - server: Server; + controller:Controller ; vmrunPath: string; - constructor(private route: ActivatedRoute, private serverService: ServerService) {} + constructor(private route: ActivatedRoute, private controllerService: ControllerService) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } diff --git a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.html b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.html index a7b1b2d3d..d22f31cd3 100644 --- a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.html +++ b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.html @@ -1,7 +1,14 @@
+
+ +
+

VMware VM configuration

+
@@ -138,7 +145,7 @@

VMware VM configuration

> diff --git a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.spec.ts b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.spec.ts index 1d618a033..9cbf0c1b8 100644 --- a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.spec.ts +++ b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -11,10 +11,10 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { VmwareConfigurationService } from '../../../../services/vmware-configuration.service'; @@ -23,11 +23,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VmwareTemplateDetailsComponent } from './vmware-template-details.component'; export class MockedVmwareService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as VmwareTemplate); } - public saveTemplate(server: Server, vmwareTemplate: VmwareTemplate) { + public saveTemplate(controller:Controller , vmwareTemplate: VmwareTemplate) { return of(vmwareTemplate); } } @@ -36,13 +36,13 @@ describe('VmwareTemplateDetailsComponent', () => { let component: VmwareTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVmwareService = new MockedVmwareService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -60,7 +60,7 @@ describe('VmwareTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VmwareService, useValue: mockedVmwareService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: VmwareConfigurationService, useClass: VmwareConfigurationService }, @@ -68,7 +68,7 @@ describe('VmwareTemplateDetailsComponent', () => { declarations: [VmwareTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VmwareTemplateDetailsComponent); diff --git a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.ts b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.ts index a282afcd7..a2ea0f5d2 100644 --- a/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.ts +++ b/src/app/components/preferences/vmware/vmware-template-details/vmware-template-details.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VmwareConfigurationService } from '../../../../services/vmware-configuration.service'; import { VmwareService } from '../../../../services/vmware.service'; @@ -16,9 +16,9 @@ import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-ada styleUrls: ['./vmware-template-details.component.scss', '../../preferences.component.scss'], }) export class VmwareTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; vmwareTemplate: VmwareTemplate; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions']; isConfiguratorOpened: boolean = false; isSymbolSelectionOpened: boolean = false; @@ -32,28 +32,28 @@ export class VmwareTemplateDetailsComponent implements OnInit { constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private vmwareService: VmwareService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private vmwareConfigurationService: VmwareConfigurationService, private router: Router ) { this.generalSettingsForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.vmwareService.getTemplate(this.server, template_id).subscribe((vmwareTemplate: VmwareTemplate) => { + this.vmwareService.getTemplate(this.controller, template_id).subscribe((vmwareTemplate: VmwareTemplate) => { this.vmwareTemplate = vmwareTemplate; this.fillCustomAdapters(); }); @@ -68,7 +68,7 @@ export class VmwareTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'vmware', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'vmware', 'templates']); } onSave() { @@ -77,7 +77,7 @@ export class VmwareTemplateDetailsComponent implements OnInit { } else { this.fillCustomAdapters(); - this.vmwareService.saveTemplate(this.server, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => { + this.vmwareService.saveTemplate(this.controller, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => { this.toasterService.success('Changes saved'); }); } diff --git a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.html b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.html index 8442faa2c..94b32c14a 100644 --- a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.html +++ b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.html @@ -1,31 +1,39 @@
+
-

VMware VM templates

- - +
+ +
+
+

VMware VM templates

+
+
+ +
- +
{{ template.name @@ -43,4 +51,4 @@

VMware VM templates

- + diff --git a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.spec.ts b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.spec.ts index 95221b5f2..3ba6f731e 100644 --- a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.spec.ts +++ b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { VmwareService } from '../../../../services/vmware.service'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VmwareTemplatesComponent } from './vmware-templates.component'; export class MockedVmwareService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as VmwareTemplate]); } } @@ -27,12 +27,12 @@ describe('VmwareTemplatesComponent', () => { let component: VmwareTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVmwareService = new MockedVmwareService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,21 +47,21 @@ describe('VmwareTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VmwareService, useValue: mockedVmwareService }, ], declarations: [VmwareTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(VmwareTemplatesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); +beforeEach(() => { + fixture = TestBed.createComponent(VmwareTemplatesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); +}); + +it('should create', () => { + expect(component).toBeTruthy(); +}); }); diff --git a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.ts b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.ts index 8700c3b68..becd6d172 100644 --- a/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.ts +++ b/src/app/components/preferences/vmware/vmware-templates/vmware-templates.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VmwareTemplate } from '../../../../models/templates/vmware-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { VmwareService } from '../../../../services/vmware.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @@ -12,26 +12,26 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./vmware-templates.component.scss', '../../preferences.component.scss'], }) export class VmwareTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; vmwareTemplates: VmwareTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private vmwareService: VmwareService ) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.vmwareService.getTemplates(this.server).subscribe((vmwareTemplates: VmwareTemplate[]) => { + this.vmwareService.getTemplates(this.controller).subscribe((vmwareTemplates: VmwareTemplate[]) => { this.vmwareTemplates = vmwareTemplates.filter((elem) => elem.template_type === 'vmware' && !elem.builtin); }); } diff --git a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.html b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.html index f650eb76f..ae8410525 100644 --- a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.html +++ b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.html @@ -1,22 +1,28 @@
-

New VPCS node template

+
+ +
+
+

New VPCS node template

+
- Run the VPCS node locally - Run the VPCS node on the GNS3 VM
diff --git a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.spec.ts b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.spec.ts index fb84fad51..40af7b8d1 100644 --- a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.spec.ts +++ b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; @@ -10,11 +10,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; import { ComputeService } from '../../../../services/compute.service'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; @@ -23,13 +23,13 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { AddVpcsTemplateComponent } from './add-vpcs-template.component'; export class MockedComputeService { - getComputes(server: Server) { + getComputes(controller:Controller ) { return of([]); } } export class MockedVpcsService { - public addTemplate(server: Server, vpcsTemplate: VpcsTemplate) { + public addTemplate(controller:Controller , vpcsTemplate: VpcsTemplate) { return of(vpcsTemplate); } } @@ -38,13 +38,13 @@ describe('AddVpcsTemplateComponent', () => { let component: AddVpcsTemplateComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVpcsService = new MockedVpcsService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); let mockedComputeService = new MockedComputeService(); - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ FormsModule, @@ -56,12 +56,12 @@ describe('AddVpcsTemplateComponent', () => { CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([ - { path: 'server/1/preferences/vpcs/templates', component: AddVpcsTemplateComponent }, + { path: 'controller/1/preferences/vpcs/templates', component: AddVpcsTemplateComponent }, ]), ], providers: [ { provide: ActivatedRoute, useValue: activatedRoute }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VpcsService, useValue: mockedVpcsService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: ComputeService, useValue: mockedComputeService }, @@ -70,7 +70,7 @@ describe('AddVpcsTemplateComponent', () => { declarations: [AddVpcsTemplateComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(AddVpcsTemplateComponent); @@ -86,7 +86,7 @@ describe('AddVpcsTemplateComponent', () => { spyOn(mockedVpcsService, 'addTemplate').and.returnValue(of({} as VpcsTemplate)); component.templateName = 'sample name'; component.templateNameForm.controls['templateName'].setValue('template name'); - component.server = { id: 1 } as Server; + component.controller = { id: 1 } as Controller ; component.addTemplate(); @@ -96,8 +96,8 @@ describe('AddVpcsTemplateComponent', () => { it('should not call add template when template name is empty', () => { spyOn(mockedVpcsService, 'addTemplate').and.returnValue(of({} as VpcsTemplate)); spyOn(mockedToasterService, 'error'); - component.templateName = ''; - component.server = { id: 1 } as Server; + component.templateName = ' '; + component.controller = { id: 1 } as Controller ; component.addTemplate(); diff --git a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.ts b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.ts index 72feec800..7cd45e38a 100644 --- a/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.ts +++ b/src/app/components/preferences/vpcs/add-vpcs-template/add-vpcs-template.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Compute } from '../../../../models/compute'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; import { ComputeService } from '../../../../services/compute.service'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { TemplateMocksService } from '../../../../services/template-mocks.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VpcsService } from '../../../../services/vpcs.service'; @@ -17,52 +17,41 @@ import { VpcsService } from '../../../../services/vpcs.service'; styleUrls: ['./add-vpcs-template.component.scss', '../../preferences.component.scss'], }) export class AddVpcsTemplateComponent implements OnInit { - server: Server; + controller:Controller ; templateName: string = ''; - templateNameForm: FormGroup; - - isGns3VmAvailable: boolean = false; - isGns3VmChosen: boolean = false; + templateNameForm: UntypedFormGroup; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private vpcsService: VpcsService, private router: Router, private toasterService: ToasterService, private templateMocksService: TemplateMocksService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private computeService: ComputeService ) { this.templateNameForm = this.formBuilder.group({ - templateName: new FormControl(null, [Validators.required]), + templateName: new UntypedFormControl(null, [Validators.required]), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; - - this.computeService.getComputes(server).subscribe((computes: Compute[]) => { - if (computes.filter((compute) => compute.compute_id === 'vm').length > 0) this.isGns3VmAvailable = true; - }); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } - setServerType(serverType: string) { - if (serverType === 'gns3 vm' && this.isGns3VmAvailable) { - this.isGns3VmChosen = true; - this.isLocalComputerChosen = false; - } else { - this.isGns3VmChosen = false; + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'vpcs', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'vpcs', 'templates']); } addTemplate() { @@ -76,10 +65,10 @@ export class AddVpcsTemplateComponent implements OnInit { }); (vpcsTemplate.template_id = uuid()), - (vpcsTemplate.name = this.templateName), - (vpcsTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local'); + (vpcsTemplate.name = this.templateName), + (vpcsTemplate.compute_id = 'local'); - this.vpcsService.addTemplate(this.server, vpcsTemplate).subscribe(() => { + this.vpcsService.addTemplate(this.controller, vpcsTemplate).subscribe(() => { this.goBack(); }); } else { diff --git a/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.spec.ts b/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.spec.ts index c6ff9dbee..f75a9691f 100644 --- a/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.spec.ts +++ b/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.spec.ts @@ -8,8 +8,8 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VpcsPreferencesComponent } from './vpcs-preferences.component'; @@ -17,11 +17,11 @@ describe('VpcsPreferencesComponent', () => { let component: VpcsPreferencesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -36,12 +36,12 @@ describe('VpcsPreferencesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, ], declarations: [VpcsPreferencesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VpcsPreferencesComponent); diff --git a/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.ts b/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.ts index 9d5fa3837..771f48617 100644 --- a/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.ts +++ b/src/app/components/preferences/vpcs/vpcs-preferences/vpcs-preferences.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; -import { ServerService } from '../../../../services/server.service'; +import{ Controller } from '../../../../models/controller'; +import { ControllerService } from '../../../../services/controller.service'; @Component({ selector: 'app-vpcs-preferences', @@ -9,16 +9,16 @@ import { ServerService } from '../../../../services/server.service'; styleUrls: ['./vpcs-preferences.component.scss'], }) export class VpcsPreferencesComponent implements OnInit { - server: Server; + controller:Controller ; vpcsExecutable: string; - constructor(private route: ActivatedRoute, private serverService: ServerService) {} + constructor(private route: ActivatedRoute, private controllerService: ControllerService) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; }); } diff --git a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.html b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.html index 922e88c25..ae1766040 100644 --- a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.html +++ b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.html @@ -1,7 +1,20 @@
-

VPCS device configuration

+
+ +
+
+

VPCS device configuration

+
@@ -73,7 +86,7 @@

VPCS device configuration

diff --git a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.spec.ts b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.spec.ts index 608635d3e..ff4123825 100644 --- a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.spec.ts +++ b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.spec.ts @@ -10,10 +10,10 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { ToasterService } from '../../../../services/toaster.service'; import { MockedToasterService } from '../../../../services/toaster.service.spec'; import { VpcsConfigurationService } from '../../../../services/vpcs-configuration.service'; @@ -22,11 +22,11 @@ import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VpcsTemplateDetailsComponent } from './vpcs-template-details.component'; export class MockedVpcsService { - public getTemplate(server: Server, template_id: string) { + public getTemplate(controller:Controller , template_id: string) { return of({} as VpcsTemplate); } - public saveTemplate(server: Server, vpcsTemplate: VpcsTemplate) { + public saveTemplate(controller:Controller , vpcsTemplate: VpcsTemplate) { return of(vpcsTemplate); } } @@ -35,13 +35,13 @@ describe('VpcsTemplateDetailsComponent', () => { let component: VpcsTemplateDetailsComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVpcsService = new MockedVpcsService(); let mockedToasterService = new MockedToasterService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -58,7 +58,7 @@ describe('VpcsTemplateDetailsComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VpcsService, useValue: mockedVpcsService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: VpcsConfigurationService, useClass: VpcsConfigurationService }, @@ -66,7 +66,7 @@ describe('VpcsTemplateDetailsComponent', () => { declarations: [VpcsTemplateDetailsComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VpcsTemplateDetailsComponent); diff --git a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.ts b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.ts index 76dead8ae..80518e3c8 100644 --- a/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.ts +++ b/src/app/components/preferences/vpcs/vpcs-template-details/vpcs-template-details.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { ToasterService } from '../../../../services/toaster.service'; import { VpcsConfigurationService } from '../../../../services/vpcs-configuration.service'; import { VpcsService } from '../../../../services/vpcs.service'; @@ -14,38 +14,38 @@ import { VpcsService } from '../../../../services/vpcs.service'; styleUrls: ['./vpcs-template-details.component.scss', '../../preferences.component.scss'], }) export class VpcsTemplateDetailsComponent implements OnInit { - server: Server; + controller:Controller ; vpcsTemplate: VpcsTemplate; - inputForm: FormGroup; + inputForm: UntypedFormGroup; isSymbolSelectionOpened: boolean = false; consoleTypes: string[] = []; categories = []; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private vpcsService: VpcsService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private vpcsConfigurationService: VpcsConfigurationService, private router: Router ) { this.inputForm = this.formBuilder.group({ - templateName: new FormControl('', Validators.required), - defaultName: new FormControl('', Validators.required), - scriptFile: new FormControl('', Validators.required), - symbol: new FormControl('', Validators.required), + templateName: new UntypedFormControl('', Validators.required), + defaultName: new UntypedFormControl('', Validators.required), + scriptFile: new UntypedFormControl('', Validators.required), + symbol: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); const template_id = this.route.snapshot.paramMap.get('template_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getConfiguration(); - this.vpcsService.getTemplate(this.server, template_id).subscribe((vpcsTemplate: VpcsTemplate) => { + this.vpcsService.getTemplate(this.controller, template_id).subscribe((vpcsTemplate: VpcsTemplate) => { this.vpcsTemplate = vpcsTemplate; }); }); @@ -57,14 +57,14 @@ export class VpcsTemplateDetailsComponent implements OnInit { } goBack() { - this.router.navigate(['/server', this.server.id, 'preferences', 'vpcs', 'templates']); + this.router.navigate(['/controller', this.controller.id, 'preferences', 'vpcs', 'templates']); } onSave() { if (this.inputForm.invalid) { this.toasterService.error(`Fill all required fields`); } else { - this.vpcsService.saveTemplate(this.server, this.vpcsTemplate).subscribe((vpcsTemplate: VpcsTemplate) => { + this.vpcsService.saveTemplate(this.controller, this.vpcsTemplate).subscribe((vpcsTemplate: VpcsTemplate) => { this.toasterService.success('Changes saved'); }); } diff --git a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.html b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.html index 3f957137c..1d3db5a11 100644 --- a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.html +++ b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.html @@ -1,31 +1,39 @@
-

VPCS node templates

- - +
+ +
+
+

VPCS node templates

+
+
+ +
+
- +
{{ template.name @@ -34,6 +42,9 @@

VPCS node templates

more_vert + @@ -43,4 +54,4 @@

VPCS node templates

- + diff --git a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.spec.ts b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.spec.ts index eacccc118..b82a7f399 100644 --- a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.spec.ts +++ b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -9,16 +9,16 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; -import { ServerService } from '../../../../services/server.service'; -import { MockedServerService } from '../../../../services/server.service.spec'; +import { ControllerService } from '../../../../services/controller.service'; +import { MockedControllerService } from '../../../../services/controller.service.spec'; import { VpcsService } from '../../../../services/vpcs.service'; import { MockedActivatedRoute } from '../../preferences.component.spec'; import { VpcsTemplatesComponent } from './vpcs-templates.component'; export class MockedVpcsService { - public getTemplates(server: Server) { + public getTemplates(controller:Controller ) { return of([{} as VpcsTemplate]); } } @@ -27,12 +27,12 @@ describe('VpcsTemplatesComponent', () => { let component: VpcsTemplatesComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedVpcsService = new MockedVpcsService(); let activatedRoute = new MockedActivatedRoute().get(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatToolbarModule, @@ -47,13 +47,13 @@ describe('VpcsTemplatesComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: VpcsService, useValue: mockedVpcsService }, ], declarations: [VpcsTemplatesComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(VpcsTemplatesComponent); diff --git a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.ts b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.ts index f012409d6..38c95b9de 100644 --- a/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.ts +++ b/src/app/components/preferences/vpcs/vpcs-templates/vpcs-templates.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { VpcsTemplate } from '../../../../models/templates/vpcs-template'; -import { ServerService } from '../../../../services/server.service'; +import { ControllerService } from '../../../../services/controller.service'; import { VpcsService } from '../../../../services/vpcs.service'; import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component'; @@ -12,22 +12,22 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/ styleUrls: ['./vpcs-templates.component.scss', '../../preferences.component.scss'], }) export class VpcsTemplatesComponent implements OnInit { - server: Server; + controller:Controller ; vpcsTemplates: VpcsTemplate[] = []; @ViewChild(DeleteTemplateComponent) deleteComponent: DeleteTemplateComponent; - constructor(private route: ActivatedRoute, private serverService: ServerService, private vpcsService: VpcsService) {} + constructor(private route: ActivatedRoute, private controllerService: ControllerService, private vpcsService: VpcsService) {} ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - this.server = server; + const controller_id = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + this.controller = controller; this.getTemplates(); }); } getTemplates() { - this.vpcsService.getTemplates(this.server).subscribe((vpcsTemplates: VpcsTemplate[]) => { + this.vpcsService.getTemplates(this.controller).subscribe((vpcsTemplates: VpcsTemplate[]) => { this.vpcsTemplates = vpcsTemplates.filter((elem) => elem.template_type === 'vpcs' && !elem.builtin); }); } diff --git a/src/app/components/project-map/change-hostname-dialog/change-hostname-dialog.component.ts b/src/app/components/project-map/change-hostname-dialog/change-hostname-dialog.component.ts index 9a034805e..240417049 100644 --- a/src/app/components/project-map/change-hostname-dialog/change-hostname-dialog.component.ts +++ b/src/app/components/project-map/change-hostname-dialog/change-hostname-dialog.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../cartography/models/node'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { NodeService } from '../../../services/node.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -12,24 +12,24 @@ import { ToasterService } from '../../../services/toaster.service'; styleUrls: ['./change-hostname-dialog.component.scss'], }) export class ChangeHostnameDialogComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; - inputForm: FormGroup; + inputForm: UntypedFormGroup; name: string; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.inputForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = this.node.name; }); @@ -37,7 +37,7 @@ export class ChangeHostnameDialogComponent implements OnInit { onSaveClick() { if (this.inputForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.html b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.html index e9cd084c6..bded9dab8 100644 --- a/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.html +++ b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.html @@ -2,7 +2,7 @@

Change symbol for node: {{ node.name }}

diff --git a/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts index 484239dc6..5778932b4 100644 --- a/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts +++ b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../cartography/models/node'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { NodeService } from '../../../services/node.service'; @Component({ @@ -10,7 +10,7 @@ import { NodeService } from '../../../services/node.service'; styleUrls: ['./change-symbol-dialog.component.scss'], }) export class ChangeSymbolDialogComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; symbol: string; @@ -29,7 +29,7 @@ export class ChangeSymbolDialogComponent implements OnInit { } onSelectClick() { - this.nodeService.updateSymbol(this.server, this.node, this.symbol).subscribe(() => { + this.nodeService.updateSymbol(this.controller, this.node, this.symbol).subscribe(() => { this.onCloseClick(); }); } diff --git a/src/app/components/project-map/console-wrapper/console-wrapper.component.html b/src/app/components/project-map/console-wrapper/console-wrapper.component.html index 35dd3bacb..6fb665fb0 100644 --- a/src/app/components/project-map/console-wrapper/console-wrapper.component.html +++ b/src/app/components/project-map/console-wrapper/console-wrapper.component.html @@ -1,26 +1,10 @@ -
+
+
-
- +
@@ -33,63 +17,34 @@
{{ node.name }}
-
- - -
- + + -
- +
+ +
-
+
\ No newline at end of file diff --git a/src/app/components/project-map/console-wrapper/console-wrapper.component.spec.ts b/src/app/components/project-map/console-wrapper/console-wrapper.component.spec.ts index c9753326a..2093ffba1 100644 --- a/src/app/components/project-map/console-wrapper/console-wrapper.component.spec.ts +++ b/src/app/components/project-map/console-wrapper/console-wrapper.component.spec.ts @@ -16,8 +16,8 @@ describe('ConsoleWrapperComponent', () => { let mapSettingsService: MapSettingsService; let toasterService: ToasterService; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [RouterTestingModule, MatSnackBarModule], providers: [NodeConsoleService, ThemeService, MapSettingsService, ToasterService] }).compileComponents(); @@ -26,7 +26,7 @@ describe('ConsoleWrapperComponent', () => { nodeConsoleService = TestBed.inject(NodeConsoleService); themeService = TestBed.inject(ThemeService); mapSettingsService = TestBed.inject(MapSettingsService); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ConsoleWrapperComponent); diff --git a/src/app/components/project-map/console-wrapper/console-wrapper.component.ts b/src/app/components/project-map/console-wrapper/console-wrapper.component.ts index fd92b2628..4fdbee701 100644 --- a/src/app/components/project-map/console-wrapper/console-wrapper.component.ts +++ b/src/app/components/project-map/console-wrapper/console-wrapper.component.ts @@ -1,9 +1,9 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { UntypedFormControl } from '@angular/forms'; import { ResizeEvent } from 'angular-resizable-element'; import { Node } from '../../../cartography/models/node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { MapSettingsService } from '../../../services/mapsettings.service'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { ThemeService } from '../../../services/theme.service'; @@ -14,11 +14,11 @@ import { ThemeService } from '../../../services/theme.service'; styleUrls: ['./console-wrapper.component.scss'], }) export class ConsoleWrapperComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Output() closeConsole = new EventEmitter(); - filters: string[] = ['all', 'errors', 'warnings', 'info', 'map updates', 'server requests']; + filters: string[] = ['all', 'errors', 'warnings', 'info', 'map updates', 'controller requests']; selectedFilter: string = 'all'; public style: object = {}; @@ -37,7 +37,7 @@ export class ConsoleWrapperComponent implements OnInit { ) {} nodes: Node[] = []; - selected = new FormControl(0); + selected = new UntypedFormControl(0); ngOnInit() { this.themeService.getActualTheme() === 'light' diff --git a/src/app/components/project-map/context-console-menu/context-console-menu.component.spec.ts b/src/app/components/project-map/context-console-menu/context-console-menu.component.spec.ts index dbd0d0980..ac9c4e667 100644 --- a/src/app/components/project-map/context-console-menu/context-console-menu.component.spec.ts +++ b/src/app/components/project-map/context-console-menu/context-console-menu.component.spec.ts @@ -1,12 +1,12 @@ import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatMenuModule } from '@angular/material/menu'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { BrowserModule } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { ElectronService } from 'ngx-electron'; import { Node } from '../../../cartography/models/node'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { MapSettingsService } from '../../../services/mapsettings.service'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { ProjectService } from '../../../services/project.service'; @@ -32,12 +32,12 @@ describe('ContextConsoleMenuComponent', () => { status: 'started', }; - beforeEach(async(() => { + beforeEach(async () => { const electronMock = { isElectronApp: true, }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [MatMenuModule, BrowserModule, MatSnackBarModule], providers: [ { provide: ChangeDetectorRef }, @@ -57,56 +57,56 @@ describe('ContextConsoleMenuComponent', () => { toasterService = TestBed.inject(ToasterService); mapSettingsService = TestBed.inject(MapSettingsService); nodeConsoleService = TestBed.inject(NodeConsoleService); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ContextConsoleMenuComponent); - component = fixture.componentInstance; - component.server = { location: 'local' } as Server; - fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); +beforeEach(() => { + fixture = TestBed.createComponent(ContextConsoleMenuComponent); + component = fixture.componentInstance; + component.controller = { location: 'local' } as Controller ; + fixture.detectChanges(); +}); - it('should define property if running in electron ', () => { - expect(component.isElectronApp).toBeTruthy(); - }); +it('should create', () => { + expect(component).toBeTruthy(); +}); - it('should open menu if there is no default settings', () => { - let spy = spyOn(component.contextConsoleMenu, 'openMenu'); - localStorage.removeItem('consoleContextMenu'); +it('should define property if running in electron ', () => { + expect(component.isElectronApp).toBeTruthy(); +}); - component.openMenu((node as unknown) as Node, 0, 0); +it('should open menu if there is no default settings', () => { + let spy = spyOn(component.contextConsoleMenu, 'openMenu'); + localStorage.removeItem('consoleContextMenu'); - expect(spy.calls.any()).toBeTruthy(); - }); + component.openMenu((node as unknown) as Node, 0, 0); - it('should call open web console when web console action in settings', () => { - let spy = spyOn(component, 'openWebConsole'); - mapSettingsService.setConsoleContextMenuAction('web console'); + expect(spy.calls.any()).toBeTruthy(); +}); - component.openMenu((node as unknown) as Node, 0, 0); +it('should call open web console when web console action in settings', () => { + let spy = spyOn(component, 'openWebConsole'); + mapSettingsService.setConsoleContextMenuAction('web console'); - expect(spy.calls.any()).toBeTruthy(); - }); + component.openMenu((node as unknown) as Node, 0, 0); - it('should call open web console in new tab when web console in new tab action in settings', () => { - let spy = spyOn(component, 'openWebConsoleInNewTab'); - mapSettingsService.setConsoleContextMenuAction('web console in new tab'); + expect(spy.calls.any()).toBeTruthy(); +}); - component.openMenu((node as unknown) as Node, 0, 0); +it('should call open web console in new tab when web console in new tab action in settings', () => { + let spy = spyOn(component, 'openWebConsoleInNewTab'); + mapSettingsService.setConsoleContextMenuAction('web console in new tab'); - expect(spy.calls.any()).toBeTruthy(); - }); + component.openMenu((node as unknown) as Node, 0, 0); - it('should call open console when console action in settings', () => { - let spy = spyOn(component, 'openConsole'); - mapSettingsService.setConsoleContextMenuAction('console'); + expect(spy.calls.any()).toBeTruthy(); +}); - component.openMenu((node as unknown) as Node, 0, 0); +it('should call open console when console action in settings', () => { + let spy = spyOn(component, 'openConsole'); + mapSettingsService.setConsoleContextMenuAction('console'); - expect(spy.calls.any()).toBeTruthy(); - }); + component.openMenu((node as unknown) as Node, 0, 0); + + expect(spy.calls.any()).toBeTruthy(); +}); }); diff --git a/src/app/components/project-map/context-console-menu/context-console-menu.component.ts b/src/app/components/project-map/context-console-menu/context-console-menu.component.ts index d90d940de..ce0ca024c 100644 --- a/src/app/components/project-map/context-console-menu/context-console-menu.component.ts +++ b/src/app/components/project-map/context-console-menu/context-console-menu.component.ts @@ -15,7 +15,7 @@ import { Router } from '@angular/router'; import { ElectronService } from 'ngx-electron'; import { Node } from '../../../cartography/models/node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { MapSettingsService } from '../../../services/mapsettings.service'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -29,7 +29,7 @@ import { ConsoleDeviceActionComponent } from '../context-menu/actions/console-de }) export class ContextConsoleMenuComponent implements OnInit { @Input() project: Project; - @Input() server: Server; + @Input() controller:Controller ; @ViewChild(MatMenuTrigger) contextConsoleMenu: MatMenuTrigger; @ViewChild('container', { read: ViewContainerRef }) container; componentRef: ComponentRef; @@ -86,7 +86,7 @@ export class ContextConsoleMenuComponent implements OnInit { ConsoleDeviceActionComponent ); this.componentRef = this.container.createComponent(factory); - this.componentRef.instance.server = this.server; + this.componentRef.instance.controller = this.controller; this.componentRef.instance.nodes = [this.node]; this.componentRef.instance.console(); @@ -95,7 +95,7 @@ export class ContextConsoleMenuComponent implements OnInit { ConsoleDeviceActionBrowserComponent ); this.componentBrowserRef = this.container.createComponent(factory); - this.componentBrowserRef.instance.server = this.server; + this.componentBrowserRef.instance.controller = this.controller; this.componentBrowserRef.instance.node = this.node; this.componentBrowserRef.instance.openConsole(); diff --git a/src/app/components/project-map/context-menu/actions/align-horizontally/align-horizontally.component.ts b/src/app/components/project-map/context-menu/actions/align-horizontally/align-horizontally.component.ts index bab33ea4b..3970d900b 100644 --- a/src/app/components/project-map/context-menu/actions/align-horizontally/align-horizontally.component.ts +++ b/src/app/components/project-map/context-menu/actions/align-horizontally/align-horizontally.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; @Component({ @@ -9,7 +9,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './align-horizontally.component.html', }) export class AlignHorizontallyActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; constructor(private nodesDataSource: NodesDataSource, private nodeService: NodeService) {} @@ -27,7 +27,7 @@ export class AlignHorizontallyActionComponent implements OnInit { node.y = averageY; this.nodesDataSource.update(node); - this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + this.nodeService.update(this.controller, node).subscribe((node: Node) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/align_vertically/align-vertically.component.ts b/src/app/components/project-map/context-menu/actions/align_vertically/align-vertically.component.ts index 771a2ac96..1e8acebec 100644 --- a/src/app/components/project-map/context-menu/actions/align_vertically/align-vertically.component.ts +++ b/src/app/components/project-map/context-menu/actions/align_vertically/align-vertically.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; @Component({ @@ -9,7 +9,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './align-vertically.component.html', }) export class AlignVerticallyActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; constructor(private nodesDataSource: NodesDataSource, private nodeService: NodeService) {} @@ -27,7 +27,7 @@ export class AlignVerticallyActionComponent implements OnInit { node.x = averageX; this.nodesDataSource.update(node); - this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + this.nodeService.update(this.controller, node).subscribe((node: Node) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts index bdbb9a789..b23af2fb6 100644 --- a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -28,8 +28,8 @@ describe('BringToFrontActionComponent', () => { let nodeService = new MockedNodeService(); let nodesDataSource = new MockedNodesDataSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule], providers: [ { provide: DrawingService, useValue: drawingService }, @@ -39,35 +39,35 @@ describe('BringToFrontActionComponent', () => { ], declarations: [BringToFrontActionComponent], }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(BringToFrontActionComponent); - component = fixture.componentInstance; - fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); +beforeEach(() => { + fixture = TestBed.createComponent(BringToFrontActionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); +}); - it('should call node service when bring to front action called', () => { - spyOn(nodeService, 'update').and.returnValue(of()); - component.nodes = [{ z: 0 } as Node]; - component.drawings = []; +it('should create', () => { + expect(component).toBeTruthy(); +}); - component.bringToFront(); +it('should call node service when bring to front action called', () => { + spyOn(nodeService, 'update').and.returnValue(of()); + component.nodes = [{ z: 0 } as Node]; + component.drawings = []; - expect(nodeService.update).toHaveBeenCalled(); - }); + component.bringToFront(); - it('should call drawing service when bring to front action called', () => { - spyOn(drawingService, 'update').and.returnValue(of()); - component.nodes = []; - component.drawings = [{ z: 0 } as Drawing]; + expect(nodeService.update).toHaveBeenCalled(); +}); - component.bringToFront(); +it('should call drawing service when bring to front action called', () => { + spyOn(drawingService, 'update').and.returnValue(of()); + component.nodes = []; + component.drawings = [{ z: 0 } as Drawing]; - expect(drawingService.update).toHaveBeenCalled(); - }); + component.bringToFront(); + + expect(drawingService.update).toHaveBeenCalled(); +}); }); diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts index 95fc56f75..9b0ade8e8 100644 --- a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts @@ -3,7 +3,7 @@ import { DrawingsDataSource } from '../../../../../cartography/datasources/drawi import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { NodeService } from '../../../../../services/node.service'; @@ -12,7 +12,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './bring-to-front-action.component.html', }) export class BringToFrontActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; @Input() drawings: Drawing[]; @@ -35,14 +35,14 @@ export class BringToFrontActionComponent implements OnInit { node.z = maxZValue; this.nodesDataSource.update(node); - this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + this.nodeService.update(this.controller, node).subscribe((node: Node) => {}); }); this.drawings.forEach((drawing) => { drawing.z = maxZValue; this.drawingsDataSource.update(drawing); - this.drawingService.update(this.server, drawing).subscribe((drawing: Drawing) => {}); + this.drawingService.update(this.controller, drawing).subscribe((drawing: Drawing) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/change-hostname/change-hostname-action.component.ts b/src/app/components/project-map/context-menu/actions/change-hostname/change-hostname-action.component.ts index cef0973e0..b39db1557 100644 --- a/src/app/components/project-map/context-menu/actions/change-hostname/change-hostname-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/change-hostname/change-hostname-action.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { ChangeHostnameDialogComponent } from '../../../change-hostname-dialog/change-hostname-dialog.component'; @Component({ @@ -9,7 +9,7 @@ import { ChangeHostnameDialogComponent } from '../../../change-hostname-dialog/c templateUrl: './change-hostname-action.component.html', }) export class ChangeHostnameActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private dialog: MatDialog) {} @@ -22,7 +22,7 @@ export class ChangeHostnameActionComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.node = this.node; } } diff --git a/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts index cb568fce8..b354f71e3 100644 --- a/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { ChangeSymbolDialogComponent } from '../../../change-symbol-dialog/change-symbol-dialog.component'; @Component({ @@ -9,7 +9,7 @@ import { ChangeSymbolDialogComponent } from '../../../change-symbol-dialog/chang templateUrl: './change-symbol-action.component.html', }) export class ChangeSymbolActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private dialog: MatDialog) {} @@ -24,7 +24,7 @@ export class ChangeSymbolActionComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.node = this.node; } } diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts index 1b76fd419..7b34a332a 100644 --- a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { ConfiguratorDialogAtmSwitchComponent } from '../../../node-editors/configurator/atm_switch/configurator-atm-switch.component'; import { ConfiguratorDialogCloudComponent } from '../../../node-editors/configurator/cloud/configurator-cloud.component'; import { ConfiguratorDialogDockerComponent } from '../../../node-editors/configurator/docker/configurator-docker.component'; @@ -12,7 +12,6 @@ import { ConfiguratorDialogIouComponent } from '../../../node-editors/configurat import { ConfiguratorDialogNatComponent } from '../../../node-editors/configurator/nat/configurator-nat.component'; import { ConfiguratorDialogQemuComponent } from '../../../node-editors/configurator/qemu/configurator-qemu.component'; import { ConfiguratorDialogSwitchComponent } from '../../../node-editors/configurator/switch/configurator-switch.component'; -import { ConfiguratorDialogTracengComponent } from '../../../node-editors/configurator/traceng/configurator-traceng.component'; import { ConfiguratorDialogVirtualBoxComponent } from '../../../node-editors/configurator/virtualbox/configurator-virtualbox.component'; import { ConfiguratorDialogVmwareComponent } from '../../../node-editors/configurator/vmware/configurator-vmware.component'; import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configurator/vpcs/configurator-vpcs.component'; @@ -22,11 +21,11 @@ import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configura templateUrl: './config-action.component.html', }) export class ConfigActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; private conf = { autoFocus: false, - width: '800px', + width: '950px', disableClose: true, }; dialogRef; @@ -60,12 +59,10 @@ export class ConfigActionComponent { this.dialogRef = this.dialog.open(ConfiguratorDialogSwitchComponent, this.conf); } else if (this.node.node_type === 'atm_switch') { this.dialogRef = this.dialog.open(ConfiguratorDialogAtmSwitchComponent, this.conf); - } else if (this.node.node_type === 'traceng') { - this.dialogRef = this.dialog.open(ConfiguratorDialogTracengComponent, this.conf); } let instance = this.dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.node = this.node; } } diff --git a/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts index 23875107b..b5ae982a5 100644 --- a/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts +++ b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -10,13 +10,13 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './console-device-action-browser.component.html', }) export class ConsoleDeviceActionBrowserComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private toasterService: ToasterService, private nodeService: NodeService, private deviceService: DeviceDetectorService) {} openConsole() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.startConsole(); }); @@ -56,7 +56,7 @@ export class ConsoleDeviceActionBrowserComponent { this.node.console_host === '0:0:0:0:0:0:0:0' || this.node.console_host === '::' ) { - this.node.console_host = this.server.host; + this.node.console_host = this.controller.host; } const device = this.deviceService.getDeviceInfo(); diff --git a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts index d96305918..fa6505b5f 100644 --- a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts @@ -1,11 +1,11 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { ElectronService } from 'ngx-electron'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; -import { ServerService } from '../../../../../services/server.service'; -import { MockedServerService } from '../../../../../services/server.service.spec'; +import { ControllerService } from '../../../../../services/controller.service'; +import { MockedControllerService } from '../../../../../services/controller.service.spec'; import { SettingsService } from '../../../../../services/settings.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { MockedToasterService } from '../../../../../services/toaster.service.spec'; @@ -16,9 +16,9 @@ describe('ConsoleDeviceActionComponent', () => { let component: ConsoleDeviceActionComponent; let fixture: ComponentFixture; let electronService; - let server: Server; + let controller:Controller ; let settingsService: SettingsService; - let mockedServerService: MockedServerService; + let mockedControllerService: MockedControllerService; let mockedToaster: MockedToasterService; let mockedNodeService: MockedNodeService = new MockedNodeService(); @@ -34,17 +34,17 @@ describe('ConsoleDeviceActionComponent', () => { }, }; - mockedServerService = new MockedServerService(); + mockedControllerService = new MockedControllerService(); mockedToaster = new MockedToasterService(); - server = { host: 'localhost', port: 222 } as Server; + controller = { host: 'localhost', port: 222 } as Controller ; }); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ providers: [ { provide: ElectronService, useValue: electronService }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: SettingsService }, { provide: ToasterService, useValue: mockedToaster }, { provide: NodeService, useValue: mockedNodeService }, @@ -54,7 +54,7 @@ describe('ConsoleDeviceActionComponent', () => { }).compileComponents(); settingsService = TestBed.inject(SettingsService); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ConsoleDeviceActionComponent); @@ -83,7 +83,7 @@ describe('ConsoleDeviceActionComponent', () => { ]; component.nodes = nodes; - component.server = server; + component.controller = controller; settingsService.setConsoleSettings('command'); spyOn(component, 'openConsole'); @@ -100,7 +100,7 @@ describe('ConsoleDeviceActionComponent', () => { name: 'Node 1', project_id: '1111', node_id: '2222', - server_url: 'localhost:222', + controller_url: 'localhost:222', }); }); diff --git a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts index f804893c6..e601b9b58 100644 --- a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts @@ -1,9 +1,9 @@ import { Component, Input, OnInit } from '@angular/core'; import { ElectronService } from 'ngx-electron'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; -import { ServerService } from '../../../../../services/server.service'; +import { ControllerService } from '../../../../../services/controller.service'; import { SettingsService } from '../../../../../services/settings.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,12 +12,12 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './console-device-action.component.html', }) export class ConsoleDeviceActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; constructor( private electronService: ElectronService, - private serverService: ServerService, + private controllerService: ControllerService, private settingsService: SettingsService, private toasterService: ToasterService, private nodeService: NodeService @@ -49,7 +49,7 @@ export class ConsoleDeviceActionComponent implements OnInit { name: node.name, project_id: node.project_id, node_id: node.node_id, - server_url: this.serverService.getServerUrl(this.server), + controller_url: this.controllerService.getControllerUrl(this.controller), }; await this.openConsole(consoleRequest); } diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts index 9a1d510ce..ca368fc18 100644 --- a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -23,8 +23,8 @@ describe('DeleteActionComponent', () => { let mockedDrawingService: MockedDrawingService = new MockedDrawingService(); let mockedLinkService: MockedLinkService = new MockedLinkService(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [MatIconModule, MatMenuModule, NoopAnimationsModule, MatBottomSheetModule], providers: [ { provide: NodesDataSource, useClass: NodesDataSource }, @@ -36,7 +36,7 @@ describe('DeleteActionComponent', () => { ], declarations: [DeleteActionComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DeleteActionComponent); diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts index 693cb21ab..af9ace233 100644 --- a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts @@ -7,7 +7,7 @@ import { NodesDataSource } from '../../../../../cartography/datasources/nodes-da import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; import { Link } from '../../../../../models/link'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { LinkService } from '../../../../../services/link.service'; import { NodeService } from '../../../../../services/node.service'; @@ -17,7 +17,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './delete-action.component.html', }) export class DeleteActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; @Input() drawings: Drawing[]; @Input() links: Link[]; @@ -49,19 +49,19 @@ export class DeleteActionComponent implements OnInit { this.nodes.forEach((node) => { this.nodesDataSource.remove(node); - this.nodeService.delete(this.server, node).subscribe((node: Node) => {}); + this.nodeService.delete(this.controller, node).subscribe((node: Node) => {}); }); this.drawings.forEach((drawing) => { this.drawingsDataSource.remove(drawing); - this.drawingService.delete(this.server, drawing).subscribe((drawing: Drawing) => {}); + this.drawingService.delete(this.controller, drawing).subscribe((drawing: Drawing) => {}); }); this.links.forEach((link) => { this.linksDataSource.remove(link); - this.linkService.deleteLink(this.server, link).subscribe(() => {}); + this.linkService.deleteLink(this.controller, link).subscribe(() => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts index 02ebbef18..719084b04 100644 --- a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @@ -21,8 +21,8 @@ describe('DuplicateActionComponent', () => { let mockedDrawingService: MockedDrawingService = new MockedDrawingService(); let mockedToasterService = new MockedToasterService(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [MatIconModule, MatMenuModule, NoopAnimationsModule], providers: [ { provide: NodesDataSource, useClass: NodesDataSource }, @@ -33,7 +33,7 @@ describe('DuplicateActionComponent', () => { ], declarations: [DuplicateActionComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DuplicateActionComponent); diff --git a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts index a2cf43a3e..acf9f2e84 100644 --- a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts @@ -4,7 +4,7 @@ import { NodesDataSource } from '../../../../../cartography/datasources/nodes-da import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -14,7 +14,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './duplicate-action.component.html', }) export class DuplicateActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() drawings: Drawing[]; @Input() nodes: Node[]; @@ -31,7 +31,7 @@ export class DuplicateActionComponent { let runningNodes: string = ''; for (let node of this.nodes) { if (node.status === 'stopped') { - this.nodeService.duplicate(this.server, node).subscribe((node: Node) => { + this.nodeService.duplicate(this.controller, node).subscribe((node: Node) => { this.nodesDataSource.add(node); }); } else { @@ -40,7 +40,7 @@ export class DuplicateActionComponent { } for (let drawing of this.drawings) { - this.drawingService.duplicate(this.server, drawing.project_id, drawing).subscribe((drawing: Drawing) => { + this.drawingService.duplicate(this.controller, drawing.project_id, drawing).subscribe((drawing: Drawing) => { this.drawingsDataSource.add(drawing); }); } diff --git a/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts index e172382a8..2f2686e73 100644 --- a/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { ConfigEditorDialogComponent } from '../../../node-editors/config-editor/config-editor.component'; @Component({ @@ -10,7 +10,7 @@ import { ConfigEditorDialogComponent } from '../../../node-editors/config-editor templateUrl: './edit-config-action.component.html', }) export class EditConfigActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() node: Node; @@ -24,7 +24,7 @@ export class EditConfigActionComponent { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; instance.node = this.node; } diff --git a/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.html b/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.html new file mode 100644 index 000000000..43ab8ded2 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.ts new file mode 100644 index 000000000..66a0f2fcb --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.ts @@ -0,0 +1,33 @@ +import { Component, Input, OnChanges } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { Link } from '../../../../../models/link'; +import { Project } from '../../../../../models/project'; +import{ Controller } from '../../../../../models/controller'; +import { LinkStyleEditorDialogComponent } from '../../../drawings-editors/link-style-editor/link-style-editor.component'; + +@Component({ + selector: 'app-edit-link-style-action', + + templateUrl: './edit-link-style-action.component.html', +}) +export class EditLinkStyleActionComponent implements OnChanges { + @Input() controller:Controller ; + @Input() project: Project; + @Input() link: Link; + + constructor(private dialog: MatDialog) {} + + ngOnChanges() {} + + editStyle() { + const dialogRef = this.dialog.open(LinkStyleEditorDialogComponent, { + width: '800px', + autoFocus: false, + disableClose: true, + }); + let instance = dialogRef.componentInstance; + instance.controller = this.controller; + instance.project = this.project; + instance.link = this.link; + } +} diff --git a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts index 37e89e4e5..ed57c9836 100644 --- a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts @@ -3,7 +3,7 @@ import { MatDialog } from '@angular/material/dialog'; import { Drawing } from '../../../../../cartography/models/drawing'; import { ImageElement } from '../../../../../cartography/models/drawings/image-element'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { StyleEditorDialogComponent } from '../../../drawings-editors/style-editor/style-editor.component'; @Component({ @@ -11,7 +11,7 @@ import { StyleEditorDialogComponent } from '../../../drawings-editors/style-edit templateUrl: './edit-style-action.component.html', }) export class EditStyleActionComponent implements OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() drawing: Drawing; isImageDrawing: boolean = false; @@ -29,7 +29,7 @@ export class EditStyleActionComponent implements OnChanges { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; instance.drawing = this.drawing; } diff --git a/src/app/components/project-map/context-menu/actions/edit-text-action/edit-text-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-text-action/edit-text-action.component.ts index ee8472197..2f7389479 100644 --- a/src/app/components/project-map/context-menu/actions/edit-text-action/edit-text-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/edit-text-action/edit-text-action.component.ts @@ -6,7 +6,7 @@ import { Node } from '../../../../../cartography/models/node'; import { Link } from '../../../../../models/link'; import { LinkNode } from '../../../../../models/link-node'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { TextEditorDialogComponent } from '../../../drawings-editors/text-editor/text-editor.component'; @Component({ @@ -14,7 +14,7 @@ import { TextEditorDialogComponent } from '../../../drawings-editors/text-editor templateUrl: './edit-text-action.component.html', }) export class EditTextActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() drawing: Drawing; @Input() node: Node; @@ -33,7 +33,7 @@ export class EditTextActionComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; instance.drawing = this.drawing; instance.node = this.node; diff --git a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts index 84e8396a7..2d506ba42 100644 --- a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog.component'; @@ -10,14 +10,14 @@ import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog templateUrl: './export-config-action.component.html', }) export class ExportConfigActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private nodeService: NodeService, private dialog: MatDialog) {} exportConfig() { if (this.node.node_type === 'vpcs') { - this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => { + this.nodeService.getStartupConfiguration(this.controller, this.node).subscribe((config: any) => { this.downloadByHtmlTag(config); }); } else { @@ -29,11 +29,11 @@ export class ExportConfigActionComponent { let instance = dialogRef.componentInstance; dialogRef.afterClosed().subscribe((configType: string) => { if (configType === 'startup-config') { - this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => { + this.nodeService.getStartupConfiguration(this.controller, this.node).subscribe((config: any) => { this.downloadByHtmlTag(config); }); } else if (configType === 'private-config') { - this.nodeService.getPrivateConfiguration(this.server, this.node).subscribe((config: any) => { + this.nodeService.getPrivateConfiguration(this.controller, this.node).subscribe((config: any) => { this.downloadByHtmlTag(config); }); } diff --git a/src/app/components/project-map/context-menu/actions/http-console-new-tab/http-console-new-tab-action.component.ts b/src/app/components/project-map/context-menu/actions/http-console-new-tab/http-console-new-tab-action.component.ts index 73cf9ddde..d09da9273 100644 --- a/src/app/components/project-map/context-menu/actions/http-console-new-tab/http-console-new-tab-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/http-console-new-tab/http-console-new-tab-action.component.ts @@ -1,14 +1,14 @@ import { Component, Input, OnInit } from '@angular/core'; import { NodeConsoleService } from '../../../../../services/nodeConsole.service'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; @Component({ selector: 'app-http-console-new-tab-action', templateUrl: './http-console-new-tab-action.component.html', }) export class HttpConsoleNewTabActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; constructor(private nodeConsoleService: NodeConsoleService) {} diff --git a/src/app/components/project-map/context-menu/actions/http-console/http-console-action.component.ts b/src/app/components/project-map/context-menu/actions/http-console/http-console-action.component.ts index 523cdb4cb..e29d63a91 100644 --- a/src/app/components/project-map/context-menu/actions/http-console/http-console-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/http-console/http-console-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeConsoleService } from '../../../../../services/nodeConsole.service'; @Component({ @@ -8,7 +8,7 @@ import { NodeConsoleService } from '../../../../../services/nodeConsole.service' templateUrl: './http-console-action.component.html', }) export class HttpConsoleActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; constructor(private nodeConsoleService: NodeConsoleService) {} diff --git a/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts index 524e74baa..fb02fe16c 100644 --- a/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts @@ -1,7 +1,7 @@ import { Component, ElementRef, Input, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog.component'; @@ -12,7 +12,7 @@ import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog styleUrls: ['./import-config-action.component.scss'], }) export class ImportConfigActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; @ViewChild('fileInput') fileInput: ElementRef; configType: string; @@ -47,11 +47,11 @@ export class ImportConfigActionComponent { } if (this.configType === 'startup-config') { - this.nodeService.saveConfiguration(this.server, this.node, content).subscribe(() => { + this.nodeService.saveConfiguration(this.controller, this.node, content).subscribe(() => { this.toasterService.success(`Configuration for node ${this.node.name} imported.`); }); } else if (this.configType === 'private-config') { - this.nodeService.savePrivateConfiguration(this.server, this.node, content).subscribe(() => { + this.nodeService.savePrivateConfiguration(this.controller, this.node, content).subscribe(() => { this.toasterService.success(`Configuration for node ${this.node.name} imported.`); }); } diff --git a/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.html b/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.html new file mode 100644 index 000000000..3465e9b3e --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.ts b/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.ts new file mode 100644 index 000000000..a41330002 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.ts @@ -0,0 +1,27 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import{ Controller } from '../../../../../models/controller'; +import { NodeService } from '../../../../../services/node.service'; +import { ToasterService } from '../../../../../services/toaster.service'; + +@Component({ + selector: 'app-isolate-node-action', + templateUrl: './isolate-node-action.component.html', +}) +export class IsolateNodeActionComponent implements OnInit { + @Input() controller:Controller ; + @Input() node: Node; + + constructor(private nodeService: NodeService, private toasterService: ToasterService) {} + + ngOnInit() {} + + isolate() { + this.nodeService.isolate(this.controller, this.node).subscribe( + (n: Node) => {}, + (error) => { + this.toasterService.error(error.error.message); + } + ); + } +} diff --git a/src/app/components/project-map/context-menu/actions/lock-action/lock-action.component.ts b/src/app/components/project-map/context-menu/actions/lock-action/lock-action.component.ts index 3c2276337..1a7956d6b 100644 --- a/src/app/components/project-map/context-menu/actions/lock-action/lock-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/lock-action/lock-action.component.ts @@ -3,16 +3,17 @@ import { DrawingsDataSource } from '../../../../../cartography/datasources/drawi import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import { Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { NodeService } from '../../../../../services/node.service'; +import { ProjectService } from '../../../../../services/project.service'; @Component({ selector: 'app-lock-action', templateUrl: './lock-action.component.html', }) export class LockActionComponent implements OnChanges { - @Input() server: Server; + @Input() controller: Controller; @Input() nodes: Node[]; @Input() drawings: Drawing[]; command: string; @@ -21,7 +22,8 @@ export class LockActionComponent implements OnChanges { private nodesDataSource: NodesDataSource, private drawingsDataSource: DrawingsDataSource, private nodeService: NodeService, - private drawingService: DrawingService + private drawingService: DrawingService, + private projectService: ProjectService ) {} ngOnChanges() { @@ -34,19 +36,20 @@ export class LockActionComponent implements OnChanges { } } - lock() { - this.nodes.forEach((node) => { + async lock() { + await this.nodes.forEach((node) => { node.locked = !node.locked; - this.nodeService.updateNode(this.server, node).subscribe((node) => { + this.nodeService.updateNode(this.controller, node).subscribe((node) => { this.nodesDataSource.update(node); }); }); - this.drawings.forEach((drawing) => { + await this.drawings.forEach((drawing) => { drawing.locked = !drawing.locked; - this.drawingService.update(this.server, drawing).subscribe((drawing) => { + this.drawingService.update(this.controller, drawing).subscribe((drawing) => { this.drawingsDataSource.update(drawing); }); }); + this.projectService.projectUpdateLockIcon() } } diff --git a/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.spec.ts index ea2cc3ea8..0e84bde75 100644 --- a/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.spec.ts @@ -1,15 +1,17 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatTableModule } from '@angular/material/table'; import { MoveLayerDownActionComponent } from './move-layer-down-action.component'; describe('MoveLayerDownActionComponent', () => { let component: MoveLayerDownActionComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [MoveLayerDownActionComponent], + imports:[MatTableModule] }).compileComponents(); - })); + }); // beforeEach(() => { // fixture = TestBed.createComponent(MoveLayerDownActionComponent); @@ -17,7 +19,7 @@ describe('MoveLayerDownActionComponent', () => { // fixture.detectChanges(); // }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component) + }); }); diff --git a/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.ts b/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.ts index 306cf028a..ed63ec204 100644 --- a/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/move-layer-down-action/move-layer-down-action.component.ts @@ -3,7 +3,7 @@ import { DrawingsDataSource } from '../../../../../cartography/datasources/drawi import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { NodeService } from '../../../../../services/node.service'; @@ -12,7 +12,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './move-layer-down-action.component.html', }) export class MoveLayerDownActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; @Input() drawings: Drawing[]; @@ -30,14 +30,14 @@ export class MoveLayerDownActionComponent implements OnInit { node.z--; this.nodesDataSource.update(node); - this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + this.nodeService.update(this.controller, node).subscribe((node: Node) => {}); }); this.drawings.forEach((drawing) => { drawing.z--; this.drawingsDataSource.update(drawing); - this.drawingService.update(this.server, drawing).subscribe((drawing: Drawing) => {}); + this.drawingService.update(this.controller, drawing).subscribe((drawing: Drawing) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.spec.ts index ba7b949e5..e75ee6964 100644 --- a/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MoveLayerUpActionComponent } from './move-layer-up-action.component'; describe('MoveLayerUpActionComponent', () => { let component: MoveLayerUpActionComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async() => { TestBed.configureTestingModule({ declarations: [MoveLayerUpActionComponent], }).compileComponents(); - })); + }); // beforeEach(() => { // fixture = TestBed.createComponent(MoveLayerUpActionComponent); @@ -17,7 +17,7 @@ describe('MoveLayerUpActionComponent', () => { // fixture.detectChanges(); // }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component) + }); }); diff --git a/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.ts b/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.ts index b89012712..625dc1105 100644 --- a/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.ts @@ -3,7 +3,7 @@ import { DrawingsDataSource } from '../../../../../cartography/datasources/drawi import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; import { Drawing } from '../../../../../cartography/models/drawing'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DrawingService } from '../../../../../services/drawing.service'; import { NodeService } from '../../../../../services/node.service'; @@ -12,7 +12,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './move-layer-up-action.component.html', }) export class MoveLayerUpActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; @Input() drawings: Drawing[]; @@ -30,14 +30,14 @@ export class MoveLayerUpActionComponent implements OnInit { node.z++; this.nodesDataSource.update(node); - this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + this.nodeService.update(this.controller, node).subscribe((node: Node) => {}); }); this.drawings.forEach((drawing) => { drawing.z++; this.drawingsDataSource.update(drawing); - this.drawingService.update(this.server, drawing).subscribe((drawing: Drawing) => {}); + this.drawingService.update(this.controller, drawing).subscribe((drawing: Drawing) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/open-file-explorer/open-file-explorer-action.component.ts b/src/app/components/project-map/context-menu/actions/open-file-explorer/open-file-explorer-action.component.ts index fc032a097..0416dd9c2 100644 --- a/src/app/components/project-map/context-menu/actions/open-file-explorer/open-file-explorer-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/open-file-explorer/open-file-explorer-action.component.ts @@ -1,14 +1,14 @@ import { Component, Input, OnInit } from '@angular/core'; import { ElectronService } from 'ngx-electron'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; @Component({ selector: 'app-open-file-explorer-action', templateUrl: './open-file-explorer-action.component.html', }) export class OpenFileExplorerActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private electronService: ElectronService) {} diff --git a/src/app/components/project-map/context-menu/actions/packet-filters-action/packet-filters-action.component.ts b/src/app/components/project-map/context-menu/actions/packet-filters-action/packet-filters-action.component.ts index 953aafd29..bf10db5a6 100644 --- a/src/app/components/project-map/context-menu/actions/packet-filters-action/packet-filters-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/packet-filters-action/packet-filters-action.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Link } from '../../../../../models/link'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { PacketFiltersDialogComponent } from '../../../packet-capturing/packet-filters/packet-filters.component'; @Component({ @@ -10,7 +10,7 @@ import { PacketFiltersDialogComponent } from '../../../packet-capturing/packet-f templateUrl: './packet-filters-action.component.html', }) export class PacketFiltersActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() link: Link; @@ -24,7 +24,7 @@ export class PacketFiltersActionComponent { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; instance.link = this.link; } diff --git a/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts index 90fcf6876..2754620cf 100644 --- a/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; @Component({ @@ -8,7 +8,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './reload-node-action.component.html', }) export class ReloadNodeActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; filteredNodes: Node[] = []; @@ -30,7 +30,7 @@ export class ReloadNodeActionComponent implements OnInit { reloadNodes() { this.filteredNodes.forEach((node) => { - this.nodeService.reload(this.server, node).subscribe((n: Node) => {}); + this.nodeService.reload(this.controller, node).subscribe((n: Node) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.html b/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.html new file mode 100644 index 000000000..f216e4dba --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.ts b/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.ts new file mode 100644 index 000000000..6048d9bb2 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { Controller } from '../../../../../models/controller'; +import { Link } from '../../../../../models/link'; +import { LinkService } from '../../../../../services/link.service'; + +@Component({ + selector: 'app-reset-link-action', + templateUrl: './reset-link-action.component.html', +}) +export class ResetLinkActionComponent { + @Input() controller: Controller; + @Input() link: Link; + + constructor(private linkService: LinkService) {} + + resetLink() { + this.linkService.resetLink(this.controller, this.link).subscribe(() => {}); + } +} diff --git a/src/app/components/project-map/context-menu/actions/resume-link-action/resume-link-action.component.ts b/src/app/components/project-map/context-menu/actions/resume-link-action/resume-link-action.component.ts index 356c933ac..908a46852 100644 --- a/src/app/components/project-map/context-menu/actions/resume-link-action/resume-link-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/resume-link-action/resume-link-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { Link } from '../../../../../models/link'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { LinkService } from '../../../../../services/link.service'; @Component({ @@ -8,13 +8,13 @@ import { LinkService } from '../../../../../services/link.service'; templateUrl: './resume-link-action.component.html', }) export class ResumeLinkActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() link: Link; constructor(private linkService: LinkService) {} resumeLink() { this.link.suspend = false; - this.linkService.updateLink(this.server, this.link).subscribe(() => {}); + this.linkService.updateLink(this.controller, this.link).subscribe(() => {}); } } diff --git a/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts index 3a10e6cf4..1509cda71 100644 --- a/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { InfoDialogComponent } from '../../../info-dialog/info-dialog.component'; @Component({ @@ -10,7 +10,7 @@ import { InfoDialogComponent } from '../../../info-dialog/info-dialog.component' }) export class ShowNodeActionComponent { @Input() node: Node; - @Input() server: Server; + @Input() controller:Controller ; constructor(private dialog: MatDialog) {} @@ -23,6 +23,6 @@ export class ShowNodeActionComponent { }); let instance = dialogRef.componentInstance; instance.node = this.node; - instance.server = this.server; + instance.controller = this.controller; } } diff --git a/src/app/components/project-map/context-menu/actions/start-capture-on-started-link/start-capture-on-started-link.component.ts b/src/app/components/project-map/context-menu/actions/start-capture-on-started-link/start-capture-on-started-link.component.ts index ca7e8a71a..442d267ed 100644 --- a/src/app/components/project-map/context-menu/actions/start-capture-on-started-link/start-capture-on-started-link.component.ts +++ b/src/app/components/project-map/context-menu/actions/start-capture-on-started-link/start-capture-on-started-link.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { Link } from '../../../../../models/link'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { PacketCaptureService } from '../../../../../services/packet-capture.service'; @Component({ @@ -9,7 +9,7 @@ import { PacketCaptureService } from '../../../../../services/packet-capture.ser templateUrl: './start-capture-on-started-link.component.html', }) export class StartCaptureOnStartedLinkActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() link: Link; @@ -17,6 +17,6 @@ export class StartCaptureOnStartedLinkActionComponent { startCapture() { var splittedFileName = this.link.capture_file_name.split('.'); - this.packetCaptureService.startCapture(this.server, this.project, this.link, splittedFileName[0]); + this.packetCaptureService.startCapture(this.controller, this.project, this.link, splittedFileName[0]); } } diff --git a/src/app/components/project-map/context-menu/actions/start-capture/start-capture-action.component.ts b/src/app/components/project-map/context-menu/actions/start-capture/start-capture-action.component.ts index 6a1a13e75..e68461cf1 100644 --- a/src/app/components/project-map/context-menu/actions/start-capture/start-capture-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/start-capture/start-capture-action.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Link } from '../../../../../models/link'; import { Project } from '../../../../../models/project'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { StartCaptureDialogComponent } from '../../../packet-capturing/start-capture/start-capture.component'; @Component({ @@ -10,7 +10,7 @@ import { StartCaptureDialogComponent } from '../../../packet-capturing/start-cap templateUrl: './start-capture-action.component.html', }) export class StartCaptureActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() link: Link; @@ -23,7 +23,7 @@ export class StartCaptureActionComponent { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; instance.link = this.link; } diff --git a/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.spec.ts index fb2ba8699..2a689131c 100644 --- a/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.spec.ts @@ -1,15 +1,29 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MockedNodeService } from 'app/components/project-map/project-map.component.spec'; +import { HttpController } from 'app/services/http-controller.service'; +import { NodeService } from 'app/services/node.service'; +import { ToasterService } from 'app/services/toaster.service'; +import { MockedToasterService } from 'app/services/toaster.service.spec'; import { StartNodeActionComponent } from './start-node-action.component'; describe('StartNodeActionComponent', () => { let component: StartNodeActionComponent; let fixture: ComponentFixture; + let mockedNodeService: MockedNodeService; + let mockedToasterService: MockedToasterService; - beforeEach(async(() => { + beforeEach(async () => { TestBed.configureTestingModule({ declarations: [StartNodeActionComponent], + imports:[MatProgressSpinnerModule ], + providers: [ + { provide: NodeService, useValue: mockedNodeService }, + { provide: HttpController, useValue: {} }, + { provide: ToasterService, useValue: mockedToasterService }, + ], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(StartNodeActionComponent); @@ -17,7 +31,7 @@ describe('StartNodeActionComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.ts b/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.ts index 11c886ada..fd735d00e 100644 --- a/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/start-node-action/start-node-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -9,7 +9,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './start-node-action.component.html', }) export class StartNodeActionComponent implements OnInit, OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; isNodeWithStoppedStatus: boolean; @@ -30,7 +30,7 @@ export class StartNodeActionComponent implements OnInit, OnChanges { startNodes() { this.nodes.forEach((node) => { - this.nodeService.start(this.server, node).subscribe( + this.nodeService.start(this.controller, node).subscribe( (n: Node) => {}, (error) => { this.toasterService.error(error.error.message); diff --git a/src/app/components/project-map/context-menu/actions/stop-capture/stop-capture-action.component.ts b/src/app/components/project-map/context-menu/actions/stop-capture/stop-capture-action.component.ts index 4b875d208..e9bf2c53d 100644 --- a/src/app/components/project-map/context-menu/actions/stop-capture/stop-capture-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/stop-capture/stop-capture-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { Link } from '../../../../../models/link'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { LinkService } from '../../../../../services/link.service'; @Component({ @@ -8,12 +8,12 @@ import { LinkService } from '../../../../../services/link.service'; templateUrl: './stop-capture-action.component.html', }) export class StopCaptureActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() link: Link; constructor(private linkService: LinkService) {} stopCapture() { - this.linkService.stopCaptureOnLink(this.server, this.link).subscribe(() => {}); + this.linkService.stopCaptureOnLink(this.controller, this.link).subscribe(() => {}); } } diff --git a/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.spec.ts index 533a98319..79e322a44 100644 --- a/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.spec.ts @@ -1,15 +1,22 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MockedNodeService } from 'app/components/project-map/project-map.component.spec'; +import { HttpController } from 'app/services/http-controller.service'; +import { NodeService } from 'app/services/node.service'; import { StopNodeActionComponent } from './stop-node-action.component'; describe('StopNodeActionComponent', () => { let component: StopNodeActionComponent; let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ + let mockedNodeService : MockedNodeService + + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [StopNodeActionComponent], + providers:[ + {provide:NodeService , useValue: mockedNodeService}, + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(StopNodeActionComponent); @@ -17,7 +24,7 @@ describe('StopNodeActionComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.ts b/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.ts index 8e1e24b65..56106f093 100644 --- a/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/stop-node-action/stop-node-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; @Component({ @@ -8,7 +8,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './stop-node-action.component.html', }) export class StopNodeActionComponent implements OnInit, OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; isNodeWithStartedStatus: boolean; @@ -29,7 +29,7 @@ export class StopNodeActionComponent implements OnInit, OnChanges { stopNodes() { this.nodes.forEach((node) => { - this.nodeService.stop(this.server, node).subscribe((n: Node) => {}); + this.nodeService.stop(this.controller, node).subscribe((n: Node) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/suspend-link/suspend-link-action.component.ts b/src/app/components/project-map/context-menu/actions/suspend-link/suspend-link-action.component.ts index e0049122e..50690cc80 100644 --- a/src/app/components/project-map/context-menu/actions/suspend-link/suspend-link-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/suspend-link/suspend-link-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { Link } from '../../../../../models/link'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { LinkService } from '../../../../../services/link.service'; @Component({ @@ -8,13 +8,13 @@ import { LinkService } from '../../../../../services/link.service'; templateUrl: './suspend-link-action.component.html', }) export class SuspendLinkActionComponent { - @Input() server: Server; + @Input() controller:Controller ; @Input() link: Link; constructor(private linkService: LinkService) {} suspendLink() { this.link.suspend = true; - this.linkService.updateLink(this.server, this.link).subscribe(() => {}); + this.linkService.updateLink(this.controller, this.link).subscribe(() => {}); } } diff --git a/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts index 375959e74..9ba7109da 100644 --- a/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; @Component({ @@ -8,7 +8,7 @@ import { NodeService } from '../../../../../services/node.service'; templateUrl: './suspend-node-action.component.html', }) export class SuspendNodeActionComponent implements OnInit, OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; isNodeWithStartedStatus: boolean; @@ -29,7 +29,7 @@ export class SuspendNodeActionComponent implements OnInit, OnChanges { suspendNodes() { this.nodes.forEach((node) => { - this.nodeService.suspend(this.server, node).subscribe((n: Node) => {}); + this.nodeService.suspend(this.controller, node).subscribe((n: Node) => {}); }); } } diff --git a/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.html b/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.html new file mode 100644 index 000000000..6413b1d99 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.ts b/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.ts new file mode 100644 index 000000000..2793077fd --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.ts @@ -0,0 +1,27 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import{ Controller } from '../../../../../models/controller'; +import { NodeService } from '../../../../../services/node.service'; +import { ToasterService } from '../../../../../services/toaster.service'; + +@Component({ + selector: 'app-unisolate-node-action', + templateUrl: './unisolate-node-action.component.html', +}) +export class UnisolateNodeActionComponent implements OnInit { + @Input() controller:Controller ; + @Input() node: Node; + + constructor(private nodeService: NodeService, private toasterService: ToasterService) {} + + ngOnInit() {} + + unisolate() { + this.nodeService.unisolate(this.controller, this.node).subscribe( + (n: Node) => {}, + (error) => { + this.toasterService.error(error.error.message); + } + ); + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index eb81e95e7..5d51d8b20 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -1,57 +1,59 @@
- - - - - - + + + + + + + + @@ -62,7 +64,7 @@ (labels.length === 1 && linkNodes.length === 0 && drawings.length === 0) || (linkNodes.length === 1 && labels.length === 0 && drawings.length === 0)) " - [server]="server" + [controller]="controller" [project]="project" [drawing]="drawings[0]" [node]="nodes[0]" @@ -72,7 +74,7 @@ > @@ -81,7 +83,7 @@ nodes.length === 1 && (nodes[0].node_type === 'vpcs' || nodes[0].node_type === 'iou' || nodes[0].node_type === 'dynamips') " - [server]="server" + [controller]="controller" [node]="nodes[0]" > @@ -124,7 +126,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [link]="links[0]" > @@ -147,7 +149,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [project]="project" [link]="links[0]" > @@ -159,7 +161,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [link]="links[0]" > + + @@ -185,19 +204,19 @@ (drawings.length > 0 || nodes.length > 0 || links.length > 0) && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [nodes]="nodes" [drawings]="drawings" [links]="links" > diff --git a/src/app/components/project-map/context-menu/context-menu.component.spec.ts b/src/app/components/project-map/context-menu/context-menu.component.spec.ts index 1c5b187e7..55673af62 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.spec.ts +++ b/src/app/components/project-map/context-menu/context-menu.component.spec.ts @@ -1,12 +1,12 @@ import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; import { BrowserModule } from '@angular/platform-browser'; import { ElectronService } from 'ngx-electron'; import { Drawing } from '../../../cartography/models/drawing'; import { RectElement } from '../../../cartography/models/drawings/rect-element'; import { TextElement } from '../../../cartography/models/drawings/text-element'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ProjectService } from '../../../services/project.service'; import { MockedProjectService } from '../../projects/add-blank-project-dialog/add-blank-project-dialog.component.spec'; import { ContextMenuComponent } from './context-menu.component'; @@ -15,12 +15,12 @@ describe('ContextMenuComponent', () => { let component: ContextMenuComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(async() => { const electronMock = { isElectronApp: true, }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [MatMenuModule, BrowserModule], providers: [ { provide: ChangeDetectorRef }, @@ -30,12 +30,12 @@ describe('ContextMenuComponent', () => { declarations: [ContextMenuComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ContextMenuComponent); component = fixture.componentInstance; - component.server = { location: 'local' } as Server; + component.controller = { location: 'local' } as Controller ; fixture.detectChanges(); }); diff --git a/src/app/components/project-map/context-menu/context-menu.component.ts b/src/app/components/project-map/context-menu/context-menu.component.ts index 6f3d7053a..b70c771d6 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.ts +++ b/src/app/components/project-map/context-menu/context-menu.component.ts @@ -9,7 +9,7 @@ import { Node } from '../../../cartography/models/node'; import { Link } from '../../../models/link'; import { LinkNode } from '../../../models/link-node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ProjectService } from '../../../services/project.service'; @Component({ @@ -19,7 +19,7 @@ import { ProjectService } from '../../../services/project.service'; }) export class ContextMenuComponent implements OnInit { @Input() project: Project; - @Input() server: Server; + @Input() controller:Controller ; @ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger; @@ -34,7 +34,7 @@ export class ContextMenuComponent implements OnInit { hasTextCapabilities = false; isElectronApp = false; - isBundledServer: boolean = false; + isBundledController: boolean = false; constructor( private sanitizer: DomSanitizer, @@ -47,7 +47,7 @@ export class ContextMenuComponent implements OnInit { this.setPosition(0, 0); this.isElectronApp = this.electronService.isElectronApp; - this.isBundledServer = this.server.location === 'bundled'; + this.isBundledController = this.controller.location === 'bundled'; } public setPosition(top: number, left: number) { diff --git a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.spec.ts b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.spec.ts index 01e15d3ab..eebd8a7a4 100644 --- a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.spec.ts +++ b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.spec.ts @@ -1,15 +1,41 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { LabelToMapLabelConverter } from 'app/cartography/converters/map/label-to-map-label-converter'; +import { MapLabelToLabelConverter } from 'app/cartography/converters/map/map-label-to-label-converter'; +import { MapNodeToNodeConverter } from 'app/cartography/converters/map/map-node-to-node-converter'; +import { MapPortToPortConverter } from 'app/cartography/converters/map/map-port-to-port-converter'; +import { NodeToMapNodeConverter } from 'app/cartography/converters/map/node-to-map-node-converter'; +import { PortToMapPortConverter } from 'app/cartography/converters/map/port-to-map-port-converter'; +import { LinksEventSource } from 'app/cartography/events/links-event-source'; +import { NodesEventSource } from 'app/cartography/events/nodes-event-source'; +import { CssFixer } from 'app/cartography/helpers/css-fixer'; +import { FontBBoxCalculator } from 'app/cartography/helpers/font-bbox-calculator'; +import { FontFixer } from 'app/cartography/helpers/font-fixer'; +import { DrawingLineWidget } from 'app/cartography/widgets/drawing-line'; import { DrawLinkToolComponent } from './draw-link-tool.component'; describe('DrawLinkToolComponent', () => { let component: DrawLinkToolComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [DrawLinkToolComponent], + providers:[ + DrawingLineWidget, + NodesEventSource, + LinksEventSource, + MapNodeToNodeConverter, + MapLabelToLabelConverter, + FontBBoxCalculator, + MapPortToPortConverter, + CssFixer, + FontFixer, + NodeToMapNodeConverter, + LabelToMapLabelConverter, + PortToMapPortConverter + ] }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(DrawLinkToolComponent); @@ -17,7 +43,7 @@ describe('DrawLinkToolComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.html b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.html new file mode 100644 index 000000000..8c947b08a --- /dev/null +++ b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.html @@ -0,0 +1,33 @@ +

Style editor

+ + + +
+ + +
diff --git a/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.scss b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.scss new file mode 100644 index 000000000..38ca9c486 --- /dev/null +++ b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.scss @@ -0,0 +1,54 @@ + .item { + height: 25px; + font-size: 10pt; + margin-bottom: 10px; + } + + .item-name { + margin-bottom: 10px; + } + + .item-value { + width: 100%; + margin-bottom: 10px; + } + + .input-color { + padding: 0px; + border-width: 0px; + width: 100%; + background-color: transparent; + outline: none; + } + + input:focus { + outline: none; + } + + input[type='color'] { + -webkit-appearance: none; + border: none; + height: 25px; + } + + input[type='color']::-webkit-color-swatch-wrapper { + padding: 0; + } + + input[type='color']::-webkit-color-swatch { + border: none; + } + + .modal-form-container { + display: flex; + flex-direction: column; + } + + .modal-form-container > * { + width: 100%; + } + + .form-field { + width: 100%; + } + \ No newline at end of file diff --git a/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.ts b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.ts new file mode 100644 index 000000000..91192d671 --- /dev/null +++ b/src/app/components/project-map/drawings-editors/link-style-editor/link-style-editor.component.ts @@ -0,0 +1,83 @@ +import { Component, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { MatDialogRef } from '@angular/material/dialog'; +import { Link } from '../../../../models/link'; +import { Project } from '../../../../models/project'; +import{ Controller } from '../../../../models/controller'; +import { ToasterService } from '../../../../services/toaster.service'; +import { NonNegativeValidator } from '../../../../validators/non-negative-validator'; +import { LinkService } from '../../../../services/link.service'; +import { LinksDataSource } from '../../../../cartography/datasources/links-datasource'; +import { LinksEventSource } from '../../../../cartography/events/links-event-source'; +import { LinkToMapLinkConverter } from '../../../../cartography/converters/map/link-to-map-link-converter'; + +@Component({ + selector: 'app-link-style-editor', + templateUrl: './link-style-editor.component.html', + styleUrls: ['./link-style-editor.component.scss'], +}) +export class LinkStyleEditorDialogComponent implements OnInit { + controller:Controller ; + project: Project; + link: Link; + formGroup: UntypedFormGroup; + borderTypes = ["Solid", "Dash", "Dot", "Dash Dot", "Dash Dot Dot"]; + + constructor( + public dialogRef: MatDialogRef, + private formBuilder: UntypedFormBuilder, + private toasterService: ToasterService, + private linkService: LinkService, + private linksDataSource: LinksDataSource, + private linksEventSource: LinksEventSource, + private linkToMapLink: LinkToMapLinkConverter, + private nonNegativeValidator: NonNegativeValidator + ) { + this.formGroup = this.formBuilder.group({ + color: new UntypedFormControl('', [Validators.required]), + width: new UntypedFormControl('', [Validators.required, nonNegativeValidator.get]), + type: new UntypedFormControl('', [Validators.required]) + }); + } + + ngOnInit() { + if (!this.link.link_style?.color) { + this.formGroup.controls['color'].setValue("#000000"); + } else { + this.formGroup.controls['color'].setValue(this.link.link_style.color); + } + + this.formGroup.controls['width'].setValue(this.link.link_style.width); + + let type = this.borderTypes[0]; + if (this.link.link_style?.type) { + type = this.borderTypes[this.link.link_style.type]; + } + this.formGroup.controls['type'].setValue(type); + } + + onNoClick() { + this.dialogRef.close(); + } + + onYesClick() { + if (this.formGroup.valid) { + this.link.link_style.color = this.formGroup.get('color').value; + this.link.link_style.width = this.formGroup.get('width').value; + + let type = this.borderTypes.indexOf(this.formGroup.get('type').value); + this.link.link_style.type = type; + + this.linkService.updateLinkStyle(this.controller, this.link).subscribe((link) => { + this.linksDataSource.update(link); + this.linksEventSource.edited.next(this.linkToMapLink.convert(link)); + location.reload() + // we add this code/line for reload the entire page because single graph/link style is not updated automatically. + // this.toasterService.success("Link updated"); + this.dialogRef.close(); + }); + } else { + this.toasterService.error(`Entered data is incorrect`); + } + } +} diff --git a/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.html b/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.html index be6c49aa7..0807857ee 100644 --- a/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.html +++ b/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.html @@ -25,15 +25,10 @@

Style editor

- - - + + + {{ type.name }} + @@ -42,7 +37,7 @@

Style editor

-
+
diff --git a/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.ts b/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.ts index e216ab40b..8df3b4aa3 100644 --- a/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.ts +++ b/src/app/components/project-map/drawings-editors/style-editor/style-editor.component.ts @@ -1,15 +1,16 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { DrawingToMapDrawingConverter } from '../../../../cartography/converters/map/drawing-to-map-drawing-converter'; import { MapDrawingToSvgConverter } from '../../../../cartography/converters/map/map-drawing-to-svg-converter'; import { DrawingsDataSource } from '../../../../cartography/datasources/drawings-datasource'; +import { QtDasharrayFixer } from '../../../../cartography/helpers/qt-dasharray-fixer'; import { Drawing } from '../../../../cartography/models/drawing'; import { EllipseElement } from '../../../../cartography/models/drawings/ellipse-element'; import { LineElement } from '../../../../cartography/models/drawings/line-element'; import { RectElement } from '../../../../cartography/models/drawings/rect-element'; +import { Controller } from '../../../../models/controller'; import { Project } from '../../../../models/project'; -import { Server } from '../../../../models/server'; import { DrawingService } from '../../../../services/drawing.service'; import { ToasterService } from '../../../../services/toaster.service'; import { NonNegativeValidator } from '../../../../validators/non-negative-validator'; @@ -21,11 +22,19 @@ import { RotationValidator } from '../../../../validators/rotation-validator'; styleUrls: ['./style-editor.component.scss'], }) export class StyleEditorDialogComponent implements OnInit { - server: Server; + controller: Controller; project: Project; drawing: Drawing; element: ElementData; - formGroup: FormGroup; + formGroup: UntypedFormGroup; + borderTypes = [ + { qt: 'none', value: 'none', name: 'Solid' }, + { qt: '10, 2', value: '25, 25', name: 'Dash' }, + { qt: '4, 2', value: '5, 25', name: 'Dot' }, + { qt: '12, 3, 5, 3', value: '5, 25, 25', name: 'Dash Dot' }, + { qt: '12, 3, 5, 3, 5, 3', value: '25, 25, 5, 25, 5', name: 'Dash Dot Dot' }, + { qt: '', value: '', name: 'No border' }, + ]; constructor( public dialogRef: MatDialogRef, @@ -33,28 +42,30 @@ export class StyleEditorDialogComponent implements OnInit { private mapDrawingToSvgConverter: MapDrawingToSvgConverter, private drawingService: DrawingService, private drawingsDataSource: DrawingsDataSource, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private toasterService: ToasterService, private nonNegativeValidator: NonNegativeValidator, - private rotationValidator: RotationValidator + private rotationValidator: RotationValidator, + private qtDasharrayFixer: QtDasharrayFixer ) { this.formGroup = this.formBuilder.group({ - borderWidth: new FormControl('', [Validators.required, nonNegativeValidator.get]), - rotation: new FormControl('', [Validators.required, rotationValidator.get]), + borderWidth: new UntypedFormControl('', [Validators.required, nonNegativeValidator.get]), + rotation: new UntypedFormControl('', [Validators.required, rotationValidator.get]), }); } ngOnInit() { + let dasharray_find_value; this.element = new ElementData(); - if (this.drawing.element instanceof RectElement || this.drawing.element instanceof EllipseElement) { this.element.fill = this.drawing.element.fill; this.element.stroke = this.drawing.element.stroke; - this.element.stroke_dasharray = this.drawing.element.stroke_dasharray; + console.log(this.drawing.element.stroke_dasharray, this.drawing.element.stroke_width) + this.element.stroke_dasharray = (this.drawing.element.stroke_dasharray == undefined && this.drawing.element.stroke_width == undefined ) ? '': this.drawing.element.stroke_dasharray ?? 'none' ; this.element.stroke_width = this.drawing.element.stroke_width; } else if (this.drawing.element instanceof LineElement) { this.element.stroke = this.drawing.element.stroke; - this.element.stroke_dasharray = this.drawing.element.stroke_dasharray; + this.element.stroke_dasharray = (this.drawing.element.stroke_dasharray == undefined && this.drawing.element.stroke_width == undefined ) ? '': this.drawing.element.stroke_dasharray ?? 'none' ; this.element.stroke_width = this.drawing.element.stroke_width; } @@ -69,27 +80,38 @@ export class StyleEditorDialogComponent implements OnInit { onYesClick() { if (this.formGroup.valid) { - this.element.stroke_width = this.formGroup.get('borderWidth').value; + if (this.element.stroke_dasharray == '') { + this.element.stroke_width = 0; + } else { + this.element.stroke_width = + this.formGroup.get('borderWidth').value === 0 ? 2 : this.formGroup.get('borderWidth').value; + } this.drawing.rotation = this.formGroup.get('rotation').value; if (this.drawing.element instanceof RectElement || this.drawing.element instanceof EllipseElement) { this.drawing.element.fill = this.element.fill; - this.drawing.element.stroke = this.element.stroke; + this.drawing.element.stroke = this.element.stroke ?? "#000000"; this.drawing.element.stroke_dasharray = this.element.stroke_dasharray; this.drawing.element.stroke_width = this.element.stroke_width; } else if (this.drawing.element instanceof LineElement) { + if (this.element.stroke_dasharray != '') { + this.drawing.element.stroke = this.element.stroke ?? "#000000"; + this.drawing.element.stroke_dasharray = this.element.stroke_dasharray === '' ? 'none' : this.element.stroke_dasharray; + this.drawing.element.stroke_width = this.element.stroke_width === 0 ? 2 : this.element.stroke_width; + } else { + this.toasterService.warning(`No border style line element not supported`); + } this.drawing.element.stroke = this.element.stroke; this.drawing.element.stroke_dasharray = this.element.stroke_dasharray; - this.drawing.element.stroke_width = this.element.stroke_width; + this.drawing.element.stroke_width = this.element.stroke_width === 0 ? 2 : this.element.stroke_width; } - let mapDrawing = this.drawingToMapDrawingConverter.convert(this.drawing); mapDrawing.element = this.drawing.element; this.drawing.svg = this.mapDrawingToSvgConverter.convert(mapDrawing); - this.drawingService.update(this.server, this.drawing).subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.update(serverDrawing); + this.drawingService.update(this.controller, this.drawing).subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.update(controllerDrawing); this.dialogRef.close(); }); } else { diff --git a/src/app/components/project-map/drawings-editors/text-editor/text-editor.component.ts b/src/app/components/project-map/drawings-editors/text-editor/text-editor.component.ts index 8440f5b06..2021667d0 100644 --- a/src/app/components/project-map/drawings-editors/text-editor/text-editor.component.ts +++ b/src/app/components/project-map/drawings-editors/text-editor/text-editor.component.ts @@ -1,5 +1,5 @@ import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { DrawingToMapDrawingConverter } from '../../../../cartography/converters/map/drawing-to-map-drawing-converter'; import { MapDrawingToSvgConverter } from '../../../../cartography/converters/map/map-drawing-to-svg-converter'; @@ -15,7 +15,7 @@ import { Node } from '../../../../cartography/models/node'; import { Link } from '../../../../models/link'; import { LinkNode } from '../../../../models/link-node'; import { Project } from '../../../../models/project'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DrawingService } from '../../../../services/drawing.service'; import { LinkService } from '../../../../services/link.service'; import { NodeService } from '../../../../services/node.service'; @@ -30,7 +30,7 @@ import { RotationValidator } from '../../../../validators/rotation-validator'; export class TextEditorDialogComponent implements OnInit { @ViewChild('textArea', { static: true }) textArea: ElementRef; - server: Server; + controller:Controller ; project: Project; drawing: Drawing; node: Node; @@ -40,7 +40,7 @@ export class TextEditorDialogComponent implements OnInit { element: TextElement; rotation: string; isTextEditable: boolean; - formGroup: FormGroup; + formGroup: UntypedFormGroup; constructor( private dialogRef: MatDialogRef, @@ -53,7 +53,7 @@ export class TextEditorDialogComponent implements OnInit { private nodesDataSource: NodesDataSource, private linkService: LinkService, private linksDataSource: LinksDataSource, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private toasterService: ToasterService, private rotationValidator: RotationValidator, private fontFixer: FontFixer @@ -61,7 +61,7 @@ export class TextEditorDialogComponent implements OnInit { ngOnInit() { this.formGroup = this.formBuilder.group({ - rotation: new FormControl('', [Validators.required, this.rotationValidator.get]), + rotation: new UntypedFormControl('', [Validators.required, this.rotationValidator.get]), }); if (this.label && this.node) { @@ -140,7 +140,7 @@ export class TextEditorDialogComponent implements OnInit { this.node.label.style = this.getStyleFromTextElement(); this.node.label.rotation = +this.rotation; - this.nodeService.updateLabel(this.server, this.node, this.node.label).subscribe((node: Node) => { + this.nodeService.updateLabel(this.controller, this.node, this.node.label).subscribe((node: Node) => { this.nodesDataSource.update(node); this.dialogRef.close(); }); @@ -149,7 +149,7 @@ export class TextEditorDialogComponent implements OnInit { this.label.rotation = +this.rotation; this.label.text = this.element.text; - this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => { + this.linkService.updateLink(this.controller, this.link).subscribe((link: Link) => { this.linksDataSource.update(link); this.dialogRef.close(); }); @@ -162,8 +162,8 @@ export class TextEditorDialogComponent implements OnInit { this.drawing.svg = this.mapDrawingToSvgConverter.convert(mapDrawing); - this.drawingService.update(this.server, this.drawing).subscribe((serverDrawing: Drawing) => { - this.drawingsDataSource.update(serverDrawing); + this.drawingService.update(this.controller, this.drawing).subscribe((controllerDrawing: Drawing) => { + this.drawingsDataSource.update(controllerDrawing); this.dialogRef.close(); }); } diff --git a/src/app/components/project-map/import-appliance/import-appliance.component.ts b/src/app/components/project-map/import-appliance/import-appliance.component.ts index f080506ad..1c6d8aea3 100644 --- a/src/app/components/project-map/import-appliance/import-appliance.component.ts +++ b/src/app/components/project-map/import-appliance/import-appliance.component.ts @@ -1,7 +1,8 @@ import { Component, Input, OnInit } from '@angular/core'; +import { environment } from 'environments/environment'; import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { DockerTemplate } from '../../../models/templates/docker-template'; import { IosTemplate } from '../../../models/templates/ios-template'; import { IouTemplate } from '../../../models/templates/iou-template'; @@ -19,7 +20,7 @@ import { ToasterService } from '../../../services/toaster.service'; }) export class ImportApplianceComponent implements OnInit { @Input('project') project: Project; - @Input('server') server: Server; + @Input('controller') controller:Controller ; uploader: FileUploader; template; @@ -32,7 +33,7 @@ export class ImportApplianceComponent implements OnInit { ) {} ngOnInit() { - this.uploader = new FileUploader({}); + this.uploader = new FileUploader({url: ''}); this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; }; @@ -48,13 +49,13 @@ export class ImportApplianceComponent implements OnInit { headers: ParsedResponseHeaders ) => { if (this.template.template_type === 'qemu') { - this.qemuService.addTemplate(this.server, this.template).subscribe(() => this.onUploadComplete()); + this.qemuService.addTemplate(this.controller, this.template).subscribe(() => this.onUploadComplete()); } else if (this.template.template_type === 'iou') { - this.iouService.addTemplate(this.server, this.template).subscribe(() => this.onUploadComplete()); + this.iouService.addTemplate(this.controller, this.template).subscribe(() => this.onUploadComplete()); } else if (this.template.template_type === 'dynamips') { - this.iosService.addTemplate(this.server, this.template).subscribe(() => this.onUploadComplete()); + this.iosService.addTemplate(this.controller, this.template).subscribe(() => this.onUploadComplete()); } else if (this.template.template_type === 'docker') { - this.dockerService.addTemplate(this.server, this.template).subscribe(() => this.onUploadComplete()); + this.dockerService.addTemplate(this.controller, this.template).subscribe(() => this.onUploadComplete()); } }; } @@ -129,8 +130,8 @@ export class ImportApplianceComponent implements OnInit { template.default_name_format = '{name}-{0}'; template.compute_id = 'vm'; // qemu - VM - // iou - VM + main server - // dynamips - vm + main server + // iou - VM + main controller + // dynamips - vm + main controller // docker - vm if (template.category === 'guest') { @@ -140,7 +141,7 @@ export class ImportApplianceComponent implements OnInit { } this.template = template; - const url = this.getUploadPath(this.server, template.template_type, name); + const url = this.getUploadPath(this.controller, template.template_type, name); this.uploader.queue.forEach((elem) => (elem.url = url)); const itemToUpload = this.uploader.queue[0]; this.uploader.uploadItem(itemToUpload); @@ -148,7 +149,7 @@ export class ImportApplianceComponent implements OnInit { fileReader.readAsText(file); } - private getUploadPath(server: Server, emulator: string, filename: string) { - return `${server.protocol}//${server.host}:${server.port}/v2/${emulator}/images/${filename}`; + private getUploadPath(controller:Controller , emulator: string, filename: string) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/${emulator}/images/${filename}`; } } diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.ts b/src/app/components/project-map/info-dialog/info-dialog.component.ts index 296132b6e..56a10ad3c 100644 --- a/src/app/components/project-map/info-dialog/info-dialog.component.ts +++ b/src/app/components/project-map/info-dialog/info-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../cartography/models/node'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { InfoService } from '../../../services/info.service'; @Component({ @@ -10,7 +10,7 @@ import { InfoService } from '../../../services/info.service'; styleUrls: ['./info-dialog.component.scss'], }) export class InfoDialogComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; infoList: string[] = []; usage: string = ''; @@ -19,7 +19,7 @@ export class InfoDialogComponent implements OnInit { constructor(public dialogRef: MatDialogRef, private infoService: InfoService) {} ngOnInit() { - this.infoList = this.infoService.getInfoAboutNode(this.node, this.server); + this.infoList = this.infoService.getInfoAboutNode(this.node, this.controller); this.commandLine = this.infoService.getCommandLine(this.node); this.usage = this.node.usage ? this.node.usage : `No usage information has been provided for this node.`; } diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html index c73a091da..b27924f7d 100644 --- a/src/app/components/project-map/log-console/log-console.component.html +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -9,7 +9,7 @@ - +
diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts index 1d7886c32..ff2dc462a 100644 --- a/src/app/components/project-map/log-console/log-console.component.spec.ts +++ b/src/app/components/project-map/log-console/log-console.component.spec.ts @@ -9,8 +9,8 @@ import { ToasterService } from '../../../services/toaster.service'; import { of } from 'rxjs'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler'; -import { Server } from '../../../models/server'; -import { HttpServer, ServerErrorHandler } from '../../../services/http-server.service'; +import{ Controller } from '../../../models/controller'; +import { HttpController, ControllerErrorHandler } from '../../../services/http-controller.service'; import { NodeService } from '../../../services/node.service'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { MockedNodesDataSource, MockedNodeService } from '../project-map.component.spec'; @@ -39,17 +39,17 @@ describe('LogConsoleComponent', () => { let mapSettingsService: MapSettingsService; let toasterService: ToasterService; - let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler); + let httpController = new HttpController({} as HttpClient, {} as ControllerErrorHandler); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [HttpClientTestingModule, RouterTestingModule, MatMenuModule, BrowserModule, MatSnackBarModule], providers: [ { provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler }, { provide: NodeService, useValue: mockedNodeService }, { provide: NodesDataSource, useValue: mockedNodesDataSource }, { provide: LogEventsDataSource, useClass: LogEventsDataSource }, - { provide: HttpServer, useValue: httpServer }, + { provide: HttpController, useValue: httpController }, NodeConsoleService, ToasterService, MapSettingsService @@ -61,12 +61,12 @@ describe('LogConsoleComponent', () => { toasterService = TestBed.inject(ToasterService); mapSettingsService = TestBed.inject(MapSettingsService); nodeConsoleService = TestBed.inject(NodeConsoleService); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(LogConsoleComponent); component = fixture.componentInstance; - component.server = { location: 'local' } as Server; + component.controller = { location: 'local' } as Controller ; fixture.detectChanges(); }); diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 82d7a986c..dcb06b47b 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -9,7 +9,7 @@ import { OnInit, ViewChild, } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { UntypedFormControl } from '@angular/forms'; import { Subscription } from 'rxjs'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { Drawing } from '../../../cartography/models/drawing'; @@ -19,8 +19,8 @@ import { Link } from '../../../models/link'; import { LogEvent } from '../../../models/logEvent'; import { Port } from '../../../models/port'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; -import { HttpServer } from '../../../services/http-server.service'; +import{ Controller } from '../../../models/controller'; +import { HttpController } from '../../../services/http-controller.service'; import { NodeService } from '../../../services/node.service'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { ThemeService } from '../../../services/theme.service'; @@ -34,7 +34,7 @@ import { LogEventsDataSource } from './log-events-datasource'; styleUrls: ['./log-console.component.scss'], }) export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @ViewChild('console') console: ElementRef; @@ -43,13 +43,13 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private nodeSubscription: Subscription; private linkSubscription: Subscription; private drawingSubscription: Subscription; - private serverRequestsSubscription: Subscription; + private controllerRequestsSubscription: Subscription; private errorSubscription: Subscription; private warningSubscription: Subscription; private infoSubscription: Subscription; public command: string = ''; - public filters: string[] = ['all', 'errors', 'warnings', 'info', 'map updates', 'server requests']; + public filters: string[] = ['all', 'errors', 'warnings', 'info', 'map updates', 'controller requests']; public selectedFilter: string = 'all'; public filteredEvents: LogEvent[] = []; @@ -63,14 +63,14 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { public style: object = {}; public isDraggingEnabled: boolean = false; public isLightThemeEnabled: boolean = false; - public selected = new FormControl(0); + public selected = new UntypedFormControl(0); constructor( private projectWebServiceHandler: ProjectWebServiceHandler, private nodeService: NodeService, private nodesDataSource: NodesDataSource, private logEventsDataSource: LogEventsDataSource, - private httpService: HttpServer, + private httpService: HttpController, private themeService: ThemeService, private cd: ChangeDetectorRef, private nodeConsoleService: NodeConsoleService, @@ -119,9 +119,9 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { message: message, }); }); - this.serverRequestsSubscription = this.httpService.requestsNotificationEmitter.subscribe((message) => { + this.controllerRequestsSubscription = this.httpService.requestsNotificationEmitter.subscribe((message) => { this.showMessage({ - type: 'server request', + type: 'controller request', message: message, }); }); @@ -153,7 +153,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.nodeSubscription.unsubscribe(); this.linkSubscription.unsubscribe(); this.drawingSubscription.unsubscribe(); - this.serverRequestsSubscription.unsubscribe(); + this.controllerRequestsSubscription.unsubscribe(); this.errorSubscription.unsubscribe(); this.warningSubscription.unsubscribe(); this.infoSubscription.unsubscribe(); @@ -180,22 +180,22 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.showCommand('Current version: ' + this.version); } else if (this.command === 'start all') { this.showCommand('Starting all nodes...'); - this.nodeService.startAll(this.server, this.project).subscribe(() => { + this.nodeService.startAll(this.controller, this.project).subscribe(() => { this.showCommand('All nodes started.'); }); } else if (this.command === 'stop all') { this.showCommand('Stopping all nodes...'); - this.nodeService.stopAll(this.server, this.project).subscribe(() => { + this.nodeService.stopAll(this.controller, this.project).subscribe(() => { this.showCommand('All nodes stopped.'); }); } else if (this.command === 'suspend all') { this.showCommand('Suspending all nodes...'); - this.nodeService.suspendAll(this.server, this.project).subscribe(() => { + this.nodeService.suspendAll(this.controller, this.project).subscribe(() => { this.showCommand('All nodes suspended.'); }); } else if (this.command === 'reload all') { this.showCommand('Reloading all nodes...'); - this.nodeService.reloadAll(this.server, this.project).subscribe(() => { + this.nodeService.reloadAll(this.controller, this.project).subscribe(() => { this.showCommand('All nodes reloaded.'); }); } else if ( @@ -211,16 +211,16 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { if (node) { if (this.regexStart.test(this.command)) { this.showCommand(`Starting node ${splittedCommand[1]}...`); - this.nodeService.start(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} started.`)); + this.nodeService.start(this.controller, node).subscribe(() => this.showCommand(`Node ${node.name} started.`)); } else if (this.regexStop.test(this.command)) { this.showCommand(`Stopping node ${splittedCommand[1]}...`); - this.nodeService.stop(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} stopped.`)); + this.nodeService.stop(this.controller, node).subscribe(() => this.showCommand(`Node ${node.name} stopped.`)); } else if (this.regexSuspend.test(this.command)) { this.showCommand(`Suspending node ${splittedCommand[1]}...`); - this.nodeService.suspend(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} suspended.`)); + this.nodeService.suspend(this.controller, node).subscribe(() => this.showCommand(`Node ${node.name} suspended.`)); } else if (this.regexReload.test(this.command)) { this.showCommand(`Reloading node ${splittedCommand[1]}...`); - this.nodeService.reload(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} reloaded.`)); + this.nodeService.reload(this.controller, node).subscribe(() => this.showCommand(`Node ${node.name} reloaded.`)); } else if (this.regexConsole.test(this.command)) { if (node.status === 'started') { this.showCommand(`Launching console for node ${splittedCommand[1]}...`); @@ -280,8 +280,8 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { } getFilteredEvents(): LogEvent[] { - if (this.selectedFilter === 'server requests') { - return this.logEventsDataSource.getItems().filter((n) => n.type === 'server request'); + if (this.selectedFilter === 'controller requests') { + return this.logEventsDataSource.getItems().filter((n) => n.type === 'controller request'); } else if (this.selectedFilter === 'errors') { return this.logEventsDataSource.getItems().filter((n) => n.type === 'error'); } else if (this.selectedFilter === 'warnings') { diff --git a/src/app/components/project-map/new-template-dialog/new-template-dialog.component.html b/src/app/components/project-map/new-template-dialog/new-template-dialog.component.html index 643908019..350795fb1 100644 --- a/src/app/components/project-map/new-template-dialog/new-template-dialog.component.html +++ b/src/app/components/project-map/new-template-dialog/new-template-dialog.component.html @@ -6,7 +6,7 @@

Add new template

Install new appliance from the GNS serverInstall new appliance from the GNS controller
Import an appliance fileAdd new template {{ secondActionTitle }} - - Please configure GNS3 VM to install selected appliance - - - +
-
- Server type
- - Install the appliance locally - Install the appliance on the GNS3 VM - -
-
- Qemu binary
- - - {{ binary.path }} - - -
Install required files
-
+
{{ applianceToInstall.name }} version {{ version.name }} @@ -250,6 +212,7 @@

Add new template

[uploader]="uploaderImage" /> +
-
- Server type
- - Install the appliance locally - Install the appliance on the GNS3 VM - -
+
-
- Server type
- - Install the appliance locally - Install the appliance on the GNS3 VM - -
Install required files
-
- Server type
- - Install the appliance locally - Install the appliance on the GNS3 VM - -
Install required files
-
-
- - +
+ + +
diff --git a/src/app/components/project-map/node-editors/configurator/cloud/configurator-cloud.component.ts b/src/app/components/project-map/node-editors/configurator/cloud/configurator-cloud.component.ts index fd34de07b..52add1389 100644 --- a/src/app/components/project-map/node-editors/configurator/cloud/configurator-cloud.component.ts +++ b/src/app/components/project-map/node-editors/configurator/cloud/configurator-cloud.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { UdpTunnelsComponent } from '../../../../../components/preferences/common/udp-tunnels/udp-tunnels.component'; import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity'; import { QemuBinary } from '../../../../../models/qemu/qemu-binary'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -16,12 +16,11 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogCloudComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; consoleTypes: string[] = []; - binaries: QemuBinary[] = []; onCloseOptions = []; bootPriorities = []; diskInterfaces: string[] = []; @@ -42,16 +41,16 @@ export class ConfiguratorDialogCloudComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -98,7 +97,7 @@ export class ConfiguratorDialogCloudComponent implements OnInit { .concat(this.portsMappingEthernet) .concat(this.portsMappingTap); - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.html b/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.html index d093bc2e6..15c42a254 100644 --- a/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.html +++ b/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.html @@ -32,8 +32,17 @@

Configurator for node {{ name }}

/> + + + MB + + + + + + @@ -99,9 +108,9 @@
Extra hosts

-
Additional directories
+
Additional volumes
- + diff --git a/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.ts b/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.ts index 5597cdd87..0a734ea01 100644 --- a/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.ts +++ b/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.ts @@ -1,13 +1,14 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { DockerConfigurationService } from '../../../../../services/docker-configuration.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { ConfigureCustomAdaptersDialogComponent } from './configure-custom-adapters/configure-custom-adapters.component'; import { EditNetworkConfigurationDialogComponent } from './edit-network-configuration/edit-network-configuration.component'; +import { NonNegativeValidator } from '../../../../../validators/non-negative-validator'; @Component({ selector: 'app-configurator-docker', @@ -15,10 +16,10 @@ import { EditNetworkConfigurationDialogComponent } from './edit-network-configur styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogDockerComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; consoleTypes: string[] = []; consoleResolutions: string[] = ['2560x1440', '1920x1080', '1680x1050', '1440x900', '1366x768', '1280x1024', '1280x800', '1024x768', '800x600', '640x480']; private conf = { @@ -27,37 +28,34 @@ export class ConfiguratorDialogDockerComponent implements OnInit { disableClose: true, }; dialogRef; - additionalDirectories: string = ""; constructor( - public dialogReference: MatDialogRef, - public nodeService: NodeService, - private toasterService: ToasterService, - private formBuilder: FormBuilder, - private dockerConfigurationService: DockerConfigurationService, - private dialog: MatDialog + public dialogReference: MatDialogRef, + public nodeService: NodeService, + private toasterService: ToasterService, + private formBuilder: UntypedFormBuilder, + private dockerConfigurationService: DockerConfigurationService, + private nonNegativeValidator: NonNegativeValidator, + private dialog: MatDialog ) { - this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), - adapter: new FormControl('', Validators.required), - startCommand: new FormControl(''), - consoleHttpPort: new FormControl('', Validators.required), - consoleHttpPath: new FormControl('', Validators.required), - }); + this.generalSettingsForm = this.formBuilder.group({ + name: new UntypedFormControl('', Validators.required), + adapter: new UntypedFormControl('', Validators.required), + memory: new UntypedFormControl('', nonNegativeValidator.get), + cpus: new UntypedFormControl('', nonNegativeValidator.get), + startCommand: new UntypedFormControl(''), + consoleHttpPort: new UntypedFormControl('', Validators.required), + consoleHttpPath: new UntypedFormControl('', Validators.required) + }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { - this.node = node; - this.name = node.name; - this.getConfiguration(); - if (this.node.properties.extra_volumes && this.node.properties.extra_volumes.length>0) { - for (let index = 0; index < this.node.properties.extra_volumes.length - 1; index++) { - this.additionalDirectories = this.additionalDirectories + this.node.properties.extra_volumes[index] + "\n"; - } - this.additionalDirectories = this.additionalDirectories + this.node.properties.extra_volumes[this.node.properties.extra_volumes.length - 1]; - } - }); + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { + this.node = node; + this.name = node.name; + this.getConfiguration(); + if (!this.node.properties.cpus) this.node.properties.cpus = 0.0; + }); } getConfiguration() { @@ -67,29 +65,20 @@ export class ConfiguratorDialogDockerComponent implements OnInit { configureCustomAdapters() { this.dialogRef = this.dialog.open(ConfigureCustomAdaptersDialogComponent, this.conf); let instance = this.dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.node = this.node; } editNetworkConfiguration() { this.dialogRef = this.dialog.open(EditNetworkConfigurationDialogComponent, this.conf); let instance = this.dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.node = this.node; } onSaveClick() { - var extraVolumes = this.additionalDirectories.split("\n").filter(elem => elem != ""); - for (const item of extraVolumes) { - console.log(item); - if (!item.startsWith("/")) { - this.toasterService.error(`Wrong format for additional directories.`); - return; - } - } if (this.generalSettingsForm.valid) { - this.node.properties.extra_volumes = extraVolumes; - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/docker/configure-custom-adapters/configure-custom-adapters.component.ts b/src/app/components/project-map/node-editors/configurator/docker/configure-custom-adapters/configure-custom-adapters.component.ts index 2441fc826..b6ea74e4b 100644 --- a/src/app/components/project-map/node-editors/configurator/docker/configure-custom-adapters/configure-custom-adapters.component.ts +++ b/src/app/components/project-map/node-editors/configurator/docker/configure-custom-adapters/configure-custom-adapters.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder } from '@angular/forms'; +import { UntypedFormBuilder } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../../cartography/models/node'; -import { Server } from '../../../../../../models/server'; +import{ Controller } from '../../../../../../models/controller'; import { DockerConfigurationService } from '../../../../../../services/docker-configuration.service'; import { NodeService } from '../../../../../../services/node.service'; import { ToasterService } from '../../../../../../services/toaster.service'; @@ -13,7 +13,7 @@ import { ToasterService } from '../../../../../../services/toaster.service'; styleUrls: ['./configure-custom-adapters.component.scss'], }) export class ConfigureCustomAdaptersDialogComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; displayedColumns: string[] = ['adapter_number', 'port_name']; adapters: CustomAdapter[] = []; @@ -22,7 +22,7 @@ export class ConfigureCustomAdaptersDialogComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private dockerConfigurationService: DockerConfigurationService ) {} @@ -42,7 +42,7 @@ export class ConfigureCustomAdaptersDialogComponent implements OnInit { onSaveClick() { this.node.custom_adapters = this.adapters; - this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => { + this.nodeService.updateNodeWithCustomAdapters(this.controller, this.node).subscribe(() => { this.onCancelClick(); this.toasterService.success(`Configuration saved for node ${this.node.name}`); }); diff --git a/src/app/components/project-map/node-editors/configurator/docker/edit-network-configuration/edit-network-configuration.component.ts b/src/app/components/project-map/node-editors/configurator/docker/edit-network-configuration/edit-network-configuration.component.ts index 2f298783c..0984400a5 100644 --- a/src/app/components/project-map/node-editors/configurator/docker/edit-network-configuration/edit-network-configuration.component.ts +++ b/src/app/components/project-map/node-editors/configurator/docker/edit-network-configuration/edit-network-configuration.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../../cartography/models/node'; -import { Server } from '../../../../../../models/server'; +import{ Controller } from '../../../../../../models/controller'; import { NodeService } from '../../../../../../services/node.service'; import { ToasterService } from '../../../../../../services/toaster.service'; @@ -11,7 +11,7 @@ import { ToasterService } from '../../../../../../services/toaster.service'; styleUrls: ['./edit-network-configuration.component.scss'], }) export class EditNetworkConfigurationDialogComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; configuration: string; @@ -22,14 +22,14 @@ export class EditNetworkConfigurationDialogComponent implements OnInit { ) {} ngOnInit() { - this.nodeService.getNetworkConfiguration(this.server, this.node).subscribe((response: string) => { + this.nodeService.getNetworkConfiguration(this.controller, this.node).subscribe((response: string) => { this.configuration = response; }); } onSaveClick() { this.nodeService - .saveNetworkConfiguration(this.server, this.node, this.configuration) + .saveNetworkConfiguration(this.controller, this.node, this.configuration) .subscribe((response: string) => { this.onCancelClick(); this.toasterService.success(`Configuration for node ${this.node.name} saved.`); diff --git a/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts index 296182c06..63c78b7b7 100644 --- a/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts +++ b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { PortsComponent } from '../../../../../components/preferences/common/ports/ports.component'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -15,26 +15,26 @@ import { ToasterService } from '../../../../../services/toaster.service'; }) export class ConfiguratorDialogEthernetSwitchComponent implements OnInit { @ViewChild(PortsComponent) portsComponent: PortsComponent; - server: Server; + controller:Controller ; node: Node; name: string; - inputForm: FormGroup; + inputForm: UntypedFormGroup; consoleTypes: string[] = []; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private ethernetSwitchesConfigurationService: BuiltInTemplatesConfigurationService ) { this.inputForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = this.node.name; this.getConfiguration(); @@ -48,7 +48,7 @@ export class ConfiguratorDialogEthernetSwitchComponent implements OnInit { onSaveClick() { if (this.inputForm.valid) { this.node.properties.ports_mapping = this.portsComponent.ethernetPorts; - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts index 4b4e2e47c..813ae377c 100644 --- a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts +++ b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; @@ -13,10 +13,10 @@ import { VpcsConfigurationService } from '../../../../../services/vpcs-configura styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogEthernetHubComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; numberOfPorts: number; - inputForm: FormGroup; + inputForm: UntypedFormGroup; consoleTypes: string[] = []; categories = []; name: string; @@ -25,16 +25,16 @@ export class ConfiguratorDialogEthernetHubComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private vpcsConfigurationService: VpcsConfigurationService ) { this.inputForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = this.node.name; this.numberOfPorts = this.node.ports.length; @@ -57,7 +57,7 @@ export class ConfiguratorDialogEthernetHubComponent implements OnInit { }); } - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/ios/configurator-ios.component.ts b/src/app/components/project-map/node-editors/configurator/ios/configurator-ios.component.ts index 9090e1f5a..a7ca7d4f4 100644 --- a/src/app/components/project-map/node-editors/configurator/ios/configurator-ios.component.ts +++ b/src/app/components/project-map/node-editors/configurator/ios/configurator-ios.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { IosConfigurationService } from '../../../../../services/ios-configuration.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -13,32 +13,32 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogIosComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; - memoryForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + memoryForm: UntypedFormGroup; consoleTypes: string[] = []; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private configurationService: IosConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); this.memoryForm = this.formBuilder.group({ - ram: new FormControl('', Validators.required), - nvram: new FormControl('', Validators.required), + ram: new UntypedFormControl('', Validators.required), + nvram: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -51,7 +51,7 @@ export class ConfiguratorDialogIosComponent implements OnInit { onSaveClick() { if (this.generalSettingsForm.valid && this.memoryForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/iou/configurator-iou.component.ts b/src/app/components/project-map/node-editors/configurator/iou/configurator-iou.component.ts index b336bcc64..c98066e63 100644 --- a/src/app/components/project-map/node-editors/configurator/iou/configurator-iou.component.ts +++ b/src/app/components/project-map/node-editors/configurator/iou/configurator-iou.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { IouConfigurationService } from '../../../../../services/iou-configuration.service'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -13,32 +13,32 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogIouComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; - networkForm: FormGroup; + generalSettingsForm: UntypedFormGroup; + networkForm: UntypedFormGroup; consoleTypes: string[] = []; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private configurationService: IouConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); this.networkForm = this.formBuilder.group({ - ethernetAdapters: new FormControl('', Validators.required), - serialAdapters: new FormControl('', Validators.required), + ethernetAdapters: new UntypedFormControl('', Validators.required), + serialAdapters: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -51,7 +51,7 @@ export class ConfiguratorDialogIouComponent implements OnInit { onSaveClick() { if (this.generalSettingsForm.valid && this.networkForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/nat/configurator-nat.component.ts b/src/app/components/project-map/node-editors/configurator/nat/configurator-nat.component.ts index c42da4d12..be80af17b 100644 --- a/src/app/components/project-map/node-editors/configurator/nat/configurator-nat.component.ts +++ b/src/app/components/project-map/node-editors/configurator/nat/configurator-nat.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,24 +12,24 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogNatComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; }); @@ -37,7 +37,7 @@ export class ConfiguratorDialogNatComponent implements OnInit { onSaveClick() { if (this.generalSettingsForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.html b/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.html index 190fb0fb4..97a483c62 100644 --- a/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.html +++ b/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.html @@ -11,6 +11,13 @@

Configurator for node {{ name }}

+ + + + {{ platform }} + + + Configurator for node {{ name }} - - - - {{ binary.path }} - - - + @@ -143,9 +144,7 @@

Configurator for node {{ name }}

-
- Use the legacy networking mode - +

Replicate network connection state @@ -241,6 +240,9 @@

Configurator for node {{ name }}


Enable the Trusted Platform Module (TPM) +
+ Enable the UEFI boot mode +
diff --git a/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.ts b/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.ts index e03d477c1..656c2e21e 100644 --- a/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.ts +++ b/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component'; import { QemuBinary } from '../../../../../models/qemu/qemu-binary'; import { QemuImage } from '../../../../../models/qemu/qemu-image'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { QemuConfigurationService } from '../../../../../services/qemu-configuration.service'; import { QemuService } from '../../../../../services/qemu.service'; @@ -18,12 +18,11 @@ import { QemuImageCreatorComponent } from './qemu-image-creator/qemu-image-creat styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogQemuComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; consoleTypes: string[] = []; - binaries: QemuBinary[] = []; onCloseOptions = []; bootPriorities = []; diskInterfaces: string[] = []; @@ -31,6 +30,7 @@ export class ConfiguratorDialogQemuComponent implements OnInit { displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions']; networkTypes = []; qemuImages: QemuImage[] = []; + selectPlatform: string[] = []; private conf = { autoFocus: false, @@ -46,36 +46,34 @@ export class ConfiguratorDialogQemuComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private qemuService: QemuService, private qemuConfigurationService: QemuConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), - ram: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), + ram: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); }); - this.qemuService.getBinaries(this.server).subscribe((qemuBinaries: QemuBinary[]) => { - this.binaries = qemuBinaries; - }); - - this.qemuService.getImages(this.server).subscribe((qemuImages: QemuImage[]) => { + this.qemuService.getImages(this.controller).subscribe((qemuImages: QemuImage[]) => { this.qemuImages = qemuImages; }); + this.selectPlatform = this.qemuConfigurationService.getPlatform(); + } openQemuImageCreator() { this.dialogRefQemuImageCreator = this.dialog.open(QemuImageCreatorComponent, this.conf); let instance = this.dialogRefQemuImageCreator.componentInstance; - instance.server = this.server; + instance.controller = this.controller; } uploadCdromImageFile(event) { @@ -116,7 +114,7 @@ export class ConfiguratorDialogQemuComponent implements OnInit { this.node.properties.adapters = this.node.custom_adapters.length; - this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => { + this.nodeService.updateNodeWithCustomAdapters(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component.ts b/src/app/components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component.ts index 5287f987a..40a215d5f 100644 --- a/src/app/components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component.ts +++ b/src/app/components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { QemuImg } from '../../../../../../models/qemu/qemu-img'; -import { Server } from '../../../../../../models/server'; +import{ Controller } from '../../../../../../models/controller'; import { NodeService } from '../../../../../../services/node.service'; import { QemuService } from '../../../../../../services/qemu.service'; import { ToasterService } from '../../../../../../services/toaster.service'; @@ -13,7 +13,7 @@ import { ToasterService } from '../../../../../../services/toaster.service'; styleUrls: ['../../configurator.component.scss'], }) export class QemuImageCreatorComponent implements OnInit { - server: Server; + controller:Controller ; qemuImg: QemuImg; formatOptions: string[] = ['qcow2', 'qcow', 'vhd', 'vdi', 'vmdk', 'raw']; @@ -75,19 +75,19 @@ export class QemuImageCreatorComponent implements OnInit { lazyRefcountsOptions: string[] = ['off', 'on']; refcountBitsOptions: number[] = [1, 2, 4, 8, 16, 32, 64]; zeroedGrainOptions: string[] = ['on', 'off']; - inputForm: FormGroup; + inputForm: UntypedFormGroup; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private qemuService: QemuService ) { this.inputForm = this.formBuilder.group({ - qemu_img: new FormControl('', Validators.required), - path: new FormControl('', Validators.required), - size: new FormControl('', Validators.required), + qemu_img: new UntypedFormControl('', Validators.required), + path: new UntypedFormControl('', Validators.required), + size: new UntypedFormControl('', Validators.required), }); } @@ -101,7 +101,7 @@ export class QemuImageCreatorComponent implements OnInit { onSaveClick() { if (this.inputForm.valid && this.qemuImg.format) { - this.qemuService.addImage(this.server, this.qemuImg).subscribe(() => { + this.qemuService.addImage(this.controller, this.qemuImg).subscribe(() => { this.dialogRef.close(); }); } else { diff --git a/src/app/components/project-map/node-editors/configurator/switch/configurator-switch.component.ts b/src/app/components/project-map/node-editors/configurator/switch/configurator-switch.component.ts index ada8e2041..51692af7d 100644 --- a/src/app/components/project-map/node-editors/configurator/switch/configurator-switch.component.ts +++ b/src/app/components/project-map/node-editors/configurator/switch/configurator-switch.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,11 +12,11 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss', '../../../../preferences/preferences.component.scss'], }) export class ConfiguratorDialogSwitchComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - nameForm: FormGroup; - inputForm: FormGroup; + nameForm: UntypedFormGroup; + inputForm: UntypedFormGroup; consoleTypes: string[] = []; nodeMappings = new Map(); @@ -33,22 +33,22 @@ export class ConfiguratorDialogSwitchComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder + private formBuilder: UntypedFormBuilder ) { this.nameForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); this.inputForm = this.formBuilder.group({ - sourcePort: new FormControl('', Validators.required), - sourceDlci: new FormControl('', Validators.required), - destinationPort: new FormControl('', Validators.required), - destinationDlci: new FormControl('', Validators.required), + sourcePort: new UntypedFormControl('', Validators.required), + sourceDlci: new UntypedFormControl('', Validators.required), + destinationPort: new UntypedFormControl('', Validators.required), + destinationDlci: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; @@ -115,7 +115,7 @@ export class ConfiguratorDialogSwitchComponent implements OnInit { {} ); - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.html b/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.html deleted file mode 100644 index e257af66e..000000000 --- a/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.html +++ /dev/null @@ -1,20 +0,0 @@ -

Configurator for node {{ name }}

- - - -
- - -
diff --git a/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.ts b/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.ts deleted file mode 100644 index 7bb08222d..000000000 --- a/src/app/components/project-map/node-editors/configurator/traceng/configurator-traceng.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { MatDialogRef } from '@angular/material/dialog'; -import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; -import { NodeService } from '../../../../../services/node.service'; -import { ToasterService } from '../../../../../services/toaster.service'; - -@Component({ - selector: 'app-configurator-traceng', - templateUrl: './configurator-traceng.component.html', - styleUrls: ['../configurator.component.scss'], -}) -export class ConfiguratorDialogTracengComponent implements OnInit { - server: Server; - node: Node; - name: string; - generalSettingsForm: FormGroup; - - constructor( - public dialogRef: MatDialogRef, - public nodeService: NodeService, - private toasterService: ToasterService, - private formBuilder: FormBuilder - ) { - this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), - }); - } - - ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { - this.node = node; - this.name = node.name; - }); - } - - onSaveClick() { - if (this.generalSettingsForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { - this.toasterService.success(`Node ${this.node.name} updated.`); - this.onCancelClick(); - }); - } else { - this.toasterService.error(`Fill all required fields.`); - } - } - - onCancelClick() { - this.dialogRef.close(); - } -} diff --git a/src/app/components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component.ts b/src/app/components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component.ts index 629f2aed4..c0b032695 100644 --- a/src/app/components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component.ts +++ b/src/app/components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VirtualBoxConfigurationService } from '../../../../../services/virtual-box-configuration.service'; @@ -14,10 +14,10 @@ import { VirtualBoxConfigurationService } from '../../../../../services/virtual- styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogVirtualBoxComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; consoleTypes: string[] = []; onCloseOptions = []; @@ -30,17 +30,17 @@ export class ConfiguratorDialogVirtualBoxComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private virtualBoxConfigurationService: VirtualBoxConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), - ram: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), + ram: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -65,7 +65,7 @@ export class ConfiguratorDialogVirtualBoxComponent implements OnInit { this.node.properties.adapters = this.node.custom_adapters.length; - this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => { + this.nodeService.updateNodeWithCustomAdapters(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/vmware/configurator-vmware.component.ts b/src/app/components/project-map/node-editors/configurator/vmware/configurator-vmware.component.ts index 854021cd0..f0aad466c 100644 --- a/src/app/components/project-map/node-editors/configurator/vmware/configurator-vmware.component.ts +++ b/src/app/components/project-map/node-editors/configurator/vmware/configurator-vmware.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VmwareConfigurationService } from '../../../../../services/vmware-configuration.service'; @@ -14,10 +14,10 @@ import { VmwareConfigurationService } from '../../../../../services/vmware-confi styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogVmwareComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - generalSettingsForm: FormGroup; + generalSettingsForm: UntypedFormGroup; consoleTypes: string[] = []; onCloseOptions = []; @@ -30,16 +30,16 @@ export class ConfiguratorDialogVmwareComponent implements OnInit { public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private vmwareConfigurationService: VmwareConfigurationService ) { this.generalSettingsForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -64,7 +64,7 @@ export class ConfiguratorDialogVmwareComponent implements OnInit { this.node.properties.adapters = this.node.custom_adapters.length; - this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => { + this.nodeService.updateNodeWithCustomAdapters(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts index 920e94c98..f10689f48 100644 --- a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts +++ b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Node } from '../../../../../cartography/models/node'; -import { Server } from '../../../../../models/server'; +import{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; @@ -13,26 +13,26 @@ import { VpcsConfigurationService } from '../../../../../services/vpcs-configura styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogVpcsComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; - inputForm: FormGroup; + inputForm: UntypedFormGroup; consoleTypes: string[] = []; constructor( public dialogRef: MatDialogRef, public nodeService: NodeService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private vpcsConfigurationService: VpcsConfigurationService ) { this.inputForm = this.formBuilder.group({ - name: new FormControl('', Validators.required), + name: new UntypedFormControl('', Validators.required), }); } ngOnInit() { - this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => { this.node = node; this.name = node.name; this.getConfiguration(); @@ -45,7 +45,7 @@ export class ConfiguratorDialogVpcsComponent implements OnInit { onSaveClick() { if (this.inputForm.valid) { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.nodeService.updateNode(this.controller, this.node).subscribe(() => { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); }); diff --git a/src/app/components/project-map/node-select-interface/node-select-interface.component.spec.ts b/src/app/components/project-map/node-select-interface/node-select-interface.component.spec.ts index 38a8a0832..efd21b5cc 100644 --- a/src/app/components/project-map/node-select-interface/node-select-interface.component.spec.ts +++ b/src/app/components/project-map/node-select-interface/node-select-interface.component.spec.ts @@ -1,15 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NodeSelectInterfaceComponent } from './node-select-interface.component'; describe('NodeSelectInterfaceComponent', () => { let component: NodeSelectInterfaceComponent; let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ declarations: [NodeSelectInterfaceComponent], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(NodeSelectInterfaceComponent); @@ -17,7 +17,7 @@ describe('NodeSelectInterfaceComponent', () => { fixture.detectChanges(); }); - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.html b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.html new file mode 100644 index 000000000..dae4f3f1d --- /dev/null +++ b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.html @@ -0,0 +1,13 @@ +
+
+
Confirm {{ confirmActionData.actionType}} All
+
+
+ + +

Are you sure you want to {{confirmActionData.actionType}} all devices?

+
+ + + + diff --git a/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.scss b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.scss new file mode 100644 index 000000000..c74494a94 --- /dev/null +++ b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.scss @@ -0,0 +1,19 @@ +.close-btn{ + height: 30px; + width: 30px; + margin-left: 10px; + margin-bottom:10px +} +.close-icon{ + font-size: 15px; +} +.text-padding{ + padding: 15px 0 0 0; + +} +.mat-dialog-actions { + min-height: 31px; +} +.heading-txt{ + text-transform: capitalize; +} \ No newline at end of file diff --git a/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.spec.ts b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.spec.ts new file mode 100644 index 000000000..ae514afeb --- /dev/null +++ b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.spec.ts @@ -0,0 +1,44 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatToolbarModule } from '@angular/material/toolbar'; + +import { NodesMenuConfirmationDialogComponent } from './nodes-menu-confirmation-dialog.component'; + +describe('NodesMenuConfirmationDialogComponent', () => { + let component: NodesMenuConfirmationDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports:[ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule, + MatSnackBarModule, + ], + providers: [ + + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: MatDialogRef, useValue: {} }, + ], + declarations: [ NodesMenuConfirmationDialogComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NodesMenuConfirmationDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.ts b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.ts new file mode 100644 index 000000000..3c9125346 --- /dev/null +++ b/src/app/components/project-map/nodes-menu/nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component.ts @@ -0,0 +1,27 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-nodes-menu-confirmation-dialog', + templateUrl: './nodes-menu-confirmation-dialog.component.html', + styleUrls: ['./nodes-menu-confirmation-dialog.component.scss'], +}) +export class NodesMenuConfirmationDialogComponent implements OnInit { + confirmActionData = { + actionType: 'start', + isAction:false + }; + constructor( + @Inject(MAT_DIALOG_DATA) public data: any, + public dialogRef: MatDialogRef + ) {} + + ngOnInit(): void { + this.confirmActionData.actionType = this.data; + } + + confirmAction() { + this.confirmActionData.isAction = true + this.dialogRef.close(this.confirmActionData); + } +} diff --git a/src/app/components/project-map/nodes-menu/nodes-menu.component.html b/src/app/components/project-map/nodes-menu/nodes-menu.component.html index b495ad3c9..7414dc46c 100644 --- a/src/app/components/project-map/nodes-menu/nodes-menu.component.html +++ b/src/app/components/project-map/nodes-menu/nodes-menu.component.html @@ -12,7 +12,7 @@ matTooltip="Start/Resume all nodes" matTooltipClass="custom-tooltip" mat-icon-button - (click)="startNodes()" + (click)="confirmControlsActions('start')" class="menu-button" > play_arrow @@ -21,7 +21,7 @@ matTooltip="Suspend all nodes" matTooltipClass="custom-tooltip" mat-icon-button - (click)="suspendNodes()" + (click)="confirmControlsActions('suspend')" class="menu-button" > pause @@ -30,7 +30,7 @@ matTooltip="Stop all nodes" matTooltipClass="custom-tooltip" mat-icon-button - (click)="stopNodes()" + (click)="confirmControlsActions('stop')" class="menu-button" > stop @@ -39,9 +39,19 @@ matTooltip="Reload all nodes" matTooltipClass="custom-tooltip" mat-icon-button - (click)="reloadNodes()" + (click)="confirmControlsActions('reload')" class="menu-button" > replay + +
diff --git a/src/app/components/project-map/nodes-menu/nodes-menu.component.spec.ts b/src/app/components/project-map/nodes-menu/nodes-menu.component.spec.ts index 9e2c45274..bf5e1952a 100644 --- a/src/app/components/project-map/nodes-menu/nodes-menu.component.spec.ts +++ b/src/app/components/project-map/nodes-menu/nodes-menu.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @@ -8,7 +8,7 @@ import { ElectronService } from 'ngx-electron'; import { of } from 'rxjs'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { NodeService } from '../../../services/node.service'; -import { ServerService } from '../../../services/server.service'; +import { ControllerService } from '../../../services/controller.service'; import { SettingsService } from '../../../services/settings.service'; import { ToasterService } from '../../../services/toaster.service'; import { MockedToasterService } from '../../../services/toaster.service.spec'; @@ -22,21 +22,21 @@ xdescribe('NodesMenuComponent', () => { let mockedNodeService: MockedNodeService = new MockedNodeService(); let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [MatButtonModule, MatIconModule, CommonModule, NoopAnimationsModule], providers: [ { provide: NodeService, useValue: mockedNodeService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: NodesDataSource, useValue: mockedNodesDataSource }, - { provide: ServerService }, + { provide: ControllerService }, { provide: SettingsService }, { provide: ElectronService }, ], declarations: [NodesMenuComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(NodesMenuComponent); diff --git a/src/app/components/project-map/nodes-menu/nodes-menu.component.ts b/src/app/components/project-map/nodes-menu/nodes-menu.component.ts index 839ccbbe5..111b4f3a1 100644 --- a/src/app/components/project-map/nodes-menu/nodes-menu.component.ts +++ b/src/app/components/project-map/nodes-menu/nodes-menu.component.ts @@ -1,14 +1,16 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { MapSettingsService } from '../../../services/mapsettings.service'; +import { MatDialog } from '@angular/material/dialog'; import { ElectronService } from 'ngx-electron'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; +import { MapSettingsService } from '../../../services/mapsettings.service'; import { NodeService } from '../../../services/node.service'; -import { ServerService } from '../../../services/server.service'; +import { NodeConsoleService } from '../../../services/nodeConsole.service'; +import { ControllerService } from '../../../services/controller.service'; import { SettingsService } from '../../../services/settings.service'; import { ToasterService } from '../../../services/toaster.service'; -import { NodeConsoleService } from '../../../services/nodeConsole.service'; +import { NodesMenuConfirmationDialogComponent } from './nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component'; @Component({ selector: 'app-nodes-menu', @@ -18,17 +20,18 @@ import { NodeConsoleService } from '../../../services/nodeConsole.service'; }) export class NodesMenuComponent { @Input('project') project: Project; - @Input('server') server: Server; + @Input('controller') controller:Controller ; constructor( private nodeService: NodeService, private nodeConsoleService: NodeConsoleService, private nodesDataSource: NodesDataSource, private toasterService: ToasterService, - private serverService: ServerService, + private controllerService: ControllerService, private settingsService: SettingsService, private mapSettingsService: MapSettingsService, - private electronService: ElectronService + private electronService: ElectronService, + private dialog: MatDialog ) {} async startConsoleForAllNodes() { @@ -47,7 +50,7 @@ export class NodesMenuComponent { name: node.name, project_id: node.project_id, node_id: node.node_id, - server_url: this.serverService.getServerUrl(this.server), + controller_url: this.controllerService.getControllerUrl(this.controller), }; await this.electronService.remote.require('./console-executor.js').openConsole(request); } @@ -61,26 +64,56 @@ export class NodesMenuComponent { } startNodes() { - this.nodeService.startAll(this.server, this.project).subscribe(() => { + this.nodeService.startAll(this.controller, this.project).subscribe(() => { this.toasterService.success('All nodes successfully started'); }); } stopNodes() { - this.nodeService.stopAll(this.server, this.project).subscribe(() => { + this.nodeService.stopAll(this.controller, this.project).subscribe(() => { this.toasterService.success('All nodes successfully stopped'); }); } suspendNodes() { - this.nodeService.suspendAll(this.server, this.project).subscribe(() => { + this.nodeService.suspendAll(this.controller, this.project).subscribe(() => { this.toasterService.success('All nodes successfully suspended'); }); } reloadNodes() { - this.nodeService.reloadAll(this.server, this.project).subscribe(() => { + this.nodeService.reloadAll(this.controller, this.project).subscribe(() => { this.toasterService.success('All nodes successfully reloaded'); }); } + + resetNodes() { + this.nodeService.resetAllNodes(this.controller, this.project).subscribe(() => { + this.toasterService.success('Successfully reset all console connections'); + }); + } + + public confirmControlsActions(type) { + const dialogRef = this.dialog.open(NodesMenuConfirmationDialogComponent, { + width: '500px', + maxHeight: '200px', + autoFocus: false, + disableClose: true, + data: type, + }); + + dialogRef.afterClosed().subscribe((confirmAction_result) => { + if (confirmAction_result.isAction && confirmAction_result.actionType == 'start') { + this.startNodes(); + } else if (confirmAction_result.isAction && confirmAction_result.actionType == 'stop') { + this.stopNodes(); + } else if (confirmAction_result.isAction && confirmAction_result.actionType == 'reload') { + this.reloadNodes(); + } else if (confirmAction_result.isAction && confirmAction_result.actionType == 'suspend') { + this.suspendNodes(); + } else { + this.resetNodes() + } + }); + } } diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts index 08f9a5bba..1b4842162 100644 --- a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts +++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts @@ -23,8 +23,8 @@ describe('PacketFiltersDialogComponent', () => { close: jasmine.createSpy('close'), }; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ MatDialogModule, FormsModule, @@ -44,7 +44,7 @@ describe('PacketFiltersDialogComponent', () => { declarations: [PacketFiltersDialogComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(PacketFiltersDialogComponent); diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts index 3b22edefe..ed86dc8d6 100644 --- a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts +++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts @@ -5,7 +5,7 @@ import { FilterDescription } from '../../../../models/filter-description'; import { Link } from '../../../../models/link'; import { Message } from '../../../../models/message'; import { Project } from '../../../../models/project'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { LinkService } from '../../../../services/link.service'; import { HelpDialogComponent } from '../../help-dialog/help-dialog.component'; @@ -15,7 +15,7 @@ import { HelpDialogComponent } from '../../help-dialog/help-dialog.component'; styleUrls: ['./packet-filters.component.scss'], }) export class PacketFiltersDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; link: Link; filters: Filter; @@ -28,7 +28,7 @@ export class PacketFiltersDialogComponent implements OnInit { ) {} ngOnInit() { - this.linkService.getLink(this.server, this.link.project_id, this.link.link_id).subscribe((link: Link) => { + this.linkService.getLink(this.controller, this.link.project_id, this.link.link_id).subscribe((link: Link) => { this.link = link; this.filters = { bpf: [], @@ -47,7 +47,7 @@ export class PacketFiltersDialogComponent implements OnInit { } }); - this.linkService.getAvailableFilters(this.server, this.link).subscribe((availableFilters: FilterDescription[]) => { + this.linkService.getAvailableFilters(this.controller, this.link).subscribe((availableFilters: FilterDescription[]) => { this.availableFilters = availableFilters; }); } @@ -65,14 +65,14 @@ export class PacketFiltersDialogComponent implements OnInit { packet_loss: [0], }; - this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => { + this.linkService.updateLink(this.controller, this.link).subscribe((link: Link) => { this.dialogRef.close(); }); } onYesClick() { this.link.filters = this.filters; - this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => { + this.linkService.updateLink(this.controller, this.link).subscribe((link: Link) => { this.dialogRef.close(); }); } diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts index ebb8a6445..69bdd22bd 100644 --- a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts +++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; @@ -29,8 +29,8 @@ describe('StartCaptureDialogComponent', () => { close: jasmine.createSpy('close'), }; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ imports: [ MatDialogModule, FormsModule, @@ -53,7 +53,7 @@ describe('StartCaptureDialogComponent', () => { declarations: [StartCaptureDialogComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(StartCaptureDialogComponent); diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts index 5426758e0..9ef998e7a 100644 --- a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts +++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { NodesDataSource } from '../../../../cartography/datasources/nodes-datasource'; import { CapturingSettings } from '../../../../models/capturingSettings'; import { Link } from '../../../../models/link'; import { LinkNode } from '../../../../models/link-node'; import { Project } from '../../../../models/project'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { LinkService } from '../../../../services/link.service'; import { PacketCaptureService } from '../../../../services/packet-capture.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -18,24 +18,24 @@ import { PacketFiltersDialogComponent } from '../packet-filters/packet-filters.c styleUrls: ['./start-capture.component.scss'], }) export class StartCaptureDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; link: Link; linkTypes = []; - inputForm: FormGroup; + inputForm: UntypedFormGroup; startProgram: boolean; constructor( private dialogRef: MatDialogRef, private linkService: LinkService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private toasterService: ToasterService, private nodesDataSource: NodesDataSource, private packetCaptureService: PacketCaptureService ) { this.inputForm = this.formBuilder.group({ - linkType: new FormControl('', Validators.required), - fileName: new FormControl('', Validators.required), + linkType: new UntypedFormControl('', Validators.required), + fileName: new UntypedFormControl('', Validators.required), }); } @@ -78,10 +78,10 @@ export class StartCaptureDialogComponent implements OnInit { }; if (this.startProgram) { - this.packetCaptureService.startCapture(this.server, this.project, this.link, captureSettings.capture_file_name); + this.packetCaptureService.startCapture(this.controller, this.project, this.link, captureSettings.capture_file_name); } - this.linkService.startCaptureOnLink(this.server, this.link, captureSettings).subscribe(() => { + this.linkService.startCaptureOnLink(this.controller, this.link, captureSettings).subscribe(() => { this.dialogRef.close(); }); } diff --git a/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.html b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.html new file mode 100644 index 000000000..82b5771ca --- /dev/null +++ b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.html @@ -0,0 +1,14 @@ +
+
+
Confirm {{ confirmActionData.actionType}} All
+
+
+ + +

Are you sure you want to {{confirmActionData.actionType}} all devices?

+
+ + + + + \ No newline at end of file diff --git a/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.scss b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.spec.ts b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.spec.ts new file mode 100644 index 000000000..121362263 --- /dev/null +++ b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.spec.ts @@ -0,0 +1,44 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatToolbarModule } from '@angular/material/toolbar'; + +import { ProjectMapLockConfirmationDialogComponent } from './project-map-lock-confirmation-dialog.component'; + +describe('ProjectMapLockConfirmationDialogComponent', () => { + let component: ProjectMapLockConfirmationDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports:[ + MatIconModule, + MatToolbarModule, + MatMenuModule, + MatCheckboxModule, + MatDialogModule, + MatSnackBarModule, + ], + providers: [ + + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: MatDialogRef, useValue: {} }, + ], + declarations: [ ProjectMapLockConfirmationDialogComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProjectMapLockConfirmationDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.ts b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.ts new file mode 100644 index 000000000..1b8141f87 --- /dev/null +++ b/src/app/components/project-map/project-map-menu/project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component.ts @@ -0,0 +1,28 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-project-map-lock-confirmation-dialog', + templateUrl: './project-map-lock-confirmation-dialog.component.html', + styleUrls: ['./project-map-lock-confirmation-dialog.component.scss'] +}) +export class ProjectMapLockConfirmationDialogComponent implements OnInit { + confirmActionData = { + actionType: 'Unlock', + isAction:false + }; + constructor( + @Inject(MAT_DIALOG_DATA) public data: any, + public dialogRef: MatDialogRef + ) {} + + ngOnInit(): void { + this.confirmActionData.actionType = this.data.actionType; + } + + confirmAction() { + this.confirmActionData.isAction = this.data.actionType == 'Lock'? true : false; + this.dialogRef.close(this.confirmActionData); + } + +} diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.html b/src/app/components/project-map/project-map-menu/project-map-menu.component.html index 81f0fc0f7..e3b53e86e 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.html +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.html @@ -86,7 +86,7 @@ class="menu-button" (click)="changeLockValue()" > - lock + {{lock}} { let component: ProjectMapMenuComponent; @@ -24,9 +31,14 @@ describe('ProjectMapMenuComponent', () => { let drawingService = new MockedDrawingService(); let mapSettingService = new MapSettingsService(); let mockedSymbolService = new MockedSymbolService(); + let mockedProjectService: MockedProjectService = new MockedProjectService(); + let mockedNodeService: MockedNodeService = new MockedNodeService(); + let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource(); + let mockedDrawingsDataSource = new MockedDrawingsDataSource(); + let mockedDrawingsEventSource = new DrawingsEventSource(); - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatIconModule, MatDialogModule, @@ -38,15 +50,20 @@ describe('ProjectMapMenuComponent', () => { ], providers: [ { provide: DrawingService, useValue: drawingService }, - { provide: ToolsService }, + { provide: DrawingsDataSource, useValue: mockedDrawingsDataSource }, + { provide: DrawingsEventSource, useValue: mockedDrawingsEventSource }, + { provide: ProjectService, useValue: mockedProjectService }, + { provide: ToolsService, useClass: ToolsService }, { provide: MapSettingsService, useValue: mapSettingService }, { provide: SymbolService, useValue: mockedSymbolService }, + { provide: NodeService, useValue: mockedNodeService }, + { provide: NodesDataSource, useValue: mockedNodesDataSource }, { provide: ElectronService }, ], declarations: [ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ProjectMapMenuComponent); @@ -77,9 +94,9 @@ describe('ProjectMapMenuComponent', () => { spyOn(mapSettingService, 'changeMapLockValue'); component.changeLockValue(); - expect(mapSettingService.changeMapLockValue).toHaveBeenCalledWith(true); + expect(mapSettingService.changeMapLockValue).toHaveBeenCalledWith(true);; component.changeLockValue(); - expect(mapSettingService.changeMapLockValue).toHaveBeenCalledWith(false); + expect(mapSettingService.changeMapLockValue).toHaveBeenCalledWith(false);; }); }); diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts index 827e81473..06064435c 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts @@ -1,17 +1,24 @@ import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; +import { NodeService } from '../../../services/node.service'; import { select } from 'd3-selection'; +import { Subscription } from 'rxjs'; import * as svg from 'save-svg-as-png'; import downloadSvg from 'svg-crowbar'; +import { Drawing } from '../../../cartography/models/drawing'; +import { Node } from '../../../cartography/models/node'; +import { Controller } from '../../../models/controller'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; import { DrawingService } from '../../../services/drawing.service'; import { MapSettingsService } from '../../../services/mapsettings.service'; +import { ProjectService } from '../../../services/project.service'; import { SymbolService } from '../../../services/symbol.service'; import { ThemeService } from '../../../services/theme.service'; import { ToolsService } from '../../../services/tools.service'; import { Screenshot, ScreenshotDialogComponent } from '../screenshot-dialog/screenshot-dialog.component'; - +import { ProjectMapLockConfirmationDialogComponent } from './project-map-lock-confirmation-dialog/project-map-lock-confirmation-dialog.component'; +import { DrawingsDataSource } from '../../../cartography/datasources/drawings-datasource'; +import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; @Component({ selector: 'app-project-map-menu', templateUrl: './project-map-menu.component.html', @@ -20,9 +27,12 @@ import { Screenshot, ScreenshotDialogComponent } from '../screenshot-dialog/scre }) export class ProjectMapMenuComponent implements OnInit, OnDestroy { @Input() project: Project; - @Input() server: Server; + @Input() controller: Controller; + private nodes: Node[] = []; + private drawing: Drawing[] = []; public selectedDrawing: string; + public lock: string = 'lock_open'; public drawTools = { isRectangleChosen: false, isEllipseChosen: false, @@ -31,20 +41,30 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { }; public isLocked: boolean = false; public isLightThemeEnabled: boolean = false; - + private projectSubscription: Subscription; constructor( private toolsService: ToolsService, private mapSettingsService: MapSettingsService, private drawingService: DrawingService, private symbolService: SymbolService, private dialog: MatDialog, - private themeService: ThemeService + private themeService: ThemeService, + private projectServices: ProjectService, + private nodeService : NodeService, + private nodesDataSource: NodesDataSource, + private drawingsDataSource: DrawingsDataSource, ) {} ngOnInit() { this.themeService.getActualTheme() === 'light' ? (this.isLightThemeEnabled = true) : (this.isLightThemeEnabled = false); + this.projectSubscription = this.projectServices.projectLockIconSubject.subscribe((isRedraw: boolean) => { + if (isRedraw) { + this.getAllNodesAndDrawingStatus(); + } + }); + this.getAllNodesAndDrawingStatus(); } getCssClassForIcon(type: string) { @@ -85,7 +105,7 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { let splittedImage = splittedSvg[i].split('"'); let splittedUrl = splittedImage[1].split('/'); - let elem = await this.symbolService.raw(this.server, splittedUrl[7]).toPromise(); + let elem = await this.symbolService.raw(this.controller, splittedUrl[7]).toPromise(); let splittedElement = elem.split('-->'); splittedSvg[i] = splittedElement[1].substring(2); i += 2; @@ -104,11 +124,15 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { } public addDrawing(selectedObject: string) { - if ((selectedObject === 'rectangle' && this.drawTools.isRectangleChosen) || (selectedObject === 'ellipse' && this.drawTools.isEllipseChosen) || - (selectedObject === 'line' && this.drawTools.isLineChosen) || (selectedObject === 'text' && this.drawTools.isTextChosen)) { - document.documentElement.style.cursor = "default"; + if ( + (selectedObject === 'rectangle' && this.drawTools.isRectangleChosen) || + (selectedObject === 'ellipse' && this.drawTools.isEllipseChosen) || + (selectedObject === 'line' && this.drawTools.isLineChosen) || + (selectedObject === 'text' && this.drawTools.isTextChosen) + ) { + document.documentElement.style.cursor = 'default'; } else { - document.documentElement.style.cursor = "crosshair"; + document.documentElement.style.cursor = 'crosshair'; } switch (selectedObject) { @@ -147,8 +171,7 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { } public resetDrawToolChoice() { - document.documentElement.style.cursor = "default"; - + document.documentElement.style.cursor = 'default'; this.drawTools.isRectangleChosen = false; this.drawTools.isEllipseChosen = false; this.drawTools.isLineChosen = false; @@ -156,10 +179,70 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { this.selectedDrawing = ''; this.toolsService.textAddingToolActivation(this.drawTools.isTextChosen); } + getAllNodesAndDrawingStatus() { + this.projectServices.getProjectStatus(this.controller,this.project.project_id).subscribe((status)=>{ + if (status) { + this.isLocked = true; + this.lock = 'lock'; + } else { + this.isLocked = false; + this.lock = 'lock_open'; + } + }) + this.projectServices.nodes(this.controller, this.project.project_id).subscribe((response) => { + this.nodes = response; + this.nodes.forEach((node) => { + this.nodeService.updateNode(this.controller, node).subscribe((node) => { + this.nodesDataSource.update(node); + }); + }); + }); + + this.projectServices.drawings(this.controller, this.project.project_id).subscribe((response) => { + this.drawing = response; + this.drawing.forEach((drawing) => { + this.drawingService.update(this.controller, drawing).subscribe((drawing) => { + this.drawingsDataSource.update(drawing); + }); + }); + }); + } public changeLockValue() { this.isLocked = !this.isLocked; this.mapSettingsService.changeMapLockValue(this.isLocked); + const dialogRef = this.dialog.open(ProjectMapLockConfirmationDialogComponent, { + width: '500px', + maxHeight: '200px', + autoFocus: false, + disableClose: true, + data: { isAction: this.isLocked, actionType: this.isLocked == true ? 'Lock' : 'Unlock' }, + }); + + dialogRef.afterClosed().subscribe((confirmAction_result) => { + if (confirmAction_result && confirmAction_result != '') { + if (confirmAction_result.actionType == 'Lock' && confirmAction_result.isAction) { + this.lockAllNode(); + } else { + this.unlockAllNode(); + } + } else { + } + }); + } + + lockAllNode() { + this.lock = 'lock'; + this.drawingService.lockAllNodes(this.controller, this.project).subscribe((res) => { + this.getAllNodesAndDrawingStatus(); + }); + } + + unlockAllNode() { + this.lock = 'lock_open'; + this.drawingService.unLockAllNodes(this.controller, this.project).subscribe((res) => { + this.getAllNodesAndDrawingStatus(); + }); } public uploadImageFile(event) { @@ -175,7 +258,7 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { let image = fileReader.result; let svg = this.createSvgFileForImage(image, imageToUpload); this.drawingService - .add(this.server, this.project.project_id, -(imageToUpload.width / 2), -(imageToUpload.height / 2), svg) + .add(this.controller, this.project.project_id, -(imageToUpload.width / 2), -(imageToUpload.height / 2), svg) .subscribe(() => {}); }; @@ -186,9 +269,11 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { } private createSvgFileForImage(image: string | ArrayBuffer, imageToUpload: HTMLImageElement) { - return `\n\n`; } - ngOnDestroy() {} + ngOnDestroy() { + // this.projectSubscription.unsubscribe(); + } } diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index ffd368c45..ec2554a2c 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -1,7 +1,7 @@
- - - - - + + + - @@ -131,11 +132,11 @@
- +
- +
- - - - - - - - + + + + + + + +
- \ No newline at end of file + diff --git a/src/app/components/project-map/project-map.component.scss b/src/app/components/project-map/project-map.component.scss index e32958950..dacbf3c97 100644 --- a/src/app/components/project-map/project-map.component.scss +++ b/src/app/components/project-map/project-map.component.scss @@ -73,10 +73,6 @@ g.node:hover { font-size: 28px !important; } - .map-settings-button mat-icon { - font-size: 22px !important; - } - .selected { background: rgba(0, 151, 167, 0.1); @@ -386,6 +382,9 @@ g.node text, .context-menu-items .mat-menu-item:focus { background: none; } +.light-theme .context-menu-items .mat-menu-item:hover { + background-color: rgba(153, 152, 152, 0.795) !important; +} .visible { display: none; diff --git a/src/app/components/project-map/project-map.component.spec.ts b/src/app/components/project-map/project-map.component.spec.ts index bdad1e589..f60cb0c34 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -1,9 +1,9 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatDialogModule } from '@angular/material/dialog'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { MatToolbarModule } from '@angular/material/toolbar'; @@ -46,7 +46,7 @@ import { ProjectWebServiceHandler } from '../../handlers/project-web-service-han import { CapturingSettings } from '../../models/capturingSettings'; import { Link } from '../../models/link'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { DrawingService } from '../../services/drawing.service'; import { LinkService } from '../../services/link.service'; import { MapScaleService } from '../../services/mapScale.service'; @@ -56,8 +56,8 @@ import { NotificationService } from '../../services/notification.service'; import { ProjectService } from '../../services/project.service'; import { MockedProjectService } from '../../services/project.service.spec'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; -import { ServerService } from '../../services/server.service'; -import { MockedServerService } from '../../services/server.service.spec'; +import { ControllerService } from '../../services/controller.service'; +import { MockedControllerService } from '../../services/controller.service.spec'; import { SettingsService } from '../../services/settings.service'; import { ToasterService } from '../../services/toaster.service'; import { MockedToasterService } from '../../services/toaster.service.spec'; @@ -89,55 +89,55 @@ export class MockedNodeService { return of(this.node); } - delete(server: Server, node: Node) { + delete(controller:Controller , node: Node) { return of(); } - startAll(server: Server, project: Project) { + startAll(controller:Controller , project: Project) { return of(); } - stopAll(server: Server, project: Project) { + stopAll(controller:Controller , project: Project) { return of(); } - suspendAll(server: Server, project: Project) { + suspendAll(controller:Controller , project: Project) { return of(); } - reloadAll(server: Server, project: Project) { + reloadAll(controller:Controller , project: Project) { return of(); } - start(server: Server, node: Node) { + start(controller:Controller , node: Node) { return of(); } - stop(server: Server, node: Node) { + stop(controller:Controller , node: Node) { return of(); } - suspend(server: Server, node: Node) { + suspend(controller:Controller , node: Node) { return of(); } - reload(server: Server, node: Node) { + reload(controller:Controller , node: Node) { return of(); } - duplicate(server: Server, node: Node) { + duplicate(controller:Controller , node: Node) { return of(node); } - getStartupConfiguration(server: Server, node: Node) { + getStartupConfiguration(controller:Controller , node: Node) { return of('sample config'); } - saveConfiguration(server: Server, node: Node, configuration: string) { + saveConfiguration(controller:Controller , node: Node, configuration: string) { return of(configuration); } - update(server: Server, node: Node) { + update(controller:Controller , node: Node) { return of(node); } } @@ -146,31 +146,31 @@ export class MockedDrawingService { public drawing = {} as Drawing; constructor() {} - add(_server: Server, _project_id: string, _x: number, _y: number, _svg: string) { + add(_controller:Controller , _project_id: string, _x: number, _y: number, _svg: string) { return of(this.drawing); } - duplicate(server: Server, project_id: string, drawing: Drawing) { + duplicate(controller:Controller , project_id: string, drawing: Drawing) { return of(drawing); } - updatePosition(_server: Server, _project: Project, _drawing: Drawing, _x: number, _y: number) { + updatePosition(_controller:Controller , _project: Project, _drawing: Drawing, _x: number, _y: number) { return of(this.drawing); } - updateSizeAndPosition(_server: Server, _drawing: Drawing, _x: number, _y: number, _svg: string) { + updateSizeAndPosition(_controller:Controller , _drawing: Drawing, _x: number, _y: number, _svg: string) { return of(this.drawing); } - update(_server: Server, _drawing: Drawing) { + update(_controller:Controller , _drawing: Drawing) { return of(this.drawing); } - delete(_server: Server, _drawing: Drawing) { + delete(_controller:Controller , _drawing: Drawing) { return of(this.drawing); } - updateText(_server: Server, _drawing: Drawing, _svg: string): Observable { + updateText(_controller:Controller , _drawing: Drawing, _svg: string): Observable { return of(this.drawing); } } @@ -178,15 +178,15 @@ export class MockedDrawingService { export class MockedLinkService { constructor() {} - getLink(server: Server, projectId: string, linkId: string) { + getLink(controller:Controller , projectId: string, linkId: string) { return of({}); } - deleteLink(_server: Server, link: Link) { + deleteLink(_controller:Controller , link: Link) { return of({}); } - updateLink(server: Server, link: Link) { + updateLink(controller:Controller , link: Link) { return of({}); } @@ -198,11 +198,11 @@ export class MockedLinkService { return of({}); } - startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) { + startCaptureOnLink(controller:Controller , link: Link, settings: CapturingSettings) { return of({}); } - getAvailableFilters(server: Server, link: Link) { + getAvailableFilters(controller:Controller , link: Link) { return of({}); } } @@ -258,12 +258,12 @@ xdescribe('ProjectMapComponent', () => { let nodeCreatedLabelStylesFixer; let mockedRouter = new MockedActivatedRoute(); - beforeEach(async(() => { + beforeEach(async() => { nodeCreatedLabelStylesFixer = { fix: (node) => node, }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [ MatBottomSheetModule, MatIconModule, @@ -276,7 +276,7 @@ xdescribe('ProjectMapComponent', () => { ], providers: [ { provide: ActivatedRoute }, - { provide: ServerService, useClass: MockedServerService }, + { provide: ControllerService, useClass: MockedControllerService }, { provide: ProjectService, useClass: MockedProjectService }, { provide: NodeService }, { provide: LinkService }, @@ -319,11 +319,15 @@ xdescribe('ProjectMapComponent', () => { { provide: MapSymbolsDataSource, useClass: MapSymbolsDataSource }, { provide: MapSettingsService, useClass: MapSettingsService }, { provide: NotificationService }, + { provide: MatDialogRef, useValue: {}}, + { provide: MAT_DIALOG_DATA, useValue: {}}, + + ], declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(ProjectMapComponent); diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 3f2ce336b..7705a19ad 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -1,11 +1,22 @@ -import { ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Injector, OnDestroy, OnInit, SimpleChange, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + ComponentRef, + OnDestroy, + OnInit, + ViewChild, + ViewContainerRef, + ViewEncapsulation, +} from '@angular/core'; import { MatBottomSheet } from '@angular/material/bottom-sheet'; import { MatDialog } from '@angular/material/dialog'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { ExportPortableProjectComponent } from '../../components/export-portable-project/export-portable-project.component'; +import { environment } from 'environments/environment'; import * as Mousetrap from 'mousetrap'; import { from, Observable, Subscription } from 'rxjs'; -import { map, mergeMap, takeUntil } from 'rxjs/operators'; +import { map, mergeMap } from 'rxjs/operators'; import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component'; import { MapDrawingToDrawingConverter } from '../../cartography/converters/map/map-drawing-to-drawing-converter'; import { MapLabelToLabelConverter } from '../../cartography/converters/map/map-label-to-label-converter'; @@ -51,7 +62,7 @@ import { ProgressService } from '../../common/progress/progress.service'; import { ProjectWebServiceHandler } from '../../handlers/project-web-service-handler'; import { Link } from '../../models/link'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { Symbol } from '../../models/symbol'; import { DrawingService } from '../../services/drawing.service'; import { MapScaleService } from '../../services/mapScale.service'; @@ -61,7 +72,7 @@ import { NodeConsoleService } from '../../services/nodeConsole.service'; import { NotificationService } from '../../services/notification.service'; import { ProjectService } from '../../services/project.service'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; -import { ServerService } from '../../services/server.service'; +import { ControllerService } from '../../services/controller.service'; import { Settings, SettingsService } from '../../services/settings.service'; import { SymbolService } from '../../services/symbol.service'; import { ThemeService } from '../../services/theme.service'; @@ -79,6 +90,7 @@ import { ContextMenuComponent } from './context-menu/context-menu.component'; import { NodeCreatedLabelStylesFixer } from './helpers/node-created-label-styles-fixer'; import { NewTemplateDialogComponent } from './new-template-dialog/new-template-dialog.component'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; +import { ProjectReadmeComponent } from './project-readme/project-readme.component'; @Component({ selector: 'app-project-map', @@ -92,7 +104,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public drawings: Drawing[] = []; public symbols: Symbol[] = []; public project: Project; - public server: Server; + public controller:Controller ; public projectws: WebSocket; public ws: WebSocket; public isProjectMapMenuVisible: boolean = false; @@ -105,6 +117,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public toolbarVisibility: boolean = true; public symbolScaling: boolean = true; private instance: ComponentRef; + // private instance: any tools = { selection: true, @@ -123,13 +136,13 @@ export class ProjectMapComponent implements OnInit, OnDestroy { @ViewChild(ContextMenuComponent) contextMenu: ContextMenuComponent; @ViewChild(D3MapComponent) mapChild: D3MapComponent; @ViewChild(ProjectMapMenuComponent) projectMapMenuComponent: ProjectMapMenuComponent; - @ViewChild('topologySummaryContainer', {read: ViewContainerRef}) topologySummaryContainer: ViewContainerRef; + @ViewChild('topologySummaryContainer', { read: ViewContainerRef }) topologySummaryContainer: ViewContainerRef; private projectMapSubscription: Subscription = new Subscription(); constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private projectService: ProjectService, private nodeService: NodeService, public drawingService: DrawingService, @@ -174,19 +187,23 @@ export class ProjectMapComponent implements OnInit, OnDestroy { private nodeConsoleService: NodeConsoleService, private symbolService: SymbolService, private cd: ChangeDetectorRef, - private cfr: ComponentFactoryResolver, - private injector: Injector + // private cfr: ComponentFactoryResolver, + // private injector: Injector, + private viewContainerRef: ViewContainerRef ) {} + // constructor(private viewContainerRef: ViewContainerRef) {} + // createMyComponent() {this.viewContainerRef.createComponent(MyComponent);} + ngOnInit() { this.getSettings(); this.progressService.activate(); - if (this.serverService.isServiceInitialized) { + if (this.controllerService.isServiceInitialized) { this.getData(); } else { this.projectMapSubscription.add( - this.serverService.serviceInitialized.subscribe((val) => { + this.controllerService.serviceInitialized.subscribe((val) => { if (val) this.getData(); }) ); @@ -219,17 +236,19 @@ export class ProjectMapComponent implements OnInit, OnDestroy { 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; + const { TopologySummaryComponent } = await import('../topology-summary/topology-summary.component'); + this.instance = this.viewContainerRef.createComponent(TopologySummaryComponent); + + // const componentFactory = this.cfr.resolveComponentFactory(TopologySummaryComponent); + // this.instance = this.topologySummaryContainer.createComponent(componentFactory, null, this.injector); + this.instance.instance.controller = this.controller; this.instance.instance.project = this.project; } else if (this.instance) { - if (this.instance.instance) { + if (this.instance.instance) { this.instance.instance.ngOnDestroy(); this.instance.destroy(); } - } + } } addSubscriptions() { @@ -248,15 +267,15 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.projectMapSubscription.add( this.nodesDataSource.changes.subscribe((nodes: Node[]) => { - if (!this.server) return; + if (!this.controller) return; nodes.forEach(async (node: Node) => { - node.symbol_url = `${this.server.protocol}//${this.server.host}:${this.server.port}/v2/symbols/${node.symbol}/raw`; + node.symbol_url = `${this.controller.protocol}//${this.controller.host}:${this.controller.port}/${environment.current_version}/symbols/${node.symbol}/raw`; - // if (node.width == 0 && node.height == 0) { - // let symbolDimensions = await this.symbolService.getDimensions(this.server, node.symbol).toPromise(); - // node.width = symbolDimensions.width; - // node.height = symbolDimensions.height; - // } + if (node.width == 0 && node.height == 0) { + let symbolDimensions = await this.symbolService.getDimensions(this.controller, node.symbol).toPromise(); + node.width = symbolDimensions.width; + node.height = symbolDimensions.height; + } }); this.nodes = nodes; @@ -267,6 +286,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.projectMapSubscription.add( this.linksDataSource.changes.subscribe((links: Link[]) => { + console.log('from project map component'); this.links = links; this.mapChangeDetectorRef.detectChanges(); }) @@ -309,15 +329,14 @@ export class ProjectMapComponent implements OnInit, OnDestroy { getData() { const routeSub = this.route.paramMap.subscribe((paramMap: ParamMap) => { - const server_id = parseInt(paramMap.get('server_id'), 10); + const controller_id = parseInt(paramMap.get('controller_id'), 10); - from(this.serverService.get(server_id)) + from(this.controllerService.get(controller_id)) .pipe( - mergeMap((server: Server) => { - if (!server) this.router.navigate(['/servers']); - - this.server = server; - return this.projectService.get(server, paramMap.get('project_id')).pipe( + mergeMap((controller:Controller ) => { + if (!controller) this.router.navigate(['/controllers']); + this.controller = controller; + return this.projectService.get(controller, paramMap.get('project_id')).pipe( map((project) => { return project; }) @@ -325,28 +344,28 @@ export class ProjectMapComponent implements OnInit, OnDestroy { }), mergeMap((project: Project) => { this.project = project; - if (!project) this.router.navigate(['/servers']); + if (!project) this.router.navigate(['/controllers']); - this.projectService.open(this.server, this.project.project_id); + this.projectService.open(this.controller, this.project.project_id); this.title.setTitle(this.project.name); - this.isInterfaceLabelVisible = this.mapSettingsService.showInterfaceLabels; this.toggleShowTopologySummary(this.mapSettingsService.isTopologySummaryVisible); - this.recentlyOpenedProjectService.setServerId(this.server.id.toString()); + this.recentlyOpenedProjectService.setcontrollerId(this.controller.id.toString()); if (this.project.status === 'opened') { return new Observable((observer) => { observer.next(this.project); }); } else { - return this.projectService.open(this.server, this.project.project_id); + return this.projectService.open(this.controller, this.project.project_id); } }) ) .subscribe( (project: Project) => { this.onProjectLoad(project); + if (this.mapSettingsService.openReadme) this.showReadme(); }, (error) => { this.progressService.setError(error); @@ -397,7 +416,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { Mousetrap.bind('ctrl+shift+s', (event: Event) => { event.preventDefault(); - this.router.navigate(['/server', this.server.id, 'preferences']); + this.router.navigate(['/controller', this.controller.id, 'preferences']); }); Mousetrap.bind('del', (event: Event) => { @@ -418,7 +437,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { .filter((item) => item instanceof MapNode) .forEach((item: MapNode) => { const node = this.mapNodeToNode.convert(item); - this.nodeService.delete(this.server, node).subscribe((data) => { + this.nodeService.delete(this.controller, node).subscribe((data) => { this.toasterService.success('Node has been deleted'); }); }); @@ -427,7 +446,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { .filter((item) => item instanceof MapDrawing) .forEach((item: MapDrawing) => { const drawing = this.mapDrawingToDrawing.convert(item); - this.drawingService.delete(this.server, drawing).subscribe((data) => { + this.drawingService.delete(this.controller, drawing).subscribe((data) => { this.toasterService.success('Drawing has been deleted'); }); }); @@ -440,15 +459,15 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.recentlyOpenedProjectService.setProjectId(this.project.project_id); const subscription = this.projectService - .nodes(this.server, project.project_id) + .nodes(this.controller, project.project_id) .pipe( mergeMap((nodes: Node[]) => { this.nodesDataSource.set(nodes); - return this.projectService.links(this.server, project.project_id); + return this.projectService.links(this.controller, project.project_id); }), mergeMap((links: Link[]) => { this.linksDataSource.set(links); - return this.projectService.drawings(this.server, project.project_id); + return this.projectService.drawings(this.controller, project.project_id); }) ) .subscribe((drawings: Drawing[]) => { @@ -463,7 +482,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } setUpProjectWS(project: Project) { - this.projectws = new WebSocket(this.notificationService.projectNotificationsPath(this.server, project.project_id)); + this.projectws = new WebSocket(this.notificationService.projectNotificationsPath(this.controller, project.project_id)); this.projectws.onmessage = (event: MessageEvent) => { this.projectWebServiceHandler.handleMessage(JSON.parse(event.data)); @@ -475,7 +494,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } setUpWS() { - this.ws = new WebSocket(this.notificationService.notificationsPath(this.server)); + this.ws = new WebSocket(this.notificationService.notificationsPath(this.controller)); } setUpMapCallbacks() { @@ -573,25 +592,25 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.progressService.activate(); this.nodeService .createFromTemplate( - this.server, + this.controller, this.project, nodeAddedEvent.template, nodeAddedEvent.x, nodeAddedEvent.y, - nodeAddedEvent.server + nodeAddedEvent.controller ) .subscribe( (node: Node) => { // if (nodeAddedEvent.name !== nodeAddedEvent.template.name) { // node.name = nodeAddedEvent.name; - // this.nodeService.updateNode(this.server, node).subscribe(()=>{}); + // this.nodeService.updateNode(this.controller, node).subscribe(()=>{}); // } - this.projectService.nodes(this.server, this.project.project_id).subscribe((nodes: Node[]) => { + this.projectService.nodes(this.controller, this.project.project_id).subscribe((nodes: Node[]) => { nodes .filter((node) => node.label.style === null) .forEach((node) => { const fixedNode = this.nodeCreatedLabelStylesFixer.fix(node); - this.nodeService.updateLabel(this.server, node, fixedNode.label).subscribe(); + this.nodeService.updateLabel(this.controller, node, fixedNode.label).subscribe(); }); this.nodesDataSource.set(nodes); @@ -906,7 +925,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; } saveProject() { @@ -916,7 +935,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; } @@ -927,7 +946,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; } @@ -939,22 +958,22 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; const subscription = dialogRef.componentInstance.onImportProject.subscribe((projectId: string) => { uuid = projectId; }); - dialogRef.afterClosed().subscribe(() => { + dialogRef.afterClosed().subscribe((isCancel:boolean) => { subscription.unsubscribe(); - if (uuid) { + if (uuid && !isCancel) { this.bottomSheet.open(NavigationDialogComponent); let bottomSheetRef = this.bottomSheet._openedBottomSheetRef; bottomSheetRef.instance.projectMessage = 'imported project'; const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { if (result) { - this.projectService.open(this.server, uuid).subscribe(() => { - this.router.navigate(['/server', this.server.id, 'project', uuid]); + this.projectService.open(this.controller, uuid).subscribe(() => { + this.router.navigate(['/controller', this.controller.id, 'project', uuid]); }); } }); @@ -975,10 +994,23 @@ export class ProjectMapComponent implements OnInit, OnDestroy { ) { this.toasterService.error('Project with running nodes cannot be exported.'); } else { - location.assign(this.projectService.getExportPath(this.server, this.project)); + // location.assign(this.projectService.getExportPath(this.controller, this.project)); + this.exportPortableProjectDialog(); } } + exportPortableProjectDialog() { + const dialogRef = this.dialog.open(ExportPortableProjectComponent, { + width: '700px', + maxHeight: '850px', + autoFocus: false, + disableClose: true, + data: {controllerDetails:this.controller,projectDetails:this.project}, + }); + + dialogRef.afterClosed().subscribe((isAddes: boolean) => {}); + } + public uploadImageFile(event) { this.readImageFile(event.target); } @@ -990,11 +1022,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy { fileReader.onloadend = () => { let image = fileReader.result; - let svg = `\n\n\n`; this.drawingService - .add(this.server, this.project.project_id, -(imageToUpload.width / 2), -(imageToUpload.height / 2), svg) + .add(this.controller, this.project.project_id, -(imageToUpload.width / 2), -(imageToUpload.height / 2), svg) .subscribe(() => {}); }; @@ -1010,8 +1042,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy { bottomSheetRef.instance.message = 'Do you want to close the project?'; const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { if (result) { - this.projectService.close(this.server, this.project.project_id).subscribe(() => { - this.router.navigate(['/server', this.server.id, 'projects']); + this.projectService.close(this.controller, this.project.project_id).subscribe(() => { + this.router.navigate(['/controller', this.controller.id, 'projects']); }); } }); @@ -1023,8 +1055,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy { bottomSheetRef.instance.message = 'Do you want to delete the project?'; const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { if (result) { - this.projectService.delete(this.server, this.project.project_id).subscribe(() => { - this.router.navigate(['/server', this.server.id, 'projects']); + this.projectService.delete(this.controller, this.project.project_id).subscribe(() => { + this.router.navigate(['/controller', this.controller.id, 'projects']); }); } }); @@ -1038,7 +1070,19 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; + instance.project = this.project; + } + + public showReadme() { + const dialogRef = this.dialog.open(ProjectReadmeComponent, { + width: '600px', + height: '650px', + autoFocus: false, + disableClose: true, + }); + let instance = dialogRef.componentInstance; + instance.controller = this.controller; instance.project = this.project; } diff --git a/src/app/components/project-map/project-readme/project-readme.component.html b/src/app/components/project-map/project-readme/project-readme.component.html new file mode 100644 index 000000000..263e05cf5 --- /dev/null +++ b/src/app/components/project-map/project-readme/project-readme.component.html @@ -0,0 +1,7 @@ +

Project README

+ +
+ +
+ +
\ No newline at end of file diff --git a/src/app/components/project-map/project-readme/project-readme.component.scss b/src/app/components/project-map/project-readme/project-readme.component.scss new file mode 100644 index 000000000..605a3657e --- /dev/null +++ b/src/app/components/project-map/project-readme/project-readme.component.scss @@ -0,0 +1,4 @@ +.textWrapper { + height: 500px!important; + overflow-y: scroll; +} diff --git a/src/app/components/project-map/project-readme/project-readme.component.ts b/src/app/components/project-map/project-readme/project-readme.component.ts new file mode 100644 index 000000000..646c9d25f --- /dev/null +++ b/src/app/components/project-map/project-readme/project-readme.component.ts @@ -0,0 +1,45 @@ +import { Component, AfterViewInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; +import{ Controller } from '../../../models/controller'; +import { Project } from '../../../models/project'; +import { ProjectService } from '../../../services/project.service'; +import * as marked from 'marked'; +import { ElementRef } from '@angular/core'; +import { Renderer2 } from '@angular/core'; +import { ViewChild } from '@angular/core'; + +@Component({ + selector: 'app-project-readme', + templateUrl: './project-readme.component.html', + styleUrls: ['./project-readme.component.scss'] +}) +export class ProjectReadmeComponent implements AfterViewInit { + controller:Controller ; + project: Project; + @ViewChild('text', {static: false}) text: ElementRef; + + constructor( + public dialogRef: MatDialogRef, + private projectService: ProjectService, + private elementRef: ElementRef, + private renderer: Renderer2 + ) {} + + ngAfterViewInit() { + let markdown = ``; + + this.projectService.getReadmeFile(this.controller, this.project.project_id).subscribe(file => { + if (file) { + markdown = file; + setTimeout(function(){ + const markdownHtml = marked(markdown); + document.getElementById('text').innerHTML = markdownHtml; + }, 1000); + } + }); + } + + onNoClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts b/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts index b7fed3660..f7cc74de5 100644 --- a/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts +++ b/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { DeviceDetectorService } from 'ngx-device-detector'; import { ElectronService } from 'ngx-electron'; @@ -11,19 +11,19 @@ import { ToasterService } from '../../../services/toaster.service'; styleUrls: ['./screenshot-dialog.component.scss'], }) export class ScreenshotDialogComponent implements OnInit { - nameForm: FormGroup; + nameForm: UntypedFormGroup; isPngAvailable: boolean; filetype: string = 'svg'; constructor( public dialogRef: MatDialogRef, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private electronService: ElectronService, private deviceService: DeviceDetectorService ) { this.nameForm = this.formBuilder.group({ - screenshotName: new FormControl(`screenshot-${Date.now()}`, [Validators.required]), + screenshotName: new UntypedFormControl(`screenshot-${Date.now()}`, [Validators.required]), }); this.isPngAvailable = this.electronService.isWindows || this.deviceService.getDeviceInfo().os === 'Windows'; } diff --git a/src/app/components/project-map/web-console/web-console.component.ts b/src/app/components/project-map/web-console/web-console.component.ts index c3a6a89a8..c3df43a3a 100644 --- a/src/app/components/project-map/web-console/web-console.component.ts +++ b/src/app/components/project-map/web-console/web-console.component.ts @@ -4,7 +4,7 @@ import { AttachAddon } from 'xterm-addon-attach'; import { FitAddon } from 'xterm-addon-fit'; import { Node } from '../../../cartography/models/node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { NodeConsoleService } from '../../../services/nodeConsole.service'; import { ThemeService } from '../../../services/theme.service'; @@ -15,7 +15,7 @@ import { ThemeService } from '../../../services/theme.service'; styleUrls: ['../../../../../node_modules/xterm/css/xterm.css', './web-console.component.scss'], }) export class WebConsoleComponent implements OnInit, AfterViewInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() node: Node; @@ -53,7 +53,7 @@ export class WebConsoleComponent implements OnInit, AfterViewInit { if (this.isLightThemeEnabled) this.term.setOption('theme', { background: 'white', foreground: 'black', cursor: 'black' }); - const socket = new WebSocket(this.consoleService.getUrl(this.server, this.node)); + const socket = new WebSocket(this.consoleService.getUrl(this.controller, this.node)); socket.onerror = (event) => { this.term.write('Connection lost'); diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts index 77cc7a32e..349730a17 100644 --- a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -8,7 +8,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; import { of } from 'rxjs/internal/observable/of'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ProjectService } from '../../../services/project.service'; import { ToasterService } from '../../../services/toaster.service'; import { AddBlankProjectDialogComponent } from './add-blank-project-dialog.component'; @@ -53,7 +53,7 @@ export class MockedProjectService { describe('AddBlankProjectDialogComponent', () => { let component: AddBlankProjectDialogComponent; let fixture: ComponentFixture; - let server: Server; + let controller:Controller ; let router = { navigate: jasmine.createSpy('navigate'), }; @@ -64,8 +64,8 @@ describe('AddBlankProjectDialogComponent', () => { close: jasmine.createSpy('close'), }; - beforeEach(async(() => { - TestBed.configureTestingModule({ + beforeEach(async() => { + await TestBed.configureTestingModule({ imports: [ MatDialogModule, MatFormFieldModule, @@ -85,15 +85,15 @@ describe('AddBlankProjectDialogComponent', () => { declarations: [AddBlankProjectDialogComponent], }).compileComponents(); - server = new Server(); - server.host = 'localhost'; - server.port = 80; - })); + controller = new Controller (); + controller.host = 'localhost'; + controller.port = 80; + }); beforeEach(() => { fixture = TestBed.createComponent(AddBlankProjectDialogComponent); component = fixture.componentInstance; - component.server = server; + component.controller = controller; fixture.detectChanges(); }); diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts index 7fd23fbcc..8683eff17 100644 --- a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts @@ -1,10 +1,10 @@ import { Component, EventEmitter, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { v4 as uuid } from 'uuid'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ProjectService } from '../../../services/project.service'; import { ToasterService } from '../../../services/toaster.service'; import { projectNameAsyncValidator } from '../../../validators/project-name-async-validator'; @@ -18,8 +18,8 @@ import { ProjectNameValidator } from '../models/projectNameValidator'; providers: [ProjectNameValidator], }) export class AddBlankProjectDialogComponent implements OnInit { - server: Server; - projectNameForm: FormGroup; + controller:Controller ; + projectNameForm: UntypedFormGroup; uuid: string; onAddProject = new EventEmitter(); @@ -29,16 +29,16 @@ export class AddBlankProjectDialogComponent implements OnInit { private dialog: MatDialog, private projectService: ProjectService, private toasterService: ToasterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private projectNameValidator: ProjectNameValidator ) {} ngOnInit() { this.projectNameForm = this.formBuilder.group({ - projectName: new FormControl( + projectName: new UntypedFormControl( null, [Validators.required, this.projectNameValidator.get], - [projectNameAsyncValidator(this.server, this.projectService)] + [projectNameAsyncValidator(this.controller, this.projectService)] ), }); } @@ -51,7 +51,7 @@ export class AddBlankProjectDialogComponent implements OnInit { if (this.projectNameForm.invalid) { return; } - this.projectService.list(this.server).subscribe((projects: Project[]) => { + this.projectService.list(this.controller).subscribe((projects: Project[]) => { const projectName = this.projectNameForm.controls['projectName'].value; let existingProject = projects.find((project) => project.name === projectName); @@ -70,11 +70,11 @@ export class AddBlankProjectDialogComponent implements OnInit { addProject(): void { this.uuid = uuid(); this.projectService - .add(this.server, this.projectNameForm.controls['projectName'].value, this.uuid) + .add(this.controller, this.projectNameForm.controls['projectName'].value, this.uuid) .subscribe((project: Project) => { this.dialogRef.close(); this.toasterService.success(`Project ${project.name} added`); - this.router.navigate(['/server', this.server.id, 'project', project.project_id]); + this.router.navigate(['/controller', this.controller.id, 'project', project.project_id]); }); } @@ -97,8 +97,8 @@ export class AddBlankProjectDialogComponent implements OnInit { dialogRef.afterClosed().subscribe((answer: boolean) => { if (answer) { - this.projectService.close(this.server, existingProject.project_id).subscribe(() => { - this.projectService.delete(this.server, existingProject.project_id).subscribe(() => { + this.projectService.close(this.controller, existingProject.project_id).subscribe(() => { + this.projectService.delete(this.controller, existingProject.project_id).subscribe(() => { this.addProject(); }); }); diff --git a/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.html b/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.html index 42d261a1d..22505eb65 100644 --- a/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.html +++ b/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.html @@ -1,4 +1,4 @@ -

Please choose name for exporting project

+

Save project as