diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c6921a33..7e06c0cb 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,14 +10,17 @@ 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 ${{ matrix.node }} + uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: ${{ matrix.node }} - uses: c-hive/gha-yarn-cache@v1 - name: Install JS dependencies run: yarn install diff --git a/e2e/controllers.e2e-spec.ts b/e2e/controllers.e2e-spec.ts new file mode 100644 index 00000000..ff046a80 --- /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 90250c7e..90b6e6dc 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 8986d97a..faa7a5ac 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 01df6aee..6c022045 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 45da0436..00000000 --- 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 8800de06..cd9196c5 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/local-server.js b/local-controller.js similarity index 54% rename from local-server.js rename to local-controller.js index a8948c30..aabf3eb0 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 513d0e93..70f228cd 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "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 es5 browser module main --first-only --create-ivy-entry-points --tsconfig \"./src/tsconfig.app.json\" && ngcc --properties es2015 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, @@ -53,6 +53,7 @@ "@angular/platform-browser-dynamic": "^13.3.5", "@angular/router": "^13.3.5", "@sentry/browser": "^6.14.1", + "@snyk/protect": "^1.972.0", "@types/jest": "^27.0.2", "@types/mocha": "^9.1.1", "@types/react": "^17.0.34", @@ -82,7 +83,6 @@ "rxjs": "^6.6.7", "rxjs-compat": "^6.6.7", "save-svg-as-png": "^1.4.17", - "snyk": "^1.915.0", "spark-md5": "^3.0.2", "svg-crowbar": "^0.7.0", "tree-kill": "^1.2.2", diff --git a/src/ReleaseNotes.txt b/src/ReleaseNotes.txt index 17a32fc2..87a2f5fc 100644 --- a/src/ReleaseNotes.txt +++ b/src/ReleaseNotes.txt @@ -67,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 73ffcf54..f87fd595 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,6 +1,6 @@ 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'; @@ -44,7 +44,7 @@ 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'; @@ -53,172 +53,257 @@ import { WebConsoleFullWindowComponent } from './components/web-console-full-win 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: 'server/:server_id/login', component: LoginComponent }, - { path: 'server/:server_id/loggeduser', component: LoggedUserComponent }, - {path : 'server/:server_id/image-manager', component: ImageManagerComponent}, + { 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, canActivate: [LoginGuard], - resolve: { server: ServerResolve }, + resolve: { 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, canActivate: [LoginGuard] }, - - { path: 'server/:server_ip/:server_port/project/:project_id', component: DirectLinkComponent, canActivate: [LoginGuard] }, { - path: 'server/:server_id/project/:project_id/snapshots', + path: 'controller/:controller_id/management/users/:user_id', + component: UserDetailComponent, + canActivate: [LoginGuard], + resolve: { + user: UserDetailResolver, + groups: UserGroupsResolver, + permissions: UserPermissionsResolver, + controller: ControllerResolve}, + }, + { path: 'installed-software', component: InstalledSoftwareComponent }, + { path: 'controller/:controller_id/systemstatus', component: SystemStatusComponent, canActivate: [LoginGuard] }, + + { path: 'controller/:controller_ip/:controller_port/project/:project_id', component: DirectLinkComponent, canActivate: [LoginGuard] }, + { + path: 'controller/:controller_id/project/:project_id/snapshots', component: ListOfSnapshotsComponent, canActivate: [LoginGuard], - resolve: { server: ServerResolve }, + resolve: { controller: ControllerResolve }, }, - { path: 'server/:server_id/preferences', component: PreferencesComponent, canActivate: [LoginGuard] }, - // { path: 'server/:server_id/preferences/general', component: GeneralPreferencesComponent }, - { path: 'server/:server_id/preferences/builtin', component: BuiltInPreferencesComponent, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent, canActivate: [LoginGuard] }, + //{ 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, canActivate: [LoginGuard] }, + // { 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, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent, canActivate: [LoginGuard] }, + // { 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, canActivate: [LoginGuard] }, + // { 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, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, + // { 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, canActivate: [LoginGuard] }, + { path: 'controller/:controller_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent, canActivate: [LoginGuard] }, + { 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, canActivate: [LoginGuard] }, - - { path: 'server/:server_id/preferences/iou/templates', component: IouTemplatesComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/iou/templates/:template_id/copy', component: CopyIouTemplateComponent, canActivate: [LoginGuard] }, - { path: 'server/:server_id/preferences/iou/addtemplate', component: AddIouTemplateComponent, canActivate: [LoginGuard] }, + { 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: 'user_management', - component: UserManagementComponent - }, { path: '**', component: PageNotFoundComponent, } - + ]; @NgModule({ @@ -231,4 +316,5 @@ const routes: Routes = [ ], exports: [RouterModule], }) -export class AppRoutingModule {} +export class AppRoutingModule { +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 45dae901..44adba00 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,3 +1,4 @@ +/* tslint:disable */ import { DragDropModule } from '@angular/cdk/drag-drop'; import { OverlayModule } from '@angular/cdk/overlay'; import { CdkTableModule } from '@angular/cdk/table'; @@ -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'; @@ -132,7 +133,7 @@ import { StartNodeActionComponent } from './components/project-map/context-menu/ import { StopCaptureActionComponent } from './components/project-map/context-menu/actions/stop-capture/stop-capture-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 {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'; @@ -187,9 +188,9 @@ import { ProjectNameValidator } from './components/projects/models/projectNameVa 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 { 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'; @@ -214,7 +215,7 @@ 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'; @@ -224,7 +225,7 @@ import { DockerService } from './services/docker.service'; import { DrawingService } from './services/drawing.service'; import { ExternalSoftwareDefinitionService } from './services/external-software-definition.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'; @@ -271,9 +272,50 @@ 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 { 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'; @@ -288,8 +330,8 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co LoggedUserComponent, ProjectMapComponent, LoginComponent, - ServersComponent, - AddServerDialogComponent, + ControllersComponent, + AddControllerDialogComponent, CreateSnapshotDialogComponent, SnapshotMenuItemComponent, ProjectsComponent, @@ -320,9 +362,9 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co SuspendLinkActionComponent, SettingsComponent, PreferencesComponent, - BundledServerFinderComponent, + BundledControllerFinderComponent, ProgressComponent, - ServerDiscoveryComponent, + ControllerDiscoveryComponent, NodeSelectInterfaceComponent, DrawLinkToolComponent, InstalledSoftwareComponent, @@ -471,6 +513,47 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co 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, @@ -491,6 +574,8 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co NgxElectronModule, FileUploadModule, MatSidenavModule, + MatFormFieldModule, + MatMenuModule, ResizableModule, DragAndDropModule, DragDropModule, @@ -498,21 +583,24 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co MATERIAL_IMPORTS, NgCircleProgressModule.forRoot(), OverlayModule, + MatSlideToggleModule, + MatCheckboxModule, + MatAutocompleteModule, ], providers: [ SettingsService, - { provide: ErrorHandler, useClass: ToasterErrorHandler }, - { provide: HTTP_INTERCEPTORS, useClass: HttpRequestsInterceptor, multi: true }, + {provide: ErrorHandler, useClass: ToasterErrorHandler}, + {provide: HTTP_INTERCEPTORS, useClass: HttpRequestsInterceptor, multi: true}, D3Service, VersionService, ProjectService, SymbolService, - ServerService, + ControllerService, TemplateService, NodeService, LinkService, DrawingService, - HttpServer, + HttpController, SnapshotService, ProgressDialogService, ToasterService, @@ -525,11 +613,11 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co SelectionManager, InRectangleHelper, DrawingsDataSource, - ServerErrorHandler, - ServerDatabase, + ControllerErrorHandler, + ControllerDatabase, ProjectNameValidator, ToolsService, - ServerSettingsService, + ControllerSettingsService, QemuService, VpcsService, TemplateMocksService, @@ -551,7 +639,7 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co IouService, IouConfigurationService, RecentlyOpenedProjectService, - ServerManagementService, + ControllerManagementService, MapScaleService, ConsoleService, DefaultConsoleService, @@ -566,7 +654,7 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co ThemeService, GoogleAnalyticsService, NodeConsoleService, - ServerResolve, + ControllerResolve, LoginGuard, ConsoleGuard, Title, @@ -576,7 +664,7 @@ import { ConfirmationDeleteAllProjectsComponent } from './components/projects/co UserService ], entryComponents: [ - AddServerDialogComponent, + AddControllerDialogComponent, CreateSnapshotDialogComponent, ProgressDialogComponent, TemplateListDialogComponent, 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 c066bb4a..ee3a26dd 100644 --- a/src/app/cartography/components/d3-map/d3-map.component.html +++ b/src/app/cartography/components/d3-map/d3-map.component.html @@ -44,6 +44,6 @@ - + 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 b79b3bbe..b0c0f950 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/text-editor/text-editor.component.ts b/src/app/cartography/components/text-editor/text-editor.component.ts index 70f690a5..ef7eff1a 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/models/map/map-link.ts b/src/app/cartography/models/map/map-link.ts index 339f165d..aebfac0d 100644 --- a/src/app/cartography/models/map/map-link.ts +++ b/src/app/cartography/models/map/map-link.ts @@ -16,13 +16,13 @@ export class MapLink implements Indexed { 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/common/uploading-processbar/uploading-processbar.component.ts b/src/app/common/uploading-processbar/uploading-processbar.component.ts index ef545a53..f4fcee46 100644 --- a/src/app/common/uploading-processbar/uploading-processbar.component.ts +++ b/src/app/common/uploading-processbar/uploading-processbar.component.ts @@ -22,7 +22,6 @@ export class UploadingProcessbarComponent implements OnInit { ngOnInit() { this.upload_file_type = this.data.upload_file_type - debugger this.subscription = this._US.currentCount.subscribe((count:number) => { this.uploadProgress = count; if (this.uploadProgress === 100 || this.uploadProgress == null ) { 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/bundled-server-finder/bundled-server-finder.component.scss b/src/app/components/bundled-controller-finder/bundled-controller-finder.component.scss similarity index 100% rename from src/app/components/bundled-server-finder/bundled-server-finder.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 00000000..9dec69cf --- /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 b8595a17..cfa332b0 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,8 +31,8 @@ export class BundledServerFinderComponent implements OnInit { port = 80; } - this.serverService.getLocalServer(this.document.location.hostname, port).then((server: Server) => { - this.router.navigate(['/server', server.id, 'projects']); + this.controllerService.getLocalController(this.document.location.hostname, port).then((controller:Controller ) => { + this.router.navigate(['/controller', controller.id, 'projects']); this.progressService.deactivate(); }); }, 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 48bd0075..00000000 --- a/src/app/components/bundled-server-finder/bundled-server-finder.component.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -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 { 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 service: ServerService; - let progressService: MockedProgressService = new MockedProgressService(); - let serverServiceMock: jasmine.SpyObj; - - - beforeEach(async () => { - router = { - navigate: jasmine.createSpy('navigate'), - }; - - - - serverServiceMock = jasmine.createSpyObj([ - "getLocalServer" - ]); - - - // serverService = new MockedServerService(); - // spyOn(serverService, 'getLocalServer').and.returnValue(Promise.resolve(server)); - - await TestBed.configureTestingModule({ - providers: [ - { provide: Router, useValue: router }, - { provide: ServerService, useValue: serverServiceMock }, - { 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(() => { - const server = new Server(); - server.id = 99; - serverServiceMock.getLocalServer.and.returnValue( - Promise.resolve(server) - ); - expect(component).toBeTruthy(); - tick(101) - fixture.detectChanges() - fixture.whenStable().then(() => { - expect(serverServiceMock.getLocalServer).toHaveBeenCalledWith('vps3.gns3.net',3000); - expect(router.navigate).toHaveBeenCalledWith(['/server', 99, 'projects']); - }) - service = TestBed.inject(ServerService); - })); -}); 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 73% 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 85916267..7c806c01 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 - + + + diff --git a/src/app/components/servers/add-server-dialog/add-server-dialog.component.scss b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.scss similarity index 100% rename from src/app/components/servers/add-server-dialog/add-server-dialog.component.scss rename to src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.scss diff --git a/src/app/components/servers/add-server-dialog/add-server-dialog.component.ts b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts similarity index 54% rename from src/app/components/servers/add-server-dialog/add-server-dialog.component.ts rename to src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts index 799fd950..9f59966a 100644 --- a/src/app/components/servers/add-server-dialog/add-server-dialog.component.ts +++ b/src/app/components/controllers/add-controller-dialog/add-controller-dialog.component.ts @@ -2,22 +2,22 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ElectronService } from 'ngx-electron'; -import { Server } from '../../../models/server'; -import { ServerService } from '../../../services/server.service'; +import { Controller } from '../../../models/controller'; +import { ControllerService } from '../../../services/controller.service'; import { ToasterService } from '../../../services/toaster.service'; @Component({ - selector: 'app-add-server-dialog', - templateUrl: 'add-server-dialog.component.html', + selector: 'app-add-controller-dialog', + templateUrl: 'add-controller-dialog.component.html', }) -export class AddServerDialogComponent implements OnInit { +export class AddControllerDialogComponent implements OnInit { protocols = [ { key: 'http:', name: 'HTTP' }, { key: 'https:', name: 'HTTPS' }, ]; locations = []; - serverForm = new FormGroup({ + controllerForm = new FormGroup({ name: new FormControl('', [Validators.required]), location: new FormControl(''), path: new FormControl(''), @@ -28,18 +28,18 @@ export class AddServerDialogComponent implements OnInit { }); constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, private electronService: ElectronService, - private serverService: ServerService, + private controllerService: ControllerService, private toasterService: ToasterService, @Inject(MAT_DIALOG_DATA) public data: any ) {} async getLocations() { - const localServers = await this.numberOfLocalServers(); + const localControllers = await this.numberOfLocalControllers(); let locations = []; - if (this.electronService.isElectronApp && localServers === 0) { + if (this.electronService.isElectronApp && localControllers === 0) { locations.push({ key: 'local', name: 'Local' }); } locations.push({ key: 'remote', name: 'Remote' }); @@ -47,17 +47,17 @@ export class AddServerDialogComponent implements OnInit { } async getDefaultLocation() { - const localServers = await this.numberOfLocalServers(); - if (this.electronService.isElectronApp && localServers === 0) { + const localControllers = await this.numberOfLocalControllers(); + if (this.electronService.isElectronApp && localControllers === 0) { return 'local'; } return 'remote'; } - async numberOfLocalServers() { - const servers = await this.serverService.findAll(); + async numberOfLocalControllers() { + const controllers = await this.controllerService.findAll(); - return servers.filter((server) => server.location === 'local').length; + return controllers.filter((controller) => controller.location === 'local').length; } getDefaultHost() { @@ -68,16 +68,16 @@ export class AddServerDialogComponent implements OnInit { return 3080; } - async getDefaultLocalServerPath() { + async getDefaultLocalControllerPath() { if (this.electronService.isElectronApp) { - return await this.electronService.remote.require('./local-server.js').getLocalServerPath(); + return await this.electronService.remote.require('./local-controller.js').getLocalControllerPath(); } return; } async getDefaultUbridgePath() { if (this.electronService.isElectronApp) { - return await this.electronService.remote.require('./local-server.js').getUbridgePath(); + return await this.electronService.remote.require('./local-controller.js').getUbridgePath(); } return; } @@ -85,15 +85,15 @@ export class AddServerDialogComponent implements OnInit { async ngOnInit() { this.locations = await this.getLocations(); - const defaultLocalServerPath = await this.getDefaultLocalServerPath(); + const defaultLocalControllerPath = await this.getDefaultLocalControllerPath(); const defaultUbridgePath = await this.getDefaultUbridgePath(); - this.serverForm.get('location').valueChanges.subscribe((location: string) => { - const pathControl = this.serverForm.get('path'); - const ubridgePathControl = this.serverForm.get('ubridge_path'); + 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(defaultLocalServerPath); + pathControl.setValue(defaultLocalControllerPath); pathControl.setValidators([Validators.required]); ubridgePathControl.setValue(defaultUbridgePath); @@ -114,29 +114,29 @@ export class AddServerDialogComponent implements OnInit { }); const defaultLocation = await this.getDefaultLocation(); - this.serverForm.get('location').setValue(defaultLocation); - this.serverForm.get('host').setValue(this.getDefaultHost()); - this.serverForm.get('port').setValue(this.getDefaultPort()); + this.controllerForm.get('location').setValue(defaultLocation); + this.controllerForm.get('host').setValue(this.getDefaultHost()); + this.controllerForm.get('port').setValue(this.getDefaultPort()); } onAddClick(): void { - if (!this.serverForm.valid) { + if (!this.controllerForm.valid) { return; } - const server: Server = Object.assign({}, this.serverForm.value); - this.serverService.checkServerVersion(server).subscribe( - (serverInfo) => { - if (serverInfo.version.split('.')[0] >= 3) { - this.dialogRef.close(server); - this.toasterService.success(`Server ${server.name} added.`); + 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(`Server version is not supported.`); + this.toasterService.error(`Controller version is not supported.`); } }, (error) => { - this.toasterService.error('Cannot connect to the server: ' + error); + this.toasterService.error('Cannot connect to the controller: ' + error); } ); } 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 00000000..37d5a8fc --- /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/servers/server-discovery/server-discovery.component.scss b/src/app/components/controllers/controller-discovery/controller-discovery.component.scss similarity index 100% rename from src/app/components/servers/server-discovery/server-discovery.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 00000000..ddd845b4 --- /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 00000000..4488a120 --- /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 f627d98b..67fdb29b 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 00000000..06283dbb --- /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/servers/servers.component.spec.ts b/src/app/components/controllers/controllers.component.spec.ts similarity index 67% rename from src/app/components/servers/servers.component.spec.ts rename to src/app/components/controllers/controllers.component.spec.ts index 60944f30..5efb12a3 100644 --- a/src/app/components/servers/servers.component.spec.ts +++ b/src/app/components/controllers/controllers.component.spec.ts @@ -4,11 +4,11 @@ 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 { ServerDatabase } from '../../services/server.database'; -import { ServerService } from '../../services/server.service'; -import { MockedServerService } from 'app/services/server.service.spec'; -import { ServersComponent } from './servers.component'; -import { ServerManagementService } from 'app/services/server-management.service'; +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'; @@ -18,16 +18,16 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ChangeDetectorRef } from '@angular/core'; import { MockedRouter } from 'app/common/progress/progress.component.spec'; -describe('ServersComponent', () => { - let component: ServersComponent; - let fixture: ComponentFixture; - let serverMockedService: MockedServerService +describe('ControllersComponent', () => { + let component: ControllersComponent; + let fixture: ComponentFixture; + let controllerMockedService: MockedControllerService let mockedActivatedRoute: MockedActivatedRoute let mockedRouter : MockedRouter beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ServersComponent], + declarations: [ControllersComponent], imports: [ MatDialogModule, RouterTestingModule, @@ -35,13 +35,13 @@ describe('ServersComponent', () => { ], providers: [ MatDialog, - ServerDatabase, - ServerManagementService, + ControllerDatabase, + ControllerManagementService, ElectronService, MatBottomSheet, ChildProcessService, ChangeDetectorRef, - { provide: ServerService, useValue: serverMockedService }, + { provide: ControllerService, useValue: controllerMockedService }, { provide: ActivatedRoute, useValue: mockedActivatedRoute }, { provide: Router, useValue: mockedRouter }, ] @@ -49,7 +49,7 @@ describe('ServersComponent', () => { }); beforeEach(() => { - fixture = TestBed.createComponent(ServersComponent); + fixture = TestBed.createComponent(ControllersComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/components/controllers/controllers.component.ts b/src/app/components/controllers/controllers.component.ts new file mode 100644 index 00000000..9bae27f1 --- /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 20eca142..a591ab36 100644 --- a/src/app/components/direct-link/direct-link.component.html +++ b/src/app/components/direct-link/direct-link.component.html @@ -1,23 +1,23 @@ -
+
-

Add new server

+

Add new controller

- + - You must enter a value + You must enter a value - + {{ location.name }} - + {{ protocol.name }} @@ -26,7 +26,7 @@
- +
diff --git a/src/app/components/direct-link/direct-link.component.ts b/src/app/components/direct-link/direct-link.component.ts index d8f6a3b9..f7cee146 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 { 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,9 +13,9 @@ 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; protocols = [ @@ -27,61 +27,61 @@ export class DirectLinkComponent implements OnInit { { key: 'remote', name: 'Remote' }, ]; - serverForm = new FormGroup({ + controllerForm = new FormGroup({ name: new FormControl('', [Validators.required]), location: new FormControl(''), protocol: new FormControl('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) { + 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; + 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.ts b/src/app/components/drawings-listeners/drawing-added/drawing-added.component.ts index f43c825f..fd0dfb33 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.ts b/src/app/components/drawings-listeners/drawing-dragged/drawing-dragged.component.ts index dc33b8fa..8954e944 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.ts b/src/app/components/drawings-listeners/drawing-resized/drawing-resized.component.ts index ef8fc203..1bfabf80 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.ts b/src/app/components/drawings-listeners/interface-label-dragged/interface-label-dragged.component.ts index 124674ea..0e82d866 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.ts b/src/app/components/drawings-listeners/link-created/link-created.component.ts index f115ca90..a5c027c6 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.ts b/src/app/components/drawings-listeners/node-dragged/node-dragged.component.ts index 7730d4b2..f651e94c 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.ts b/src/app/components/drawings-listeners/node-label-dragged/node-label-dragged.component.ts index 9a3bcc47..4f878032 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.ts b/src/app/components/drawings-listeners/text-added/text-added.component.ts index d14311ee..dfd05038 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.ts b/src/app/components/drawings-listeners/text-edited/text-edited.component.ts index d5d5eaec..32a138e5 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 index f232dba0..de20ebe8 100644 --- a/src/app/components/export-portable-project/export-portable-project.component.html +++ b/src/app/components/export-portable-project/export-portable-project.component.html @@ -21,7 +21,7 @@ {{ - compressionValue.name + compressionValue?.name }} 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 index b4f05311..3f348646 100644 --- a/src/app/components/export-portable-project/export-portable-project.component.ts +++ b/src/app/components/export-portable-project/export-portable-project.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ProjectService } from '../../services/project.service'; @Component({ @@ -16,7 +16,7 @@ export class ExportPortableProjectComponent implements OnInit { compression_methods: any = []; compression_level: any = []; compression_filter_value: any = []; - server: Server; + controller:Controller ; project: Project; index: number = 4; fileName: string; @@ -30,7 +30,7 @@ export class ExportPortableProjectComponent implements OnInit { ) {} async ngOnInit() { - this.server = this.data.serverDetails; + this.controller = this.data.controllerDetails; this.project = this.data.projectDetails; this.fileName = this.project.name + '.gns3project'; await this.formControls(); @@ -65,7 +65,7 @@ export class ExportPortableProjectComponent implements OnInit { 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.server, this.project.project_id, this.export_project_form.value)) + 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 00000000..dff5bcd0 --- /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 00000000..01cd6a62 --- /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/group-details/add-role-to-group/add-role-to-group.component.spec.ts b/src/app/components/group-details/add-role-to-group/add-role-to-group.component.spec.ts new file mode 100644 index 00000000..e69de29b 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 00000000..e6bf8350 --- /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 00000000..5c397473 --- /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 00000000..01cd6a62 --- /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/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.spec.ts b/src/app/components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b 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 00000000..4aac2293 --- /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 00000000..9bec7a3a --- /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 00000000..e8417eab --- /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/group-details/group-details.component.spec.ts b/src/app/components/group-details/group-details.component.spec.ts new file mode 100644 index 00000000..e69de29b 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 00000000..da341a1f --- /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 {FormControl, FormGroup} 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: FormGroup; + pageEvent: PageEvent | undefined; + searchMembers: string; + roles: Role[]; + + constructor(private route: ActivatedRoute, + private dialog: MatDialog, + private groupService: GroupService, + private toastService: ToasterService) { + + this.editGroupForm = new FormGroup({ + groupname: new FormControl(''), + }); + + 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/components/group-details/members-filter.pipe.spec.ts b/src/app/components/group-details/members-filter.pipe.spec.ts new file mode 100644 index 00000000..e69de29b 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 00000000..570a1456 --- /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 00000000..e69de29b 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 00000000..7bc69424 --- /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 00000000..e5811dad --- /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 00000000..8ebc2b8a --- /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 00000000..e69de29b 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 00000000..2e86af2e --- /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 00000000..ef70a89f --- /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 00000000..09b9cda8 --- /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 00000000..8bb21d51 --- /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 00000000..0ab6fbfb --- /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 00000000..e69de29b 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 00000000..48deaeda --- /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 {FormBuilder, FormControl, FormGroup, 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: FormGroup; + controller: Controller; + + users: User[]; + usersToAdd: Set = new Set([]); + filteredUsers: Observable + loading = false; + autocompleteControl = new FormControl(); + + + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { controller: Controller }, + private formBuilder: FormBuilder, + 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 FormControl( + 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 00000000..7ca6a54b --- /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 { FormControl } 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: FormControl) => { + 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 00000000..4ab22367 --- /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 00000000..1b0fdabd --- /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 00000000..e69de29b 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 00000000..b4af6d15 --- /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 00000000..5773ec49 --- /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 00000000..2b5547ab --- /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 00000000..e69de29b 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 00000000..6a459b5e --- /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/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 index d56eb2d5..0e319041 100644 --- 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 @@ -5,10 +5,10 @@ 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 { 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 { of } from 'rxjs'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { AddImageDialogComponent } from './add-image-dialog.component'; import { NO_ERRORS_SCHEMA } from '@angular/core'; @@ -17,7 +17,7 @@ import { MockedToasterService } from 'app/services/toaster.service.spec'; import { MatSnackBarModule } from '@angular/material/snack-bar'; export class MockedImageManagerService { - public getImages(server: Server) { + public getImages(controller:Controller ) { return of(); } @@ -26,8 +26,8 @@ export class MockedImageManagerService { describe('AddImageDialogComponent', () => { let component: AddImageDialogComponent; let fixture: ComponentFixture; - - let mockedServerService = new MockedServerService(); + + let mockedControllerService = new MockedControllerService(); let mockedImageManagerService = new MockedImageManagerService() let mockedToasterService = new MockedToasterService() @@ -42,7 +42,7 @@ describe('AddImageDialogComponent', () => { MatSnackBarModule ], providers: [ - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: ImageManagerService, useValue: mockedImageManagerService }, { provide: MAT_DIALOG_DATA, useValue: {} }, { provide: MatDialogRef, useValue: {} }, 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 index 60099892..f796ac48 100644 --- 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 @@ -3,7 +3,7 @@ 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 { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ImageManagerService } from '../../../services/image-manager.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -20,7 +20,7 @@ import { ToasterService } from '../../../services/toaster.service'; ], }) export class AddImageDialogComponent implements OnInit { - server: Server; + controller:Controller ; isInstallAppliance: boolean = false; install_appliance: boolean = false; selectFile: any = []; @@ -36,7 +36,7 @@ export class AddImageDialogComponent implements OnInit { ) {} public ngOnInit() { - this.server = this.data; + this.controller =this.data; this.uploaderImage = new FileUploader({}); this.uploaderImage.onAfterAddingFile = (file) => { @@ -98,11 +98,11 @@ export class AddImageDialogComponent implements OnInit { let file = event; let fileReader: FileReader = new FileReader(); fileReader.onloadend = () => { - const url = this.imageService.getImagePath(this.server, this.install_appliance, fileName); + 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.server.authToken }]; + (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.spec.ts b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.spec.ts index 43aea89c..eeb3a8d9 100644 --- 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 @@ -10,14 +10,14 @@ import { MockedToasterService } from 'app/services/toaster.service.spec'; import { Server } from 'http'; import { of } from 'rxjs'; import { ImageManagerService } from '../../../services/image-manager.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 { ImageManagerComponent } from '../image-manager.component'; import { DeleteAllImageFilesDialogComponent } from './deleteallfiles-dialog.component'; export class MockedImageManagerService { - public deleteALLFile(server: Server, image_path) { + public deleteALLFile(controller:Server , image_path) { return of(); } } @@ -25,7 +25,7 @@ export class MockedImageManagerService { describe('DeleteAllImageFilesDialogComponent', () => { let component: DeleteAllImageFilesDialogComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedImageManagerService = new MockedImageManagerService() let mockedToasterService = new MockedToasterService() @@ -39,7 +39,7 @@ export class MockedImageManagerService { MatDialogModule, ], providers: [ - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: ImageManagerService, useValue: mockedImageManagerService }, { provide: MAT_DIALOG_DATA, useValue: {} }, { provide: MatDialogRef, useValue: {} }, 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 index 6fd33fca..99077c72 100644 --- a/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.ts +++ b/src/app/components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component.ts @@ -35,7 +35,7 @@ export class DeleteAllImageFilesDialogComponent implements OnInit { deleteFile() { const calls = []; this.deleteData.deleteFilesPaths.forEach(pathElement => { - calls.push(this.imageService.deleteFile(this.deleteData.server, pathElement.filename).pipe(catchError(error => of(error)))) + 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) diff --git a/src/app/components/image-manager/image-database-file.ts b/src/app/components/image-manager/image-database-file.ts index 09415d7b..d328229a 100644 --- a/src/app/components/image-manager/image-database-file.ts +++ b/src/app/components/image-manager/image-database-file.ts @@ -20,14 +20,14 @@ export class imageDatabase { } export class imageDataSource extends DataSource { - constructor(private serverDatabase: imageDatabase) { + constructor(private controllerDatabase: imageDatabase) { super(); } connect(): Observable { - return merge(this.serverDatabase.dataChange).pipe( + return merge(this.controllerDatabase.dataChange).pipe( map(() => { - return this.serverDatabase.data; + return this.controllerDatabase.data; }) ); } diff --git a/src/app/components/image-manager/image-manager.component.html b/src/app/components/image-manager/image-manager.component.html index 5dde19d3..1dfc888c 100644 --- a/src/app/components/image-manager/image-manager.component.html +++ b/src/app/components/image-manager/image-manager.component.html @@ -15,7 +15,7 @@
- +
diff --git a/src/app/components/image-manager/image-manager.component.spec.ts b/src/app/components/image-manager/image-manager.component.spec.ts index bdba7db1..4d1d9e86 100644 --- a/src/app/components/image-manager/image-manager.component.spec.ts +++ b/src/app/components/image-manager/image-manager.component.spec.ts @@ -6,10 +6,10 @@ 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 { ServerService } from 'app/services/server.service'; -import { MockedServerService } from 'app/services/server.service.spec'; +import { ControllerService } from 'app/services/controller.service'; +import { MockedControllerService } from 'app/services/controller.service.spec'; import { of } from 'rxjs'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ImageManagerComponent } from './image-manager.component'; import { Image } from '../../models/images'; @@ -23,11 +23,11 @@ import { ToasterService } from 'app/services/toaster.service'; import { MockedToasterService } from 'app/services/toaster.service.spec'; export class MockedImageManagerService { - public getImages(server: Server) { + public getImages(controller:Controller ) { return of(); } - public deleteFile(server: Server, image_path) { + public deleteFile(controller:Controller , image_path) { return of(); } @@ -37,7 +37,7 @@ describe('ImageManagerComponent', () => { let component: ImageManagerComponent; let fixture: ComponentFixture; - let mockedServerService = new MockedServerService(); + let mockedControllerService = new MockedControllerService(); let mockedImageManagerService = new MockedImageManagerService() let mockedProgressService = new MockedProgressService() let mockedVersionService = new MockedVersionService() @@ -59,7 +59,7 @@ describe('ImageManagerComponent', () => { provide: ActivatedRoute, useValue: activatedRoute, }, - { provide: ServerService, useValue: mockedServerService }, + { provide: ControllerService, useValue: mockedControllerService }, { provide: ImageManagerService, useValue: mockedImageManagerService }, { provide: ProgressService, useValue: mockedProgressService }, { provide: VersionService, useValue: mockedVersionService }, diff --git a/src/app/components/image-manager/image-manager.component.ts b/src/app/components/image-manager/image-manager.component.ts index 5a3c09eb..7ccd3d31 100644 --- a/src/app/components/image-manager/image-manager.component.ts +++ b/src/app/components/image-manager/image-manager.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { ServerService } from '../../services/server.service'; +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 { Server } from '../../models/server'; +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'; @@ -19,7 +19,7 @@ import { imageDataSource, imageDatabase } from "./image-database-file"; styleUrls: ['./image-manager.component.scss'] }) export class ImageManagerComponent implements OnInit { - server: Server; + controller:Controller ; public version: string; dataSource: imageDataSource; imageDatabase = new imageDatabase(); @@ -32,7 +32,7 @@ export class ImageManagerComponent implements OnInit { private imageService: ImageManagerService, private progressService: ProgressService, private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private versionService: VersionService, private dialog: MatDialog, private toasterService: ToasterService, @@ -40,13 +40,13 @@ export class ImageManagerComponent implements OnInit { ) { } ngOnInit(): void { - let server_id = parseInt(this.route.snapshot.paramMap.get('server_id')); - this.serverService.get(server_id).then((server: Server) => { - this.server = server; - if (server.authToken) { + 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.server).subscribe((version: Version) => { + // this.versionService.get(this.controller).subscribe((version: Version) => { // this.version = version.version; // }); }); @@ -54,7 +54,7 @@ export class ImageManagerComponent implements OnInit { } getImages() { - this.imageService.getImages(this.server).subscribe( + this.imageService.getImages(this.controller).subscribe( (images: Image[]) => { this.imageDatabase.addImages(images) }, @@ -66,7 +66,7 @@ export class ImageManagerComponent implements OnInit { } deleteFile(path) { - this.imageService.deleteFile(this.server, path).subscribe( + this.imageService.deleteFile(this.controller, path).subscribe( (res) => { this.getImages() this.unChecked() @@ -106,7 +106,7 @@ export class ImageManagerComponent implements OnInit { maxHeight: '550px', autoFocus: false, disableClose: true, - data: this.server + data: this.controller }); dialogRef.afterClosed().subscribe((isAddes: boolean) => { @@ -128,7 +128,7 @@ export class ImageManagerComponent implements OnInit { autoFocus: false, disableClose: true, data: { - server: this.server, + controller: this.controller, deleteFilesPaths: this.selection.selected } }); diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts index 3d9ab2bf..0e431d42 100644 --- a/src/app/components/login/login.component.ts +++ b/src/app/components/login/login.component.ts @@ -2,11 +2,11 @@ import { Component, DoCheck, OnInit, ViewEncapsulation } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { AuthResponse } from '../../models/authResponse'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { Version } from '../../models/version'; import { LoginService } from '../../services/login.service'; -import { ServerDatabase } from '../../services/server.database'; -import { ServerService } from '../../services/server.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'; @@ -18,7 +18,7 @@ import { VersionService } from '../../services/version.service'; encapsulation: ViewEncapsulation.None, }) export class LoginComponent implements OnInit, DoCheck { - private server: Server; + private controller:Controller ; public version: string; public isLightThemeEnabled: boolean = false; public loginError: boolean = false; @@ -33,8 +33,8 @@ export class LoginComponent implements OnInit, DoCheck { constructor( private loginService: LoginService, - private serverService: ServerService, - private serverDatabase: ServerDatabase, + private controllerService: ControllerService, + private controllerDatabase: ControllerDatabase, private route: ActivatedRoute, private router: Router, private toasterService: ToasterService, @@ -43,16 +43,16 @@ export class LoginComponent implements OnInit, DoCheck { ) {} async ngOnInit() { - const server_id = this.route.snapshot.paramMap.get('server_id'); + const controller_id = this.route.snapshot.paramMap.get('controller_id'); this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/'; - 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; - if (server.authToken) { - this.router.navigate(['/server', this.server.id, 'projects']); + if (controller.authToken) { + this.router.navigate(['/controller', this.controller.id, 'projects']); } - this.versionService.get(this.server).subscribe((version: Version) => { + this.versionService.get(this.controller).subscribe((version: Version) => { this.version = version.version; }); }); @@ -78,17 +78,17 @@ export class LoginComponent implements OnInit, DoCheck { let username = this.loginForm.get('username').value; let password = this.loginForm.get('password').value; - this.loginService.login(this.server, username, password).subscribe( + this.loginService.login(this.controller, username, password).subscribe( async (response: AuthResponse) => { - let server = this.server; - server.authToken = response.access_token; - server.username = username; - server.password = password; - server.tokenExpired = false; - await this.serverService.update(server); + 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(['/server', this.server.id, 'projects']); + this.router.navigate(['/controller', this.controller.id, 'projects']); } else { this.router.navigateByUrl(this.returnUrl); } diff --git a/src/app/components/management/management.component.html b/src/app/components/management/management.component.html new file mode 100644 index 00000000..24f7e2ed --- /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 00000000..e69de29b 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 00000000..e69de29b diff --git a/src/app/components/management/management.component.ts b/src/app/components/management/management.component.ts new file mode 100644 index 00000000..8bb190e6 --- /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 d4b33a2d..22598e3c 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 00000000..cac08740 --- /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 00000000..fe2111dc --- /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 00000000..e69de29b 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 00000000..9cf23619 --- /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 00000000..4a743b78 --- /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 00000000..aed624da --- /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 00000000..bea06b2b --- /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 00000000..5e6436fd --- /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 00000000..9c1f35fb --- /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 00000000..5e84941b --- /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 00000000..11fe2675 --- /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 00000000..fb5e7afa --- /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 00000000..9fcf0be0 --- /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 00000000..b4297c5e --- /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 00000000..2720f01e --- /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 00000000..e69de29b 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 00000000..c7441b3f --- /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 00000000..1983ebb8 --- /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 00000000..51a31794 --- /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 00000000..e69de29b 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 00000000..cc1a149c --- /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 00000000..d72a8516 --- /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 00000000..c7abac9f --- /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 00000000..4e4a10cc --- /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 00000000..cc1b1778 --- /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 00000000..087ced03 --- /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 00000000..b9a2c373 --- /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 00000000..b2a58b23 --- /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 00000000..8d6e5890 --- /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 00000000..e69de29b 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 00000000..df2fa857 --- /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 00000000..41802817 --- /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 00000000..71b4e75f --- /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 00000000..e0ae94c1 --- /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 00000000..e7b3efa5 --- /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 00000000..e69de29b 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 00000000..b62f708d --- /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 00000000..a5ce9fe0 --- /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 04a5bb21..c914afb5 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 @@ -2,7 +2,7 @@

Built-in preferences

-
@@ -10,13 +10,13 @@
- + Ethernet hubs - + Ethernet switches - Cloud nodes + Cloud nodes
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 40f09c82..99b9e8da 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 @@ -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 7749d54f..145b3a3e 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 9f45ad6b..d9347027 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 @@ -7,7 +7,7 @@
- Run the cloud node locally 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 de51f38b..f33ac462 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 @@ -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,7 +33,7 @@ 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(); @@ -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 }, @@ -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 47146b34..aa668c47 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 @@ -3,11 +3,11 @@ import { FormBuilder, FormControl, FormGroup, 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,14 +17,14 @@ 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; isLocalComputerChosen: boolean = true; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private builtInTemplatesService: BuiltInTemplatesService, private router: Router, private toasterService: ToasterService, @@ -38,20 +38,20 @@ export class CloudNodesAddTemplateComponent implements OnInit { } 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; }); } - setServerType(serverType: string) { - if (serverType === 'local') { + 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() { @@ -66,7 +66,7 @@ export class CloudNodesAddTemplateComponent implements OnInit { cloudTemplate.name = this.formGroup.get('templateName').value; 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 9aad82bb..ce992fe5 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 @@ -181,7 +181,7 @@
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 cb888516..d5e2a062 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,7 +36,7 @@ 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(); @@ -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 }, 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 e6877a49..72fd1529 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 22cfab26..88aa3267 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 @@ -3,18 +3,18 @@

Cloud nodes templates

- +
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 15e6024b..1db2a26a 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.ts b/src/app/components/preferences/common/symbols/symbols.component.ts index 965cc9a2..0e82e324 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { environment } from 'environments/environment'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { Symbol } from '../../../../models/symbol'; import { SymbolService } from '../../../../services/symbol.service'; @@ -10,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(); @@ -42,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; }); @@ -61,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(); }); }; @@ -78,6 +78,6 @@ export class SymbolsComponent implements OnInit { } getImageSourceForTemplate(symbol: string) { - return `${this.server.protocol}//${this.server.host}:${this.server.port}/${environment.current_version}/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 07694078..c59350f5 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,10 +7,10 @@
- + - - Run this Docker container on a remote compute --> + Run this Docker container locally 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 5282e649..8950502d 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 @@ -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,7 +41,7 @@ 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(); @@ -67,12 +67,12 @@ 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 }, @@ -106,7 +106,7 @@ xdescribe('AddDockerTemplateComponent', () => { await fixture.whenStable().then(() => { let selectedLabel = fixture.nativeElement.querySelector('[aria-selected="true"]'); - expect(selectedLabel.textContent).toMatch('Server type'); + expect(selectedLabel.textContent).toMatch('Controller type'); }); }); 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 e496b159..ae559896 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 @@ -4,12 +4,12 @@ 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; @@ -34,7 +34,7 @@ export class AddDockerTemplateComponent implements OnInit { constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private router: Router, @@ -59,9 +59,9 @@ export class AddDockerTemplateComponent implements OnInit { } 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(); @@ -69,14 +69,14 @@ export class AddDockerTemplateComponent implements OnInit { this.dockerTemplate = dockerTemplate; }); - this.dockerService.getImages(server).subscribe((images) => { + this.dockerService.getImages(controller).subscribe((images) => { this.dockerImages = images; }); }); } - setServerType(serverType: string) { - if (serverType === 'local') { + setControllerType(controllerType: string) { + if (controllerType === 'local') { this.isLocalComputerChosen = true; } } @@ -86,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() { @@ -107,7 +107,7 @@ export class AddDockerTemplateComponent implements OnInit { this.dockerTemplate.adapters = +this.networkAdaptersForm.get('adapters').value; 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.ts b/src/app/components/preferences/docker/copy-docker-template/copy-docker-template.component.ts index 6e8c13c8..bda62773 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 @@ -2,10 +2,10 @@ 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{ 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,14 +14,14 @@ 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; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private router: Router, @@ -33,12 +33,12 @@ export class CopyDockerTemplateComponent 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.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 e36dccf0..757da7b2 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 @@ -143,7 +143,7 @@
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 4e0c4e4a..8d134acd 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 @@ -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,7 +35,7 @@ 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(); @@ -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 }, 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 3c57a696..052d7636 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 @@ -2,11 +2,11 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, 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; @@ -30,7 +30,7 @@ export class DockerTemplateDetailsComponent implements OnInit { constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private dockerService: DockerService, private toasterService: ToasterService, private configurationService: DockerConfigurationService, @@ -46,13 +46,13 @@ export class DockerTemplateDetailsComponent 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.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 72227b93..3ffbf3a5 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 @@ -3,18 +3,18 @@

Docker container templates

- +
- +
\ No newline at end of file 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 fd92b262..e604a4f9 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 @@ -3,7 +3,7 @@ import { FormControl } 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 = {}; 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 ddd1f4fe..ac9c4e66 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 @@ -6,7 +6,7 @@ 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'; @@ -62,7 +62,7 @@ describe('ContextConsoleMenuComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ContextConsoleMenuComponent); 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-console-menu/context-console-menu.component.ts b/src/app/components/project-map/context-console-menu/context-console-menu.component.ts index d90d940d..ce0ca024 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 bab33ea4..3970d900 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 771a2ac9..1e8acebe 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.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts index 95fc56f7..9b0ade8e 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 cef0973e..b39db155 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 cb568fce..b354f71e 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 e85d8f65..81f5932f 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'; @@ -21,7 +21,7 @@ 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, @@ -62,7 +62,7 @@ export class ConfigActionComponent { } 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 f822d129..b2db1704 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,6 +1,6 @@ import { Component, Input } 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,13 +9,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) {} 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(); }); @@ -30,7 +30,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; } if ( 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 81064dcd..fa6505b5 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 @@ -2,10 +2,10 @@ 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() => { 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 }, @@ -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 f826a59a..dad3c488 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.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts index 693cb21a..af9ace23 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.ts b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts index a2cf43a3..acf9f2e8 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 e172382a..2f2686e7 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.ts b/src/app/components/project-map/context-menu/actions/edit-link-style-action/edit-link-style-action.component.ts index de5ea91b..66a0f2fc 100644 --- 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 @@ -2,7 +2,7 @@ import { Component, Input, OnChanges } 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 { LinkStyleEditorDialogComponent } from '../../../drawings-editors/link-style-editor/link-style-editor.component'; @Component({ @@ -11,7 +11,7 @@ import { LinkStyleEditorDialogComponent } from '../../../drawings-editors/link-s templateUrl: './edit-link-style-action.component.html', }) export class EditLinkStyleActionComponent implements OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Input() link: Link; @@ -26,7 +26,7 @@ export class EditLinkStyleActionComponent implements OnChanges { 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/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 37e89e4e..ed57c983 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 ee847219..2f738947 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 84e8396a..2d506ba4 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 73cf9ddd..d09da927 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 523cdb4c..e29d63a9 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 524e74ba..fb02fe16 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.ts b/src/app/components/project-map/context-menu/actions/isolate-node-action/isolate-node-action.component.ts index 5f6808e1..a4133000 100644 --- 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 @@ -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'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -9,7 +9,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './isolate-node-action.component.html', }) export class IsolateNodeActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private nodeService: NodeService, private toasterService: ToasterService) {} @@ -17,7 +17,7 @@ export class IsolateNodeActionComponent implements OnInit { ngOnInit() {} isolate() { - this.nodeService.isolate(this.server, this.node).subscribe( + 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 3c227633..195b7e30 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,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: './lock-action.component.html', }) export class LockActionComponent implements OnChanges { - @Input() server: Server; + @Input() controller:Controller ; @Input() nodes: Node[]; @Input() drawings: Drawing[]; command: string; @@ -37,14 +37,14 @@ export class LockActionComponent implements OnChanges { lock() { 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) => { drawing.locked = !drawing.locked; - this.drawingService.update(this.server, drawing).subscribe((drawing) => { + this.drawingService.update(this.controller, drawing).subscribe((drawing) => { this.drawingsDataSource.update(drawing); }); }); 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 306cf028..ed63ec20 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.ts b/src/app/components/project-map/context-menu/actions/move-layer-up-action/move-layer-up-action.component.ts index b8901271..625dc110 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 fc032a09..0416dd9c 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 953aafd2..bf10db5a 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 90fcf687..2754620c 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.ts b/src/app/components/project-map/context-menu/actions/reset-link/reset-link-action.component.ts index 085e8896..6048d9bb 100644 --- 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 @@ -1,21 +1,19 @@ import { Component, Input } from '@angular/core'; -import { Server } from '../../../../../models/server'; +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' + templateUrl: './reset-link-action.component.html', }) export class ResetLinkActionComponent { - @Input() server: Server; + @Input() controller: Controller; @Input() link: Link; - constructor( - private linkService: LinkService - ) {} + constructor(private linkService: LinkService) {} resetLink() { - this.linkService.resetLink(this.server, this.link).subscribe(() => {}); + 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 356c933a..908a4685 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 3a10e6cf..1509cda7 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 ca7e8a71..442d267e 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 6a1a13e7..e68461cf 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 54576831..2a689131 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,7 +1,7 @@ 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 { HttpServer } from 'app/services/http-server.service'; +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'; @@ -19,7 +19,7 @@ describe('StartNodeActionComponent', () => { imports:[MatProgressSpinnerModule ], providers: [ { provide: NodeService, useValue: mockedNodeService }, - { provide: HttpServer, useValue: {} }, + { provide: HttpController, useValue: {} }, { provide: ToasterService, useValue: mockedToasterService }, ], }).compileComponents(); 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 11c886ad..fd735d00 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 4b875d20..e9bf2c53 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 a363d8fc..79e322a4 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,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockedNodeService } from 'app/components/project-map/project-map.component.spec'; -import { HttpServer } from 'app/services/http-server.service'; +import { HttpController } from 'app/services/http-controller.service'; import { NodeService } from 'app/services/node.service'; import { StopNodeActionComponent } from './stop-node-action.component'; 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 8e1e24b6..56106f09 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 e0049122..50690cc8 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 375959e7..9ba7109d 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.ts b/src/app/components/project-map/context-menu/actions/unisolate-node-action/unisolate-node-action.component.ts index a8226e4c..2793077f 100644 --- 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 @@ -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'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -9,7 +9,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; templateUrl: './unisolate-node-action.component.html', }) export class UnisolateNodeActionComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() node: Node; constructor(private nodeService: NodeService, private toasterService: ToasterService) {} @@ -17,7 +17,7 @@ export class UnisolateNodeActionComponent implements OnInit { ngOnInit() {} unisolate() { - this.nodeService.unisolate(this.server, this.node).subscribe( + 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 85f6fec9..5d51d8b2 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,59 +1,59 @@
- - - - - - + + + + + + - - + + @@ -64,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]" @@ -74,7 +74,7 @@ > @@ -83,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]" > @@ -126,7 +126,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [link]="links[0]" > @@ -149,7 +149,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [project]="project" [link]="links[0]" > @@ -161,7 +161,7 @@ links.length === 1 && linkNodes.length === 0 " - [server]="server" + [controller]="controller" [link]="links[0]" > @@ -204,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 6e41f76b..55673af6 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 @@ -6,7 +6,7 @@ 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'; @@ -35,7 +35,7 @@ describe('ContextMenuComponent', () => { 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 6f3d7053..b70c771d 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/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 index fca658ea..735a1872 100644 --- 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 @@ -3,7 +3,7 @@ import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms' import { MatDialogRef } 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 { ToasterService } from '../../../../services/toaster.service'; import { NonNegativeValidator } from '../../../../validators/non-negative-validator'; import { LinkService } from '../../../../services/link.service'; @@ -17,7 +17,7 @@ import { LinkToMapLinkConverter } from '../../../../cartography/converters/map/l styleUrls: ['./link-style-editor.component.scss'], }) export class LinkStyleEditorDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; link: Link; formGroup: FormGroup; @@ -68,7 +68,7 @@ export class LinkStyleEditorDialogComponent implements OnInit { let type = this.borderTypes.indexOf(this.formGroup.get('type').value); this.link.link_style.type = type; - this.linkService.updateLinkStyle(this.server, this.link).subscribe((link) => { + this.linkService.updateLinkStyle(this.controller, this.link).subscribe((link) => { this.linksDataSource.update(link); this.linksEventSource.edited.next(this.linkToMapLink.convert(link)); location.reload() 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 e216ab40..583fe236 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 @@ -9,7 +9,7 @@ import { EllipseElement } from '../../../../cartography/models/drawings/ellipse- import { LineElement } from '../../../../cartography/models/drawings/line-element'; import { RectElement } from '../../../../cartography/models/drawings/rect-element'; import { Project } from '../../../../models/project'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { DrawingService } from '../../../../services/drawing.service'; import { ToasterService } from '../../../../services/toaster.service'; import { NonNegativeValidator } from '../../../../validators/non-negative-validator'; @@ -21,7 +21,7 @@ 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; @@ -88,8 +88,8 @@ export class StyleEditorDialogComponent 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(); }); } 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 8440f5b0..421df7bb 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 @@ -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; @@ -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 95f04332..e5ae84b8 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 @@ -2,7 +2,7 @@ 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'; @@ -20,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; @@ -49,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()); } }; } @@ -130,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') { @@ -141,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); @@ -149,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}/${environment.current_version}/${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 296132b6..56a10ad3 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 c73a091d..b27924f7 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 a7c01728..ff2dc462 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,7 +39,7 @@ 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() => { await TestBed.configureTestingModule({ @@ -49,7 +49,7 @@ describe('LogConsoleComponent', () => { { provide: NodeService, useValue: mockedNodeService }, { provide: NodesDataSource, useValue: mockedNodesDataSource }, { provide: LogEventsDataSource, useClass: LogEventsDataSource }, - { provide: HttpServer, useValue: httpServer }, + { provide: HttpController, useValue: httpController }, NodeConsoleService, ToasterService, MapSettingsService @@ -66,7 +66,7 @@ describe('LogConsoleComponent', () => { 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 1c5209d7..f8e35030 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 @@ -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[] = []; @@ -70,7 +70,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { 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') { @@ -297,28 +297,28 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { printNode(node: Node): string { return ( - `command_line: ${node.command_line}, - compute_id: ${node.compute_id}, - console: ${node.console}, - console_host: ${node.console_host}, - console_type: ${node.console_type}, - first_port_name: ${node.first_port_name}, - height: ${node.height}, - label: ${node.label.text}, - name: ${node.name}, - node_directory: ${node.node_directory}, - node_id: ${node.node_id}, - node_type: ${node.node_type}, - port_name_format: ${node.port_name_format}, + `command_line: ${node.command_line}, + compute_id: ${node.compute_id}, + console: ${node.console}, + console_host: ${node.console_host}, + console_type: ${node.console_type}, + first_port_name: ${node.first_port_name}, + height: ${node.height}, + label: ${node.label.text}, + name: ${node.name}, + node_directory: ${node.node_directory}, + node_id: ${node.node_id}, + node_type: ${node.node_type}, + port_name_format: ${node.port_name_format}, port_segment_size: ${node.port_segment_size}, ` + this.printPorts(node.ports) + - `project_id: ${node.project_id}, - status: ${node.status}, - symbol: ${node.symbol}, - symbol_url: ${node.symbol_url}, - width: ${node.width}, - x: ${node.x}, - y: ${node.y}, + `project_id: ${node.project_id}, + status: ${node.status}, + symbol: ${node.symbol}, + symbol_url: ${node.symbol_url}, + width: ${node.width}, + x: ${node.x}, + y: ${node.y}, z: ${node.z}` ); } @@ -328,31 +328,31 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { ports.forEach((port) => { response = response + - `adapter_number: ${port.adapter_number}, - link_type: ${port.link_type}, - name: ${port.name}, - port_number: ${port.port_number}, + `adapter_number: ${port.adapter_number}, + link_type: ${port.link_type}, + name: ${port.name}, + port_number: ${port.port_number}, short_name: ${port.short_name}, `; }); return response; } printLink(link: Link): string { - return `capture_file_name: ${link.capture_file_name}, - capture_file_path: ${link.capture_file_path}, - capturing: ${link.capturing}, - link_id: ${link.link_id}, - link_type: ${link.link_type}, - project_id: ${link.project_id}, + return `capture_file_name: ${link.capture_file_name}, + capture_file_path: ${link.capture_file_path}, + capturing: ${link.capturing}, + link_id: ${link.link_id}, + link_type: ${link.link_type}, + project_id: ${link.project_id}, suspend: ${link.suspend}, `; } printDrawing(drawing: Drawing): string { - return `drawing_id: ${drawing.drawing_id}, - project_id: ${drawing.project_id}, - rotation: ${drawing.rotation}, - x: ${drawing.x}, - y: ${drawing.y}, + return `drawing_id: ${drawing.drawing_id}, + project_id: ${drawing.project_id}, + rotation: ${drawing.rotation}, + x: ${drawing.x}, + y: ${drawing.y}, z: ${drawing.z}`; } } 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 9039fe0e..848ab358 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 @@ Install new appliance from the GNS serverInstall new appliance from the GNS controller
Import an appliance file { + this.applianceService.getAppliances(this.controller).subscribe((appliances) => { this.appliances = appliances; this.appliances.forEach((appliance) => { if (appliance.docker) appliance.emulator = 'Docker'; @@ -116,33 +116,33 @@ export class NewTemplateDialogComponent implements OnInit { this.dataSource.paginator = this.paginator; }); - this.templateService.list(this.server).subscribe((templates) => { + this.templateService.list(this.controller).subscribe((templates) => { this.templates = templates; }); - this.computeService.getComputes(this.server).subscribe((computes) => { + this.computeService.getComputes(this.controller).subscribe((computes) => { computes.forEach((compute) => { if (compute.capabilities.platform === 'linux') this.isLinuxPlatform = true; }); }); - this.qemuService.getBinaries(this.server).subscribe((binaries) => { + this.qemuService.getBinaries(this.controller).subscribe((binaries) => { this.qemuBinaries = binaries; }); - this.qemuService.getImages(this.server).subscribe((qemuImages) => { + this.qemuService.getImages(this.controller).subscribe((qemuImages) => { this.qemuImages = qemuImages; }); - this.iosService.getImages(this.server).subscribe((iosImages) => { + this.iosService.getImages(this.controller).subscribe((iosImages) => { this.iosImages = iosImages; }); - this.iouService.getImages(this.server).subscribe((iouImages) => { + this.iouService.getImages(this.controller).subscribe((iouImages) => { this.iouImages = iouImages; }); - this.applianceService.getAppliances(this.server).subscribe((appliances) => { + this.applianceService.getAppliances(this.controller).subscribe((appliances) => { this.appliances = appliances; this.appliances.forEach((appliance) => { if (appliance.docker) appliance.emulator = 'Docker'; @@ -218,7 +218,7 @@ export class NewTemplateDialogComponent implements OnInit { updateAppliances() { this.progressService.activate(); - this.applianceService.updateAppliances(this.server).subscribe( + this.applianceService.updateAppliances(this.controller).subscribe( (appliances) => { this.appliances = appliances; this.progressService.deactivate(); @@ -232,15 +232,15 @@ export class NewTemplateDialogComponent implements OnInit { } refreshImages() { - this.qemuService.getImages(this.server).subscribe((qemuImages) => { + this.qemuService.getImages(this.controller).subscribe((qemuImages) => { this.qemuImages = qemuImages; }); - this.iosService.getImages(this.server).subscribe((iosImages) => { + this.iosService.getImages(this.controller).subscribe((iosImages) => { this.iosImages = iosImages; }); - this.iouService.getImages(this.server).subscribe((iouImages) => { + this.iouService.getImages(this.controller).subscribe((iouImages) => { this.iouImages = iouImages; }); @@ -249,7 +249,7 @@ export class NewTemplateDialogComponent implements OnInit { getAppliance(url: string) { let str = url.split(`/${environment.current_version}`); let appliancePath = str[str.length - 1]; - this.applianceService.getAppliance(this.server, appliancePath).subscribe((appliance: Appliance) => { + this.applianceService.getAppliance(this.controller, appliancePath).subscribe((appliance: Appliance) => { this.applianceToInstall = appliance; setTimeout(() => { this.stepper.next(); @@ -272,11 +272,11 @@ export class NewTemplateDialogComponent implements OnInit { if (appliance.iou) emulator = 'iou'; if (appliance.qemu) emulator = 'qemu'; - const url = this.applianceService.getUploadPath(this.server, emulator, fileName); + const url = this.applianceService.getUploadPath(this.controller, emulator, fileName); 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; ((itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.server.authToken }]) + 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); }; @@ -302,13 +302,13 @@ export class NewTemplateDialogComponent implements OnInit { setAction(action: string) { this.action = action; if (action === 'install') { - this.actionTitle = 'Install appliance from server'; + this.actionTitle = 'Install appliance from controller'; } else if (action === 'import') { this.actionTitle = 'Import an appliance file'; } } - setServerType(serverType: string) { + setControllerType(controllerType: string) { this.isLocalComputerChosen = true; } @@ -385,7 +385,7 @@ export class NewTemplateDialogComponent implements OnInit { autoFocus: false, disableClose: true, }); - dialogRef.componentInstance.confirmationMessage = `This is not the correct file. + dialogRef.componentInstance.confirmationMessage = `This is not the correct file. The MD5 sum is ${output} and should be ${imageToInstall.md5sum}. Do you want to accept it at your own risks?`; dialogRef.afterClosed().subscribe((answer: boolean) => { if (answer) { @@ -414,11 +414,11 @@ export class NewTemplateDialogComponent implements OnInit { if (this.applianceToInstall.dynamips) emulator = 'dynamips'; if (this.applianceToInstall.iou) emulator = 'iou'; - const url = this.applianceService.getUploadPath(this.server, emulator, fileName); + const url = this.applianceService.getUploadPath(this.controller, emulator, fileName); this.uploaderImage.queue.forEach((elem) => (elem.url = url)); const itemToUpload = this.uploaderImage.queue[0]; - if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.server.authToken }]) + 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); }; @@ -534,11 +534,11 @@ export class NewTemplateDialogComponent implements OnInit { name: this.applianceToInstall.name, }, }); - dialogRef.componentInstance.server = this.server; + dialogRef.componentInstance.controller = this.controller; dialogRef.afterClosed().subscribe((answer: string) => { if (answer) { iouTemplate.name = answer; - this.iouService.addTemplate(this.server, iouTemplate).subscribe((template) => { + this.iouService.addTemplate(this.controller, iouTemplate).subscribe((template) => { this.templateService.newTemplateCreated.next(template); this.toasterService.success('Template added'); this.dialogRef.close(); @@ -582,12 +582,12 @@ export class NewTemplateDialogComponent implements OnInit { name: this.applianceToInstall.name, }, }); - dialogRef.componentInstance.server = this.server; + dialogRef.componentInstance.controller = this.controller; dialogRef.afterClosed().subscribe((answer: string) => { if (answer) { iosTemplate.name = answer; - this.iosService.addTemplate(this.server, iosTemplate).subscribe((template) => { + this.iosService.addTemplate(this.controller, iosTemplate).subscribe((template) => { this.templateService.newTemplateCreated.next((template as any) as Template); this.toasterService.success('Template added'); this.dialogRef.close(); @@ -620,12 +620,12 @@ export class NewTemplateDialogComponent implements OnInit { name: this.applianceToInstall.name, }, }); - dialogRef.componentInstance.server = this.server; + dialogRef.componentInstance.controller = this.controller; dialogRef.afterClosed().subscribe((answer: string) => { if (answer) { dockerTemplate.name = answer; - this.dockerService.addTemplate(this.server, dockerTemplate).subscribe((template) => { + this.dockerService.addTemplate(this.controller, dockerTemplate).subscribe((template) => { this.templateService.newTemplateCreated.next((template as any) as Template); this.toasterService.success('Template added'); this.dialogRef.close(); @@ -679,12 +679,12 @@ export class NewTemplateDialogComponent implements OnInit { name: this.applianceToInstall.name, }, }); - dialogRef.componentInstance.server = this.server; + dialogRef.componentInstance.controller = this.controller; dialogRef.afterClosed().subscribe((answer: string) => { if (answer) { qemuTemplate.name = answer; - this.qemuService.addTemplate(this.server, qemuTemplate).subscribe((template) => { + this.qemuService.addTemplate(this.controller, qemuTemplate).subscribe((template) => { this.templateService.newTemplateCreated.next((template as any) as Template); this.toasterService.success('Template added'); this.dialogRef.close(); diff --git a/src/app/components/project-map/new-template-dialog/template-name-dialog/template-name-dialog.component.ts b/src/app/components/project-map/new-template-dialog/template-name-dialog/template-name-dialog.component.ts index 6d100673..d99cf647 100644 --- a/src/app/components/project-map/new-template-dialog/template-name-dialog/template-name-dialog.component.ts +++ b/src/app/components/project-map/new-template-dialog/template-name-dialog/template-name-dialog.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { Router } from '@angular/router'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { Template } from '../../../../models/template'; import { TemplateService } from '../../../../services/template.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -16,7 +16,7 @@ import { ProjectNameValidator } from '../../../projects/models/projectNameValida providers: [ProjectNameValidator], }) export class TemplateNameDialogComponent implements OnInit { - server: Server; + controller:Controller ; templateNameForm: FormGroup; constructor( @@ -36,7 +36,7 @@ export class TemplateNameDialogComponent implements OnInit { templateName: new FormControl( name, [Validators.required, this.templateNameValidator.get], - [templateNameAsyncValidator(this.server, this.templateService)] + [templateNameAsyncValidator(this.controller, this.templateService)] ), }); @@ -54,7 +54,7 @@ export class TemplateNameDialogComponent implements OnInit { this.toasterService.error('Please enter correct name for new template'); return; } - this.templateService.list(this.server).subscribe((templates: Template[]) => { + this.templateService.list(this.controller).subscribe((templates: Template[]) => { const templateName = this.templateNameForm.controls['templateName'].value; let existingProject = templates.find((t) => t.name === templateName); diff --git a/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts b/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts index b3b47295..82205692 100644 --- a/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts +++ b/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts @@ -7,7 +7,7 @@ import { MatTabsModule } from '@angular/material/tabs'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of } from 'rxjs/internal/observable/of'; 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 { MockedNodeService } from '../../project-map.component.spec'; @@ -16,7 +16,7 @@ import { ConfigEditorDialogComponent } from './config-editor.component'; describe('ConfigEditorDialogComponent', () => { let component: ConfigEditorDialogComponent; let fixture: ComponentFixture; - let server: Server; + let controller:Controller ; let node: Node; let toaster = { success: jasmine.createSpy('success'), @@ -45,9 +45,9 @@ describe('ConfigEditorDialogComponent', () => { declarations: [ConfigEditorDialogComponent], }).compileComponents(); - server = new Server(); - server.host = 'localhost'; - server.port = 80; + controller = new Controller (); + controller.host = 'localhost'; + controller.port = 80; node = new Node(); node.name = 'sample name'; @@ -56,7 +56,7 @@ describe('ConfigEditorDialogComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ConfigEditorDialogComponent); component = fixture.componentInstance; - component.server = server; + component.controller = controller; component.node = node; fixture.detectChanges(); }); diff --git a/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts b/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts index e624d8ef..b069c724 100644 --- a/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts +++ b/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { MatDialogRef } 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 { NodeService } from '../../../../services/node.service'; import { ToasterService } from '../../../../services/toaster.service'; @@ -12,7 +12,7 @@ import { ToasterService } from '../../../../services/toaster.service'; styleUrls: ['./config-editor.component.scss'], }) export class ConfigEditorDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; node: Node; @@ -26,21 +26,21 @@ export class ConfigEditorDialogComponent implements OnInit { ) {} ngOnInit() { - this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => { + this.nodeService.getStartupConfiguration(this.controller, this.node).subscribe((config: any) => { this.config = config; }); if (this.node.node_type === 'iou' || this.node.node_type === 'dynamips') { - this.nodeService.getPrivateConfiguration(this.server, this.node).subscribe((privateConfig: any) => { + this.nodeService.getPrivateConfiguration(this.controller, this.node).subscribe((privateConfig: any) => { this.privateConfig = privateConfig; }); } } onSaveClick() { - this.nodeService.saveConfiguration(this.server, this.node, this.config).subscribe((response) => { + this.nodeService.saveConfiguration(this.controller, this.node, this.config).subscribe((response) => { if (this.node.node_type === 'iou' || this.node.node_type === 'dynamips') { - this.nodeService.savePrivateConfiguration(this.server, this.node, this.privateConfig).subscribe((resp) => { + this.nodeService.savePrivateConfiguration(this.controller, this.node, this.privateConfig).subscribe((resp) => { this.dialogRef.close(); this.toasterService.success(`Configuration for node ${this.node.name} saved.`); }); diff --git a/src/app/components/project-map/node-editors/configurator/atm_switch/configurator-atm-switch.component.ts b/src/app/components/project-map/node-editors/configurator/atm_switch/configurator-atm-switch.component.ts index cd98de04..faebe160 100644 --- a/src/app/components/project-map/node-editors/configurator/atm_switch/configurator-atm-switch.component.ts +++ b/src/app/components/project-map/node-editors/configurator/atm_switch/configurator-atm-switch.component.ts @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,7 +12,7 @@ import { ToasterService } from '../../../../../services/toaster.service'; styleUrls: ['../configurator.component.scss', '../../../../preferences/preferences.component.scss'], }) export class ConfiguratorDialogAtmSwitchComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; nameForm: FormGroup; @@ -58,7 +58,7 @@ export class ConfiguratorDialogAtmSwitchComponent implements OnInit { } 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; @@ -146,7 +146,7 @@ export class ConfiguratorDialogAtmSwitchComponent 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/cloud/configurator-cloud.component.ts b/src/app/components/project-map/node-editors/configurator/cloud/configurator-cloud.component.ts index fd34de07..215fcc1f 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 @@ -5,7 +5,7 @@ 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,7 +16,7 @@ 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; @@ -51,7 +51,7 @@ export class ConfiguratorDialogCloudComponent implements OnInit { } 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 +98,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.ts b/src/app/components/project-map/node-editors/configurator/docker/configurator-docker.component.ts index d962c5d8..f2cc016b 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 @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, 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'; @@ -16,7 +16,7 @@ import { NonNegativeValidator } from '../../../../../validators/non-negative-val styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogDockerComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; generalSettingsForm: FormGroup; @@ -50,7 +50,7 @@ export class ConfiguratorDialogDockerComponent implements OnInit { } 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,20 +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() { 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/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 2441fc82..1bf8e408 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 @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder } 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[] = []; @@ -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 2f298783..0984400a 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 296182c0..b8dddd80 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 @@ -3,7 +3,7 @@ import { FormBuilder, FormControl, FormGroup, 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,7 +15,7 @@ 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; @@ -34,7 +34,7 @@ export class ConfiguratorDialogEthernetSwitchComponent implements OnInit { } 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 4b4e2e47..4876c3ce 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; @@ -13,7 +13,7 @@ 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; @@ -34,7 +34,7 @@ export class ConfiguratorDialogEthernetHubComponent implements OnInit { } 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 9090e1f5..6765e585 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { IosConfigurationService } from '../../../../../services/ios-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: ['../configurator.component.scss'], }) export class ConfiguratorDialogIosComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; generalSettingsForm: FormGroup; @@ -38,7 +38,7 @@ export class ConfiguratorDialogIosComponent implements OnInit { } 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 b336bcc6..f56450e5 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { IouConfigurationService } from '../../../../../services/iou-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: ['../configurator.component.scss'], }) export class ConfiguratorDialogIouComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; generalSettingsForm: FormGroup; @@ -38,7 +38,7 @@ export class ConfiguratorDialogIouComponent implements OnInit { } 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 c42da4d1..0cc3f868 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,7 +12,7 @@ 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; @@ -29,7 +29,7 @@ export class ConfiguratorDialogNatComponent implements OnInit { } 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.ts b/src/app/components/project-map/node-editors/configurator/qemu/configurator-qemu.component.ts index e03d477c..246804aa 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 @@ -5,7 +5,7 @@ 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,7 +18,7 @@ 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; @@ -57,17 +57,17 @@ export class ConfiguratorDialogQemuComponent implements OnInit { } 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.qemuService.getBinaries(this.controller).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; }); } @@ -75,7 +75,7 @@ export class ConfiguratorDialogQemuComponent implements OnInit { 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 +116,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 5287f987..031f8e5c 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 @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, 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']; @@ -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 ada8e204..84aea58b 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; @@ -12,7 +12,7 @@ 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; @@ -48,7 +48,7 @@ export class ConfiguratorDialogSwitchComponent implements OnInit { } 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/virtualbox/configurator-virtualbox.component.ts b/src/app/components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component.ts index 629f2aed..b84592be 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 @@ -3,7 +3,7 @@ import { FormBuilder, FormControl, FormGroup, 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,7 +14,7 @@ import { VirtualBoxConfigurationService } from '../../../../../services/virtual- styleUrls: ['../configurator.component.scss'], }) export class ConfiguratorDialogVirtualBoxComponent implements OnInit { - server: Server; + controller:Controller ; node: Node; name: string; generalSettingsForm: FormGroup; @@ -40,7 +40,7 @@ export class ConfiguratorDialogVirtualBoxComponent implements OnInit { } 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 854021cd..a48809e0 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 @@ -3,7 +3,7 @@ import { FormBuilder, FormControl, FormGroup, 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,7 +14,7 @@ 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; @@ -39,7 +39,7 @@ export class ConfiguratorDialogVmwareComponent implements OnInit { } 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 920e94c9..0ed4ffcf 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 @@ -2,7 +2,7 @@ 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{ Controller } from '../../../../../models/controller'; import { NodeService } from '../../../../../services/node.service'; import { ToasterService } from '../../../../../services/toaster.service'; import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; @@ -13,7 +13,7 @@ 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; @@ -32,7 +32,7 @@ export class ConfiguratorDialogVpcsComponent implements OnInit { } 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/nodes-menu/nodes-menu.component.spec.ts b/src/app/components/project-map/nodes-menu/nodes-menu.component.spec.ts index 81378b9c..bf5e1952 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 @@ -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'; @@ -29,7 +29,7 @@ xdescribe('NodesMenuComponent', () => { { provide: NodeService, useValue: mockedNodeService }, { provide: ToasterService, useValue: mockedToasterService }, { provide: NodesDataSource, useValue: mockedNodesDataSource }, - { provide: ServerService }, + { provide: ControllerService }, { provide: SettingsService }, { provide: ElectronService }, ], 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 f19dda53..111b4f3a 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 @@ -3,11 +3,11 @@ 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 { NodeConsoleService } from '../../../services/nodeConsole.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 { NodesMenuConfirmationDialogComponent } from './nodes-menu-confirmation-dialog/nodes-menu-confirmation-dialog.component'; @@ -20,14 +20,14 @@ import { NodesMenuConfirmationDialogComponent } from './nodes-menu-confirmation- }) 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, @@ -50,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); } @@ -64,31 +64,31 @@ 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.server, this.project).subscribe(() => { + this.nodeService.resetAllNodes(this.controller, this.project).subscribe(() => { this.toasterService.success('Successfully reset all console connections'); }); } 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 3b22edef..ed86dc8d 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.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts index bd568c10..5ad30d26 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 @@ -6,7 +6,7 @@ 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,7 +18,7 @@ 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 = []; @@ -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-menu.component.html b/src/app/components/project-map/project-map-menu/project-map-menu.component.html index 81f0fc0f..30495dc1 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 @@ -98,7 +98,7 @@ photo_camera '); splittedSvg[i] = splittedElement[1].substring(2); i += 2; @@ -175,7 +175,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(() => {}); }; diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 7ece4e04..cda57e4a 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 @@
- - - @@ -103,7 +103,7 @@ settings Go to settings - @@ -111,7 +111,7 @@ control_point New template - +
- +
- +
- - - - - - - - + + + + + + + +
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 686e0f34..f60cb0c3 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -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({}); } } @@ -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 }, diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 13e607d9..46ecec90 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -62,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'; @@ -72,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'; @@ -104,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; @@ -142,7 +142,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private projectService: ProjectService, private nodeService: NodeService, public drawingService: DrawingService, @@ -199,11 +199,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy { 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(); }) ); @@ -241,7 +241,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { // const componentFactory = this.cfr.resolveComponentFactory(TopologySummaryComponent); // this.instance = this.topologySummaryContainer.createComponent(componentFactory, null, this.injector); - this.instance.instance.server = this.server; + this.instance.instance.controller = this.controller; this.instance.instance.project = this.project; } else if (this.instance) { if (this.instance.instance) { @@ -267,12 +267,12 @@ 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}/${environment.current_version}/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(); + let symbolDimensions = await this.symbolService.getDimensions(this.controller, node.symbol).toPromise(); node.width = symbolDimensions.width; node.height = symbolDimensions.height; } @@ -329,14 +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; }) @@ -344,21 +344,21 @@ 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); } }) ) @@ -416,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) => { @@ -437,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'); }); }); @@ -446,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'); }); }); @@ -459,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[]) => { @@ -482,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)); @@ -494,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() { @@ -592,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); @@ -925,7 +925,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; } saveProject() { @@ -935,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; } @@ -946,12 +946,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = this.project; } importProject() { - debugger let uuid: string = ''; const dialogRef = this.dialog.open(ImportProjectDialogComponent, { width: '400px', @@ -959,7 +958,7 @@ 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; }); @@ -973,8 +972,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy { 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]); }); } }); @@ -995,7 +994,7 @@ 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(); } } @@ -1006,7 +1005,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { maxHeight: '850px', autoFocus: false, disableClose: true, - data: {serverDetails:this.server,projectDetails:this.project}, + data: {controllerDetails:this.controller,projectDetails:this.project}, }); dialogRef.afterClosed().subscribe((isAddes: boolean) => {}); @@ -1023,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(() => {}); }; @@ -1043,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']); }); } }); @@ -1056,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']); }); } }); @@ -1071,7 +1070,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; } @@ -1083,7 +1082,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; } 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 index ba3bdb5e..646c9d25 100644 --- a/src/app/components/project-map/project-readme/project-readme.component.ts +++ b/src/app/components/project-map/project-readme/project-readme.component.ts @@ -1,6 +1,6 @@ import { Component, AfterViewInit } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { Project } from '../../../models/project'; import { ProjectService } from '../../../services/project.service'; import * as marked from 'marked'; @@ -14,7 +14,7 @@ import { ViewChild } from '@angular/core'; styleUrls: ['./project-readme.component.scss'] }) export class ProjectReadmeComponent implements AfterViewInit { - server: Server; + controller:Controller ; project: Project; @ViewChild('text', {static: false}) text: ElementRef; @@ -28,7 +28,7 @@ export class ProjectReadmeComponent implements AfterViewInit { ngAfterViewInit() { let markdown = ``; - this.projectService.getReadmeFile(this.server, this.project.project_id).subscribe(file => { + this.projectService.getReadmeFile(this.controller, this.project.project_id).subscribe(file => { if (file) { markdown = file; setTimeout(function(){ 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 c3a6a89a..c3df43a3 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 d3f66f49..349730a1 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 @@ -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'), }; @@ -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 7fd23fbc..c53079ff 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 @@ -4,7 +4,7 @@ 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,7 +18,7 @@ import { ProjectNameValidator } from '../models/projectNameValidator'; providers: [ProjectNameValidator], }) export class AddBlankProjectDialogComponent implements OnInit { - server: Server; + controller:Controller ; projectNameForm: FormGroup; uuid: string; onAddProject = new EventEmitter(); @@ -38,7 +38,7 @@ export class AddBlankProjectDialogComponent implements OnInit { projectName: new FormControl( 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.ts b/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.ts index 3a0c6b9b..7d7e408b 100644 --- a/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.ts +++ b/src/app/components/projects/choose-name-dialog/choose-name-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ProjectService } from '../../../services/project.service'; @Component({ @@ -10,7 +10,7 @@ import { ProjectService } from '../../../services/project.service'; styleUrls: ['./choose-name-dialog.component.scss'], }) export class ChooseNameDialogComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; name: string; @@ -25,7 +25,7 @@ export class ChooseNameDialogComponent implements OnInit { } onSaveClick() { - this.projectService.duplicate(this.server, this.project.project_id, this.name).subscribe(() => { + this.projectService.duplicate(this.controller, this.project.project_id, this.name).subscribe(() => { this.dialogRef.close(); }); } diff --git a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.html b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.html index 2acfd347..e87a2e4d 100644 --- a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.html +++ b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.html @@ -26,7 +26,7 @@ - Open this project in the background when GNS3 server starts + Open this project in the background when GNS3 controller starts @@ -42,8 +42,8 @@ - - + + diff --git a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts index 9afb5311..26c2acd7 100644 --- a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts +++ b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, Injectable, ViewChild } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { Project, ProjectVariable } 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 { NonNegativeValidator } from '../../../validators/non-negative-validator'; @@ -16,7 +16,7 @@ import { ReadmeEditorComponent } from './readme-editor/readme-editor.component'; export class EditProjectDialogComponent implements OnInit { @ViewChild('editor') editor: ReadmeEditorComponent; - server: Server; + controller:Controller ; project: Project; formGroup: FormGroup; variableFormGroup: FormGroup; @@ -91,8 +91,8 @@ export class EditProjectDialogComponent implements OnInit { this.project.auto_close = !this.auto_close; - this.projectService.update(this.server, this.project).subscribe((project: Project) => { - this.projectService.postReadmeFile(this.server, this.project.project_id, this.editor.markdown).subscribe((response) => { + this.projectService.update(this.controller, this.project).subscribe((project: Project) => { + this.projectService.postReadmeFile(this.controller, this.project.project_id, this.editor.markdown).subscribe((response) => { this.toasterService.success(`Project ${project.name} updated.`); this.onNoClick(); }); diff --git a/src/app/components/projects/edit-project-dialog/readme-editor/readme-editor.component.ts b/src/app/components/projects/edit-project-dialog/readme-editor/readme-editor.component.ts index 6edf5950..c61a9ddf 100644 --- a/src/app/components/projects/edit-project-dialog/readme-editor/readme-editor.component.ts +++ b/src/app/components/projects/edit-project-dialog/readme-editor/readme-editor.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, ViewEncapsulation, Input } from '@angular/core'; import * as marked from 'marked'; import { ProjectService } from '../../../../services/project.service'; -import { Server } from '../../../../models/server'; +import{ Controller } from '../../../../models/controller'; import { Project } from '../../../../models/project'; @Component({ @@ -11,7 +11,7 @@ import { Project } from '../../../../models/project'; styleUrls: ['./readme-editor.component.scss'] }) export class ReadmeEditorComponent implements OnInit { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; public markdown = ``; @@ -21,7 +21,7 @@ export class ReadmeEditorComponent implements OnInit { ) {} ngOnInit() { - this.projectService.getReadmeFile(this.server, this.project.project_id).subscribe(file => { + this.projectService.getReadmeFile(this.controller, this.project.project_id).subscribe(file => { if (file) this.markdown = file; }); } diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts index 634e2536..ed8f3e06 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts @@ -15,7 +15,7 @@ import { environment } from 'environments/environment'; import { FileItem, FileSelectDirective, FileUploadModule } from 'ng2-file-upload'; 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 { ImportProjectDialogComponent } from './import-project-dialog.component'; import { ToasterService } from '../../../services/toaster.service'; @@ -51,19 +51,19 @@ export class MockedProjectService { return of(this.projects); } - getUploadPath(server: Server, uuid: string, project_name: string) { - return `http://${server.host}:${server.port}/${environment.current_version}/projects/${uuid}/import?name=${project_name}`; + getUploadPath(controller:Controller , uuid: string, project_name: string) { + return `http://${controller.host}:${controller.port}/${environment.current_version}/projects/${uuid}/import?name=${project_name}`; } - getExportPath(server: Server, project: Project) { - return `http://${server.host}:${server.port}/${environment.current_version}/projects/${project.project_id}/export`; + getExportPath(controller:Controller , project: Project) { + return `http://${controller.host}:${controller.port}/${environment.current_version}/projects/${project.project_id}/export`; } } describe('ImportProjectDialogComponent', () => { let component: ImportProjectDialogComponent; let fixture: ComponentFixture; - let server: Server; + let controller:Controller ; let debugElement: DebugElement; let fileSelectDirective: FileSelectDirective; let mockedToasterService = new MockedToasterService() @@ -99,16 +99,16 @@ describe('ImportProjectDialogComponent', () => { declarations: [ImportProjectDialogComponent], }).compileComponents(); - server = new Server(); - server.host = 'localhost'; - server.port = 80; + controller = new Controller (); + controller.host = 'localhost'; + controller.port = 80; }); beforeEach(() => { fixture = TestBed.createComponent(ImportProjectDialogComponent); debugElement = fixture.debugElement; component = fixture.componentInstance; - component.server = server; + component.controller = controller; component.projectNameForm.controls['projectName'].setValue('ValidName'); fixture.detectChanges(); diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts index b3ffe291..37c421d1 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts @@ -5,8 +5,8 @@ import { ToasterService } from '../../../services/toaster.service'; import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload'; import { v4 as uuid } from 'uuid'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; -import { ServerResponse } from '../../../models/serverResponse'; +import{ Controller } from '../../../models/controller'; +import { ControllerResponse } from '../../../models/controllerResponse'; import { ProjectService } from '../../../services/project.service'; import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; import { ProjectNameValidator } from '../models/projectNameValidator'; @@ -23,7 +23,7 @@ import { MatSnackBar } from '@angular/material/snack-bar'; export class ImportProjectDialogComponent implements OnInit { uploader: FileUploader; uploadProgress: number = 0; - server: Server; + controller:Controller ; isImportEnabled: boolean = false; isFinishEnabled: boolean = false; isDeleteVisible: boolean = false; @@ -58,8 +58,8 @@ export class ImportProjectDialogComponent implements OnInit { }; this.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { - let serverResponse: ServerResponse = JSON.parse(response); - this.resultMessage = 'An error occured: ' + serverResponse.message; + let controllerResponse: ControllerResponse = JSON.parse(response); + this.resultMessage = 'An error has occurred: ' + controllerResponse.message; this.isFinishEnabled = true; }; @@ -99,7 +99,7 @@ export class ImportProjectDialogComponent implements OnInit { if (this.projectNameForm.invalid) { this.submitted = true; } else { - 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); @@ -115,7 +115,7 @@ export class ImportProjectDialogComponent implements OnInit { importProject() { const url = this.prepareUploadPath(); this.uploader.queue.forEach((elem) => (elem.url = url)); - this.uploader.authToken = `Bearer ${this.server.authToken}` + this.uploader.authToken = `Bearer ${this.controller.authToken}` this.isFirstStepCompleted = true; const itemToUpload = this.uploader.queue[0]; this.uploader.uploadItem(itemToUpload); @@ -136,8 +136,8 @@ export class ImportProjectDialogComponent 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.importProject(); }); }); @@ -164,7 +164,7 @@ export class ImportProjectDialogComponent implements OnInit { prepareUploadPath(): string { this.uuid = uuid(); const projectName = this.projectNameForm.controls['projectName'].value; - return this.projectService.getUploadPath(this.server, this.uuid, projectName); + return this.projectService.getUploadPath(this.controller, this.uuid, projectName); } cancelUploading() { diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index 65d92452..00dd536e 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -40,7 +40,7 @@ Name - {{ row.name }} + {{ row.name }} diff --git a/src/app/components/projects/projects.component.spec.ts b/src/app/components/projects/projects.component.spec.ts index 37e00e09..68ab950c 100644 --- a/src/app/components/projects/projects.component.spec.ts +++ b/src/app/components/projects/projects.component.spec.ts @@ -17,11 +17,11 @@ import { of } from 'rxjs'; import { ProgressService } from '../../common/progress/progress.service'; import { ProjectsFilter } from '../../filters/projectsFilter.pipe'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ProjectService } from '../../services/project.service'; import { MockedProjectService } from '../../services/project.service.spec'; -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 { Settings, SettingsService } from '../../services/settings.service'; import { ToasterService } from '../../services/toaster.service'; import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component'; @@ -32,8 +32,8 @@ xdescribe('ProjectsComponent', () => { let fixture: ComponentFixture; let settingsService: SettingsService; let projectService: ProjectService; - let serverService: ServerService; - let server: Server; + let controllerService: ControllerService; + let controller:Controller ; let progressService: ProgressService; let mockedProjectService: MockedProjectService = new MockedProjectService(); let electronService; @@ -66,7 +66,7 @@ xdescribe('ProjectsComponent', () => { RouterTestingModule.withRoutes([]), ], providers: [ - { provide: ServerService, useClass: MockedServerService }, + { provide: ControllerService, useClass: MockedControllerService }, { provide: ProjectService, useValue: mockedProjectService }, { provide: SettingsService }, { provide: ToasterService }, @@ -81,17 +81,17 @@ xdescribe('ProjectsComponent', () => { }) .compileComponents(); - serverService = TestBed.inject(ServerService); + controllerService = TestBed.inject(ControllerService); settingsService = TestBed.inject(SettingsService); projectService = TestBed.inject(ProjectService); progressService = TestBed.inject(ProgressService); - server = new Server(); - server.id = 99; + controller = new Controller (); + controller.id = 99; const settings = {} as Settings; - spyOn(serverService, 'get').and.returnValue(Promise.resolve(server)); + spyOn(controllerService, 'get').and.returnValue(Promise.resolve(controller)); spyOn(settingsService, 'getAll').and.returnValue(settings); spyOn(projectService, 'list').and.returnValue(of([])); @@ -136,12 +136,12 @@ describe('ProjectComponent open', () => { spyOn(projectService, 'open').and.returnValue(of(project)); - component.server = server; + component.controller = controller; }); it('should open project', () => { component.open(project); - expect(projectService.open).toHaveBeenCalledWith(server, project.project_id); + expect(projectService.open).toHaveBeenCalledWith(controller, project.project_id); expect(progressService.activate).toHaveBeenCalled(); expect(progressService.deactivate).toHaveBeenCalled(); @@ -157,12 +157,12 @@ describe('ProjectComponent close', () => { spyOn(projectService, 'close').and.returnValue(of(project)); - component.server = server; + component.controller = controller; }); xit('should close project', () => { component.close(project); - expect(projectService.close).toHaveBeenCalledWith(server, project.project_id); + expect(projectService.close).toHaveBeenCalledWith(controller, project.project_id); expect(progressService.activate).toHaveBeenCalled(); expect(progressService.deactivate).toHaveBeenCalled(); diff --git a/src/app/components/projects/projects.component.ts b/src/app/components/projects/projects.component.ts index 09a84403..6d02f93b 100644 --- a/src/app/components/projects/projects.component.ts +++ b/src/app/components/projects/projects.component.ts @@ -10,7 +10,7 @@ import { BehaviorSubject, merge, Observable } from 'rxjs'; import { map } from 'rxjs//operators'; import { ProgressService } from '../../common/progress/progress.service'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ProjectService } from '../../services/project.service'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; import { Settings, SettingsService } from '../../services/settings.service'; @@ -28,7 +28,7 @@ import { NavigationDialogComponent } from './navigation-dialog/navigation-dialog styleUrls: ['./projects.component.scss'], }) export class ProjectsComponent implements OnInit { - server: Server; + controller:Controller ; projectDatabase = new ProjectDatabase(); dataSource: ProjectDataSource; displayedColumns = ['select', 'name', 'actions', 'delete']; @@ -54,9 +54,9 @@ export class ProjectsComponent implements OnInit { ) {} ngOnInit() { - this.server = this.route.snapshot.data['server']; - if (!this.server) this.router.navigate(['/servers']); - this.recentlyOpenedProjectService.setServerIdProjectList(this.server.id.toString()); + this.controller = this.route.snapshot.data['controller']; + if (!this.controller) this.router.navigate(['/controllers']); + this.recentlyOpenedProjectService.setcontrollerIdProjectList(this.controller.id.toString()); this.refresh(); this.sort.sort({ @@ -71,18 +71,18 @@ export class ProjectsComponent implements OnInit { goToPreferences() { this.router - .navigate(['/server', this.server.id, 'preferences']) + .navigate(['/controller', this.controller.id, 'preferences']) .catch((error) => this.toasterService.error('Cannot navigate to the preferences')); } goToSystemStatus() { this.router - .navigate(['/server', this.server.id, 'systemstatus']) + .navigate(['/controller', this.controller.id, 'systemstatus']) .catch((error) => this.toasterService.error('Cannot navigate to the system status')); } refresh() { - this.projectService.list(this.server).subscribe( + this.projectService.list(this.controller).subscribe( (projects: Project[]) => { this.projectDatabase.addProjects(projects); }, @@ -98,7 +98,7 @@ export class ProjectsComponent implements OnInit { bottomSheetRef.instance.message = 'Do you want to delete the project?'; const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { if (result) { - this.projectService.delete(this.server, project.project_id).subscribe(() => { + this.projectService.delete(this.controller, project.project_id).subscribe(() => { this.refresh(); }); } @@ -108,7 +108,7 @@ export class ProjectsComponent implements OnInit { open(project: Project) { this.progressService.activate(); - this.projectService.open(this.server, project.project_id).subscribe( + this.projectService.open(this.controller, project.project_id).subscribe( () => { this.refresh(); }, @@ -129,7 +129,7 @@ export class ProjectsComponent implements OnInit { bottomSheetRef.instance.message = 'Do you want to close the project?'; const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { if (result) { - this.projectService.close(this.server, project.project_id).subscribe(() => { + this.projectService.close(this.controller, project.project_id).subscribe(() => { this.refresh(); this.progressService.deactivate(); }); @@ -144,7 +144,7 @@ export class ProjectsComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; instance.project = project; dialogRef.afterClosed().subscribe(() => { this.refresh(); @@ -158,7 +158,7 @@ export class ProjectsComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; } importProject() { @@ -169,7 +169,7 @@ export class ProjectsComponent implements OnInit { disableClose: true, }); let instance = dialogRef.componentInstance; - instance.server = this.server; + instance.controller = this.controller; const subscription = dialogRef.componentInstance.onImportProject.subscribe((projectId: string) => { uuid = projectId; }); @@ -184,8 +184,8 @@ export class ProjectsComponent implements OnInit { 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]); }); } }); diff --git a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts index 3128dfb5..cc23f61d 100644 --- a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts +++ b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts @@ -3,7 +3,7 @@ import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms' import { MatDialogRef } from '@angular/material/dialog'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; 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 { ProjectNameValidator } from '../models/projectNameValidator'; @@ -15,7 +15,7 @@ import { ProjectNameValidator } from '../models/projectNameValidator'; providers: [ProjectNameValidator], }) export class SaveProjectDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; projectNameForm: FormGroup; onAddProject = new EventEmitter(); @@ -43,7 +43,7 @@ export class SaveProjectDialogComponent 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); @@ -72,7 +72,7 @@ export class SaveProjectDialogComponent implements OnInit { addProject(): void { this.projectService - .duplicate(this.server, this.project.project_id, this.projectNameForm.controls['projectName'].value) + .duplicate(this.controller, this.project.project_id, this.projectNameForm.controls['projectName'].value) .subscribe((project: Project) => { this.dialogRef.close(); this.toasterService.success(`Project ${project.name} added`); diff --git a/src/app/components/role-management/add-role-dialog/add-role-dialog.component.html b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.html new file mode 100644 index 00000000..d1cd0b6d --- /dev/null +++ b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.html @@ -0,0 +1,30 @@ +

Create new role

+
+ + + + role name is required + + + Role name is incorrect + + + + + +
+ + +
+
diff --git a/src/app/components/role-management/add-role-dialog/add-role-dialog.component.scss b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.scss new file mode 100644 index 00000000..d0a286af --- /dev/null +++ b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.scss @@ -0,0 +1,7 @@ +mat-form-field { + width: 100%; +} + +.project-snackbar { + background: #2196f3; +} diff --git a/src/app/components/role-management/add-role-dialog/add-role-dialog.component.spec.ts b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/add-role-dialog/add-role-dialog.component.ts b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.ts new file mode 100644 index 00000000..2a935904 --- /dev/null +++ b/src/app/components/role-management/add-role-dialog/add-role-dialog.component.ts @@ -0,0 +1,60 @@ +/* +* 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 {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {Controller} from "@models/controller"; +import {GroupNameValidator} from "@components/group-management/add-group-dialog/GroupNameValidator"; +import {GroupService} from "@services/group.service"; +import {groupNameAsyncValidator} from "@components/group-management/add-group-dialog/groupNameAsyncValidator"; + +@Component({ + selector: 'app-add-role-dialog', + templateUrl: './add-role-dialog.component.html', + styleUrls: ['./add-role-dialog.component.scss'] +}) +export class AddRoleDialogComponent implements OnInit { + + roleNameForm: FormGroup; + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { controller: Controller }, + private formBuilder: FormBuilder) { + } + + ngOnInit(): void { + this.roleNameForm = this.formBuilder.group({ + name: new FormControl(), + description: new FormControl() + }); + } + + get form() { + return this.roleNameForm.controls; + } + + onAddClick() { + if (this.roleNameForm.invalid) { + return; + } + const roleName = this.roleNameForm.controls['name'].value; + const description = this.roleNameForm.controls['description'].value; + this.dialogRef.close({name: roleName, description}); + } + + onNoClick() { + this.dialogRef.close(); + } + + +} diff --git a/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.html b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.html new file mode 100644 index 00000000..5008f0d3 --- /dev/null +++ b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.html @@ -0,0 +1,8 @@ +

Are you sure to delete role named:

+

{{role.name}}

+
+ + +
diff --git a/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.scss b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.scss new file mode 100644 index 00000000..1b0fdabd --- /dev/null +++ b/src/app/components/role-management/delete-role-dialog/delete-role-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/role-management/delete-role-dialog/delete-role-dialog.component.spec.ts b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.ts b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.ts new file mode 100644 index 00000000..01f41da8 --- /dev/null +++ b/src/app/components/role-management/delete-role-dialog/delete-role-dialog.component.ts @@ -0,0 +1,39 @@ +/* +* 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 {Role} from "@models/api/role"; + +@Component({ + selector: 'app-delete-role-dialog', + templateUrl: './delete-role-dialog.component.html', + styleUrls: ['./delete-role-dialog.component.scss'] +}) +export class DeleteRoleDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { roles: Role[] }) { } + + ngOnInit(): void { + } + + onCancel() { + this.dialogRef.close(); + } + + onDelete() { + this.dialogRef.close(true); + } + + +} diff --git a/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.html b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.html new file mode 100644 index 00000000..5785c66e --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.html @@ -0,0 +1,15 @@ +
+ +
+
{{permission.methods.join(",")}}
+
{{permission.path | displayPath: controller | async}}
+
+ + +
diff --git a/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.scss b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.scss new file mode 100644 index 00000000..07167210 --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.scss @@ -0,0 +1,42 @@ +.box { + display: flex; + flex-direction: row; + border: 1px solid; + border-radius: 20px; + margin: 10px; + font-size: 12px; + font-family: monospace; + justify-items: center; + background-color: rgba(130, 8, 8, 0.36); + justify-content: flex-start; +} + + + +.left { + justify-content: flex-end; +} + +.allow { + background-color: rgba(5, 76, 5, 0.38); +} + +.content { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-around; +} + +.content > div { + padding-right: 20px; +} + +.center { + display: flex; + align-items: center; + justify-content: center; +} +button { + border-radius: 20px; +} diff --git a/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.spec.ts b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.ts b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.ts new file mode 100644 index 00000000..e198d383 --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component.ts @@ -0,0 +1,45 @@ +/* +* 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 {Permission} from "@models/api/permission"; +import {Controller} from '@models/controller'; + +@Component({ + selector: 'app-editable-permission', + templateUrl: './editable-permission.component.html', + styleUrls: ['./editable-permission.component.scss'] +}) +export class EditablePermissionComponent implements OnInit { + + @Input() permission: Permission; + @Input() controller: Controller; + @Input() side: 'LEFT' | 'RIGHT'; + @Output() click = new EventEmitter(); + + constructor() { } + + ngOnInit(): void {} + + + onClick() { + this.click.emit(); + } + + getToolTip() { + return ` + action: ${this.permission.action} + methods: ${this.permission.methods.join(',')} + original path: ${this.permission.path} + `; + } +} diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.html b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.html new file mode 100644 index 00000000..ff0fe79f --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.html @@ -0,0 +1,33 @@ +
+
+ + +
+
+

+
Permission to Add:
+
+ +
+
Permission to Remove:
+
+ +
+
+ +
+ No change +
+
+
diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.scss b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.scss new file mode 100644 index 00000000..732815d5 --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.scss @@ -0,0 +1,33 @@ +.change { + height: 350px; + display: flex; + flex-direction: column; + justify-content: center; + overflow-y: auto; +} + +.change div { + justify-content: center; + justify-items: center; + text-align: center; +} + +.title { + font-size: 20px; +} + +.button { + position: relative; + top: 400px; + z-index: 1; +} + +.button button { + margin-right: 50px; +} + +.noChange { + display: flex; + justify-content: center; + justify-items: center; +} diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.spec.ts b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.ts b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component.ts new file mode 100644 index 00000000..b1a7dd9f --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.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, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {Group} from "@models/groups/group"; +import {Permission} from "@models/api/permission"; + +@Component({ + selector: 'app-permission-editor-validate-dialog', + templateUrl: './permission-editor-validate-dialog.component.html', + styleUrls: ['./permission-editor-validate-dialog.component.scss'] +}) +export class PermissionEditorValidateDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { add: Permission[], remove: Permission[] }) { } + + ngOnInit(): void { + } + + close() { + this.dialogRef.close(false); + } + + update() { + this.dialogRef.close(true); + } +} diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html new file mode 100644 index 00000000..176b228e --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html @@ -0,0 +1,69 @@ +
+
+
+ Allow: +
+
+
+ Deny: +
+
+
+ + + + {{option.name}} + + +
+ + +
+
+ + +
+
+
Owned
+ + + + +
+ +
+
Available
+ + + + +
+
diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.scss b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.scss new file mode 100644 index 00000000..0b325c21 --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.scss @@ -0,0 +1,54 @@ +.editor { + display: flex; + justify-content: stretch; +} +.column { + width: 50vw; +} + +.header { + margin: 10px; + display: flex; + flex-direction: row; + justify-content: space-between; + font-size: 20px; +} + +.header > div > button { + margin-right: 30px; +} + +.header > div { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 20px; + +} + +.title { + font-size: 20px; + margin-left: 20px; +} +.box { + width: 50px; + height: 25px; + border: 1px solid; + margin-right: 20px; + margin-left: 10px; +} + +.allow { + background-color: rgba(5, 76, 5, 0.38); +} + +.deny { + background-color: rgba(130, 8, 8, 0.36); +} + + +.permission-filter { + border-bottom: 1px solid; + margin: 5px; + border-bottom-color: #b0bec5; +} diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.spec.ts b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.ts b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.ts new file mode 100644 index 00000000..84759f05 --- /dev/null +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.ts @@ -0,0 +1,114 @@ +/* +* 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, Input, OnInit, Output, EventEmitter} from '@angular/core'; +import {Controller} from "@models/controller"; +import {Permission} from "@models/api/permission"; +import {MatDialog} from "@angular/material/dialog"; +import {PermissionEditorValidateDialogComponent} from "@components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component"; +import {ApiInformationService } from "@services/ApiInformation/api-information.service"; +import {PageEvent} from "@angular/material/paginator"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +@Component({ + selector: 'app-permission-editor', + templateUrl: './permission-editor.component.html', + styleUrls: ['./permission-editor.component.scss'] +}) +export class PermissionEditorComponent implements OnInit { + + owned: Set; + available: Set; + searchPermissions: any; + filteredOptions: IGenericApiObject[]; + pageEventOwned: PageEvent | undefined; + pageEventAvailable: PageEvent | undefined; + + @Input() controller: Controller; + @Input() ownedPermissions: Permission[]; + @Input() availablePermissions: Permission[]; + @Output() updatedPermissions: EventEmitter = new EventEmitter(); + + + constructor(private dialog: MatDialog, + private apiInformationService: ApiInformationService) {} + + ngOnInit(): void { + this.reset(); + } + + add(permission: Permission) { + this.available.delete(permission); + this.owned.add(permission); + } + + remove(permission: Permission) { + this.owned.delete(permission); + this.available.add(permission); + } + + reset() { + const ownedPermissionId = this.ownedPermissions.map(p => p.permission_id); + this.owned = new Set(this.ownedPermissions); + this.available = new Set(this.availablePermissions.filter(p => !ownedPermissionId.includes(p.permission_id))); + } + + update() { + const {add, remove} = this.diff(); + this.dialog + .open(PermissionEditorValidateDialogComponent, + {width: '700px', height: '500px', data: {add, remove}}) + .afterClosed() + .subscribe((confirmed: boolean) => { + if (confirmed) { + this.updatedPermissions.emit({add, remove}); + } + + }); + } + + private diff() { + const add: Permission[] = []; + + const currentRolePermissionId = this.ownedPermissions.map(p => p.permission_id); + this.owned.forEach((permission: Permission) => { + if (!currentRolePermissionId.includes(permission.permission_id)) { + add.push(permission); + } + }); + + const remove: Permission[] = []; + this.ownedPermissions.forEach((permission: Permission) => { + if (!this.owned.has(permission)) { + remove.push(permission); + } + }); + + return {add, remove}; + } + + displayFn(value): string { + return value && value.name ? value.name : ''; + } + + changeAutocomplete(inputText) { + this.filteredOptions = this.apiInformationService.getIdByObjNameFromCache(inputText); + } + + get ownedArray() { + return Array.from(this.owned.values()); + } + + get availableArray() { + return Array.from(this.available.values()); + } +} diff --git a/src/app/components/role-management/role-detail/role-detail.component.html b/src/app/components/role-management/role-detail/role-detail.component.html new file mode 100644 index 00000000..5704b0bf --- /dev/null +++ b/src/app/components/role-management/role-detail/role-detail.component.html @@ -0,0 +1,60 @@ +
+
+
+ + keyboard_arrow_left + +

Role {{role.name}} details

+
+
+
+
+ + Role name: + + +
+
+ + Description: + + +
+
Creation date: {{role.created_at}}
+
Last update Date: {{role.updated_at}}
+
UUID: {{role.role_id}}
+
+ Is build in +
+
+ +
+
+ +
+
+
Permissions
+
+ +
+
+ + +
+
+
+
diff --git a/src/app/components/role-management/role-detail/role-detail.component.scss b/src/app/components/role-management/role-detail/role-detail.component.scss new file mode 100644 index 00000000..bf38d212 --- /dev/null +++ b/src/app/components/role-management/role-detail/role-detail.component.scss @@ -0,0 +1,40 @@ +.main { + display: flex; + justify-content: space-around; +} + +.details { + width: 30vw; + display: flex; + flex-direction: column; + justify-content: center; +} + +.permissions { + width: 35vw; + display: flex; + flex-direction: column; + justify-content: stretch; +} + +.permission { + display: flex; + flex-direction: row; + justify-content: space-between; + margin-bottom: 10px; + border: 1px solid; + padding: 5px; + border-radius: 5px; + font-family: monospace; +} + +.header { + display: flex; + flex-direction: row; + justify-content: space-between; + padding-bottom: 20px; + +} +.header > div { + font-size: 2em; +} diff --git a/src/app/components/role-management/role-detail/role-detail.component.spec.ts b/src/app/components/role-management/role-detail/role-detail.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/role-detail.component.ts b/src/app/components/role-management/role-detail/role-detail.component.ts new file mode 100644 index 00000000..01bd4716 --- /dev/null +++ b/src/app/components/role-management/role-detail/role-detail.component.ts @@ -0,0 +1,61 @@ +/* +* 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 {RoleService} from "@services/role.service"; +import {ActivatedRoute} from "@angular/router"; +import {Controller} from "@models/controller"; +import {ControllerService} from "@services/controller.service"; +import {Role} from "@models/api/role"; +import {FormControl, FormGroup} from "@angular/forms"; +import {ToasterService} from "@services/toaster.service"; +import {HttpErrorResponse} from "@angular/common/http"; + +@Component({ + selector: 'app-role-detail', + templateUrl: './role-detail.component.html', + styleUrls: ['./role-detail.component.scss'] +}) +export class RoleDetailComponent implements OnInit { + controller: Controller; + role: Role; + editRoleForm: FormGroup; + + constructor(private roleService: RoleService, + private controllerService: ControllerService, + private toastService: ToasterService, + private route: ActivatedRoute) { + + this.editRoleForm = new FormGroup({ + rolename: new FormControl(), + description: new FormControl(), + }); + } + + ngOnInit(): void { + this.route.data.subscribe((d: { controller: Controller; role: Role }) => { + this.controller = d.controller; + this.role = d.role; + }); + } + + onUpdate() { + this.roleService.update(this.controller, this.role) + .subscribe(() => { + this.toastService.success(`role: ${this.role.name} was updated`); + }, + (error: HttpErrorResponse) => { + this.toastService.error(`${error.message} + ${error.error.message}`); + }); + } +} diff --git a/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.html b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.html new file mode 100644 index 00000000..d87e75c3 --- /dev/null +++ b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.html @@ -0,0 +1,16 @@ +
+ +
+ Edit {{role.name}} role permissions +
+
+ diff --git a/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.scss b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.spec.ts b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.ts b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.ts new file mode 100644 index 00000000..1b1bc521 --- /dev/null +++ b/src/app/components/role-management/role-detail/role-permissions/role-permissions.component.ts @@ -0,0 +1,70 @@ +/* +* 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 {MatDialog} from "@angular/material/dialog"; +import {ToasterService} from "@services/toaster.service"; +import {RoleService} from "@services/role.service"; +import {Controller} from "@models/controller"; +import {Role} from "@models/api/role"; +import {Permission} from "@models/api/permission"; +import {Observable} from "rxjs/Rx"; +import {forkJoin} from "rxjs"; +import {HttpErrorResponse} from "@angular/common/http"; + +@Component({ + selector: 'app-role-permissions', + templateUrl: './role-permissions.component.html', + styleUrls: ['./role-permissions.component.scss'] +}) +export class RolePermissionsComponent implements OnInit { + controller: Controller; + role: Role; + permissions: Permission[]; + + constructor(private route: ActivatedRoute, + private dialog: MatDialog, + private toastService: ToasterService, + private router: Router, + private roleService: RoleService) { + this.route.data.subscribe((data: { controller: Controller, role: Role, permissions: Permission[] }) => { + this.controller = data.controller; + this.role = data.role; + this.permissions = data.permissions; + }); + } + + ngOnInit(): void { + } + + updatePermissions(toUpdate) { + const {add, remove} = toUpdate; + const obs: Observable[] = []; + add.forEach((permission: Permission) => { + obs.push(this.roleService.addPermission(this.controller, this.role, permission)); + }); + remove.forEach((permission: Permission) => { + obs.push(this.roleService.removePermission(this.controller, this.role, permission)); + }); + + forkJoin(obs) + .subscribe(() => { + this.toastService.success(`permissions updated`); + this.router.navigate(['/controller', this.controller.id, 'management', 'roles', this.role.role_id]); + }, + (error: HttpErrorResponse) => { + this.toastService.error(`${error.message} + ${error.error.message}`); + }); + } +} diff --git a/src/app/components/role-management/role-filter.pipe.spec.ts b/src/app/components/role-management/role-filter.pipe.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-filter.pipe.ts b/src/app/components/role-management/role-filter.pipe.ts new file mode 100644 index 00000000..f9e70fcb --- /dev/null +++ b/src/app/components/role-management/role-filter.pipe.ts @@ -0,0 +1,34 @@ +/* +* 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 {Role} from "@models/api/role"; +import {User} from "@models/users/user"; +import {MatTableDataSource} from "@angular/material/table"; + +@Pipe({ + name: 'roleFilter' +}) +export class RoleFilterPipe implements PipeTransform { + + transform(roles: MatTableDataSource, searchText: string): MatTableDataSource { + if (!searchText) { + return roles; + } + searchText = searchText.trim().toLowerCase(); + roles.filter = searchText; + return roles; + + + } + +} diff --git a/src/app/components/role-management/role-management.component.html b/src/app/components/role-management/role-management.component.html new file mode 100644 index 00000000..e0d0253e --- /dev/null +++ b/src/app/components/role-management/role-management.component.html @@ -0,0 +1,91 @@ +
+
+
+

Roles Management

+ + +
+
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + Name + + {{ row.name }} + + + + Description + +
{{ row.description }}
+
+
+ + Permissions (Allow) + +
+
+
{{permission.action}}
+
{{permission.methods.join(',')}}
+
{{permission.path}}
+
+
+
+
+ + + + + + + + + +
+ + + +
+
+
+ +
+ +
+
diff --git a/src/app/components/role-management/role-management.component.scss b/src/app/components/role-management/role-management.component.scss new file mode 100644 index 00000000..2045941d --- /dev/null +++ b/src/app/components/role-management/role-management.component.scss @@ -0,0 +1,56 @@ +.add-button { + height: 40px; + width: 160px; + margin: 20px; +} + +.full-width { + width: 940px; + margin-left: -470px; + left: 50%; +} + +.small-col { + flex-grow: 0.3; +} + +.active-col { + flex-grow: 0.5; +} + +.overflow-col { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + padding-right: 5px; +} + +.permission { + display: flex; + flex-direction: row; + justify-content: space-between; +} +.permission > div { + margin-right: 20px; + font-size: 10px; +} +.custom-tooltip { + font-size:100px; +} + +.loader { + position: absolute; + margin: auto; + height: 175px; + bottom: 0; + left: 0; + right: 0; + top: 0; + width: 175px; +} + +.permissions-list { + display: flex; + flex-direction: column; + justify-content: stretch; +} diff --git a/src/app/components/role-management/role-management.component.spec.ts b/src/app/components/role-management/role-management.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/role-management/role-management.component.ts b/src/app/components/role-management/role-management.component.ts new file mode 100644 index 00000000..7a8598fc --- /dev/null +++ b/src/app/components/role-management/role-management.component.ts @@ -0,0 +1,149 @@ +/* +* 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 {Controller} from "@models/controller"; +import {MatTableDataSource} from "@angular/material/table"; +import {SelectionModel} from "@angular/cdk/collections"; +import {MatPaginator} from "@angular/material/paginator"; +import {MatSort} from "@angular/material/sort"; +import {ActivatedRoute, Router} from "@angular/router"; +import {ProgressService} from "../../common/progress/progress.service"; +import {ControllerService} from "@services/controller.service"; +import {MatDialog} from "@angular/material/dialog"; +import {ToasterService} from "@services/toaster.service"; +import {Role} from "@models/api/role"; +import {RoleService} from "@services/role.service"; +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 {forkJoin} from "rxjs"; +import {HttpErrorResponse} from "@angular/common/http"; + + +@Component({ + selector: 'app-role-management', + templateUrl: './role-management.component.html', + styleUrls: ['./role-management.component.scss'] +}) +export class RoleManagementComponent implements OnInit { + controller: Controller; + dataSource = new MatTableDataSource(); + displayedColumns = ['select', 'name', 'description', 'permissions', 'delete']; + selection = new SelectionModel(true, []); + searchText = ''; + + @ViewChildren('rolesPaginator') rolesPaginator: QueryList; + @ViewChildren('rolesSort') rolesSort: QueryList; + isReady = false; + + + constructor( + private route: ActivatedRoute, + private router: Router, + private roleService: RoleService, + private progressService: ProgressService, + private controllerService: ControllerService, + public dialog: MatDialog, + private toasterService: ToasterService) { + } + + ngOnInit() { + const controllerId = this.route.parent.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.controller = controller; + this.refresh(); + }); + + } + + ngAfterViewInit() { + this.rolesPaginator.changes.subscribe((comps: QueryList ) => + { + this.dataSource.paginator = comps.first; + }); + this.rolesSort.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]; + } + }; + + } + + refresh() { + this.roleService.get(this.controller).subscribe( + (roles: Role[]) => { + this.isReady = true; + this.dataSource.data = roles; + }, + (error) => { + this.progressService.setError(error); + } + ); + } + + addRole() { + const dialogRef = this.dialog.open(AddRoleDialogComponent, { + width: '400px', + autoFocus: false, + disableClose: true, + data: {controller: this.controller}, + }) + .afterClosed() + .subscribe((role: { name: string; description: string }) => { + if (role) { + this.roleService.create(this.controller, role) + .subscribe(() => { + this.toasterService.success(`${role.name} role created`); + this.refresh(); + }, + (error: HttpErrorResponse) => this.toasterService.error(`${error.message} + ${error.error.message}`)); + } + }); + } + + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + onDelete(rolesToDelete: Role[]) { + this.dialog + .open(DeleteRoleDialogComponent, {width: '500px', height: '250px', data: {roles: rolesToDelete}}) + .afterClosed() + .subscribe((isDeletedConfirm) => { + if (isDeletedConfirm) { + const observables = rolesToDelete.map((role: Role) => this.roleService.delete(this.controller, role.role_id)); + forkJoin(observables) + .subscribe(() => { + this.refresh(); + }, + (error) => { + this.toasterService.error(`An error occur while trying to delete role`); + }); + } + }); + } +} diff --git a/src/app/components/servers/server-discovery/server-discovery.component.html b/src/app/components/servers/server-discovery/server-discovery.component.html deleted file mode 100644 index d0fbbc9a..00000000 --- a/src/app/components/servers/server-discovery/server-discovery.component.html +++ /dev/null @@ -1,12 +0,0 @@ - - - We've discovered GNS3 server on {{ discoveredServer?.host }}:{{ discoveredServer?.port }}, would you like to add to the list? - - - - - - - - diff --git a/src/app/components/servers/server-discovery/server-discovery.component.spec.ts b/src/app/components/servers/server-discovery/server-discovery.component.spec.ts deleted file mode 100644 index f3843bd4..00000000 --- a/src/app/components/servers/server-discovery/server-discovery.component.spec.ts +++ /dev/null @@ -1,171 +0,0 @@ -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 { Server } from '../../../models/server'; -import { Version } from '../../../models/version'; -import { ServerDatabase } from '../../../services/server.database'; -import { ServerService } from '../../../services/server.service'; -import { MockedServerService } from '../../../services/server.service.spec'; -import { VersionService } from '../../../services/version.service'; -import { MockedVersionService } from '../../../services/version.service.spec'; -import { ServerDiscoveryComponent } from './server-discovery.component'; - -xdescribe('ServerDiscoveryComponent', () => { - let component: ServerDiscoveryComponent; - let fixture: ComponentFixture; - let mockedVersionService: MockedVersionService; - let mockedServerService: MockedServerService; - - beforeEach(async () => { - mockedServerService = new MockedServerService(); - mockedVersionService = new MockedVersionService(); - await TestBed.configureTestingModule({ - imports: [MatCardModule, MatDividerModule], - providers: [ - { provide: VersionService, useFactory: () => mockedVersionService }, - { provide: ServerService, useFactory: () => mockedServerService }, - ServerDatabase, - ], - declarations: [ServerDiscoveryComponent], - }).compileComponents(); - }); - -beforeEach(() => { - fixture = TestBed.createComponent(ServerDiscoveryComponent); - - 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 server object when server is available', () => { - const version = new Version(); - version.version = '2.1.8'; - - const getVersionSpy = spyOn(mockedVersionService, 'get').and.returnValue(Observable.of(version)); - - component.isServerAvailable('127.0.0.1', 3080).subscribe((s) => { - expect(s.host).toEqual('127.0.0.1'); - expect(s.port).toEqual(3080); - }); - - const server = new Server(); - server.host = '127.0.0.1'; - server.port = 3080; - - expect(getVersionSpy).toHaveBeenCalledWith(server); - }); - - it('should throw error once server is not available', () => { - const server = new Server(); - server.host = '127.0.0.1'; - server.port = 3080; - - const getVersionSpy = spyOn(mockedVersionService, 'get').and.returnValue( - Observable.throwError(new Error('server is unavailable')) - ); - let hasExecuted = false; - - component.isServerAvailable('127.0.0.1', 3080).subscribe( - (ver) => { }, - (err) => { - hasExecuted = true; - expect(err.toString()).toEqual('Error: server is unavailable'); - } - ); - - expect(getVersionSpy).toHaveBeenCalledWith(server); - expect(hasExecuted).toBeTruthy(); - }); -}); - -describe('discovery', () => { - it('should discovery all servers available', (done) => { - const version = new Version(); - version.version = '2.1.8'; - - spyOn(component, 'isServerAvailable').and.callFake((ip, port) => { - const server = new Server(); - server.host = ip; - server.port = port; - return Observable.of(server); - }); - - 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('discoverFirstAvailableServer', () => { - let server: Server; - - beforeEach(function () { - server = new Server(); - (server.host = '199.111.111.1'), (server.port = 3333); - - spyOn(component, 'discovery').and.callFake(() => { - return Observable.of([server]); - }); - }); - - it('should get first server from discovered and with no added before', fakeAsync(() => { - expect(component.discoveredServer).toBeUndefined(); - component.discoverFirstAvailableServer(); - tick(); - expect(component.discoveredServer.host).toEqual('199.111.111.1'); - expect(component.discoveredServer.port).toEqual(3333); - })); - - it('should get first server from discovered and with already added', fakeAsync(() => { - mockedServerService.servers.push(server); - - expect(component.discoveredServer).toBeUndefined(); - component.discoverFirstAvailableServer(); - tick(); - expect(component.discoveredServer).toBeUndefined(); - })); -}); - -describe('accepting and ignoring found server', () => { - let server: Server; - beforeEach(() => { - server = new Server(); - (server.host = '199.111.111.1'), (server.port = 3333); - component.discoveredServer = server; - }); - - describe('accept', () => { - it('should add new server', fakeAsync(() => { - component.accept(server); - tick(); - expect(component.discoveredServer).toBeNull(); - expect(mockedServerService.servers[0].host).toEqual('199.111.111.1'); - expect(mockedServerService.servers[0].name).toEqual('199.111.111.1'); - expect(mockedServerService.servers[0].location).toEqual('remote'); - })); - }); - - describe('ignore', () => { - it('should reject server', fakeAsync(() => { - component.ignore(server); - tick(); - expect(component.discoveredServer).toBeNull(); - })); - }); -}); -}); diff --git a/src/app/components/servers/server-discovery/server-discovery.component.ts b/src/app/components/servers/server-discovery/server-discovery.component.ts deleted file mode 100644 index dc831ef9..00000000 --- a/src/app/components/servers/server-discovery/server-discovery.component.ts +++ /dev/null @@ -1,132 +0,0 @@ -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 { Server, ServerProtocol } from '../../../models/server'; -import { Version } from '../../../models/version'; -import { ServerDatabase } from '../../../services/server.database'; -import { ServerService } from '../../../services/server.service'; -import { VersionService } from '../../../services/version.service'; - -@Component({ - selector: 'app-server-discovery', - templateUrl: './server-discovery.component.html', - styleUrls: ['./server-discovery.component.scss'], -}) -export class ServerDiscoveryComponent implements OnInit { - private defaultServers = [ - { - host: '127.0.0.1', - port: 3080, - }, - ]; - - discoveredServer: Server; - - constructor( - private versionService: VersionService, - private serverService: ServerService, - private serverDatabase: ServerDatabase, - private route: ActivatedRoute - ) {} - - ngOnInit() { - if (this.serverService.isServiceInitialized) this.discoverFirstServer(); - this.serverService.serviceInitialized.subscribe(async (value: boolean) => { - if (value) { - this.discoverFirstServer(); - } - }); - } - - async discoverFirstServer() { - let discovered = await this.discoverServers(); - let local = await this.serverService.findAll(); - - local.forEach((added) => { - discovered = discovered.filter((server) => { - return !(server.host == added.host && server.port == added.port); - }); - }); - - if (discovered.length > 0) { - this.discoveredServer = discovered.shift(); - } - } - - async discoverServers() { - let discoveredServers: Server[] = []; - this.defaultServers.forEach(async (testServer) => { - const server = new Server(); - server.host = testServer.host; - server.port = testServer.port; - let version = await this.versionService - .get(server) - .toPromise() - .catch((error) => null); - if (version) discoveredServers.push(server); - }); - return discoveredServers; - } - - discoverFirstAvailableServer() { - forkJoin([from(this.serverService.findAll()).pipe(map((s: Server[]) => s)), this.discovery()]).subscribe( - ([local, discovered]) => { - local.forEach((added) => { - discovered = discovered.filter((server) => { - return !(server.host == added.host && server.port == added.port); - }); - }); - if (discovered.length > 0) { - this.discoveredServer = discovered.shift(); - } - }, - (error) => {} - ); - } - - discovery(): Observable { - const queries: Observable[] = []; - - this.defaultServers.forEach((testServer) => { - queries.push( - this.isServerAvailable(testServer.host, testServer.port).catch((err) => { - return Observable.of(null); - }) - ); - }); - - return new Observable((observer) => { - forkJoin(queries).subscribe((discoveredServers) => { - observer.next(discoveredServers.filter((s) => s != null)); - observer.complete(); - }); - }); - } - - isServerAvailable(ip: string, port: number): Observable { - const server = new Server(); - server.host = ip; - server.port = port; - return this.versionService.get(server).flatMap((version: Version) => Observable.of(server)); - } - - ignore(server: Server) { - this.discoveredServer = null; - } - - accept(server: Server) { - if (server.name == null) { - server.name = server.host; - } - - server.location = 'remote'; - server.protocol = location.protocol as ServerProtocol; - - this.serverService.create(server).then((created: Server) => { - this.serverDatabase.addServer(created); - this.discoveredServer = null; - }); - } -} diff --git a/src/app/components/servers/servers.component.scss b/src/app/components/servers/servers.component.scss deleted file mode 100644 index e7e1f28f..00000000 --- a/src/app/components/servers/servers.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.buttons-bar { - padding-top: 0px; -} - -.button { - margin: 20px !important; -} diff --git a/src/app/components/servers/servers.component.ts b/src/app/components/servers/servers.component.ts deleted file mode 100644 index f372e32e..00000000 --- a/src/app/components/servers/servers.component.ts +++ /dev/null @@ -1,177 +0,0 @@ -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 { Server, ServerProtocol } from '../../models/server'; -import { ServerManagementService } from '../../services/server-management.service'; -import { ServerDatabase } from '../../services/server.database'; -import { ServerService } from '../../services/server.service'; -import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component'; -import { AddServerDialogComponent } from './add-server-dialog/add-server-dialog.component'; - -@Component({ - selector: 'app-server-list', - templateUrl: './servers.component.html', - styleUrls: ['./servers.component.scss'], -}) -export class ServersComponent implements OnInit, OnDestroy { - dataSource: ServerDataSource; - displayedColumns = ['id', 'name', 'location', 'ip', 'port', 'actions']; - serverStatusSubscription: Subscription; - isElectronApp: boolean = false; - - constructor( - private dialog: MatDialog, - private serverService: ServerService, - private serverDatabase: ServerDatabase, - private serverManagement: ServerManagementService, - private changeDetector: ChangeDetectorRef, - private electronService: ElectronService, - private childProcessService: ChildProcessService, - private bottomSheet: MatBottomSheet, - private route: ActivatedRoute, - private router: Router - ) { } - - getServers() { - const runningServersNames = this.serverManagement.getRunningServers(); - - this.serverService.findAll().then((servers: Server[]) => { - servers.forEach((server) => { - const serverIndex = runningServersNames.findIndex((serverName) => server.name === serverName); - if (serverIndex >= 0) { - server.status = 'running'; - } - }); - - servers.forEach((server) => { - this.serverService.checkServerVersion(server).subscribe( - (serverInfo) => { - if (serverInfo.version.split('.')[0] >= 3) { - if (!server.protocol) server.protocol = location.protocol as ServerProtocol; - if (!this.serverDatabase.find(server.name)) this.serverDatabase.addServer(server); - } - }, - (error) => { } - ); - }); - }); - } - - ngOnInit() { - this.isElectronApp = this.electronService.isElectronApp; - - if (this.serverService && this.serverService.isServiceInitialized) this.getServers(); - - if (this.serverService && this.serverService.isServiceInitialized) { - this.serverService.serviceInitialized.subscribe(async (value: boolean) => { - if (value) { - this.getServers(); - } - }); - } - - this.dataSource = new ServerDataSource(this.serverDatabase); - - this.serverStatusSubscription = this.serverManagement.serverStatusChanged.subscribe((serverStatus) => { - const server = this.serverDatabase.find(serverStatus.serverName); - if (!server) { - return; - } - if (serverStatus.status === 'starting') { - server.status = 'starting'; - } - if (serverStatus.status === 'stopped') { - server.status = 'stopped'; - } - if (serverStatus.status === 'errored') { - server.status = 'stopped'; - } - if (serverStatus.status === 'started') { - server.status = 'running'; - } - this.serverDatabase.update(server); - this.changeDetector.detectChanges(); - }); - } - - ngOnDestroy() { - this.serverStatusSubscription.unsubscribe(); - } - - startLocalServer() { - const server = this.serverDatabase.data.find((n) => n.location === 'bundled' || 'local'); - this.startServer(server); - } - - openProjects(server) { - this.router.navigate(['/server', server.id, 'projects']); - } - - createModal() { - const dialogRef = this.dialog.open(AddServerDialogComponent, { - width: '350px', - autoFocus: false, - disableClose: true, - }); - - dialogRef.afterClosed().subscribe((server) => { - if (server) { - this.serverService.create(server).then((created: Server) => { - this.serverDatabase.addServer(created); - }); - } - }); - } - - getServerStatus(server: Server) { - if (server.location === 'local') { - if (server.status === undefined) { - return 'stopped'; - } - return server.status; - } - } - - deleteServer(server: Server) { - this.bottomSheet.open(ConfirmationBottomSheetComponent); - let bottomSheetRef = this.bottomSheet._openedBottomSheetRef; - bottomSheetRef.instance.message = 'Do you want to delete the server?'; - const bottomSheetSubscription = bottomSheetRef.afterDismissed().subscribe((result: boolean) => { - if (result) { - this.serverService.delete(server).then(() => { - this.serverDatabase.remove(server); - }); - } - }); - } - - async startServer(server: Server) { - await this.serverManagement.start(server); - } - - async stopServer(server: Server) { - await this.serverManagement.stop(server); - } -} - -export class ServerDataSource extends DataSource { - constructor(private serverDatabase: ServerDatabase) { - super(); - } - - connect(): Observable { - return merge(this.serverDatabase.dataChange).pipe( - map(() => { - return this.serverDatabase.data; - }) - ); - } - - disconnect() { } -} diff --git a/src/app/components/settings/console/console.component.html b/src/app/components/settings/console/console.component.html index 185b553e..a992f5d7 100644 --- a/src/app/components/settings/console/console.component.html +++ b/src/app/components/settings/console/console.component.html @@ -17,7 +17,7 @@ %s: path of the serial connection
%d: title of the console
%i: Project UUID
- %c: server URL (http://user:password@server:port) + %c: controller URL (http://user:password@controller:port)
diff --git a/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.html b/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.html index 5618a1ab..bcd91f6c 100644 --- a/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.html +++ b/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.html @@ -5,7 +5,7 @@ class="top-button" color="accent" (click)="onNoClick()" - routerLink="/server/{{ server?.id }}/project/{{ project?.project_id }}/snapshots" + routerLink="/controller/{{ controller?.id }}/project/{{ project?.project_id }}/snapshots" > Go to snapshots diff --git a/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.ts b/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.ts index f5b99a8e..ba0674bd 100644 --- a/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.ts +++ b/src/app/components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component.ts @@ -4,7 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { Node } from '../../../cartography/models/node'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { Snapshot } from '../../../models/snapshot'; import { SnapshotService } from '../../../services/snapshot.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -15,7 +15,7 @@ import { ToasterService } from '../../../services/toaster.service'; styleUrls: ['./create-snapshot-dialog.component.scss'], }) export class CreateSnapshotDialogComponent { - server: Server; + controller:Controller ; project: Project; snapshot: Snapshot = new Snapshot(); inputForm: FormGroup; @@ -30,7 +30,7 @@ export class CreateSnapshotDialogComponent { private nodesDataSource: NodesDataSource, @Inject(MAT_DIALOG_DATA) public data: any ) { - this.server = data['server']; + this.controller = data['controller']; this.project = data['project']; this.inputForm = this.formBuilder.group({ @@ -38,7 +38,7 @@ export class CreateSnapshotDialogComponent { }); if (this.project && this.project.project_id) { - this.snapshotService.list(this.server, this.project.project_id).subscribe((snapshots: Snapshot[]) => { + this.snapshotService.list(this.controller, this.project.project_id).subscribe((snapshots: Snapshot[]) => { snapshots.forEach((snapshot: Snapshot) => { this.snapshots.push(snapshot.name); }); diff --git a/src/app/components/snapshots/list-of-snapshots/list-of-snaphshots.component.spec.ts b/src/app/components/snapshots/list-of-snapshots/list-of-snaphshots.component.spec.ts index d418ea00..8078fa83 100644 --- a/src/app/components/snapshots/list-of-snapshots/list-of-snaphshots.component.spec.ts +++ b/src/app/components/snapshots/list-of-snapshots/list-of-snaphshots.component.spec.ts @@ -15,9 +15,9 @@ import { of } from 'rxjs'; import { ProgressDialogService } from '../../../common/progress-dialog/progress-dialog.service'; import { DateFilter } from '../../../filters/dateFilter.pipe'; import { NameFilter } from '../../../filters/nameFilter.pipe'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { Snapshot } from '../../../models/snapshot'; -import { ServerResolve } from '../../../resolvers/server-resolve'; +import { ControllerResolve } from '../../../resolvers/controller-resolve'; import { SnapshotService } from '../../../services/snapshot.service'; import { ToasterService } from '../../../services/toaster.service'; import { MockedToasterService } from '../../../services/toaster.service.spec'; @@ -39,7 +39,7 @@ export class MockedActivatedRoute { }, }, data: { - server: new Server(), + controller: new Controller (), }, }, }; @@ -47,15 +47,15 @@ export class MockedActivatedRoute { } export class MockedSnapshotService { - public list(server: Server, project_id: string) { + public list(controller:Controller , project_id: string) { return of([]); } - public delete(server: Server, project_id: string, snapshot_id: string) { + public delete(controller:Controller , project_id: string, snapshot_id: string) { return of({}); } - public restore(server: Server, project_id: string, snapshot_id: string) { + public restore(controller:Controller , project_id: string, snapshot_id: string) { return of({}); } } @@ -80,9 +80,9 @@ describe('ListOfSnapshotsComponent', () => { NoopAnimationsModule, RouterTestingModule.withRoutes([ { - path: 'server/:server_id/project/:project_id/snapshots', + path: 'controller/:controller_id/project/:project_id/snapshots', component: ListOfSnapshotsComponent, - resolve: { server: ServerResolve }, + resolve: { controller: ControllerResolve }, }, ]), ], diff --git a/src/app/components/snapshots/list-of-snapshots/list-of-snapshots.component.ts b/src/app/components/snapshots/list-of-snapshots/list-of-snapshots.component.ts index 274fa223..f1e4754b 100644 --- a/src/app/components/snapshots/list-of-snapshots/list-of-snapshots.component.ts +++ b/src/app/components/snapshots/list-of-snapshots/list-of-snapshots.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Sort } from '@angular/material/sort'; import { ActivatedRoute } from '@angular/router'; -import { Server } from '../../..//models/server'; +import{ Controller } from '../../../models/controller'; import { ProgressDialogComponent } from '../../../common/progress-dialog/progress-dialog.component'; import { ProgressDialogService } from '../../../common/progress-dialog/progress-dialog.service'; import { Project } from '../../../models/project'; @@ -15,7 +15,7 @@ import { ToasterService } from '../../../services/toaster.service'; styleUrls: ['./list-of-snapshots.component.scss'], }) export class ListOfSnapshotsComponent implements OnInit { - server: Server; + controller:Controller ; projectId: string; snapshots: Snapshot[]; displayedColumns = ['name', 'creationDate', 'actions']; @@ -30,18 +30,18 @@ export class ListOfSnapshotsComponent implements OnInit { ngOnInit() { this.projectId = this.route.snapshot.paramMap.get('project_id'); - this.server = this.route.snapshot.data['server']; + this.controller = this.route.snapshot.data['controller']; this.getSnapshots(); } getSnapshots() { - this.snapshotService.list(this.server, this.projectId).subscribe((snapshots: Snapshot[]) => { + this.snapshotService.list(this.controller, this.projectId).subscribe((snapshots: Snapshot[]) => { this.snapshots = snapshots; }); } restoreSnapshot(snapshot: Snapshot) { - const restoring = this.snapshotService.restore(this.server, this.projectId, snapshot.snapshot_id.toString()); + const restoring = this.snapshotService.restore(this.controller, this.projectId, snapshot.snapshot_id.toString()); const progress = this.progressDialogService.open(); const subscription = restoring.subscribe((project: Project) => { this.toaster.success(`Snapshot ${snapshot.name} has been restored.`); @@ -56,7 +56,7 @@ export class ListOfSnapshotsComponent implements OnInit { } deleteSnapshot(snapshot: Snapshot) { - this.snapshotService.delete(this.server, this.projectId, snapshot.snapshot_id.toString()).subscribe(() => { + this.snapshotService.delete(this.controller, this.projectId, snapshot.snapshot_id.toString()).subscribe(() => { this.getSnapshots(); this.toaster.success(`Snapshot ${snapshot.name} has been deleted.`); }); diff --git a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.spec.ts b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.spec.ts index 1c0e8496..05db7df7 100644 --- a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.spec.ts +++ b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.spec.ts @@ -5,7 +5,7 @@ import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { Context } from 'app/cartography/models/context'; import { ProgressDialogService } from 'app/common/progress-dialog/progress-dialog.service'; -import { HttpServer, ServerErrorHandler } from 'app/services/http-server.service'; +import { HttpController, ControllerErrorHandler } from 'app/services/http-controller.service'; import { SnapshotService } from 'app/services/snapshot.service'; import { ToasterService } from 'app/services/toaster.service'; import { SnapshotMenuItemComponent } from './snapshot-menu-item.component'; @@ -21,11 +21,11 @@ describe('SnapshotMenuItemComponent', () => { providers: [ SnapshotService, MatDialog, - HttpServer, + HttpController, Overlay, ScrollStrategyOptions, HttpClient, - ServerErrorHandler, + ControllerErrorHandler, ProgressDialogService, Context, ToasterService diff --git a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts index 2c676594..1a6c4ac8 100644 --- a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts +++ b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts @@ -3,7 +3,7 @@ import { MatDialog } from '@angular/material/dialog'; import { ProgressDialogComponent } from '../../../common/progress-dialog/progress-dialog.component'; import { ProgressDialogService } from '../../../common/progress-dialog/progress-dialog.service'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { Snapshot } from '../../../models/snapshot'; import { SnapshotService } from '../../../services/snapshot.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -16,7 +16,7 @@ import { CreateSnapshotDialogComponent } from '../create-snapshot-dialog/create- }) export class SnapshotMenuItemComponent implements OnInit { @Input('project') project: Project; - @Input('server') server: Server; + @Input('controller') controller:Controller ; constructor( private dialog: MatDialog, @@ -31,7 +31,7 @@ export class SnapshotMenuItemComponent implements OnInit { const dialogRef = this.dialog.open(CreateSnapshotDialogComponent, { width: '450px', data: { - server: this.server, + controller: this.controller, project: this.project, }, autoFocus: false, @@ -40,7 +40,7 @@ export class SnapshotMenuItemComponent implements OnInit { dialogRef.afterClosed().subscribe((snapshot) => { if (snapshot && this.project.project_id) { - const creation = this.snapshotService.create(this.server, this.project.project_id, snapshot); + const creation = this.snapshotService.create(this.controller, this.project.project_id, snapshot); const progress = this.progressDialogService.open(); diff --git a/src/app/components/system-status/status-info/status-info.component.ts b/src/app/components/system-status/status-info/status-info.component.ts index 04d0fc64..71abe6ab 100644 --- a/src/app/components/system-status/status-info/status-info.component.ts +++ b/src/app/components/system-status/status-info/status-info.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ComputeStatistics } from '../../../models/computeStatistics'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { ComputeService } from '../../../services/compute.service'; -import { ServerService } from '../../../services/server.service'; +import { ControllerService } from '../../../services/controller.service'; import { ToasterService } from '../../../services/toaster.service'; @Component({ @@ -12,25 +12,25 @@ import { ToasterService } from '../../../services/toaster.service'; styleUrls: ['./status-info.component.scss'], }) export class StatusInfoComponent implements OnInit { - public serverId: string = ''; + public controllerId: string = ''; public computeStatistics: ComputeStatistics[] = []; public connectionFailed: boolean; constructor( private route: ActivatedRoute, private computeService: ComputeService, - private serverService: ServerService, + private controllerService: ControllerService, private toasterService: ToasterService ) {} ngOnInit() { - this.serverId = this.route.snapshot.paramMap.get('server_id'); + this.controllerId = this.route.snapshot.paramMap.get('controller_id'); this.getStatistics(); } getStatistics() { - this.serverService.get(Number(this.serverId)).then((server: Server) => { - this.computeService.getStatistics(server).subscribe((statistics: ComputeStatistics[]) => { + this.controllerService.get(Number(this.controllerId)).then((controller:Controller ) => { + this.computeService.getStatistics(controller).subscribe((statistics: ComputeStatistics[]) => { this.computeStatistics = statistics; setTimeout(() => { this.getStatistics(); diff --git a/src/app/components/system-status/system-status.component.ts b/src/app/components/system-status/system-status.component.ts index 0b476298..9b1ab80c 100644 --- a/src/app/components/system-status/system-status.component.ts +++ b/src/app/components/system-status/system-status.component.ts @@ -7,11 +7,11 @@ import { ActivatedRoute } from '@angular/router'; styleUrls: ['./system-status.component.scss'], }) export class SystemStatusComponent 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/template/template-list-dialog/template-list-dialog.component.html b/src/app/components/template/template-list-dialog/template-list-dialog.component.html index 2f057fa4..c921ff2a 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.html +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.html @@ -5,7 +5,7 @@ class="top-button" color="accent" (click)="onNoClick()" - routerLink="/server/{{ server?.id }}/preferences" + routerLink="/controller/{{ controller?.id }}/preferences" > Go to template preferences @@ -55,8 +55,8 @@ /> - - + + {{ type }} diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.spec.ts b/src/app/components/template/template-list-dialog/template-list-dialog.component.spec.ts index 16f09c2e..204caafa 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.spec.ts +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.spec.ts @@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { RouterTestingModule } from '@angular/router/testing'; -import { HttpServer } from 'app/services/http-server.service'; -import { MockedServerService } from 'app/services/server.service.spec'; +import { HttpController } from '../../../services/http-controller.service'; +import { MockedControllerService } from 'app/services/controller.service.spec'; import { TemplateMocksService } from 'app/services/template-mocks.service'; import { TemplateService } from 'app/services/template.service'; import { ToasterService } from 'app/services/toaster.service'; @@ -28,7 +28,7 @@ describe('TemplateListDialogComponent', () => { { provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: {} }, { provide: NonNegativeValidator, useValue: {} }, - HttpServer, + HttpController, HttpClient ] }).compileComponents(); diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts index a6347fb4..cc64fb9d 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts @@ -5,7 +5,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { BehaviorSubject, merge, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Project } from '../../../models/project'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; import { Template } from '../../../models/template'; import { TemplateService } from '../../../services/template.service'; import { ToasterService } from '../../../services/toaster.service'; @@ -17,7 +17,7 @@ import { NonNegativeValidator } from '../../../validators/non-negative-validator styleUrls: ['./template-list-dialog.component.scss'], }) export class TemplateListDialogComponent implements OnInit { - server: Server; + controller:Controller ; project: Project; templateTypes: string[] = [ 'cloud', @@ -39,7 +39,7 @@ export class TemplateListDialogComponent implements OnInit { selectedTemplate: Template; searchText: string = ''; - nodeServers: string[] = ['local', 'vm']; + nodeControllers: string[] = ['local', 'vm']; constructor( public dialogRef: MatDialogRef, @@ -49,7 +49,7 @@ export class TemplateListDialogComponent implements OnInit { private toasterService: ToasterService, private nonNegativeValidator: NonNegativeValidator ) { - this.server = data['server']; + this.controller = data['controller']; this.project = data['project']; this.configurationForm = this.formBuilder.group({ numberOfNodes: new FormControl(1, [ Validators.compose([Validators.required, nonNegativeValidator.get])]), @@ -61,7 +61,7 @@ export class TemplateListDialogComponent implements OnInit { } ngOnInit() { - this.templateService.list(this.server).subscribe((listOfTemplates: Template[]) => { + this.templateService.list(this.controller).subscribe((listOfTemplates: Template[]) => { this.filteredTemplates = listOfTemplates; this.templates = listOfTemplates; }); @@ -108,7 +108,7 @@ export class TemplateListDialogComponent implements OnInit { } else { let event: NodeAddedEvent = { template: this.selectedTemplate, - server: this.selectedTemplate.compute_id, + controller: this.selectedTemplate.compute_id, // name: this.configurationForm.get('name').value, numberOfNodes: this.configurationForm.get('numberOfNodes').value, x: x, @@ -122,7 +122,7 @@ export class TemplateListDialogComponent implements OnInit { export interface NodeAddedEvent { template: Template; - server: string; + controller: string; name?: string; numberOfNodes: number; x: number; @@ -136,8 +136,8 @@ export class TemplateDatabase { return this.dataChange.value; } - constructor(private server: Server, private templateService: TemplateService) { - this.templateService.list(this.server).subscribe((templates) => { + constructor(private controller:Controller , private templateService: TemplateService) { + this.templateService.list(this.controller).subscribe((templates) => { this.dataChange.next(templates); }); } diff --git a/src/app/components/template/template.component.spec.ts b/src/app/components/template/template.component.spec.ts index f7e6c34a..9b3b4d5a 100644 --- a/src/app/components/template/template.component.spec.ts +++ b/src/app/components/template/template.component.spec.ts @@ -5,7 +5,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; import { Context } from 'app/cartography/models/context'; -import { HttpServer, ServerErrorHandler } from 'app/services/http-server.service'; +import { HttpController, ControllerErrorHandler } from 'app/services/http-controller.service'; import { MapScaleService } from 'app/services/mapScale.service'; import { SymbolService } from 'app/services/symbol.service'; import { TemplateService } from 'app/services/template.service'; @@ -24,11 +24,11 @@ describe('TemplateComponent', () => { MatDialog, Overlay, TemplateService, - HttpServer, + HttpController, MapScaleService, HttpClient, HttpHandler, - ServerErrorHandler, + ControllerErrorHandler, Context, { provide: SymbolService, useClass: mockedSymbolService }, ], diff --git a/src/app/components/template/template.component.ts b/src/app/components/template/template.component.ts index abd19ff1..a7e1bf95 100644 --- a/src/app/components/template/template.component.ts +++ b/src/app/components/template/template.component.ts @@ -4,7 +4,7 @@ import { MatDialog } from '@angular/material/dialog'; import { ThemeService } from '../../services/theme.service'; import { Subscription } from 'rxjs'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { Template } from '../../models/template'; import { MapScaleService } from '../../services/mapScale.service'; import { SymbolService } from '../../services/symbol.service'; @@ -18,7 +18,7 @@ import { DomSanitizer } from '@angular/platform-browser'; styleUrls: ['./template.component.scss'], }) export class TemplateComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Output() onNodeCreation = new EventEmitter(); overlay; @@ -67,12 +67,12 @@ export class TemplateComponent implements OnInit, OnDestroy { this.templates.push(template); }); - this.templateService.list(this.server).subscribe((listOfTemplates: Template[]) => { + this.templateService.list(this.controller).subscribe((listOfTemplates: Template[]) => { this.filteredTemplates = listOfTemplates; this.sortTemplates(); this.templates = listOfTemplates; }); - this.symbolService.list(this.server); + this.symbolService.list(this.controller); if (this.themeService.getActualTheme() === 'light') this.isLightThemeEnabled = true; this.themeSubscription = this.themeService.themeChanged.subscribe((value: string) => { if (value === 'light-theme') this.isLightThemeEnabled = true; @@ -120,13 +120,13 @@ export class TemplateComponent implements OnInit, OnDestroy { } dragEnd(ev, template: Template) { - this.symbolService.raw(this.server, template.symbol.substring(1)).subscribe((symbolSvg: string) => { + this.symbolService.raw(this.controller, template.symbol.substring(1)).subscribe((symbolSvg: string) => { let width = +symbolSvg.split('width="')[1].split('"')[0] ? +symbolSvg.split('width="')[1].split('"')[0] : 0; let scale = this.scaleService.getScale(); let nodeAddedEvent: NodeAddedEvent = { template: template, - server: 'local', + controller: 'local', numberOfNodes: 1, x: (this.startX + ev.x - this.project.scene_width / 2 - width / 2) * scale + window.scrollX, y: (this.startY + ev.y - this.project.scene_height / 2) * scale + window.scrollY, @@ -139,7 +139,7 @@ export class TemplateComponent implements OnInit, OnDestroy { const dialogRef = this.dialog.open(TemplateListDialogComponent, { width: '600px', data: { - server: this.server, + controller: this.controller, project: this.project, }, autoFocus: false, @@ -154,7 +154,7 @@ export class TemplateComponent implements OnInit, OnDestroy { } getImageSourceForTemplate(template: Template) { - return this.symbolService.getSymbolFromTemplate(this.server, template); + return this.symbolService.getSymbolFromTemplate(this.controller, template); // let symbol = this.symbolService.getSymbolFromTemplate(template); // if (symbol) return this.domSanitizer.bypassSecurityTrustUrl(`data:image/svg+xml;base64,${btoa(symbol.raw)}`); // return this.domSanitizer.bypassSecurityTrustUrl('data:image/svg+xml;base64,'); diff --git a/src/app/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html index 652d5deb..d84c7df4 100644 --- a/src/app/components/topology-summary/topology-summary.component.html +++ b/src/app/components/topology-summary/topology-summary.component.html @@ -70,9 +70,9 @@ - +
-
+
@@ -87,7 +87,7 @@ {{ compute.host }}
- {{ server.location }} + {{ controller.location }}
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index 4cef7500..ce823e5c 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -61,7 +61,7 @@ mat-tab-group { scrollbar-width: thin; } -.summaryContentServers { +.summaryContentComputes { max-height: 350px; overflow: auto; scrollbar-color: darkgrey #263238; diff --git a/src/app/components/topology-summary/topology-summary.component.spec.ts b/src/app/components/topology-summary/topology-summary.component.spec.ts index c8f099cc..0df56648 100644 --- a/src/app/components/topology-summary/topology-summary.component.spec.ts +++ b/src/app/components/topology-summary/topology-summary.component.spec.ts @@ -12,7 +12,7 @@ import { LinksDataSource } from '../../cartography/datasources/links-datasource' import { NodesDataSource } from '../../cartography/datasources/nodes-datasource'; import { Node } from '../../cartography/models/node'; import { Project } from '../../models/project'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ComputeService } from '../../services/compute.service'; import { ProjectService } from '../../services/project.service'; import { MockedProjectService } from '../../services/project.service.spec'; @@ -20,7 +20,7 @@ import { MockedLinksDataSource, MockedNodesDataSource } from '../project-map/pro import { TopologySummaryComponent } from './topology-summary.component'; export class MockedComputeService { - getComputes(server: Server) { + getComputes(controller:Controller ) { return of([]); } } diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index 1a98464a..f5e783c4 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -7,7 +7,7 @@ import { Node } from '../../cartography/models/node'; import { Compute } from '../../models/compute'; import { Project } from '../../models/project'; import { ProjectStatistics } from '../../models/project-statistics'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { ComputeService } from '../../services/compute.service'; import { ProjectService } from '../../services/project.service'; import { ThemeService } from '../../services/theme.service'; @@ -19,7 +19,7 @@ import { ThemeService } from '../../services/theme.service'; changeDetection: ChangeDetectionStrategy.Default, }) export class TopologySummaryComponent implements OnInit, OnDestroy { - @Input() server: Server; + @Input() controller:Controller ; @Input() project: Project; @Output() closeTopologySummary = new EventEmitter(); @@ -59,7 +59,7 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { this.nodes = nodes; this.nodes.forEach((n) => { if (n.console_host === '0.0.0.0' || n.console_host === '0:0:0:0:0:0:0:0' || n.console_host === '::') { - n.console_host = this.server.host; + n.console_host = this.controller.host; } }); if (this.sortingOrder === 'asc') { @@ -70,11 +70,11 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { }) ); - this.projectService.getStatistics(this.server, this.project.project_id).subscribe((stats) => { + this.projectService.getStatistics(this.controller, this.project.project_id).subscribe((stats) => { this.projectsStatistics = stats; }); - this.computeService.getComputes(this.server).subscribe((computes) => { + this.computeService.getComputes(this.controller).subscribe((computes) => { this.computes = computes; }); diff --git a/src/app/components/user-management/ConfirmPasswordValidator.ts b/src/app/components/user-management/ConfirmPasswordValidator.ts new file mode 100644 index 00000000..1e26eac3 --- /dev/null +++ b/src/app/components/user-management/ConfirmPasswordValidator.ts @@ -0,0 +1,10 @@ +import {AbstractControl, FormGroup, ValidationErrors, ValidatorFn} from '@angular/forms'; + + +export function matchingPassword(control: AbstractControl) : ValidationErrors | null { + if (control.get('password').value !== control.get('confirmPassword').value) { + control.get('confirmPassword').setErrors({confirmPasswordMatch: true}); + return; + } + return; +} diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html new file mode 100644 index 00000000..5b2c0391 --- /dev/null +++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html @@ -0,0 +1,70 @@ +

Create new user

+
+ + + Username is required + Username is incorrect + User with this username exists + + + + + + + Email is required + Email is invalid + + + + + + A password between 6 and 100 characters is required. + + + + Password and Confirm password must be the same. + + + + Is active + +
Add user to groups :
+ + + Groups + + + + {{group.name}} + + + + +
+
+
+
{{group.name}}
+ delete +
+
+
+ + +
+ + +
+
diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss new file mode 100644 index 00000000..41142daf --- /dev/null +++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss @@ -0,0 +1,22 @@ +.input-field { + width: 100%; +} + + +.button-div { + float: right; +} + +.groupList { + display: flex; + margin: 10px; + justify-content: space-between; + flex: 1 1 auto +} + +.groups { + display: flex; + height: 180px; + overflow: auto; + flex-direction: column; +} diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.spec.ts b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts new file mode 100644 index 00000000..4a412455 --- /dev/null +++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts @@ -0,0 +1,132 @@ +/* +* 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 {FormControl, FormGroup, Validators} from "@angular/forms"; +import {MatDialogRef} from "@angular/material/dialog"; +import {UserService} from "@services/user.service"; +import {Controller} from "@models/controller"; +import {User} from "@models/users/user"; +import {ToasterService} from "@services/toaster.service"; +import {userNameAsyncValidator} from "@components/user-management/add-user-dialog/userNameAsyncValidator"; +import {userEmailAsyncValidator} from "@components/user-management/add-user-dialog/userEmailAsyncValidator"; +import {BehaviorSubject} from "rxjs"; +import {Group} from "@models/groups/group"; +import {GroupService} from "@services/group.service"; +import {Observable} from "rxjs/Rx"; +import {startWith} from "rxjs/operators"; +import {map} from "rxjs//operators"; +import {matchingPassword} from "@components/user-management/ConfirmPasswordValidator"; + +@Component({ + selector: 'app-add-user-dialog', + templateUrl: './add-user-dialog.component.html', + styleUrls: ['./add-user-dialog.component.scss'] +}) +export class AddUserDialogComponent implements OnInit { + addUserForm: FormGroup; + controller: Controller; + + groups: Group[]; + groupsToAdd: Set = new Set([]); + autocompleteControl = new FormControl(); + filteredGroups: Observable; + + constructor(public dialogRef: MatDialogRef, + public userService: UserService, + private toasterService: ToasterService, + private groupService: GroupService) { } + + ngOnInit(): void { + this.addUserForm = new FormGroup({ + username: new FormControl(null, [ + Validators.required, + Validators.minLength(3), + Validators.pattern("[a-zA-Z0-9_-]+$")], + [userNameAsyncValidator(this.controller, this.userService)]), + full_name: new FormControl(), + email: new FormControl(null, + [Validators.email, Validators.required], + [userEmailAsyncValidator(this.controller, this.userService)]), + password: new FormControl(null, + [Validators.required, Validators.minLength(6), Validators.maxLength(100)]), + confirmPassword: new FormControl(null, + [Validators.minLength(6), Validators.maxLength(100), Validators.required] ), + is_active: new FormControl(true) + },{ + validators: [matchingPassword] + }); + this.groupService.getGroups(this.controller) + .subscribe((groups: Group[]) => { + this.groups = groups; + this.filteredGroups = this.autocompleteControl.valueChanges.pipe( + startWith(''), + map(value => this._filter(value)), + ); + }) + + } + + private _filter(value: string): Group[] { + if (typeof value === 'string') { + const filterValue = value.toLowerCase(); + + return this.groups.filter(option => option.name.toLowerCase().includes(filterValue)); + } + + } + + get form() { + return this.addUserForm.controls; + } + + onCancelClick() { + this.dialogRef.close(); + } + + onAddClick() { + if (!this.addUserForm.valid) { + return; + } + const newUser = this.addUserForm.value; + const toAdd = Array.from(this.groupsToAdd.values()); + this.userService.add(this.controller, newUser) + .subscribe((user: User) => { + this.toasterService.success(`User ${user.username} added`); + toAdd.forEach((group: Group) => { + this.groupService.addMemberToGroup(this.controller, group, user) + .subscribe(() => { + this.toasterService.success(`user ${user.username} was added to group ${group.name}`); + }, + (error) => { + this.toasterService.error(`An error occur while trying to add user ${user.username} to group ${group.name}`); + }) + }) + this.dialogRef.close(); + }, + (error) => { + this.toasterService.error('Cannot create user : ' + error); + }) + } + + deleteGroup(group: Group) { + this.groupsToAdd.delete(group); + } + + selectedGroup(value: any) { + this.groupsToAdd.add(value); + } + + displayFn(value): string { + return value && value.name ? value.name : ''; + } +} diff --git a/src/app/components/user-management/add-user-dialog/userEmailAsyncValidator.ts b/src/app/components/user-management/add-user-dialog/userEmailAsyncValidator.ts new file mode 100644 index 00000000..1d6ff692 --- /dev/null +++ b/src/app/components/user-management/add-user-dialog/userEmailAsyncValidator.ts @@ -0,0 +1,28 @@ +/* +* 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 {Controller} from "../../../models/controller"; +import {UserService} from "../../../services/user.service"; +import {FormControl} from "@angular/forms"; +import {timer} from "rxjs"; +import {map, switchMap} from "rxjs/operators"; + +export const userEmailAsyncValidator = (controller: Controller, userService: UserService, except: string = '') => { + return (control: FormControl) => { + return timer(500).pipe( + switchMap(() => userService.list(controller)), + map((response) => { + return (response.find((n) => n.email === control.value && control.value !== except) ? { emailExists: true } : null); + }) + ); + }; +}; diff --git a/src/app/components/user-management/add-user-dialog/userNameAsyncValidator.ts b/src/app/components/user-management/add-user-dialog/userNameAsyncValidator.ts new file mode 100644 index 00000000..72d05bbf --- /dev/null +++ b/src/app/components/user-management/add-user-dialog/userNameAsyncValidator.ts @@ -0,0 +1,28 @@ +/* +* 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 {Controller} from "../../../models/controller"; +import {FormControl} from "@angular/forms"; +import {timer} from "rxjs"; +import {map, switchMap} from "rxjs/operators"; +import {UserService} from "../../../services/user.service"; + +export const userNameAsyncValidator = (controller: Controller, userService: UserService, except: string = '') => { + return (control: FormControl) => { + return timer(500).pipe( + switchMap(() => userService.list(controller)), + map((response) => { + return (response.find((n) => n.username === control.value && control.value !== except) ? { userExists: true } : null); + }) + ); + }; +}; diff --git a/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.html b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.html new file mode 100644 index 00000000..d15b5b40 --- /dev/null +++ b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.html @@ -0,0 +1,10 @@ +

Are you sure you want to delete the following users ?

+
    +
  • {{ user.username }} {{ user.full_name ? '- ' + user.full_name : '' }}
  • +
+
+ + +
diff --git a/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.scss b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.scss new file mode 100644 index 00000000..59c53205 --- /dev/null +++ b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.scss @@ -0,0 +1,7 @@ +.button-div { + float: right; +} + +ul { + list-style-type: none; +} diff --git a/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.spec.ts b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.ts b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.component.ts new file mode 100644 index 00000000..4b7f931e --- /dev/null +++ b/src/app/components/user-management/delete-user-dialog/delete-user-dialog.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, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {User} from "@models/users/user"; +import {UserService} from "@services/user.service"; + +@Component({ + selector: 'app-delete-user-dialog', + templateUrl: './delete-user-dialog.component.html', + styleUrls: ['./delete-user-dialog.component.scss'] +}) +export class DeleteUserDialogComponent implements OnInit { + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { users: User[] }) { } + + ngOnInit(): void { + } + + onCancel() { + this.dialogRef.close(); + } + + onDelete() { + this.dialogRef.close(true); + } +} diff --git a/src/app/components/user-management/edit-user-dialog/edit-user-dialog.component.ts b/src/app/components/user-management/edit-user-dialog/edit-user-dialog.component.ts new file mode 100644 index 00000000..92b8cbf4 --- /dev/null +++ b/src/app/components/user-management/edit-user-dialog/edit-user-dialog.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, Inject, OnInit} from '@angular/core'; +import {FormControl, FormGroup, Validators} from "@angular/forms"; +import {Controller} from "@models/controller"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {UserService} from "@services/user.service"; +import {ToasterService} from "@services/toaster.service"; +import {userNameAsyncValidator} from "@components/user-management/add-user-dialog/userNameAsyncValidator"; +import {userEmailAsyncValidator} from "@components/user-management/add-user-dialog/userEmailAsyncValidator"; +import {User} from "@models/users/user"; + +@Component({ + selector: 'app-edit-user-dialog', + templateUrl: './edit-user-dialog.component.html', + styleUrls: ['./edit-user-dialog.component.scss'] +}) +export class EditUserDialogComponent implements OnInit { + + editUserForm: FormGroup; + + constructor(public dialogRef: MatDialogRef, + public userService: UserService, + private toasterService: ToasterService, + @Inject(MAT_DIALOG_DATA) public data: { user: User, controller: Controller }) {} + + ngOnInit(): void { + this.editUserForm = new FormGroup({ + username: new FormControl(this.data.user.username, [ + Validators.required, + Validators.minLength(3), + Validators.pattern("[a-zA-Z0-9_-]+$")], + [userNameAsyncValidator(this.data.controller, this.userService, this.data.user.username)]), + full_name: new FormControl(this.data.user.full_name), + email: new FormControl(this.data.user.email, + [Validators.email, Validators.required], + [userEmailAsyncValidator(this.data.controller, this.userService, this.data.user.email)]), + password: new FormControl(null, + [Validators.minLength(6), Validators.maxLength(100)]), + is_active: new FormControl(this.data.user.is_active) + }); + } + + get form() { + return this.editUserForm.controls; + } + + onCancelClick() { + this.dialogRef.close(); + } + + onEditClick() { + if (!this.editUserForm.valid) { + return; + } + const updatedUser = this.editUserForm.value; + + updatedUser.user_id = this.data.user.user_id; + console.log(updatedUser) + this.userService.update(this.data.controller, updatedUser) + .subscribe((user: User) => { + console.log("Done ", user) + this.toasterService.success(`User ${user.username} updated`); + this.dialogRef.close(); + }, + (error) => { + this.toasterService.error('Cannot update user : ' + error); + }) + } + +} diff --git a/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.html b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.html new file mode 100644 index 00000000..f61f5fa5 --- /dev/null +++ b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.html @@ -0,0 +1,25 @@ +

Change password for user :

+
+
+ + + Password must be between 6 and 100 characters. + + + + + Password and Confirm password must be the same. + + + +
+ + +
+
+
diff --git a/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.scss b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.scss new file mode 100644 index 00000000..a64b61ba --- /dev/null +++ b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.scss @@ -0,0 +1,7 @@ +.input-field { + width: 100%; +} + +.button-div { + float: right; +} diff --git a/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.spec.ts b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.ts b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.ts new file mode 100644 index 00000000..7a16fdd9 --- /dev/null +++ b/src/app/components/user-management/user-detail/change-user-password/change-user-password.component.ts @@ -0,0 +1,67 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from "@angular/forms"; +import {User} from "@models/users/user"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {UserService} from "@services/user.service"; +import {Controller} from "@models/controller"; +import {ToasterService} from "@services/toaster.service"; +import {matchingPassword} from "@components/user-management/ConfirmPasswordValidator"; + +@Component({ + selector: 'app-change-user-password', + templateUrl: './change-user-password.component.html', + styleUrls: ['./change-user-password.component.scss'] +}) +export class ChangeUserPasswordComponent implements OnInit { + + editPasswordForm: FormGroup; + user: User; + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { user: User, controller: Controller }, + private userService: UserService, + private toasterService: ToasterService) { } + + ngOnInit(): void { + this.user = this.data.user; + this.editPasswordForm = new FormGroup({ + password: new FormControl(null, + [Validators.minLength(6), Validators.maxLength(100), Validators.required] ), + confirmPassword: new FormControl(null, + [Validators.minLength(6), Validators.maxLength(100), Validators.required] ), + },{ + validators: [matchingPassword] + }) + } + + get passwordForm() { + return this.editPasswordForm.controls; + } + + + onCancel() { + this.dialogRef.close(); + } + + onPasswordSave() { + if (!this.editPasswordForm.valid) { + return; + } + + const updatedUser = {}; + updatedUser['password'] = this.editPasswordForm.get('password').value; + updatedUser['user_id'] = this.user.user_id; + + console.log(updatedUser); + + this.userService.update(this.data.controller, updatedUser) + .subscribe((user: User) => { + this.toasterService.success(`User ${user.username} password updated`); + this.editPasswordForm.reset(); + this.dialogRef.close(true); + }, + (error) => { + this.toasterService.error('Cannot update password for user : ' + error); + }) + } +} diff --git a/src/app/components/user-management/user-detail/user-detail.component.html b/src/app/components/user-management/user-detail/user-detail.component.html new file mode 100644 index 00000000..f7b8a4de --- /dev/null +++ b/src/app/components/user-management/user-detail/user-detail.component.html @@ -0,0 +1,103 @@ +
+
+
+ +

User Details

+
+
+
+ + +
+
+ + + Username is required + + Username is incorrect + + User with this username exists + + + + + + + + Email is required + + Email is invalid + + User with this email exists + + + + Is active +
+ Is Superadmin +
+ +
+ +
+
+ + + +
+
Creation date: {{user.created_at}}
+
Last update Date: {{user.updated_at}}
+
Last login: {{user.last_login}}
+
UUID: {{user.user_id}}
+
+
+ +
+ +
+ +
+
+ +
+ +
+ + + +
+
+ +
+
+ + diff --git a/src/app/components/user-management/user-detail/user-detail.component.scss b/src/app/components/user-management/user-detail/user-detail.component.scss new file mode 100644 index 00000000..a64b61ba --- /dev/null +++ b/src/app/components/user-management/user-detail/user-detail.component.scss @@ -0,0 +1,7 @@ +.input-field { + width: 100%; +} + +.button-div { + float: right; +} diff --git a/src/app/components/user-management/user-detail/user-detail.component.spec.ts b/src/app/components/user-management/user-detail/user-detail.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/user-detail/user-detail.component.ts b/src/app/components/user-management/user-detail/user-detail.component.ts new file mode 100644 index 00000000..ffcd9675 --- /dev/null +++ b/src/app/components/user-management/user-detail/user-detail.component.ts @@ -0,0 +1,110 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {FormControl, FormGroup, Validators} from "@angular/forms"; +import {Group} from "@models/groups/group"; +import {UserService} from "@services/user.service"; +import {ToasterService} from "@services/toaster.service"; +import {User} from "@models/users/user"; +import {Controller} from "@models/controller"; +import {userNameAsyncValidator} from "@components/user-management/add-user-dialog/userNameAsyncValidator"; +import {userEmailAsyncValidator} from "@components/user-management/add-user-dialog/userEmailAsyncValidator"; +import {ActivatedRoute, Router} from "@angular/router"; +import {Permission} from "@models/api/permission"; +import {Role} from "@models/api/role"; +import {AddUserDialogComponent} from "@components/user-management/add-user-dialog/add-user-dialog.component"; +import {MatDialog} from "@angular/material/dialog"; +import {ChangeUserPasswordComponent} from "@components/user-management/user-detail/change-user-password/change-user-password.component"; +import {RemoveToGroupDialogComponent} from "@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component"; + +@Component({ + selector: 'app-user-detail', + templateUrl: './user-detail.component.html', + styleUrls: ['./user-detail.component.scss'] +}) +export class UserDetailComponent implements OnInit { + + editUserForm: FormGroup; + groups: Group[]; + user: User; + controller: Controller; + user_id: string; + permissions: Permission[]; + changingPassword: boolean = false; + + constructor(public userService: UserService, + private toasterService: ToasterService, + private route: ActivatedRoute, + private router: Router, + public dialog: MatDialog) { + + } + + ngOnInit(): void { + this.controller = this.route.snapshot.data['controller']; + if (!this.controller) this.router.navigate(['/controllers']); + + this.route.data.subscribe((d: { controller: Controller; user: User, groups: Group[], permissions: Permission[]}) => { + this.user = d.user; + this.user_id = this.user.user_id; + this.groups = d.groups; + this.permissions = d.permissions; + this.initForm(); + }); + + } + + initForm() { + this.editUserForm = new FormGroup({ + username: new FormControl(this.user.username, [ + Validators.required, + Validators.minLength(3), + Validators.pattern("[a-zA-Z0-9_-]+$")], + [userNameAsyncValidator(this.controller, this.userService, this.user.username)]), + full_name: new FormControl(this.user.full_name), + email: new FormControl(this.user.email, + [Validators.email, Validators.required], + [userEmailAsyncValidator(this.controller, this.userService, this.user.email)]), + is_active: new FormControl(this.user.is_active) + }); + } + + get form() { + return this.editUserForm.controls; + } + + onEditClick() { + if (!this.editUserForm.valid) { + return; + } + + const updatedUser = this.getUpdatedValues(); + updatedUser['user_id'] = this.user.user_id; + + this.userService.update(this.controller, updatedUser) + .subscribe((user: User) => { + this.toasterService.success(`User ${user.username} updated`); + }, + (error) => { + this.toasterService.error('Cannot update user : ' + error); + }) + } + + getUpdatedValues() { + let dirtyValues = {}; + + Object.keys(this.editUserForm.controls) + .forEach(key => { + const currentControl = this.editUserForm.get(key); + + if (currentControl.dirty && currentControl.value !== this.user[key]) { + dirtyValues[key] = currentControl.value; + } + }); + + return dirtyValues; + } + + onChangePassword() { + this.dialog.open(ChangeUserPasswordComponent, + {width: '400px', height: '300px', data: {user: this.user, controller: this.controller}}); + } +} diff --git a/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.html b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.html new file mode 100644 index 00000000..b72b7b5b --- /dev/null +++ b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.html @@ -0,0 +1,16 @@ +
+ +
+ Edit {{user.username}} role permissions +
+
+ diff --git a/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.scss b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.spec.ts b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.ts b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.ts new file mode 100644 index 00000000..f037c0c4 --- /dev/null +++ b/src/app/components/user-management/user-detail/user-permissions/user-permissions.component.ts @@ -0,0 +1,64 @@ +import { Component, OnInit } from '@angular/core'; +import {Controller} from "@models/controller"; +import {Role} from "@models/api/role"; +import {Permission} from "@models/api/permission"; +import {ActivatedRoute, Router} from "@angular/router"; +import {MatDialog} from "@angular/material/dialog"; +import {ToasterService} from "@services/toaster.service"; +import {RoleService} from "@services/role.service"; +import {forkJoin} from "rxjs"; +import {Observable} from "rxjs/Rx"; +import {UserService} from "@services/user.service"; +import {User} from "@models/users/user"; +import {HttpErrorResponse} from "@angular/common/http"; + +@Component({ + selector: 'app-user-permissions', + templateUrl: './user-permissions.component.html', + styleUrls: ['./user-permissions.component.scss'] +}) +export class UserPermissionsComponent implements OnInit { + + controller: Controller; + user: User; + userPermissions: Permission[]; + permissions: Permission[]; + + constructor(private route: ActivatedRoute, + private dialog: MatDialog, + private toastService: ToasterService, + private router: Router, + private userService: UserService) { + this.route.data.subscribe((data: { controller: Controller, user: User, userPermissions: Permission[], permissions: Permission[] }) => { + this.controller = data.controller; + this.user = data.user; + this.userPermissions = data.userPermissions; + this.permissions = data.permissions; + }); + } + + ngOnInit(): void { + } + + updatePermissions(toUpdate) { + const {add, remove} = toUpdate; + const obs: Observable[] = []; + add.forEach((permission: Permission) => { + obs.push(this.userService.addPermission(this.controller, this.user.user_id, permission)); + }); + remove.forEach((permission: Permission) => { + obs.push(this.userService.removePermission(this.controller, this.user.user_id, permission)); + }); + + forkJoin(obs) + .subscribe(() => { + this.toastService.success(`permissions updated`); + this.router.navigate(['/controller', this.controller.id, 'management', 'users', this.user.user_id]); + }, + (error: HttpErrorResponse) => { + this.toastService.error(`${error.message} + ${error.error.message}`); + }); + } + +} diff --git a/src/app/components/user-management/user-management.component.html b/src/app/components/user-management/user-management.component.html index e453d528..5a98e7db 100644 --- a/src/app/components/user-management/user-management.component.html +++ b/src/app/components/user-management/user-management.component.html @@ -1,3 +1,98 @@ -

- user-management works! -

+
+
+
+

User Management

+ + +
+
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + Username + + {{ row.username }} + + + + Full Name + +
{{ row.full_name }}
+
+
+ + Mail + +
{{ row.email }}
+
+
+ + Active + {{row.is_active}} + + + Last Login + {{row.last_login}} + + + Last Update + {{row.updated_at ? row.updated_at : row.created_at}} + + + + + + + + + + + +
+ + + +
+
+
+ +
+ +
+
diff --git a/src/app/components/user-management/user-management.component.scss b/src/app/components/user-management/user-management.component.scss index e69de29b..6b41b9a7 100644 --- a/src/app/components/user-management/user-management.component.scss +++ b/src/app/components/user-management/user-management.component.scss @@ -0,0 +1,42 @@ +.add-button { + height: 40px; + width: 160px; + margin: 20px; +} + +.full-width { + width: 940px; + margin-left: -470px; + left: 50%; +} + +.small-col { + flex-grow: 0.3; +} + +.active-col { + flex-grow: 0.5; +} + +.overflow-col { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + padding-right: 5px; +} + +.custom-tooltip { + font-size:100px; + white-space: pre-line; +} + +.loader { + position: absolute; + margin: auto; + height: 175px; + bottom: 0; + left: 0; + right: 0; + top: 0; + width: 175px; +} diff --git a/src/app/components/user-management/user-management.component.spec.ts b/src/app/components/user-management/user-management.component.spec.ts index c5c67f32..e69de29b 100644 --- a/src/app/components/user-management/user-management.component.spec.ts +++ b/src/app/components/user-management/user-management.component.spec.ts @@ -1,28 +0,0 @@ -/* tslint:disable:no-unused-variable */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; - -import { UserManagementComponent } from './user-management.component'; - -describe('UserManagementComponent', () => { - let component: UserManagementComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [UserManagementComponent] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(UserManagementComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/components/user-management/user-management.component.ts b/src/app/components/user-management/user-management.component.ts index a374bb28..19d47277 100644 --- a/src/app/components/user-management/user-management.component.ts +++ b/src/app/components/user-management/user-management.component.ts @@ -1,4 +1,30 @@ -import { Component, OnInit } from '@angular/core'; +/* +* 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 {Controller} from "@models/controller"; +import {MatSort} from "@angular/material/sort"; +import {UserService} from "@services/user.service"; +import {ProgressService} from "../../common/progress/progress.service"; +import {User} from "@models/users/user"; +import {SelectionModel} from "@angular/cdk/collections"; +import {AddUserDialogComponent} from "@components/user-management/add-user-dialog/add-user-dialog.component"; +import {MatDialog} from "@angular/material/dialog"; +import {DeleteUserDialogComponent} from "@components/user-management/delete-user-dialog/delete-user-dialog.component"; +import {ToasterService} from "@services/toaster.service"; +import {MatPaginator} from "@angular/material/paginator"; +import {MatTableDataSource} from "@angular/material/table"; +import {ControllerService} from "@services/controller.service"; @Component({ selector: 'app-user-management', @@ -6,10 +32,124 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./user-management.component.scss'] }) export class UserManagementComponent implements OnInit { + controller: Controller; + dataSource = new MatTableDataSource(); + displayedColumns = ['select', 'username', 'full_name', 'email', 'is_active', 'last_login', 'updated_at', 'delete']; + selection = new SelectionModel(true, []); + searchText = ''; - constructor() { } + @ViewChildren('usersPaginator') usersPaginator: QueryList; + @ViewChildren('usersSort') usersSort: QueryList; + isReady = false; + + constructor( + private route: ActivatedRoute, + private router: Router, + private userService: UserService, + private progressService: ProgressService, + private controllerService: ControllerService, + public dialog: MatDialog, + private toasterService: ToasterService) { } ngOnInit() { + const controllerId = this.route.parent.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.controller = controller; + this.refresh(); + }); } + ngAfterViewInit() { + this.usersPaginator.changes.subscribe((comps: QueryList ) => + { + this.dataSource.paginator = comps.first; + }); + this.usersSort.changes.subscribe((comps: QueryList) => { + this.dataSource.sort = comps.first; + }) + + this.dataSource.sortingDataAccessor = (item, property) => { + switch (property) { + case 'username': + case 'full_name': + case 'email': + return item[property] ? item[property].toLowerCase() : ''; + default: + return item[property]; + } + }; + } + + refresh() { + this.userService.list(this.controller).subscribe( + (users: User[]) => { + this.isReady = true; + this.dataSource.data = users; + }, + (error) => { + this.progressService.setError(error); + } + ); + } + + addUser() { + const dialogRef = this.dialog.open(AddUserDialogComponent, { + width: '400px', + autoFocus: false, + disableClose: true, + }); + let instance = dialogRef.componentInstance; + instance.controller = this.controller; + dialogRef.afterClosed().subscribe(() => this.refresh()); + } + + onDelete(user: User) { + this.dialog + .open(DeleteUserDialogComponent, {width: '500px', data: {users: [user]}}) + .afterClosed() + .subscribe((isDeletedConfirm) => { + if (isDeletedConfirm) { + this.userService.delete(this.controller, user.user_id) + .subscribe(() => { + this.refresh() + }, (error) => { + this.toasterService.error(`An error occur while trying to delete user ${user.username}`); + }); + } + }); + } + + + + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + deleteMultiple() { + this.dialog + .open(DeleteUserDialogComponent, {width: '500px', data: {users: this.selection.selected}}) + .afterClosed() + .subscribe((isDeletedConfirm) => { + if (isDeletedConfirm) { + this.selection.selected.forEach((user: User) => { + this.userService.delete(this.controller, user.user_id) + .subscribe(() => { + this.refresh() + }, (error) => { + this.toasterService.error(`An error occur while trying to delete user ${user.username}`); + }); + }) + this.selection.clear(); + } + }); + + } } diff --git a/src/app/components/users/logged-user/logged-user.component.ts b/src/app/components/users/logged-user/logged-user.component.ts index e8b79ab4..56c7f42f 100644 --- a/src/app/components/users/logged-user/logged-user.component.ts +++ b/src/app/components/users/logged-user/logged-user.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { ServerService } from '../../../services/server.service'; +import { ControllerService } from '../../../services/controller.service'; import { UserService } from '../../../services/user.service'; import { ToasterService } from '../../../services/toaster.service'; import { User } from '../../../models/users/user'; -import { Server } from '../../../models/server'; +import{ Controller } from '../../../models/controller'; @Component({ selector: 'app-logged-user', @@ -13,20 +13,20 @@ import { Server } from '../../../models/server'; }) export class LoggedUserComponent implements OnInit { public user: User; - public server: Server; + public controller:Controller ; constructor( private route: ActivatedRoute, - private serverService: ServerService, + private controllerService: ControllerService, private userService: UserService, private toasterService: ToasterService ) {} ngOnInit() { - let serverId = this.route.snapshot.paramMap.get('server_id'); - this.serverService.get(+serverId).then((server: Server) => { - this.server = server; - this.userService.getInformationAboutLoggedUser(server).subscribe((response: any) => { + let controllerId = this.route.snapshot.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller:Controller ) => { + this.controller = controller; + this.userService.getInformationAboutLoggedUser(controller).subscribe((response: any) => { this.user = response; }); }); @@ -38,7 +38,7 @@ export class LoggedUserComponent implements OnInit { selBox.style.left = '0'; selBox.style.top = '0'; selBox.style.opacity = '0'; - selBox.value = this.server.authToken; + selBox.value = this.controller.authToken; document.body.appendChild(selBox); selBox.focus(); selBox.select(); diff --git a/src/app/components/web-console-full-window/web-console-full-window.component.ts b/src/app/components/web-console-full-window/web-console-full-window.component.ts index 47479203..ab490bbf 100644 --- a/src/app/components/web-console-full-window/web-console-full-window.component.ts +++ b/src/app/components/web-console-full-window/web-console-full-window.component.ts @@ -6,10 +6,10 @@ import { Terminal } from 'xterm'; import { AttachAddon } from 'xterm-addon-attach'; import { FitAddon } from 'xterm-addon-fit'; import { Node } from '../../cartography/models/node'; -import { Server } from '../../models/server'; +import{ Controller } from '../../models/controller'; import { NodeService } from '../../services/node.service'; import { NodeConsoleService } from '../../services/nodeConsole.service'; -import { ServerService } from '../../services/server.service'; +import { ControllerService } from '../../services/controller.service'; @Component({ encapsulation: ViewEncapsulation.None, @@ -18,11 +18,11 @@ import { ServerService } from '../../services/server.service'; styleUrls: ['../../../../node_modules/xterm/css/xterm.css'], }) export class WebConsoleFullWindowComponent implements OnInit { - private serverId: string; + private controllerId: string; private projectId: string; private nodeId: string; private subscriptions: Subscription = new Subscription(); - private server: Server; + private controller:Controller ; private node: Node; public term: Terminal = new Terminal(); @@ -32,18 +32,18 @@ export class WebConsoleFullWindowComponent implements OnInit { constructor( private consoleService: NodeConsoleService, - private serverService: ServerService, + private controllerService: ControllerService, private route: ActivatedRoute, private title: Title, private nodeService: NodeService ) {} ngOnInit() { - if (this.serverService.isServiceInitialized) { + if (this.controllerService.isServiceInitialized) { this.getData(); } else { this.subscriptions.add( - this.serverService.serviceInitialized.subscribe((val) => { + this.controllerService.serviceInitialized.subscribe((val) => { if (val) this.getData(); }) ); @@ -51,7 +51,7 @@ export class WebConsoleFullWindowComponent implements OnInit { } getData() { - this.serverId = this.route.snapshot.paramMap.get('server_id'); + this.controllerId = this.route.snapshot.paramMap.get('controller_id'); this.projectId = this.route.snapshot.paramMap.get('project_id'); this.nodeId = this.route.snapshot.paramMap.get('node_id'); @@ -59,9 +59,9 @@ export class WebConsoleFullWindowComponent implements OnInit { this.fitAddon.fit(); }); - this.serverService.get(+this.serverId).then((server: Server) => { - this.server = server; - this.nodeService.getNodeById(this.server, this.projectId, this.nodeId).subscribe((node: Node) => { + this.controllerService.get(+this.controllerId).then((controller:Controller ) => { + this.controller = controller; + this.nodeService.getNodeById(this.controller, this.projectId, this.nodeId).subscribe((node: Node) => { this.node = node; this.title.setTitle(this.node.name); this.openTerminal(); @@ -72,7 +72,7 @@ export class WebConsoleFullWindowComponent implements OnInit { openTerminal() { setTimeout(() => { this.term.open(this.terminal.nativeElement); - 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' + '\r\n'); diff --git a/src/app/filters/authImageFilter.ts b/src/app/filters/authImageFilter.ts index 72f6cbe8..0b7833ac 100644 --- a/src/app/filters/authImageFilter.ts +++ b/src/app/filters/authImageFilter.ts @@ -1,7 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Console } from 'console'; -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 { DomSanitizer } from '@angular/platform-browser'; import { environment } from 'environments/environment'; @@ -11,13 +11,13 @@ import { environment } from 'environments/environment'; export class AuthImageFilter implements PipeTransform { constructor( - private httpServer: HttpServer, + private httpController: HttpController, private domSanitizer: DomSanitizer ) { } - async transform(src: string, server: Server) { + async transform(src: string, controller:Controller ) { let url = src.split(`${environment.current_version}`)[1]; - const imageBlob: Blob = await this.httpServer.getBlob(server, url).toPromise(); + const imageBlob: Blob = await this.httpController.getBlob(controller, url).toPromise(); const reader = new FileReader(); return new Promise((resolve, reject) => { reader.onloadend = () => resolve(this.domSanitizer.bypassSecurityTrustUrl(reader.result as string)); diff --git a/src/app/filters/group-filter.pipe.ts b/src/app/filters/group-filter.pipe.ts new file mode 100644 index 00000000..8bda5a94 --- /dev/null +++ b/src/app/filters/group-filter.pipe.ts @@ -0,0 +1,33 @@ +/* +* 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 {Group} from "../models/groups/group"; +import {MatTableDataSource} from "@angular/material/table"; + +@Pipe({ + name: 'groupFilter' +}) +export class GroupFilterPipe implements PipeTransform { + + transform(groups: MatTableDataSource, searchText: string): MatTableDataSource { + + if (!searchText) { + return groups; + } + + searchText = searchText.trim().toLowerCase(); + groups.filter = searchText; + return groups; + } + +} diff --git a/src/app/filters/user-filter.pipe.ts b/src/app/filters/user-filter.pipe.ts new file mode 100644 index 00000000..fec797e9 --- /dev/null +++ b/src/app/filters/user-filter.pipe.ts @@ -0,0 +1,33 @@ +/* +* 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 {MatTableDataSource} from "@angular/material/table"; + +@Pipe({ + name: 'userFilter' +}) +export class UserFilterPipe implements PipeTransform { + + transform(items: MatTableDataSource, searchText: string) { + if (!items) return []; + if (!searchText) return items; + searchText = searchText.toLowerCase(); + return items.data.filter((item: User) => { + return (item.username && item.username.toLowerCase().includes(searchText)) + || (item.full_name && item.full_name.toLowerCase().includes(searchText)) + || (item.email && item.email.toLowerCase().includes(searchText)); + }); + } + +} diff --git a/src/app/guards/login-guard.ts b/src/app/guards/login-guard.ts index 9be04166..176c847d 100644 --- a/src/app/guards/login-guard.ts +++ b/src/app/guards/login-guard.ts @@ -1,25 +1,25 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { LoginService } from '@services/login.service'; -import { Server } from '../models/server'; -import { ServerService } from '../services/server.service'; +import{ Controller } from '../models/controller'; +import { ControllerService } from '../services/controller.service'; @Injectable() export class LoginGuard implements CanActivate { - constructor(private serverService: ServerService, private loginService: LoginService, private router: Router) {} + constructor(private controllerService: ControllerService, private loginService: LoginService, private router: Router) {} async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { - const server_id = next.paramMap.get('server_id'); - this.loginService.server_id = server_id; - let server = await this.serverService.get(parseInt(server_id, 10)); + const controller_id = next.paramMap.get('controller_id'); + this.loginService.controller_id = controller_id; + let controller = await this.controllerService.get(parseInt(controller_id, 10)); try { - await this.loginService.getLoggedUser(server); + await this.loginService.getLoggedUser(controller); } catch (e) {} - return this.serverService.get(parseInt(server_id, 10)).then((server: Server) => { - if (server.authToken && !server.tokenExpired) { + return this.controllerService.get(parseInt(controller_id, 10)).then((controller:Controller ) => { + if (controller.authToken && !controller.tokenExpired) { return true; } - this.router.navigate(['/server', server.id, 'login'], { queryParams: { returnUrl: state.url } }); + this.router.navigate(['/controller', controller.id, 'login'], { queryParams: { returnUrl: state.url } }); }); } } diff --git a/src/app/interceptors/http.interceptor.ts b/src/app/interceptors/http.interceptor.ts index 0b1ea7b5..52cd60ce 100644 --- a/src/app/interceptors/http.interceptor.ts +++ b/src/app/interceptors/http.interceptor.ts @@ -1,13 +1,13 @@ import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { LoginService } from '@services/login.service'; -import { ServerService } from '@services/server.service'; +import { LoginService } from '../services/login.service'; +import { ControllerService } from '../services/controller.service'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable() export class HttpRequestsInterceptor implements HttpInterceptor { - constructor(private serverService: ServerService, private loginService: LoginService) {} + constructor(private controllerService: ControllerService, private loginService: LoginService) {} intercept(httpRequest: HttpRequest, next: HttpHandler): Observable> { return next.handle(httpRequest).pipe( catchError((err) => { @@ -22,17 +22,17 @@ export class HttpRequestsInterceptor implements HttpInterceptor { async call() { let getCurrentUser = JSON.parse(localStorage.getItem(`isRememberMe`)) ?? null; - const server_id = this.loginService.server_id; - let server = await this.serverService.get(parseInt(server_id, 10)); - server.tokenExpired = true; - await this.serverService.update(server); + const controller_id = this.loginService.controller_id; + let controller = await this.controllerService.get(parseInt(controller_id, 10)); + controller.tokenExpired = true; + await this.controllerService.update(controller); try { if (getCurrentUser && getCurrentUser.isRememberMe) { - let response = await this.loginService.getLoggedUserRefToken(server, getCurrentUser); - server.authToken = response.access_token; - server.tokenExpired = false; - await this.serverService.update(server); - await this.loginService.getLoggedUser(server); + let response = await this.loginService.getLoggedUserRefToken(controller, getCurrentUser); + controller.authToken = response.access_token; + controller.tokenExpired = false; + await this.controllerService.update(controller); + await this.loginService.getLoggedUser(controller); this.reloadCurrentRoute(); } } catch (e) { diff --git a/src/app/layouts/default-layout/default-layout.component.html b/src/app/layouts/default-layout/default-layout.component.html index f5d8c421..0988670a 100644 --- a/src/app/layouts/default-layout/default-layout.component.html +++ b/src/app/layouts/default-layout/default-layout.component.html @@ -2,19 +2,19 @@ - + - - - @@ -35,23 +35,28 @@ settings Settings - - - - @@ -63,4 +68,4 @@ -
GNS3 Web UI © 2021 - v{{ uiVersion }}
+
GNS3 Web UI © 2022 - v{{ uiVersion }}
diff --git a/src/app/layouts/default-layout/default-layout.component.spec.ts b/src/app/layouts/default-layout/default-layout.component.spec.ts index 173c28c6..b22011b0 100644 --- a/src/app/layouts/default-layout/default-layout.component.spec.ts +++ b/src/app/layouts/default-layout/default-layout.component.spec.ts @@ -4,25 +4,25 @@ import { MatMenuModule } from '@angular/material/menu'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatToolbarModule } from '@angular/material/toolbar'; import { RouterTestingModule } from '@angular/router/testing'; -import { ServerService } from '../../services/server.service'; +import { ControllerService } from '../../services/controller.service'; import { ElectronService } from 'ngx-electron'; import { Subject } from 'rxjs'; import { ProgressComponent } from '../../common/progress/progress.component'; import { ProgressService } from '../../common/progress/progress.service'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; -import { ServerManagementService, ServerStateEvent } from '../../services/server-management.service'; +import { ControllerManagementService, ControllerStateEvent } from '../../services/controller-management.service'; import { ToasterService } from '../../services/toaster.service'; import { MockedToasterService } from '../../services/toaster.service.spec'; import { DefaultLayoutComponent } from './default-layout.component'; -import { HttpServer, ServerErrorHandler } from '../../services/http-server.service'; +import { HttpController, ControllerErrorHandler } from '../../services/http-controller.service'; import { HttpClientModule } from '@angular/common/http'; class ElectronServiceMock { public isElectronApp: boolean; } -class MockedServerManagementService { - public serverStatusChanged; +class MockedControllerManagementService { + public controllerStatusChanged; public stopAll() {} } @@ -30,14 +30,14 @@ describe('DefaultLayoutComponent', () => { let component: DefaultLayoutComponent; let fixture: ComponentFixture; let electronServiceMock: ElectronServiceMock; - let serverManagementService = new MockedServerManagementService(); - let serverService: ServerService; - let httpServer: HttpServer; - let errorHandler: ServerErrorHandler; + let controllerManagementService = new MockedControllerManagementService(); + let controllerService: ControllerService; + let httpController: HttpController; + let errorHandler: ControllerErrorHandler; beforeEach(async() => { electronServiceMock = new ElectronServiceMock(); - serverManagementService.serverStatusChanged = new Subject(); + controllerManagementService.controllerStatusChanged = new Subject(); await TestBed.configureTestingModule({ declarations: [DefaultLayoutComponent, ProgressComponent], @@ -48,8 +48,8 @@ describe('DefaultLayoutComponent', () => { useValue: electronServiceMock, }, { - provide: ServerManagementService, - useValue: serverManagementService, + provide: ControllerManagementService, + useValue: controllerManagementService, }, { provide: ToasterService, @@ -59,16 +59,16 @@ describe('DefaultLayoutComponent', () => { provide: RecentlyOpenedProjectService, useClass: RecentlyOpenedProjectService, }, - { provide: ServerService }, - { provide: HttpServer }, - { provide: ServerErrorHandler }, + { provide: ControllerService }, + { provide: HttpController }, + { provide: ControllerErrorHandler }, ProgressService, ], }).compileComponents(); - errorHandler = TestBed.inject(ServerErrorHandler); - httpServer = TestBed.inject(HttpServer); - serverService = TestBed.inject(ServerService); + errorHandler = TestBed.inject(ControllerErrorHandler); + httpController = TestBed.inject(HttpController); + controllerService = TestBed.inject(ControllerService); }); beforeEach(() => { @@ -93,39 +93,39 @@ describe('DefaultLayoutComponent', () => { expect(component.isInstalledSoftwareAvailable).toBeFalsy(); }); - it('should show error when server management service throw event', () => { + it('should show error when controller management service throw event', () => { const toaster: MockedToasterService = TestBed.get(ToasterService); - serverManagementService.serverStatusChanged.next({ + controllerManagementService.controllerStatusChanged.next({ status: 'errored', message: 'Message', }); expect(toaster.errors).toEqual(['Message']); }); - it('should not show error when server management service throw event', () => { + it('should not show error when controller management service throw event', () => { component.ngOnDestroy(); const toaster: MockedToasterService = TestBed.get(ToasterService); - serverManagementService.serverStatusChanged.next({ + controllerManagementService.controllerStatusChanged.next({ status: 'errored', message: 'Message', }); expect(toaster.errors).toEqual([]); }); - describe('auto stopping servers', () => { + describe('auto stopping controllers', () => { let event; beforeEach(() => { event = new Event('onbeforeunload'); }); it('should close window with no action when not in electron', async () => { - component.shouldStopServersOnClosing = false; + component.shouldStopControllersOnClosing = false; const isClosed = await component.onBeforeUnload(event); expect(isClosed).toBeUndefined(); }); - it('should stop all servers and close window', () => { - component.shouldStopServersOnClosing = true; + it('should stop all controllers and close window', () => { + component.shouldStopControllersOnClosing = true; const isClosed = component.onBeforeUnload(event); expect(isClosed).toBeTruthy(); }); diff --git a/src/app/layouts/default-layout/default-layout.component.ts b/src/app/layouts/default-layout/default-layout.component.ts index b4c15303..fbd2fc7e 100644 --- a/src/app/layouts/default-layout/default-layout.component.ts +++ b/src/app/layouts/default-layout/default-layout.component.ts @@ -1,14 +1,15 @@ import { Component, HostListener, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; +import { NavigationEnd } from '@angular/router'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { ControllerService } from '../../services/controller.service'; import { ElectronService } from 'ngx-electron'; import { Subscription } from 'rxjs'; import { ProgressService } from '../../common/progress/progress.service'; -import { Server } from '../../models/server'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; -import { ServerManagementService } from '../../services/server-management.service'; -import { ServerService } from '../../services/server.service'; +import { ControllerManagementService } from '../../services/controller-management.service'; import { ToasterService } from '../../services/toaster.service'; import { version } from './../../version'; +import { Controller } from '../../models/controller'; @Component({ selector: 'app-default-layout', @@ -22,26 +23,32 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy { public isLoginPage = false; public routeSubscription; - serverStatusSubscription: Subscription; - shouldStopServersOnClosing = true; - - recentlyOpenedServerId: string; + controllerStatusSubscription: Subscription; + shouldStopControllersOnClosing = true; + recentlyOpenedcontrollerId: string; recentlyOpenedProjectId: string; - serverIdProjectList: string; - controller: Server; + controllerIdProjectList: string; + controllerId: string | undefined | null; constructor( private electronService: ElectronService, private recentlyOpenedProjectService: RecentlyOpenedProjectService, - private serverManagement: ServerManagementService, + private controllerManagement: ControllerManagementService, private toasterService: ToasterService, private progressService: ProgressService, private router: Router, - private serverService: ServerService, - private route: ActivatedRoute - ) {} + private route: ActivatedRoute, + private controllerService: ControllerService + ) { + this.router.events.subscribe((data) => { + if (data instanceof NavigationEnd) { + this.controllerId = this.route.children[0].snapshot.paramMap.get("controller_id"); + } + }); + } ngOnInit() { + this.checkIfUserIsLoginPage(); this.controller = this.route.snapshot.data['server']; @@ -49,39 +56,31 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy { if (val instanceof NavigationEnd) this.checkIfUserIsLoginPage(); }); - this.recentlyOpenedServerId = this.recentlyOpenedProjectService.getServerId(); + this.recentlyOpenedcontrollerId = this.recentlyOpenedProjectService.getcontrollerId(); this.recentlyOpenedProjectId = this.recentlyOpenedProjectService.getProjectId(); - this.serverIdProjectList = this.recentlyOpenedProjectService.getServerIdProjectList(); + this.controllerIdProjectList = this.recentlyOpenedProjectService.getcontrollerIdProjectList(); this.isInstalledSoftwareAvailable = this.electronService.isElectronApp; - // attach to notification stream when any of running local servers experienced issues - this.serverStatusSubscription = this.serverManagement.serverStatusChanged.subscribe((serverStatus) => { - if (serverStatus.status === 'errored') { - console.error(serverStatus.message); - this.toasterService.error(serverStatus.message); + // attach to notification stream when any of running local controllers experienced issues + this.controllerStatusSubscription = this.controllerManagement.controllerStatusChanged.subscribe((controllerStatus) => { + if (controllerStatus.status === 'errored') { + console.error(controllerStatus.message); + this.toasterService.error(controllerStatus.message); } - if (serverStatus.status === 'stderr') { - console.error(serverStatus.message); - this.toasterService.error(serverStatus.message); + if (controllerStatus.status === 'stderr') { + console.error(controllerStatus.message); + this.toasterService.error(controllerStatus.message); } }); - // stop servers only when in Electron - this.shouldStopServersOnClosing = this.electronService.isElectronApp; - } - - goToUserInfo() { - let serverId = this.router.url.split('/server/')[1].split('/')[0]; - this.serverService.get(+serverId).then((server: Server) => { - this.router.navigate(['/server', server.id, 'loggeduser']); - }); + // stop controllers only when in Electron + this.shouldStopControllersOnClosing = this.electronService.isElectronApp; } goToDocumentation() { - let serverId = this.router.url.split('/server/')[1].split('/')[0]; - this.serverService.get(+serverId).then((server: Server) => { - (window as any).open(`http://${server.host}:${server.port}/docs`); + this.controllerService.get(+this.controllerId).then((controller: Controller) => { + (window as any).open(`http://${controller.host}:${controller.port}/docs`); }); } @@ -94,22 +93,21 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy { } logout() { - let serverId = this.router.url.split('/server/')[1].split('/')[0]; - this.serverService.get(+serverId).then((server: Server) => { - server.authToken = null; - this.serverService.update(server).then((val) => this.router.navigate(['/server', server.id, 'login'])); + this.controllerService.get(+this.controllerId).then((controller: Controller) => { + controller.authToken = null; + this.controllerService.update(controller).then(val => this.router.navigate(['/controller', controller.id, 'login'])); }); } listProjects() { this.router - .navigate(['/server', this.serverIdProjectList, 'projects']) + .navigate(['/controller', this.controllerIdProjectList, 'projects']) .catch((error) => this.toasterService.error('Cannot list projects')); } backToProject() { this.router - .navigate(['/server', this.recentlyOpenedServerId, 'project', this.recentlyOpenedProjectId]) + .navigate(['/controller', this.recentlyOpenedcontrollerId, 'project', this.recentlyOpenedProjectId]) .catch((error) => this.toasterService.error('Cannot navigate to the last opened project')); } @@ -135,21 +133,21 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy { @HostListener('window:beforeunload', ['$event']) async onBeforeUnload($event) { - if (!this.shouldStopServersOnClosing) { + if (!this.shouldStopControllersOnClosing) { return; } $event.preventDefault(); $event.returnValue = false; this.progressService.activate(); - await this.serverManagement.stopAll(); - this.shouldStopServersOnClosing = false; + await this.controllerManagement.stopAll(); + this.shouldStopControllersOnClosing = false; this.progressService.deactivate(); window.close(); return false; } ngOnDestroy() { - this.serverStatusSubscription.unsubscribe(); + this.controllerStatusSubscription.unsubscribe(); this.routeSubscription.unsubscribe(); } } diff --git a/src/app/models/LocalStorage.ts b/src/app/models/LocalStorage.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/models/api/permission.ts b/src/app/models/api/permission.ts new file mode 100644 index 00000000..3a187279 --- /dev/null +++ b/src/app/models/api/permission.ts @@ -0,0 +1,35 @@ +/* +* 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 enum Methods { + GET = 'GET', + HEAD = 'HEAD', + POST = 'POST', + PATCH = 'PATCH', + PUT = 'PUT', + DELETE = 'DELETE' +} + +export enum PermissionActions { + ALLOW = 'ALLOW', + DENY = 'DENY' +} + +export interface Permission { + methods: Methods[]; + path: string; + action: PermissionActions; + description: string; + created_at?: string; + updated_at?: string; + permission_id?: string; +} diff --git a/src/app/models/api/role.ts b/src/app/models/api/role.ts new file mode 100644 index 00000000..16519371 --- /dev/null +++ b/src/app/models/api/role.ts @@ -0,0 +1,11 @@ +import {Permission} from "./permission"; + +export interface Role { + name: string; + description: string; + created_at: string; + updated_at: string; + role_id: string; + is_builtin: boolean; + permissions: Permission[]; +} diff --git a/src/app/models/server-settings-models/builtin.ts b/src/app/models/controller-settings-models/builtin.ts similarity index 100% rename from src/app/models/server-settings-models/builtin.ts rename to src/app/models/controller-settings-models/builtin.ts diff --git a/src/app/models/server-settings-models/docker.ts b/src/app/models/controller-settings-models/docker.ts similarity index 100% rename from src/app/models/server-settings-models/docker.ts rename to src/app/models/controller-settings-models/docker.ts diff --git a/src/app/models/server-settings-models/dynamips.ts b/src/app/models/controller-settings-models/dynamips.ts similarity index 100% rename from src/app/models/server-settings-models/dynamips.ts rename to src/app/models/controller-settings-models/dynamips.ts diff --git a/src/app/models/server-settings-models/graphics-view.ts b/src/app/models/controller-settings-models/graphics-view.ts similarity index 100% rename from src/app/models/server-settings-models/graphics-view.ts rename to src/app/models/controller-settings-models/graphics-view.ts diff --git a/src/app/models/server-settings-models/iou.ts b/src/app/models/controller-settings-models/iou.ts similarity index 100% rename from src/app/models/server-settings-models/iou.ts rename to src/app/models/controller-settings-models/iou.ts diff --git a/src/app/models/server-settings-models/qemu.ts b/src/app/models/controller-settings-models/qemu.ts similarity index 100% rename from src/app/models/server-settings-models/qemu.ts rename to src/app/models/controller-settings-models/qemu.ts diff --git a/src/app/models/server-settings-models/virtual-box.ts b/src/app/models/controller-settings-models/virtual-box.ts similarity index 100% rename from src/app/models/server-settings-models/virtual-box.ts rename to src/app/models/controller-settings-models/virtual-box.ts diff --git a/src/app/models/server-settings-models/vmware.ts b/src/app/models/controller-settings-models/vmware.ts similarity index 100% rename from src/app/models/server-settings-models/vmware.ts rename to src/app/models/controller-settings-models/vmware.ts diff --git a/src/app/models/server-settings-models/vpcs.ts b/src/app/models/controller-settings-models/vpcs.ts similarity index 100% rename from src/app/models/server-settings-models/vpcs.ts rename to src/app/models/controller-settings-models/vpcs.ts diff --git a/src/app/models/controller.ts b/src/app/models/controller.ts new file mode 100644 index 00000000..a4a7145d --- /dev/null +++ b/src/app/models/controller.ts @@ -0,0 +1,19 @@ +export type ControllerLocation = 'local' | 'remote' | 'bundled'; +export type ControllerStatus = 'stopped' | 'starting' | 'running'; +export type ControllerProtocol = 'http:' | 'https:'; + +export class Controller { + authToken: string; + id: number; + name: string; + location: ControllerLocation; + host: string; + port: number; + path: string; + ubridge_path: string; + status: ControllerStatus; + protocol: ControllerProtocol; + username: string; + password: string; + tokenExpired: boolean; +} diff --git a/src/app/models/serverResponse.ts b/src/app/models/controllerResponse.ts similarity index 53% rename from src/app/models/serverResponse.ts rename to src/app/models/controllerResponse.ts index 5d4b4b6c..e4bcf88c 100644 --- a/src/app/models/serverResponse.ts +++ b/src/app/models/controllerResponse.ts @@ -1,4 +1,4 @@ -export class ServerResponse { +export class ControllerResponse { message: string; status: number; } diff --git a/src/app/models/controllerSettings.ts b/src/app/models/controllerSettings.ts new file mode 100644 index 00000000..04c2fd4d --- /dev/null +++ b/src/app/models/controllerSettings.ts @@ -0,0 +1,22 @@ +import { Builtin } from './controller-settings-models/builtin'; +import { Docker } from './controller-settings-models/docker'; +import { Dynamips } from './controller-settings-models/dynamips'; +import { GraphicsView } from './controller-settings-models/graphics-view'; +import { IOU } from './controller-settings-models/iou'; +import { Qemu } from './controller-settings-models/qemu'; +import { VirtualBox } from './controller-settings-models/virtual-box'; +import { VMware } from './controller-settings-models/vmware'; +import { VPCS } from './controller-settings-models/vpcs'; + +export class ControllerSettings { + Builtin: Builtin; + Docker: Docker; + Dynamips: Dynamips; + Graphicsview: GraphicsView; + IOU: IOU; + Qemu: Qemu; + VMware: VMware; + VPCS: VPCS; + VirtualBox: VirtualBox; + modification_uuid: string; +} diff --git a/src/app/models/groups/group.ts b/src/app/models/groups/group.ts new file mode 100644 index 00000000..3996f52a --- /dev/null +++ b/src/app/models/groups/group.ts @@ -0,0 +1,19 @@ +/* +* 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 interface Group { + name: string; + created_at: string; + updated_at: string; + user_group_id: string; + is_builtin: boolean; +} diff --git a/src/app/models/link.ts b/src/app/models/link.ts index 46a898fd..5594e694 100644 --- a/src/app/models/link.ts +++ b/src/app/models/link.ts @@ -15,11 +15,11 @@ export class Link { suspend: boolean; link_style?: LinkStyle; - distance: number; // this is not from server - length: number; // this is not from server - source: Node; // this is not from server - target: Node; // this is not from server + distance: number; // this is not from controller + length: number; // this is not from controller + source: Node; // this is not from controller + target: Node; // this is not from controller - x: number; // this is not from server - y: number; // this is not from server + x: number; // this is not from controller + y: number; // this is not from controller } diff --git a/src/app/models/server.ts b/src/app/models/server.ts deleted file mode 100644 index 67d50d2b..00000000 --- a/src/app/models/server.ts +++ /dev/null @@ -1,19 +0,0 @@ -export type ServerLocation = 'local' | 'remote' | 'bundled'; -export type ServerStatus = 'stopped' | 'starting' | 'running'; -export type ServerProtocol = 'http:' | 'https:'; - -export class Server { - authToken: string; - id: number; - name: string; - location: ServerLocation; - host: string; - port: number; - path: string; - ubridge_path: string; - status: ServerStatus; - protocol: ServerProtocol; - username: string; - password: string; - tokenExpired: boolean; -} diff --git a/src/app/models/serverSettings.ts b/src/app/models/serverSettings.ts deleted file mode 100644 index 89037eb6..00000000 --- a/src/app/models/serverSettings.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Builtin } from './server-settings-models/builtin'; -import { Docker } from './server-settings-models/docker'; -import { Dynamips } from './server-settings-models/dynamips'; -import { GraphicsView } from './server-settings-models/graphics-view'; -import { IOU } from './server-settings-models/iou'; -import { Qemu } from './server-settings-models/qemu'; -import { VirtualBox } from './server-settings-models/virtual-box'; -import { VMware } from './server-settings-models/vmware'; -import { VPCS } from './server-settings-models/vpcs'; - -export class ServerSettings { - Builtin: Builtin; - Docker: Docker; - Dynamips: Dynamips; - Graphicsview: GraphicsView; - IOU: IOU; - Qemu: Qemu; - VMware: VMware; - VPCS: VPCS; - VirtualBox: VirtualBox; - modification_uuid: string; -} diff --git a/src/app/models/users/user.ts b/src/app/models/users/user.ts index 880734dd..a385cc85 100644 --- a/src/app/models/users/user.ts +++ b/src/app/models/users/user.ts @@ -2,6 +2,7 @@ export interface User { created_at: string; email: string; full_name: string; + last_login: string; is_active: boolean; is_superadmin: boolean; updated_at: string; diff --git a/src/app/resolvers/controller-resolve.ts b/src/app/resolvers/controller-resolve.ts new file mode 100644 index 00000000..8a1eecd0 --- /dev/null +++ b/src/app/resolvers/controller-resolve.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import{ Controller } from '../models/controller'; +import { ControllerService } from '../services/controller.service'; + +@Injectable() +export class ControllerResolve implements Resolve { + constructor(private controllerService: ControllerService) {} + + resolve(route: ActivatedRouteSnapshot) { + return this.controllerService.get(parseInt(route.params['controller_id'])); + } +} diff --git a/src/app/resolvers/group-members.resolver.ts b/src/app/resolvers/group-members.resolver.ts new file mode 100644 index 00000000..c6c1eabe --- /dev/null +++ b/src/app/resolvers/group-members.resolver.ts @@ -0,0 +1,50 @@ +/* +* 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'; +import { + Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, Subscriber} from 'rxjs'; +import {ControllerService} from "../services/controller.service"; +import {GroupService} from "../services/group.service"; +import {Controller} from "../models/controller"; +import {Group} from "../models/groups/group"; +import {User} from "../models/users/user"; + +@Injectable({ + providedIn: 'root' +}) +export class GroupMembersResolver implements Resolve { + + constructor(private controllerService: ControllerService, + private groupService: GroupService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const groupId = route.paramMap.get('user_group_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.groupService.getGroupMember(controller, groupId).subscribe((users: User[]) => { + subscriber.next(users); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/resolvers/group-role.resolver.ts b/src/app/resolvers/group-role.resolver.ts new file mode 100644 index 00000000..cdcc0cce --- /dev/null +++ b/src/app/resolvers/group-role.resolver.ts @@ -0,0 +1,50 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {ControllerService} from "../services/controller.service"; +import {GroupService} from "../services/group.service"; +import {User} from "../models/users/user"; +import {Controller} from "../models/controller"; +import {Role} from "../models/api/role"; + +@Injectable({ + providedIn: 'root' +}) +export class GroupRoleResolver implements Resolve { + + constructor(private controllerService: ControllerService, + private groupService: GroupService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const groupId = route.paramMap.get('user_group_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.groupService.getGroupRole(controller, groupId).subscribe((role: Role[]) => { + subscriber.next(role); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/resolvers/group.resolver.ts b/src/app/resolvers/group.resolver.ts new file mode 100644 index 00000000..07d608d7 --- /dev/null +++ b/src/app/resolvers/group.resolver.ts @@ -0,0 +1,51 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {ControllerService} from "@services/controller.service"; +import {GroupService} from "@services/group.service"; +import {User} from "@models/users/user"; +import {Controller} from "@models/controller"; +import {Group} from "@models/groups/group"; + +@Injectable({ + providedIn: 'root' +}) +export class GroupResolver implements Resolve { + + + constructor(private controllerService: ControllerService, + private groupService: GroupService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const groupId = route.paramMap.get('user_group_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.groupService.get(controller, groupId).subscribe((group: Group) => { + subscriber.next(group); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/resolvers/permission.resolver.ts b/src/app/resolvers/permission.resolver.ts new file mode 100644 index 00000000..173e6755 --- /dev/null +++ b/src/app/resolvers/permission.resolver.ts @@ -0,0 +1,47 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {Permission} from "@models/api/permission"; +import {PermissionsService} from "@services/permissions.service"; +import {ControllerService} from "@services/controller.service"; +import {Controller} from "@models/controller"; + +@Injectable({ + providedIn: 'root' +}) +export class PermissionResolver implements Resolve { + + constructor(private permissionService: PermissionsService, + private controllerService: ControllerService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return new Observable((observer: Subscriber) => { + const controllerId = route.paramMap.get('controller_id'); + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.permissionService.list(controller).subscribe((permission: Permission[]) => { + observer.next(permission); + observer.complete(); + }); + }); + }); + + + } +} diff --git a/src/app/resolvers/role-detail.resolver.ts b/src/app/resolvers/role-detail.resolver.ts new file mode 100644 index 00000000..5f29e1b1 --- /dev/null +++ b/src/app/resolvers/role-detail.resolver.ts @@ -0,0 +1,48 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {Controller} from "../models/controller"; +import {Role} from "../models/api/role"; +import {ControllerService} from "../services/controller.service"; +import {RoleService} from "../services/role.service"; + +@Injectable({ + providedIn: 'root' +}) +export class RoleDetailResolver implements Resolve { + + constructor(private controllerService: ControllerService, + private roleService: RoleService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return new Observable((observer: Subscriber) => { + const controllerId = route.paramMap.get('controller_id'); + const roleId = route.paramMap.get('role_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.roleService.getById(controller, roleId).subscribe((role: Role) => { + observer.next( role); + observer.complete(); + }); + }); + }); + + } +} diff --git a/src/app/resolvers/server-resolve.ts b/src/app/resolvers/server-resolve.ts deleted file mode 100644 index 1532baed..00000000 --- a/src/app/resolvers/server-resolve.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; -import { Server } from '../models/server'; -import { ServerService } from '../services/server.service'; - -@Injectable() -export class ServerResolve implements Resolve { - constructor(private serverService: ServerService) {} - - resolve(route: ActivatedRouteSnapshot) { - return this.serverService.get(parseInt(route.params['server_id'])); - } -} diff --git a/src/app/resolvers/user-detail.resolver.ts b/src/app/resolvers/user-detail.resolver.ts new file mode 100644 index 00000000..61553b6a --- /dev/null +++ b/src/app/resolvers/user-detail.resolver.ts @@ -0,0 +1,48 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {ControllerService} from "@services/controller.service"; +import {UserService} from "@services/user.service"; +import {User} from "@models/users/user"; +import {Controller} from "@models/controller"; + +@Injectable({ + providedIn: 'root' +}) +export class UserDetailResolver implements Resolve { + + constructor(private controllerService: ControllerService, + private userService: UserService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const userId = route.paramMap.get('user_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.userService.get(controller, userId).subscribe((user: User) => { + subscriber.next(user); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/resolvers/user-groups.resolver.ts b/src/app/resolvers/user-groups.resolver.ts new file mode 100644 index 00000000..45cf782d --- /dev/null +++ b/src/app/resolvers/user-groups.resolver.ts @@ -0,0 +1,48 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {Group} from "../models/groups/group"; +import {User} from "../models/users/user"; +import {Controller} from "../models/controller"; +import {ControllerService} from "../services/controller.service"; +import {UserService} from "../services/user.service"; + +@Injectable({ + providedIn: 'root' +}) +export class UserGroupsResolver implements Resolve { + constructor(private controllerService: ControllerService, + private userService: UserService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const userId = route.paramMap.get('user_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.userService.getGroupsByUserId(controller, userId).subscribe((groups: Group[]) => { + subscriber.next(groups); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/resolvers/user-permissions.resolver.ts b/src/app/resolvers/user-permissions.resolver.ts new file mode 100644 index 00000000..ec087915 --- /dev/null +++ b/src/app/resolvers/user-permissions.resolver.ts @@ -0,0 +1,48 @@ +/* +* 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'; +import { + Router, Resolve, + RouterStateSnapshot, + ActivatedRouteSnapshot +} from '@angular/router'; +import {Observable, of, Subscriber} from 'rxjs'; +import {ControllerService} from "../services/controller.service"; +import {UserService} from "../services/user.service"; +import {Controller} from "../models/controller"; +import {Permission} from "../models/api/permission"; + +@Injectable({ + providedIn: 'root' +}) +export class UserPermissionsResolver implements Resolve { + + constructor(private controllerService: ControllerService, + private userService: UserService) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return new Observable((subscriber: Subscriber) => { + + const controllerId = route.paramMap.get('controller_id'); + const userId = route.paramMap.get('user_id'); + + this.controllerService.get(+controllerId).then((controller: Controller) => { + this.userService.getPermissionsByUserId(controller, userId).subscribe((permissions: Permission[]) => { + subscriber.next(permissions); + subscriber.complete(); + }); + }); + }); + } +} diff --git a/src/app/services/ApiInformation/ApiInformationCache.ts b/src/app/services/ApiInformation/ApiInformationCache.ts new file mode 100644 index 00000000..8c91ff0b --- /dev/null +++ b/src/app/services/ApiInformation/ApiInformationCache.ts @@ -0,0 +1,47 @@ +import {IApiData} from "./IApiData"; +import {Controller} from "../../models/controller"; +import {IExtraParams} from "./IExtraParams"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +/** + * create cache to keep controller information on client side + * reduce number of requests to the controller + */ +export class ApiInformationCache { + + private cache = new Map(); + + + public update(controller: Controller, key: string, value: string, extraParams: IExtraParams[], data: IGenericApiObject[]) { + const dataKey = this.generateKey(controller, key, value, extraParams); + this.cache.set(dataKey, {expired: Date.now() + 10000, data}); + } + + public get(controller: Controller, key: string, value: string, extraParams: IExtraParams[]): IGenericApiObject[] | undefined { + const dataKey = this.generateKey(controller, key, value, extraParams); + const data = this.cache.get(dataKey); + if (data) { + if (data.expired > Date.now()) { + return data.data; + } + } + + } + + private generateKey(controller: Controller, key: string, value: string, extraParams: IExtraParams[]) { + return `${controller.id}-${key}-${value}-${extraParams.map(param => `${param.key}+${param.value}`).join('.')}`; + } + + searchByName(name: string) { + const result: IGenericApiObject[] = []; + this.cache.forEach((apiData: IApiData) => { + apiData.data.forEach((value: IGenericApiObject) => { + if (value.name.includes(name)) { + result.push(value); + } + }); + }); + + return result; + } +} diff --git a/src/app/services/ApiInformation/GetObjectIdHelper.ts b/src/app/services/ApiInformation/GetObjectIdHelper.ts new file mode 100644 index 00000000..b4c9f86e --- /dev/null +++ b/src/app/services/ApiInformation/GetObjectIdHelper.ts @@ -0,0 +1,123 @@ +import {ApiInformationService, IApiObject} from "@services/ApiInformation/api-information.service"; +import {Controller} from "@models/controller"; +import {IExtraParams} from "@services/ApiInformation/IExtraParams"; +import {forkJoin, Observable, of} from "rxjs"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; +import {map} from "rxjs/operators"; + +export class GetObjectIdHelper { + + public static getIdNameFromKey(key: string): string { + return /{([^)]+)}/.exec(key)[1]; + } + + /** + * find the GET query corresponding to the key in Object list + * @param key + */ + public static findElementInObjectListFn(key): (data: IApiObject[]) => IApiObject { + return function findElement(data: IApiObject[]): IApiObject { + const elem = data.find(d => d.name === key); + if (!elem) { + throw new Error('entry not found'); + } + return elem; + }; + } + + /** + * Build the request, append the value if required + * @param controller + * @param value + * @param extraParams + */ + public static buildRequestURL(controller: Controller, value: string, extraParams: IExtraParams[]): (elem) => string { + return (elem): string => { + let url = `${controller.protocol}//${controller.host}:${controller.port}${elem.path}`; + if (extraParams) { + extraParams.forEach((param) => { + url = url.replace(param.key, param.value); + }); + } + + if (value) { + url = `${url}/${value}`; + } + return url; + }; + } + + /** + * Map the data from controller to a generic response object + * @param key + * @param extraParams + * @param service + * @param controller + */ + public static createResponseObject(key: string, + extraParams: IExtraParams[], + service: ApiInformationService, + controller: Controller + ): (response) => Observable { + + const idName = key ? GetObjectIdHelper.getIdNameFromKey(key) : undefined; + return (response): Observable => { + + if (!(response instanceof Array)) { + response = [response]; + } + if (response.length === 0) { + return of([]); + } + + /* + specific treatment for link_id + */ + if (key === '{link_id}') { + return GetObjectIdHelper.setLinkObjectInformation(response, extraParams, service, controller); + } else { + return GetObjectIdHelper.setGenericObjectInformation(response, idName); + } + }; + } + + private static setGenericObjectInformation(response: any[], idName: string): Observable { + const keys = Object.keys(response[0]); + const idKey = keys.find(k => k.match(/_id$|filename/)); + const nameKey = keys.find(k => k.match(/name/)); + response = response.map(o => { + return { + id: o[idName] || o[idKey], + name: o[nameKey] + }; + }); + return of(response); + } + + private static setLinkObjectInformation(links: any[], + extraParams: IExtraParams[], + service: ApiInformationService, + controller: Controller + ): Observable { + + return forkJoin(links.map(link => GetObjectIdHelper.getLinkInformation(link, extraParams, service, controller))); + } + + private static getLinkInformation(link: any, + extraParams: IExtraParams[], + service: ApiInformationService, + controller: Controller + ): Observable { + + const nodesDataObs = link.nodes.map(node => service.getListByObjectId(controller, '{node_id}', node.node_id, extraParams)); + return forkJoin(nodesDataObs) + .pipe(map((nodes: [any]) => { + const name = nodes + .reduce((acc, val) => acc.concat(val), []) + .map(node => node.name) + .join(' <-> '); + + return {id: link.link_id, name}; + })); + } +} diff --git a/src/app/services/ApiInformation/IApiData.ts b/src/app/services/ApiInformation/IApiData.ts new file mode 100644 index 00000000..b4b2505e --- /dev/null +++ b/src/app/services/ApiInformation/IApiData.ts @@ -0,0 +1,6 @@ +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +export interface IApiData { + expired: number; + data: IGenericApiObject[]; +} diff --git a/src/app/services/ApiInformation/IExtraParams.ts b/src/app/services/ApiInformation/IExtraParams.ts new file mode 100644 index 00000000..146914cb --- /dev/null +++ b/src/app/services/ApiInformation/IExtraParams.ts @@ -0,0 +1,8 @@ +/** + * key value association to query the api documentation + * ex : {key: 'project_id', value: 'd6381517-4ac6-436e-bff7-b667dd64f693'} + */ +export interface IExtraParams { + key: string; + value: string; +} diff --git a/src/app/services/ApiInformation/IGenericApiObject.ts b/src/app/services/ApiInformation/IGenericApiObject.ts new file mode 100644 index 00000000..e2247e3a --- /dev/null +++ b/src/app/services/ApiInformation/IGenericApiObject.ts @@ -0,0 +1,7 @@ +/** + * {id: 'project_id, name: 'test project'} + */ +export interface IGenericApiObject { + id: string; + name?: string; +} diff --git a/src/app/services/ApiInformation/api-information.service.spec.ts b/src/app/services/ApiInformation/api-information.service.spec.ts new file mode 100644 index 00000000..db24d4ee --- /dev/null +++ b/src/app/services/ApiInformation/api-information.service.spec.ts @@ -0,0 +1,310 @@ +import {ApiInformationService, IPathDict} from "@services/ApiInformation/api-information.service"; +import {HttpClient} from "@angular/common/http"; +import {fakeAsync, TestBed, tick} from "@angular/core/testing"; +import {DisplayPathPipe} from "@components/permissions-management/display-path.pipe"; +import {Observable, of, ReplaySubject} from "rxjs"; +import {Controller} from "@models/controller"; +import {getTestController} from "@services/testing"; +import {Methods} from "@models/api/permission"; +import {ApiInformationCache} from "@services/ApiInformation/ApiInformationCache"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +describe('ApiInformationService', () => { + let apiService: ApiInformationService; + let httpClientSpy: jasmine.SpyObj; + let controller: Controller; + + beforeEach(() => { + const spy = jasmine.createSpyObj('HttpClient', ['get']); + TestBed.configureTestingModule({ + providers: [ApiInformationService, {provide: HttpClient, useValue: spy}], + }); + httpClientSpy = TestBed.inject(HttpClient) as jasmine.SpyObj + httpClientSpy.get.and.returnValue(new Observable()); + apiService = TestBed.inject(ApiInformationService); + controller = getTestController(); + }); + + describe('ApiInformationService.getMethods() tests', () => { + it('create an instance', () => { + expect(apiService).toBeTruthy(); + }); + + it('Should return methods for /projects/{project_id}', fakeAsync(() => { + let res: Methods[]; + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }]; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getMethods('/projects/{project_id}').subscribe(data => { + res = data; + }); + tick(); + expect(res).toContain(Methods.GET) + expect(res).toContain(Methods.PUT) + expect(res).toContain(Methods.POST) + })); + + it('Should return empty array if no data available', fakeAsync(() => { + let res: Methods[]; + const mockGetPath: IPathDict[] = []; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getMethods('/projects/{project_id}').subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + + }) + + describe('ApiInformationService.getPath() tests', () => { + + it('Should return array of 2', fakeAsync(() => { + + let res: IPathDict[]; + const mockData: ReplaySubject = new ReplaySubject(1); + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }]; + apiService['data'] = mockData; + apiService['data'].next(mockGetPath); + apiService.getPath('/projects/{project_id}').subscribe((data) => { + res = data; + }); + tick(); + expect(res.length).toBe(2); + expect(res).toContain(mockGetPath[0]); + expect(res).toContain(mockGetPath[1]); + })); + + it('Should return empty array if ApiInformationService.data does not have info about nodes', fakeAsync(() => { + + let res: IPathDict[]; + const mockIPathDict: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }]; + const mockData: ReplaySubject = new ReplaySubject(1); + apiService['data'] = mockData; + apiService['data'].next(mockIPathDict); + + apiService.getPath('/nodes').subscribe( (data) => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + it('Should return array of 1 ', fakeAsync(() => { + + let res: IPathDict[]; + const mockData: ReplaySubject = new ReplaySubject(1); + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }, { + methods: ['GET', 'PUT', 'DELETE'], + originalPath: '/v3/projects/{project_id}/nodes/{node_id}', + path: '/projects/{project_id}/nodes/{node_id}', + subPaths: ['projects', '{project_id}', 'nodes', '{node_id}'], + }]; + apiService['data'] = mockData; + apiService['data'].next(mockGetPath); + apiService.getPath('/projects/tralala/nodes/bidule').subscribe((data) => { + res = data; + }); + tick(); + expect(res.length).toBe(1) + expect(res).toContain(mockGetPath[2]) + })); + + + }); + + describe('ApiInformationService.getPathNextElement tests ', () => { + it('Should return next path elements possible', fakeAsync(() => { + let res: string[]; + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }]; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getPathNextElement(['projects','{project_id}']).subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(1); + expect(res).toContain('nodes'); + })); + + it('Should return no next path elements for /projects/{project_id}/nodes', fakeAsync(() => { + let res: string[]; + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }, { + methods: ['GET', 'POST'], + originalPath: '/v3/projects/{project_id}/nodes', + path: '/projects/{project_id}/nodes', + subPaths: ['projects', '{project_id}', 'nodes'], + }]; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getPathNextElement(['projects', '{project_id}', 'nodes']).subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + it('Should return no next path elements for /templates', fakeAsync(() => { + let res: string[]; + const mockGetPath: IPathDict[] = []; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getPathNextElement(['templates']).subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + }); + + describe('ApiInformationService.getKeysForPath tests ', () => { + it('Should return key/value pairs for path /projects/tralala/nodes/bidule', fakeAsync(() => { + let res: { key: string; value: string }[]; + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'PUT', 'DELETE'], + originalPath: '/v3/projects/{project_id}/nodes/{node_id}', + path: '/projects/{project_id}/nodes/{node_id}', + subPaths: ['projects', '{project_id}', 'nodes', '{node_id}'], + }, { + methods: ['GET'], + originalPath: '/v3/projects/{project_id}/nodes/{node_id}/links', + path: '/projects/{project_id}/nodes/{node_id}/links', + subPaths: ['projects', '{project_id}', 'nodes', '{node_id}', 'links'], + }]; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getKeysForPath('/projects/tralala/nodes/bidule').subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(2); + expect(res).toContain({key: '{project_id}', value: 'tralala'}); + expect(res).toContain({key: '{node_id}', value: 'bidule'}); + })); + + it('Should return no key/value pairs for path /projects', fakeAsync(() => { + let res: { key: string; value: string }[]; + const mockGetPath: IPathDict[] = [{ + methods: ['GET', 'POST'], + originalPath: '/v3/projects', + path: '/projects', + subPaths: ['projects'], + }, { + methods: ['GET', 'DELETE', 'PUT'], + originalPath: '/v3/projects/{project_id}', + path: '/projects/{project_id}', + subPaths: ['projects', '{project_id}'], + }]; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getKeysForPath('/projects').subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + xit('Should return no key/value pairs for path /projects/tralala if no data available', fakeAsync(() => { + let res: { key: string; value: string }[]; + const mockGetPath: IPathDict[] = []; + spyOn(apiService, 'getPath').and.returnValue(of(mockGetPath)); + apiService.getKeysForPath('/projects').subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(0); + })); + + }); + + describe('ApiInformationService.getListByObjectId tests', () => { + + it('Should', fakeAsync(() => { + let res: IGenericApiObject[]; + const mockGetCache: IGenericApiObject[] = [{id: 'id-tralala', name: 'tralala-project'}]; + spyOn(apiService['cache'], 'get').and.returnValue(mockGetCache); + apiService.getListByObjectId(controller, '{project_id}', 'id-tralala').subscribe(data => { + res = data; + }); + tick(); + expect(res.length).toBe(1); + expect(res).toContain(mockGetCache[0]) + })); + + + + + }); + + describe('ApiInformationService.getIdByObjNameFromCache tests ', () => { + it('Should get possible id of object whose name contains tralala', () => { + const mockGetCache: IGenericApiObject[] = [{id: 'id-tralala', name: 'tralala-project'}, + {id: 'id-tralala2', name: 'other-tralala-project'}]; + spyOn(apiService['cache'], 'searchByName').and.returnValue(mockGetCache); + const res = apiService.getIdByObjNameFromCache('tralala'); + expect(res.length).toBe(2); + expect(res).toContain(mockGetCache[0]); + expect(apiService['cache'].searchByName).toHaveBeenCalled(); + }) + + it('Should get empty array for object whose name contains tralala', () => { + const mockGetCache: IGenericApiObject[] = []; + spyOn(apiService['cache'], 'searchByName').and.returnValue(mockGetCache); + const res = apiService.getIdByObjNameFromCache('tralala'); + expect(res.length).toBe(0); + expect(apiService['cache'].searchByName).toHaveBeenCalled(); + }) + }); + +}); diff --git a/src/app/services/ApiInformation/api-information.service.ts b/src/app/services/ApiInformation/api-information.service.ts new file mode 100644 index 00000000..accefe5b --- /dev/null +++ b/src/app/services/ApiInformation/api-information.service.ts @@ -0,0 +1,278 @@ +/* +* 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'; +import {HttpClient} from "@angular/common/http"; +import {Observable, of, ReplaySubject} from "rxjs"; +import {map, switchMap, take, tap} from "rxjs/operators"; +import {Methods} from "app/models/api/permission"; +import {HttpController} from "app/services/http-controller.service"; +import {Controller} from "app/models/controller"; +import {GetObjectIdHelper} from "@services/ApiInformation/GetObjectIdHelper"; +import {IExtraParams} from "@services/ApiInformation/IExtraParams"; +import {ApiInformationCache} from "@services/ApiInformation/ApiInformationCache"; +import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject"; + +/** + * representation of an APi endpoint + * { + * methods: ['GET', 'DELETE', 'PUT'], + * originalPath: '/v3/projects/{project_id}', + * path: '/projects/{project_id}', + * subPaths: ['projects', '{project_id}'], + } + */ +export interface IPathDict { + methods: ('POST' | 'GET' | 'PUT' | 'DELETE' | 'HEAD' | 'PATH')[]; + originalPath: string; + path: string; + subPaths: string[]; +} + +/** + * name: 'node_id', + * path: '/projects/{project_id}/nodes/{node_id} + */ +export interface IApiObject { + name: string; + path: string; +} + +export interface IQueryObject { + id: string; + text: string[]; +} + +@Injectable({ + providedIn: 'root' +}) +export class ApiInformationService { + + private cache = new ApiInformationCache(); + private allowed = ['projects', 'images', 'templates', 'computes', 'symbols', 'notifications']; + private data: ReplaySubject = new ReplaySubject(1); + private objs: ReplaySubject = new ReplaySubject(1); + public readonly bracketIdRegex = new RegExp("\{(.*?)\}", 'g'); + public readonly uuidRegex = new RegExp("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); + public readonly finalBracketIdRegex = new RegExp("\{(.*?)\}$"); + + + constructor(private httpClient: HttpClient) { + this.loadLocalInformation(); + + this.data.subscribe((data) => { + localStorage.setItem('api-definition', JSON.stringify(data)); + }); + + this.objs.subscribe((data) => { + localStorage.setItem('api-definition-objs', JSON.stringify(data)); + }); + + + this.httpClient + .get(`https://apiv3.gns3.net/openapi.json`) + .subscribe((openapi: any) => { + const objs = this.apiObjectModelAdapter(openapi); + const data = this.apiPathModelAdapter(openapi); + this.data.next(data); + this.objs.next(objs); + }); + + } + + /** + * Generate a list of object from the OpenAPi GNS3 documentation with the GET path to query it + * @param openapi GNS3 openapi json data + * @private + */ + private apiObjectModelAdapter(openapi: any): IApiObject[] { + + function haveGetMethod(path: string): boolean { + const obj = openapi.paths[path]; + if (obj) { + const methods = Object.keys(obj); + return methods.includes("get"); + } else { + return false; + } + } + + function extractId(originalPath: string): IApiObject { + const d = originalPath.split('/'); + + const name = d.pop(); + const path = d.join('/'); + + return {name, path}; + } + + const keys = Object.keys(openapi.paths); + return keys + .filter((path: string) => path.match(this.finalBracketIdRegex)) + .filter(haveGetMethod) + .map(extractId) + .filter((object) => haveGetMethod(object.path)); + } + + /** + * Convert OpenAPi json file from GNS3 api documentations to usable information schema + * @param openapi GNS3 openapi definition + * @private + */ + private apiPathModelAdapter(openapi: any): IPathDict[] { + const keys = Object.keys(openapi.paths); + return keys + .map(path => { + const subPaths = path.split('/').filter(elem => !(elem === '' || elem === 'v3')); + return {originalPath: path, path: subPaths.join('/'), subPaths}; + }) + .filter(d => this.allowed.includes(d.subPaths[0])) + .map(path => { + //FIXME + // @ts-ignore + const methods = Object.keys(openapi.paths[path.originalPath]); + return {methods: methods.map(m => m.toUpperCase()), ...path}; + + }) as unknown as IPathDict[]; + } + + /** + * Return availables methods for a path + * @param path '/v3/projects/{project_id} => ['GET', 'POST', 'PUT'] + */ + getMethods(path: string): Observable { + return this.getPath(path) + .pipe( + map((data: IPathDict[]) => { + const availableMethods = new Set(); + data.forEach((p: IPathDict) => { + p.methods.forEach(method => availableMethods.add(method)); + }); + return Array.from(availableMethods) as Methods[]; + }), + ); + } + + /** + * return a list of matching path + * @param path '/v3/projects/{project_id}' + */ + getPath(path: string): Observable { + return this.data + .asObservable() + .pipe( + map((data) => { + const splinted = path + .split('/') + .filter(elem => !(elem === '' || elem === 'v3')); + let remains = data; + splinted.forEach((value, index) => { + if (value === '*') { + return; + } + let matchUrl = remains.filter(val => val.subPaths[index]?.includes(value)); + + if (matchUrl.length === 0) { + matchUrl = remains.filter(val => val.subPaths[index]?.match(this.bracketIdRegex)); + } + remains = matchUrl; + }); + return remains; + }) + ); + } + + private loadLocalInformation() { + const data = JSON.parse(localStorage.getItem('api-definition')); + if (data) { + this.data.next(data); + } + const obj = JSON.parse(localStorage.getItem('api-definition-objs')); + if (obj) { + this.objs.next(obj); + } + } + + /** + * Return all available next child for a given path + * @param path api path + */ + + getPathNextElement(path: string[]): Observable { + + return this.getPath(path.join('/')) + .pipe(map((paths: IPathDict[]) => { + const set = new Set(); + paths.forEach((p) => { + if (p.subPaths[path.length]) { + set.add(p.subPaths[path.length]); + } + }); + + return Array.from(set); + })); + } + + /** + * return all keys which composed a path + * @param path '/v3/projects/7fed4f19-0c45-4461-a45b-93ff11ccdae6/nodes/62f3e04b-a22c-452a-a026-1971122d9d8a + * return: [ + * {key:'project_id', value: '7fed4f19-0c45-4461-a45b-93ff11ccdae6'}, + * {key:'node_id', value: '62f3e04b-a22c-452a-a026-1971122d9d8a'} + * ] + */ + getKeysForPath(path: string): Observable<{ key: string; value: string }[]> { + return this.getPath(path) + .pipe(map((paths: IPathDict[]) => { + const splinted = path + .split('/') + .filter(elem => !(elem === '' || elem === 'v3')); + return paths[0].subPaths.map((elem, index) => { + if (elem.match(this.bracketIdRegex)) { + + return {key: elem, value: splinted[index]}; + } + }); + }), map((values) => { + return values.filter((v) => v !== undefined); + })); + } + + /** + * get the value of specific object with his ID + * @param {controller} the controller object to query + * @param {key} to query ex :'node_id' + * @param {value} generally the object uuid + * @param {extraParams} somes params like the project_id if you query specific node_id + */ + getListByObjectId(controller: Controller, key: string, value?: string, extraParams?: IExtraParams[]): Observable { + + const cachedData = this.cache.get(controller, key, value, extraParams); + if (cachedData) { + return of(cachedData); + } + + return this.objs.pipe( + map(GetObjectIdHelper.findElementInObjectListFn(key)), + map(GetObjectIdHelper.buildRequestURL(controller, value, extraParams)), + switchMap(url => this.httpClient.get(url, {headers: {Authorization: `Bearer ${controller.authToken}`}})), + switchMap(GetObjectIdHelper.createResponseObject(key, extraParams, this, controller)), + tap(data => this.cache.update(controller, key, value, extraParams, data)), + take(1)); + } + + getIdByObjNameFromCache(name: string): IGenericApiObject[] { + return this.cache.searchByName(name); + } +} + + diff --git a/src/app/services/appliances.service.ts b/src/app/services/appliances.service.ts index 96d573fc..c4c981d3 100644 --- a/src/app/services/appliances.service.ts +++ b/src/app/services/appliances.service.ts @@ -2,26 +2,26 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; import { Appliance } from '../models/appliance'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; @Injectable() export class ApplianceService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getAppliances(server: Server): Observable { - return this.httpServer.get(server, '/appliances') as Observable; + getAppliances(controller:Controller ): Observable { + return this.httpController.get(controller, '/appliances') as Observable; } - getAppliance(server: Server, url): Observable { - return this.httpServer.get(server, url) as Observable; + getAppliance(controller:Controller , url): Observable { + return this.httpController.get(controller, url) as Observable; } - getUploadPath(server: Server, emulator: string, filename: string) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/images/upload/${filename}`; + getUploadPath(controller:Controller , emulator: string, filename: string) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/images/upload/${filename}?allow_raw_image=true`; } - updateAppliances(server: Server): Observable { - return this.httpServer.get(server, '/appliances?update=yes') as Observable; + updateAppliances(controller:Controller ): Observable { + return this.httpController.get(controller, '/appliances?update=yes') as Observable; } } diff --git a/src/app/services/built-in-templates.service.spec.ts b/src/app/services/built-in-templates.service.spec.ts index 86cd0938..ebf402f9 100644 --- a/src/app/services/built-in-templates.service.spec.ts +++ b/src/app/services/built-in-templates.service.spec.ts @@ -2,30 +2,30 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { CloudTemplate } from '../models/templates/cloud-template'; import { EthernetHubTemplate } from '../models/templates/ethernet-hub-template'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; import { BuiltInTemplatesService } from './built-in-templates.service'; -import { HttpServer } from './http-server.service'; -import { getTestServer } from './testing'; +import { HttpController } from './http-controller.service'; +import { getTestController } from './testing'; describe('BuiltInTemplatesService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, BuiltInTemplatesService], + providers: [HttpController, BuiltInTemplatesService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); }); afterEach(() => { @@ -50,7 +50,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'cloud', } as CloudTemplate; - service.saveTemplate(server, cloudtemplate).subscribe(); + service.saveTemplate(controller, cloudtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates/1`); expect(req.request.method).toEqual('PUT'); @@ -70,7 +70,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'ethernet_hub', }; - service.saveTemplate(server, ethernethubtemplate).subscribe(); + service.saveTemplate(controller, ethernethubtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates/2`); expect(req.request.method).toEqual('PUT'); @@ -90,7 +90,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'ethernet_hub', }; - service.saveTemplate(server, ethernetswitchtemplate).subscribe(); + service.saveTemplate(controller, ethernetswitchtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates/3`); expect(req.request.method).toEqual('PUT'); @@ -111,7 +111,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'cloud', } as CloudTemplate; - service.addTemplate(server, cloudtemplate).subscribe(); + service.addTemplate(controller, cloudtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates`) expect(req.request.method).toEqual('POST'); @@ -131,7 +131,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'ethernet_hub', }; - service.addTemplate(server, ethernethubtemplate).subscribe(); + service.addTemplate(controller, ethernethubtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates`) expect(req.request.method).toEqual('POST'); @@ -151,7 +151,7 @@ describe('BuiltInTemplatesService', () => { template_type: 'ethernet_hub', }; - service.addTemplate(server, ethernetswitchtemplate).subscribe(); + service.addTemplate(controller, ethernetswitchtemplate).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates`) expect(req.request.method).toEqual('POST'); diff --git a/src/app/services/built-in-templates.service.ts b/src/app/services/built-in-templates.service.ts index 56d3a696..cc87be15 100644 --- a/src/app/services/built-in-templates.service.ts +++ b/src/app/services/built-in-templates.service.ts @@ -1,27 +1,27 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; @Injectable() export class BuiltInTemplatesService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getTemplates(server: Server): Observable { - return this.httpServer.get(server, '/templates') as Observable; + getTemplates(controller:Controller ): Observable { + return this.httpController.get(controller, '/templates') as Observable; } - getTemplate(server: Server, template_id: string): Observable { - return this.httpServer.get(server, `/templates/${template_id}`) as Observable; + getTemplate(controller:Controller , template_id: string): Observable { + return this.httpController.get(controller, `/templates/${template_id}`) as Observable; } - addTemplate(server: Server, builtInTemplate: any): Observable { - return this.httpServer.post(server, `/templates`, builtInTemplate) as Observable; + addTemplate(controller:Controller , builtInTemplate: any): Observable { + return this.httpController.post(controller, `/templates`, builtInTemplate) as Observable; } - saveTemplate(server: Server, builtInTemplate: any): Observable { - return this.httpServer.put( - server, + saveTemplate(controller:Controller , builtInTemplate: any): Observable { + return this.httpController.put( + controller, `/templates/${builtInTemplate.template_id}`, builtInTemplate ) as Observable; diff --git a/src/app/services/compute.service.ts b/src/app/services/compute.service.ts index b8234b6d..ca62cd9c 100644 --- a/src/app/services/compute.service.ts +++ b/src/app/services/compute.service.ts @@ -3,22 +3,22 @@ import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; import { Compute } from '../models/compute'; import { ComputeStatistics } from '../models/computeStatistics'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; @Injectable() export class ComputeService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getComputes(server: Server): Observable { - return this.httpServer.get(server, '/computes') as Observable; + getComputes(controller:Controller ): Observable { + return this.httpController.get(controller, '/computes') as Observable; } - getUploadPath(server: Server, emulator: string, filename: string) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/${emulator}/images/${filename}`; + getUploadPath(controller:Controller , emulator: string, filename: string) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/${emulator}/images/${filename}`; } - getStatistics(server: Server): Observable { - return this.httpServer.get(server, `/statistics`); + getStatistics(controller:Controller ): Observable { + return this.httpController.get(controller, `/statistics`); } } diff --git a/src/app/services/server-management.service.spec.ts b/src/app/services/controller-management.service.spec.ts similarity index 50% rename from src/app/services/server-management.service.spec.ts rename to src/app/services/controller-management.service.spec.ts index 98aede75..1784beea 100644 --- a/src/app/services/server-management.service.spec.ts +++ b/src/app/services/controller-management.service.spec.ts @@ -1,18 +1,18 @@ import { TestBed } from '@angular/core/testing'; import { ElectronService } from 'ngx-electron'; -import { Server } from '../models/server'; -import { ServerManagementService } from './server-management.service'; +import{ Controller } from '../models/controller'; +import { ControllerManagementService } from './controller-management.service'; -describe('ServerManagementService', () => { +describe('ControllerManagementService', () => { let electronService; let callbacks; let removed; - let server; + let controller; beforeEach(() => { callbacks = []; removed = []; - server = undefined; + controller = undefined; electronService = { isElectronApp: true, ipcRenderer: { @@ -29,11 +29,11 @@ describe('ServerManagementService', () => { remote: { require: (file) => { return { - startLocalServer: (serv) => { - server = serv; + startLocalController: (serv) => { + controller = serv; }, - stopLocalServer: (serv) => { - server = serv; + stopLocalController: (serv) => { + controller = serv; }, }; }, @@ -44,51 +44,51 @@ describe('ServerManagementService', () => { beforeEach(() => TestBed.configureTestingModule({ providers: [ - ServerManagementService, + ControllerManagementService, { provide: ElectronService, useValue: electronService }, ], }) ); it('should be created', () => { - const service: ServerManagementService = TestBed.get(ServerManagementService); + const service: ControllerManagementService = TestBed.get(ControllerManagementService); expect(service).toBeTruthy(); }); it('should attach when running as electron app', () => { - TestBed.get(ServerManagementService); + TestBed.get(ControllerManagementService); expect(callbacks.length).toEqual(1); - expect(callbacks[0].channel).toEqual('local-server-status-events'); + expect(callbacks[0].channel).toEqual('local-controller-status-events'); }); it('should not attach when running as not electron app', () => { electronService.isElectronApp = false; - TestBed.get(ServerManagementService); + TestBed.get(ControllerManagementService); expect(callbacks.length).toEqual(0); }); it('should deattach when running as electron app', () => { - const service: ServerManagementService = TestBed.get(ServerManagementService); + const service: ControllerManagementService = TestBed.get(ControllerManagementService); service.ngOnDestroy(); - expect(removed).toEqual(['local-server-status-events']); + expect(removed).toEqual(['local-controller-status-events']); }); it('should not deattach when running as not electron app', () => { electronService.isElectronApp = false; - const service: ServerManagementService = TestBed.get(ServerManagementService); + const service: ControllerManagementService = TestBed.get(ControllerManagementService); service.ngOnDestroy(); expect(removed).toEqual([]); }); - it('should start local server', async () => { - const service: ServerManagementService = TestBed.get(ServerManagementService); - await service.start({ name: 'test' } as Server); - expect(server).toEqual({ name: 'test' }); + it('should start local controller', async () => { + const service: ControllerManagementService = TestBed.get(ControllerManagementService); + await service.start({ name: 'test' } as Controller ); + expect(controller).toEqual({ name: 'test' }); }); - it('should stop local server', async () => { - const service: ServerManagementService = TestBed.get(ServerManagementService); - await service.stop({ name: 'test2' } as Server); - expect(server).toEqual({ name: 'test2' }); + it('should stop local controller', async () => { + const service: ControllerManagementService = TestBed.get(ControllerManagementService); + await service.stop({ name: 'test2' } as Controller ); + expect(controller).toEqual({ name: 'test2' }); }); }); diff --git a/src/app/services/controller-management.service.ts b/src/app/services/controller-management.service.ts new file mode 100644 index 00000000..dd3fd399 --- /dev/null +++ b/src/app/services/controller-management.service.ts @@ -0,0 +1,58 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { ElectronService } from 'ngx-electron'; +import { Subject } from 'rxjs'; +import{ Controller } from '../models/controller'; + +export interface ControllerStateEvent { + controllerName: string; + status: 'starting' | 'started' | 'errored' | 'stopped' | 'stderr'; + message: string; +} + +@Injectable() +export class ControllerManagementService implements OnDestroy { + controllerStatusChanged = new Subject(); + + constructor(private electronService: ElectronService) { + if (this.electronService.isElectronApp) { + this.electronService.ipcRenderer.on(this.statusChannel, (event, data) => { + this.controllerStatusChanged.next(data); + }); + } + } + + get statusChannel() { + return 'local-controller-status-events'; + } + + async start(controller:Controller ) { + var startingEvent: ControllerStateEvent = { + controllerName: controller.name, + status: 'starting', + message: '', + }; + this.controllerStatusChanged.next(startingEvent); + return await this.electronService.remote.require('./local-controller.js').startLocalController(controller); + } + + async stop(controller:Controller ) { + return await this.electronService.remote.require('./local-controller.js').stopLocalController(controller); + } + + async stopAll() { + return await this.electronService.remote.require('./local-controller.js').stopAllLocalControllers(); + } + + getRunningControllers() { + if (this.electronService.isElectronApp) { + return this.electronService.remote.require('./local-controller.js').getRunningControllers(); + } + return []; + } + + ngOnDestroy() { + if (this.electronService.isElectronApp) { + this.electronService.ipcRenderer.removeAllListeners(this.statusChannel); + } + } +} diff --git a/src/app/services/controller-settings.service.spec.ts b/src/app/services/controller-settings.service.spec.ts new file mode 100644 index 00000000..88bbbf62 --- /dev/null +++ b/src/app/services/controller-settings.service.spec.ts @@ -0,0 +1,35 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { inject, TestBed } from '@angular/core/testing'; +import { of } from 'rxjs'; +import{ Controller } from '../models/controller'; +import { QemuSettings } from '../models/settings/qemu-settings'; +import { AppTestingModule } from '../testing/app-testing/app-testing.module'; +import { HttpController } from './http-controller.service'; +import { ControllerSettingsService } from './controller-settings.service'; + +export class MockedControllerSettingsService { + getSettingsForQemu(controller:Controller ) { + return of([]); + } + + updateSettingsForQemu(controller:Controller , qemuSettings: QemuSettings) { + return of([]); + } +} + +describe('ControllerSettingsService', () => { + let httpController: HttpController; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, AppTestingModule], + providers: [HttpController, ControllerSettingsService], + }); + + httpController = TestBed.get(HttpController); + }); + + it('should be created', inject([ControllerSettingsService], (service: ControllerSettingsService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/services/controller-settings.service.ts b/src/app/services/controller-settings.service.ts new file mode 100644 index 00000000..da69e52b --- /dev/null +++ b/src/app/services/controller-settings.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@angular/core'; +import{ Controller } from '../models/controller'; +import { ControllerSettings } from '../models/controllerSettings'; +import { QemuSettings } from '../models/settings/qemu-settings'; +import { HttpController } from './http-controller.service'; + +@Injectable() +export class ControllerSettingsService { + constructor(private httpController: HttpController) {} + + get(controller:Controller ) { + return this.httpController.get(controller, `/settings`); + } + + update(controller:Controller , controllerSettings: ControllerSettings) { + return this.httpController.post(controller, `/settings`, controllerSettings); + } + + getSettingsForQemu(controller:Controller ) { + return this.httpController.get(controller, `/settings/qemu`); + } + + updateSettingsForQemu(controller:Controller , qemuSettings: QemuSettings) { + return this.httpController.put(controller, `/settings/qemu`, { + enable_hardware_acceleration: qemuSettings.enable_hardware_acceleration, + require_hardware_acceleration: qemuSettings.require_hardware_acceleration, + }); + } +} diff --git a/src/app/services/controller-version.service.ts b/src/app/services/controller-version.service.ts new file mode 100644 index 00000000..349521d7 --- /dev/null +++ b/src/app/services/controller-version.service.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 { Injectable } from '@angular/core'; +import { HttpController } from "./http-controller.service"; +import { Controller } from "../models/controller"; +import { Observable } from "rxjs"; + +@Injectable({ + providedIn: 'root' +}) +export class ControllerVersionService { + + constructor(private httpController: HttpController) { } + + + public checkControllerVersion(controller: Controller): Observable { + return this.httpController.get(controller, '/version'); + } +} diff --git a/src/app/services/controller.database.ts b/src/app/services/controller.database.ts new file mode 100644 index 00000000..e62b71bd --- /dev/null +++ b/src/app/services/controller.database.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; +import{ Controller } from '../models/controller'; + +@Injectable() +export class ControllerDatabase { + dataChange: BehaviorSubject< Controller[] > = new BehaviorSubject< Controller[] >([]); + + constructor() {} + + get data():Controller [] { + return this.dataChange.value; + } + + public addController(controller:Controller ) { + const controllers = this.data.slice(); + controllers.push(controller); + this.dataChange.next(controllers); + } + + public addControllers(controllers:Controller []) { + this.dataChange.next(controllers); + } + + public remove(controller:Controller ) { + const index = this.data.indexOf(controller); + if (index >= 0) { + this.data.splice(index, 1); + this.dataChange.next(this.data.slice()); + } + } + + public find(controllerName: string) { + return this.data.find((controller) => controller.name === controllerName); + } + + public findIndex(controllerName: string) { + return this.data.findIndex((controller) => controller.name === controllerName); + } + + public update(controller:Controller ) { + const index = this.findIndex(controller.name); + if (index >= 0) { + this.data[index] = controller; + this.dataChange.next(this.data.slice()); + } + } +} diff --git a/src/app/services/controller.service.spec.ts b/src/app/services/controller.service.spec.ts new file mode 100644 index 00000000..d5f89758 --- /dev/null +++ b/src/app/services/controller.service.spec.ts @@ -0,0 +1,36 @@ +import{ Controller } from '../models/controller'; + +export class MockedControllerService { + public controllers:Controller [] = []; + + public create(controller:Controller ) { + return new Promise((resolve, reject) => { + this.controllers.push(controller); + resolve(controller); + }); + } + + public get(controller_id: number) { + const controller = new Controller (); + controller.id = controller_id; + return Promise.resolve(controller); + } + + public getLocalController(hostname: string, port: number) { + return new Promise((resolve, reject) => { + const controller = new Controller (); + controller.id = 99; + resolve(controller); + }); + } + + public findAll() { + return new Promise((resolve, reject) => { + resolve(this.controllers); + }); + } + + public getControllerUrl(controller:Controller) { + return `${controller.host}:${controller.port}`; + } +} diff --git a/src/app/services/controller.service.ts b/src/app/services/controller.service.ts new file mode 100644 index 00000000..6984d822 --- /dev/null +++ b/src/app/services/controller.service.ts @@ -0,0 +1,120 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import {Controller , ControllerProtocol } from '../models/controller'; +import { HttpController } from './http-controller.service'; + +@Injectable() +export class ControllerService { + private controllerIds: string[] = []; + public serviceInitialized: Subject = new Subject(); + public isServiceInitialized: boolean; + + constructor(private httpController: HttpController) { + this.controllerIds = this.getcontrollerIds(); + this.isServiceInitialized = true; + this.serviceInitialized.next(this.isServiceInitialized); + } + + getcontrollerIds() : string[]{ + let str = localStorage.getItem("controllerIds"); + if (str?.length > 0) { + return str.split(","); + } + return []; + } + + updatecontrollerIds() { + localStorage.removeItem("controllerIds"); + localStorage.setItem("controllerIds", this.controllerIds.toString()); + } + + public get(id: number): Promise { + let controller:Controller = JSON.parse(localStorage.getItem(`controller-${id}`)); + let promise = new Promise((resolve) => { + resolve(controller); + }); + return promise; + } + + public create(controller:Controller ) { + controller.id = this.controllerIds.length + 1; + localStorage.setItem(`controller-${controller.id}`, JSON.stringify(controller)); + + this.controllerIds.push(`controller-${controller.id}`); + this.updatecontrollerIds(); + + let promise = new Promise((resolve) => { + resolve(controller); + }); + return promise; + } + + public update(controller:Controller ) { + localStorage.removeItem(`controller-${controller.id}`); + localStorage.setItem(`controller-${controller.id}`, JSON.stringify(controller)); + + let promise = new Promise((resolve) => { + resolve(controller); + }); + return promise; + } + + public findAll() { + let promise = new Promise((resolve) => { + let controllers:Controller [] = []; + this.controllerIds.forEach((n) => { + let controller:Controller = JSON.parse(localStorage.getItem(n)); + controllers.push(controller); + }); + resolve(controllers); + }); + return promise; + } + + public delete(controller:Controller ) { + localStorage.removeItem(`controller-${controller.id}`); + this.controllerIds = this.controllerIds.filter((n) => n !== `controller-${controller.id}`); + this.updatecontrollerIds(); + + let promise = new Promise((resolve) => { + resolve(controller.id); + }); + return promise; + } + + public getControllerUrl(controller:Controller) { + return `${controller.protocol}//${controller.host}:${controller.port}/`; + } + + public checkControllerVersion(controller:Controller): Observable { + return this.httpController.get(controller, '/version'); + } + + public getLocalController(host: string, port: number) { + const promise = new Promise((resolve, reject) => { + this.findAll().then((controllers:Controller []) => { + const local = controllers.find((controller) => controller.location === 'bundled'); + if (local) { + local.host = host; + local.port = port; + local.protocol = location.protocol as ControllerProtocol; + this.update(local).then((updated) => { + resolve(updated); + }, reject); + } else { + const controller = new Controller (); + controller.name = 'local'; + controller.host = host; + controller.port = port; + controller.location = 'bundled'; + controller.protocol = location.protocol as ControllerProtocol; + this.create(controller).then((created) => { + resolve(created); + }, reject); + } + }, reject); + }); + + return promise; + } +} diff --git a/src/app/services/docker.service.ts b/src/app/services/docker.service.ts index eaf9b26d..56ba348f 100644 --- a/src/app/services/docker.service.ts +++ b/src/app/services/docker.service.ts @@ -2,33 +2,33 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; 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 { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class DockerService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getTemplates(server: Server): Observable { - return this.httpServer.get(server, '/templates') as Observable; + getTemplates(controller:Controller ): Observable { + return this.httpController.get(controller, '/templates') as Observable; } - getTemplate(server: Server, template_id: string): Observable { - return this.httpServer.get(server, `/templates/${template_id}`) as Observable; + getTemplate(controller:Controller , template_id: string): Observable { + return this.httpController.get(controller, `/templates/${template_id}`) as Observable; } - getImages(server: Server): Observable { - return this.httpServer.get(server, `/computes/${environment.compute_id}/docker/images`) as Observable; + getImages(controller:Controller ): Observable { + return this.httpController.get(controller, `/computes/${environment.compute_id}/docker/images`) as Observable; } - addTemplate(server: Server, dockerTemplate: any): Observable { - return this.httpServer.post(server, `/templates`, dockerTemplate) as Observable; + addTemplate(controller:Controller , dockerTemplate: any): Observable { + return this.httpController.post(controller, `/templates`, dockerTemplate) as Observable; } - saveTemplate(server: Server, dockerTemplate: any): Observable { - return this.httpServer.put( - server, + saveTemplate(controller:Controller , dockerTemplate: any): Observable { + return this.httpController.put( + controller, `/templates/${dockerTemplate.template_id}`, dockerTemplate ) as Observable; diff --git a/src/app/services/drawing.service.spec.ts b/src/app/services/drawing.service.spec.ts index d470a6a4..15894e62 100644 --- a/src/app/services/drawing.service.spec.ts +++ b/src/app/services/drawing.service.spec.ts @@ -5,29 +5,29 @@ import { environment } from 'environments/environment'; import { SvgToDrawingConverter } from '../cartography/helpers/svg-to-drawing-converter'; import { Drawing } from '../cartography/models/drawing'; import { Project } from '../models/project'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; import { DrawingService } from './drawing.service'; -import { HttpServer } from './http-server.service'; -import { getTestServer } from './testing'; +import { HttpController } from './http-controller.service'; +import { getTestController } from './testing'; describe('DrawingService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; let project: Project = new Project(); beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, SvgToDrawingConverter, DrawingService], + providers: [HttpController, SvgToDrawingConverter, DrawingService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); }); afterEach(() => { @@ -43,7 +43,7 @@ describe('DrawingService', () => { drawing.project_id = 'myproject'; drawing.drawing_id = 'id'; - service.updatePosition(server, project, drawing, 10, 20).subscribe(); + service.updatePosition(controller, project, drawing, 10, 20).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('PUT'); @@ -58,7 +58,7 @@ describe('DrawingService', () => { drawing.project_id = 'myproject'; drawing.drawing_id = 'id'; - service.updatePosition(server, project, drawing, 10.1, 20.6).subscribe(); + service.updatePosition(controller, project, drawing, 10.1, 20.6).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('PUT'); @@ -74,7 +74,7 @@ describe('DrawingService', () => { drawing.drawing_id = 'id'; let svgSample = ''; - service.updateSizeAndPosition(server, drawing, 100, 100, svgSample).subscribe(); + service.updateSizeAndPosition(controller, drawing, 100, 100, svgSample).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('PUT'); @@ -93,7 +93,7 @@ describe('DrawingService', () => { drawing.drawing_id = 'id'; let svgSample = ''; - service.updateSizeAndPosition(server, drawing, 100.1, 100.6, svgSample).subscribe(); + service.updateSizeAndPosition(controller, drawing, 100.1, 100.6, svgSample).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('PUT'); @@ -116,7 +116,7 @@ describe('DrawingService', () => { drawing.svg = ''; drawing.locked = false; - service.update(server, drawing).subscribe(); + service.update(controller, drawing).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('PUT'); @@ -135,7 +135,7 @@ describe('DrawingService', () => { drawing.project_id = 'myproject'; drawing.drawing_id = 'id'; - service.delete(server, drawing).subscribe(); + service.delete(controller, drawing).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings/id`); expect(req.request.method).toEqual('DELETE'); @@ -152,7 +152,7 @@ describe('DrawingService', () => { drawing.svg = ''; - service.duplicate(server, drawing.project_id, drawing).subscribe(); + service.duplicate(controller, drawing.project_id, drawing).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/${drawing.project_id}/drawings`); expect(req.request.method).toEqual('POST'); diff --git a/src/app/services/drawing.service.ts b/src/app/services/drawing.service.ts index 8a422996..1f4d11ae 100644 --- a/src/app/services/drawing.service.ts +++ b/src/app/services/drawing.service.ts @@ -4,15 +4,15 @@ import 'rxjs/add/operator/map'; import { SvgToDrawingConverter } from '../cartography/helpers/svg-to-drawing-converter'; import { Drawing } from '../cartography/models/drawing'; import { Project } from '../models/project'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; @Injectable() export class DrawingService { - constructor(private httpServer: HttpServer, private svgToDrawingConverter: SvgToDrawingConverter) {} + constructor(private httpController: HttpController, private svgToDrawingConverter: SvgToDrawingConverter) {} - add(server: Server, project_id: string, x: number, y: number, svg: string) { - return this.httpServer.post(server, `/projects/${project_id}/drawings`, { + add(controller:Controller , project_id: string, x: number, y: number, svg: string) { + return this.httpController.post(controller, `/projects/${project_id}/drawings`, { svg: svg, x: Math.round(x), y: Math.round(y), @@ -20,8 +20,8 @@ export class DrawingService { }); } - duplicate(server: Server, project_id: string, drawing: Drawing) { - return this.httpServer.post(server, `/projects/${project_id}/drawings`, { + duplicate(controller:Controller , project_id: string, drawing: Drawing) { + return this.httpController.post(controller, `/projects/${project_id}/drawings`, { svg: drawing.svg, rotation: drawing.rotation, x: drawing.x + 10, @@ -30,7 +30,7 @@ export class DrawingService { }); } - updatePosition(server: Server, project: Project, drawing: Drawing, x: number, y: number): Observable { + updatePosition(controller:Controller , project: Project, drawing: Drawing, x: number, y: number): Observable { let xPosition: number = Math.round(x); let yPosition: number = Math.round(y); @@ -46,22 +46,22 @@ export class DrawingService { yPosition = Math.round(yPosition - drawing.element.height / 2); } - return this.httpServer.put(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { + return this.httpController.put(controller, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { x: xPosition, y: yPosition, }); } - updateSizeAndPosition(server: Server, drawing: Drawing, x: number, y: number, svg: string): Observable { - return this.httpServer.put(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { + updateSizeAndPosition(controller:Controller , drawing: Drawing, x: number, y: number, svg: string): Observable { + return this.httpController.put(controller, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { svg: svg, x: Math.round(x), y: Math.round(y), }); } - updateText(server: Server, drawing: Drawing, svg: string): Observable { - return this.httpServer.put(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { + updateText(controller:Controller , drawing: Drawing, svg: string): Observable { + return this.httpController.put(controller, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { svg: svg, x: Math.round(drawing.x), y: Math.round(drawing.y), @@ -69,8 +69,8 @@ export class DrawingService { }); } - update(server: Server, drawing: Drawing): Observable { - return this.httpServer.put(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { + update(controller:Controller , drawing: Drawing): Observable { + return this.httpController.put(controller, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { locked: drawing.locked, svg: drawing.svg, rotation: drawing.rotation, @@ -80,7 +80,7 @@ export class DrawingService { }); } - delete(server: Server, drawing: Drawing) { - return this.httpServer.delete(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`); + delete(controller:Controller , drawing: Drawing) { + return this.httpController.delete(controller, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`); } } diff --git a/src/app/services/group.service.spec.ts b/src/app/services/group.service.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/services/group.service.ts b/src/app/services/group.service.ts new file mode 100644 index 00000000..649535a5 --- /dev/null +++ b/src/app/services/group.service.ts @@ -0,0 +1,74 @@ +/* +* 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'; +import {HttpController} from "./http-controller.service"; +import {Controller} from "../models/controller"; +import {Group} from "../models/groups/group"; +import {User} from "../models/users/user"; +import {Observable} from "rxjs"; +import {Role} from "@models/api/role"; + +@Injectable({ + providedIn: 'root' +}) +export class GroupService { + + constructor( + private httpController: HttpController + ) { + } + + getGroups(controller: Controller) { + return this.httpController.get(controller, '/groups'); + } + + getGroupMember(controller: Controller, groupId: string) { + return this.httpController.get(controller, `/groups/${groupId}/members`); + } + + addGroup(controller: Controller, name: string): Observable { + return this.httpController.post(controller, `/groups`, {name}); + } + + delete(controller: Controller, user_group_id: string) { + return this.httpController.delete(controller, `/groups/${user_group_id}`); + } + + get(controller: Controller, user_group_id: string) { + return this.httpController.get(controller, `/groups/${user_group_id}`); + } + + addMemberToGroup(controller: Controller, group: Group, user: User) { + return this.httpController.put(controller, `/groups/${group.user_group_id}/members/${user.user_id}`, {}); + } + + removeUser(controller: Controller, group: Group, user: User) { + return this.httpController.delete(controller, `/groups/${group.user_group_id}/members/${user.user_id}`); + } + + update(controller: Controller, group: Group) { + return this.httpController.put(controller, `/groups/${group.user_group_id}`, {name: group.name}); + } + + getGroupRole(controller: Controller, groupId: string) { + return this.httpController.get(controller, `/groups/${groupId}/roles`); + } + + removeRole(controller: Controller, group: Group, role: Role) { + return this.httpController.delete(controller, `/groups/${group.user_group_id}/roles/${role.role_id}`); + } + + addRoleToGroup(controller: Controller, group: Group, role: Role) { + return this.httpController.put(controller, `/groups/${group.user_group_id}/roles/${role.role_id}`, {}); + } +} diff --git a/src/app/services/http-server.service.spec.ts b/src/app/services/http-controller.service.spec.ts similarity index 78% rename from src/app/services/http-server.service.spec.ts rename to src/app/services/http-controller.service.spec.ts index 12d17859..064e2131 100644 --- a/src/app/services/http-server.service.spec.ts +++ b/src/app/services/http-controller.service.spec.ts @@ -2,38 +2,38 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer, ServerError, ServerErrorHandler } from './http-server.service'; -import { getTestServer } from './testing'; +import { HttpController, ControllerError, ControllerErrorHandler } from './http-controller.service'; +import { getTestController } from './testing'; class MyType { id: number; } -describe('ServerError', () => { +describe('ControllerError', () => { it('should construct with message', () => { const error = new Error('test'); expect(error.message).toEqual('test'); }); - it('should construct ServerError from error', () => { + it('should construct ControllerError from error', () => { const error = new Error('test'); - const serverError = ServerError.fromError('new message', error); - expect(serverError.originalError).toEqual(error); - expect(serverError.message).toEqual('new message'); + const controllerError = ControllerError.fromError('new message', error); + expect(controllerError.originalError).toEqual(error); + expect(controllerError.message).toEqual('new message'); }); }); -describe('ServerErrorHandler', () => { +describe('ControllerErrorHandler', () => { it('should handle HttpErrorResponse with status 0', (done) => { const error = new HttpErrorResponse({ status: 0 }); - const handler = new ServerErrorHandler(); + const handler = new ControllerErrorHandler(); const result = handler.handleError(error); result.subscribe(null, (err) => { - expect(err.message).toEqual('Server is unreachable'); + expect(err.message).toEqual('Controller is unreachable'); done(); }); }); @@ -41,7 +41,7 @@ describe('ServerErrorHandler', () => { it('should not handle HttpErrorResponse with status!=0', (done) => { const error = new HttpErrorResponse({ status: 499 }); - const handler = new ServerErrorHandler(); + const handler = new ControllerErrorHandler(); const result = handler.handleError(error); result.subscribe(null, (err) => { @@ -51,23 +51,23 @@ describe('ServerErrorHandler', () => { }); }); -describe('HttpServer', () => { +describe('HttpController', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let service: HttpServer; - let server: Server; + let service: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer], + providers: [HttpController], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - service = TestBed.get(HttpServer); + service = TestBed.get(HttpController); - server = getTestServer(); + controller = getTestController(); }); afterEach(() => { @@ -75,7 +75,7 @@ describe('HttpServer', () => { }); it('should make GET query for get method', () => { - service.get(server, '/test').subscribe(); + service.get(controller, '/test').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('GET'); @@ -85,7 +85,7 @@ describe('HttpServer', () => { it('should make GET query for get method and return instance of type', () => { const testData: MyType = { id: 3 }; - service.get(server, '/test').subscribe((data) => { + service.get(controller, '/test').subscribe((data) => { expect(data instanceof MyType).toBeFalsy(); expect(data).toEqual(testData); }); @@ -114,7 +114,7 @@ describe('HttpServer', () => { }); it('should make GET query for getText method', () => { - service.getText(server, '/test').subscribe(); + service.getText(controller, '/test').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('GET'); @@ -123,7 +123,7 @@ describe('HttpServer', () => { it('should make GET query for getText method and preserve options', () => { service - .getText(server, '/test', { + .getText(controller, '/test', { headers: { CustomHeader: 'value', }, @@ -137,7 +137,7 @@ describe('HttpServer', () => { }); it('should make POST query for post method', () => { - service.post(server, '/test', { test: '1' }).subscribe(); + service.post(controller, '/test', { test: '1' }).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('POST'); @@ -145,7 +145,7 @@ describe('HttpServer', () => { }); it('should make PUT query for put method', () => { - service.put(server, '/test', { test: '1' }).subscribe(); + service.put(controller, '/test', { test: '1' }).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('PUT'); @@ -153,7 +153,7 @@ describe('HttpServer', () => { }); it('should make DELETE query for delete method', () => { - service.delete(server, '/test').subscribe(); + service.delete(controller, '/test').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('DELETE'); @@ -161,7 +161,7 @@ describe('HttpServer', () => { }); it('should make PATCH query for patch method', () => { - service.patch(server, '/test', { test: '1' }).subscribe(); + service.patch(controller, '/test', { test: '1' }).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('PATCH'); @@ -169,7 +169,7 @@ describe('HttpServer', () => { }); it('should make HEAD query for head method', () => { - service.head(server, '/test').subscribe(); + service.head(controller, '/test').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('HEAD'); @@ -177,7 +177,7 @@ describe('HttpServer', () => { }); it('should make OPTIONS query for options method', () => { - service.options(server, '/test').subscribe(); + service.options(controller, '/test').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/test`); expect(req.request.method).toEqual('OPTIONS'); @@ -185,11 +185,11 @@ describe('HttpServer', () => { }); it('should make local call when ip and port is not defined', () => { - server.host = null; - server.port = null; + controller.host = null; + controller.port = null; service - .get(server, '/test', { + .get(controller, '/test', { headers: { CustomHeader: 'value', }, diff --git a/src/app/services/http-server.service.ts b/src/app/services/http-controller.service.ts similarity index 66% rename from src/app/services/http-server.service.ts rename to src/app/services/http-controller.service.ts index 5668c286..09d961ed 100644 --- a/src/app/services/http-server.service.ts +++ b/src/app/services/http-controller.service.ts @@ -3,7 +3,7 @@ import { EventEmitter, Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; -import { Server, ServerProtocol } from '../models/server'; +import {Controller , ControllerProtocol } from '../models/controller'; /* tslint:disable:interface-over-type-literal */ export type JsonOptions = { @@ -66,7 +66,7 @@ export type HeadersOptions = { }; /* tslint:enable:interface-over-type-literal */ -export class ServerError extends Error { +export class ControllerError extends Error { public originalError: Error; constructor(message: string) { @@ -74,19 +74,19 @@ export class ServerError extends Error { } static fromError(message: string, originalError: Error) { - const serverError = new ServerError(message); - serverError.originalError = originalError; - return serverError; + const controllerError = new ControllerError(message); + controllerError.originalError = originalError; + return controllerError; } } @Injectable() -export class ServerErrorHandler { +export class ControllerErrorHandler { handleError(error: HttpErrorResponse) { let err: Error = error; if (error.name === 'HttpErrorResponse' && error.status === 0) { - err = ServerError.fromError('Server is unreachable', error); + err = ControllerError.fromError('Controller is unreachable', error); } if (error.status === 401) { @@ -98,14 +98,14 @@ export class ServerErrorHandler { } @Injectable() -export class HttpServer { +export class HttpController { public requestsNotificationEmitter = new EventEmitter(); - constructor(private http: HttpClient, private errorHandler: ServerErrorHandler) {} + constructor(private http: HttpClient, private errorHandler: ControllerErrorHandler) {} - get(server: Server, url: string, options?: JsonOptions): Observable { + get(controller:Controller , url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`); return this.http @@ -113,9 +113,9 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)) as Observable; } - getText(server: Server, url: string, options?: TextOptions): Observable { + getText(controller:Controller , url: string, options?: TextOptions): Observable { options = this.getTextOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`); return this.http @@ -123,9 +123,9 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)); } - getBlob(server: Server, url: string, options?: BlobOptions): Observable { + getBlob(controller:Controller , url: string, options?: BlobOptions): Observable { options = this.getBlobOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`); return this.http @@ -133,9 +133,9 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)); } - post(server: Server, url: string, body: any | null, options?: JsonOptions): Observable { + post(controller:Controller , url: string, body: any | null, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`POST ${intercepted.url}`); return this.http @@ -143,9 +143,9 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)) as Observable; } - put(server: Server, url: string, body: any, options?: JsonOptions): Observable { + put(controller:Controller , url: string, body: any, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`PUT ${intercepted.url}`); return this.http @@ -153,9 +153,9 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)) as Observable; } - delete(server: Server, url: string, options?: JsonOptions): Observable { + delete(controller:Controller , url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); this.requestsNotificationEmitter.emit(`DELETE ${intercepted.url}`); return this.http @@ -163,25 +163,25 @@ export class HttpServer { .pipe(catchError(this.errorHandler.handleError)) as Observable; } - patch(server: Server, url: string, body: any, options?: JsonOptions): Observable { + patch(controller:Controller , url: string, body: any, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); return this.http .patch(intercepted.url, body, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; } - head(server: Server, url: string, options?: JsonOptions): Observable { + head(controller:Controller , url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); return this.http .head(intercepted.url, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; } - options(server: Server, url: string, options?: JsonOptions): Observable { + options(controller:Controller , url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); - const intercepted = this.getOptionsForServer(server, url, options); + const intercepted = this.getOptionsForController(controller, url, options); return this.http .options(intercepted.url, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; @@ -214,12 +214,12 @@ export class HttpServer { return options; } - private getOptionsForServer(server: Server, url: string, options: T) { - if (server && server.host && server.port) { - if (!server.protocol) { - server.protocol = location.protocol as ServerProtocol; + private getOptionsForController(controller:Controller , url: string, options: T) { + if (controller && controller.host && controller.port) { + if (!controller.protocol) { + controller.protocol = location.protocol as ControllerProtocol; } - url = `${server.protocol}//${server.host}:${server.port}/${environment.current_version}${url}`; + url = `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}${url}`; } else { url = `/${environment.current_version}${url}`; } @@ -228,8 +228,8 @@ export class HttpServer { options.headers = {}; } - if (server && server.authToken && !server.tokenExpired) { - options.headers['Authorization'] = `Bearer ${server.authToken}`; + if (controller && controller.authToken && !controller.tokenExpired) { + options.headers['Authorization'] = `Bearer ${controller.authToken}`; } return { diff --git a/src/app/services/image-manager.service.spec.ts b/src/app/services/image-manager.service.spec.ts index 4b02887d..33c241ec 100644 --- a/src/app/services/image-manager.service.spec.ts +++ b/src/app/services/image-manager.service.spec.ts @@ -2,9 +2,9 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { AppTestingModule } from 'app/testing/app-testing/app-testing.module'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; -import { getTestServer } from './testing'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; +import { getTestController } from './testing'; import { ImageManagerService } from './image-manager.service'; import { Image } from "../models/images"; @@ -13,19 +13,19 @@ import { environment } from 'environments/environment'; describe('ImageManagerService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, ImageManagerService], + providers: [HttpController, ImageManagerService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); // service = TestBed.inject(ImageManagerService); }); afterEach(() => { @@ -34,7 +34,7 @@ describe('ImageManagerService', () => { it('should be get Images', inject([ImageManagerService], (service: ImageManagerService) => { - service.getImages(server).subscribe(); + service.getImages(controller).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/images`); expect(req.request.method).toEqual('GET'); expect(service).toBeTruthy(); @@ -53,7 +53,7 @@ describe('ImageManagerService', () => { updated_at: '', }; - service.uploadedImage(server, install_appliance, image.filename, image).subscribe(); + service.uploadedImage(controller, install_appliance, image.filename, image).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/images/upload/?install_appliances=true`); expect(req.request.method).toEqual('POST'); expect(req.request.body).toEqual(image); diff --git a/src/app/services/image-manager.service.ts b/src/app/services/image-manager.service.ts index 9c210b6f..97c2abbb 100644 --- a/src/app/services/image-manager.service.ts +++ b/src/app/services/image-manager.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; import { Observable } from 'rxjs'; import { Image } from "../models/images"; import { environment } from 'environments/environment'; @@ -10,24 +10,24 @@ import { environment } from 'environments/environment'; }) export class ImageManagerService { - constructor(private httpServer: HttpServer) { } + constructor(private httpController: HttpController) { } - getImages(server: Server) { - return this.httpServer.get(server, '/images') as Observable; + getImages(controller:Controller ) { + return this.httpController.get(controller, '/images') as Observable; } - getImagePath(server:Server, install_appliance, image_path){ - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/images/upload/${image_path}?install_appliances=${install_appliance}`; + getImagePath(controller :Controller, install_appliance, image_path){ + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/images/upload/${image_path}?install_appliances=${install_appliance}`; } - getUploadPath(server: Server, emulator: string, filename: string) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/images/upload/${filename}`; + getUploadPath(controller:Controller , emulator: string, filename: string) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/images/upload/${filename}`; } - uploadedImage(server:Server, install_appliance, image_path, flie){ - return this.httpServer.post(server, `/images/upload/${image_path}?install_appliances=${install_appliance}`,flie) as Observable; + uploadedImage(controller :Controller, install_appliance, image_path, flie){ + return this.httpController.post(controller, `/images/upload/${image_path}?install_appliances=${install_appliance}`,flie) as Observable; } - deleteFile(server:Server, image_path){ - return this.httpServer.delete(server, `/images/${image_path}`) as Observable; + deleteFile(controller :Controller, image_path){ + return this.httpController.delete(controller, `/images/${image_path}`) as Observable; } } diff --git a/src/app/services/info.service.ts b/src/app/services/info.service.ts index 4ebb966c..eba7b226 100644 --- a/src/app/services/info.service.ts +++ b/src/app/services/info.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; import { Node } from '../cartography/models/node'; import { Port } from '../models/port'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; @Injectable() export class InfoService { - getInfoAboutNode(node: Node, server: Server): string[] { + getInfoAboutNode(node: Node, controller:Controller ): string[] { let infoList: string[] = []; if (node.node_type === 'cloud') { infoList.push(`Cloud ${node.name} is always on.`); @@ -34,8 +34,8 @@ export class InfoService { } else if (node.node_type === 'vpcs') { infoList.push(`Node ${node.name} is ${node.status}.`); } - infoList.push(`Running on server ${server.name} with port ${server.port}.`); - infoList.push(`Server ID is ${server.id}.`); + infoList.push(`Running on controller ${controller.name} with port ${controller.port}.`); + infoList.push(`Controller ID is ${controller.id}.`); if (node.console_type !== 'none' && node.console_type !== 'null') { infoList.push(`Console is on port ${node.console} and type is ${node.console_type}.`); } @@ -46,7 +46,7 @@ export class InfoService { getInfoAboutPorts(ports: Port[]): string { let response: string = `Ports: `; ports.forEach((port) => { - response += `link_type: ${port.link_type}, + response += `link_type: ${port.link_type}, name: ${port.name}; `; }); response = response.substring(0, response.length - 2); diff --git a/src/app/services/ios.service.ts b/src/app/services/ios.service.ts index 1d6e8e58..d72a1f6e 100644 --- a/src/app/services/ios.service.ts +++ b/src/app/services/ios.service.ts @@ -2,37 +2,37 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; 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 { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class IosService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getImages(server: Server): Observable { - return this.httpServer.get(server, '/images?image_type=ios') as Observable; + getImages(controller:Controller ): Observable { + return this.httpController.get(controller, '/images?image_type=ios') as Observable; } - getImagePath(server: Server, filename: string): string { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/images/upload/${filename}`; + getImagePath(controller:Controller , filename: string): string { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/images/upload/${filename}`; } - getTemplates(server: Server): Observable { - return this.httpServer.get(server, '/templates') as Observable; + getTemplates(controller:Controller ): Observable { + return this.httpController.get(controller, '/templates') as Observable; } - getTemplate(server: Server, template_id: string): Observable { - return this.httpServer.get(server, `/templates/${template_id}`) as Observable; + getTemplate(controller:Controller , template_id: string): Observable { + return this.httpController.get(controller, `/templates/${template_id}`) as Observable; } - addTemplate(server: Server, iosTemplate: IosTemplate): Observable { - return this.httpServer.post(server, `/templates`, iosTemplate) as Observable; + addTemplate(controller:Controller , iosTemplate: IosTemplate): Observable { + return this.httpController.post(controller, `/templates`, iosTemplate) as Observable; } - saveTemplate(server: Server, iosTemplate: IosTemplate): Observable { - return this.httpServer.put( - server, + saveTemplate(controller:Controller , iosTemplate: IosTemplate): Observable { + return this.httpController.put( + controller, `/templates/${iosTemplate.template_id}`, iosTemplate ) as Observable; diff --git a/src/app/services/iou.service.ts b/src/app/services/iou.service.ts index b1675e22..da3f22d9 100644 --- a/src/app/services/iou.service.ts +++ b/src/app/services/iou.service.ts @@ -2,37 +2,37 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; 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 { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class IouService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getTemplates(server: Server): Observable { - return this.httpServer.get(server, '/templates') as Observable; + getTemplates(controller:Controller ): Observable { + return this.httpController.get(controller, '/templates') as Observable; } - getTemplate(server: Server, template_id: string): Observable { - return this.httpServer.get(server, `/templates/${template_id}`) as Observable; + getTemplate(controller:Controller , template_id: string): Observable { + return this.httpController.get(controller, `/templates/${template_id}`) as Observable; } - getImages(server: Server): Observable { - return this.httpServer.get(server, '/images?image_type=iou') as Observable; + getImages(controller:Controller ): Observable { + return this.httpController.get(controller, '/images?image_type=iou') as Observable; } - getImagePath(server: Server, filename: string): string { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/images/upload/${filename}`; + getImagePath(controller:Controller , filename: string): string { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/images/upload/${filename}`; } - addTemplate(server: Server, iouTemplate: any): Observable { - return this.httpServer.post(server, `/templates`, iouTemplate) as Observable; + addTemplate(controller:Controller , iouTemplate: any): Observable { + return this.httpController.post(controller, `/templates`, iouTemplate) as Observable; } - saveTemplate(server: Server, iouTemplate: any): Observable { - return this.httpServer.put( - server, + saveTemplate(controller:Controller , iouTemplate: any): Observable { + return this.httpController.put( + controller, `/templates/${iouTemplate.template_id}`, iouTemplate ) as Observable; diff --git a/src/app/services/link.service.spec.ts b/src/app/services/link.service.spec.ts index a4cc5e8d..fdb38e6a 100644 --- a/src/app/services/link.service.spec.ts +++ b/src/app/services/link.service.spec.ts @@ -4,28 +4,28 @@ import { inject, TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; import { Node } from '../cartography/models/node'; import { Port } from '../models/port'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { LinkService } from './link.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; describe('LinkService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, LinkService], + providers: [HttpController, LinkService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); }); afterEach(() => { @@ -52,7 +52,7 @@ describe('LinkService', () => { targetPort.port_number = 3; targetPort.adapter_number = 4; - service.createLink(server, sourceNode, sourcePort, targetNode, targetPort, 0, 0, 10, 10).subscribe(); + service.createLink(controller, sourceNode, sourcePort, targetNode, targetPort, 0, 0, 10, 10).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/links`); expect(req.request.method).toEqual('POST'); diff --git a/src/app/services/link.service.ts b/src/app/services/link.service.ts index 17e722b9..79970602 100644 --- a/src/app/services/link.service.ts +++ b/src/app/services/link.service.ts @@ -6,15 +6,15 @@ import { FilterDescription } from '../models/filter-description'; import { Link } from '../models/link'; import { LinkNode } from '../models/link-node'; import { Port } from '../models/port'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; @Injectable() export class LinkService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} createLink( - server: Server, + controller:Controller , source_node: Node, source_port: Port, target_node: Node, @@ -24,7 +24,7 @@ export class LinkService { xLabelTargetNode: number, yLabelTargetNode: number ) { - return this.httpServer.post(server, `/projects/${source_node.project_id}/links`, { + return this.httpController.post(controller, `/projects/${source_node.project_id}/links`, { nodes: [ { node_id: source_node.node_id, @@ -54,33 +54,33 @@ export class LinkService { }); } - getLink(server: Server, projectId: string, linkId: string) { - return this.httpServer.get(server, `/projects/${projectId}/links/${linkId}`); + getLink(controller:Controller , projectId: string, linkId: string) { + return this.httpController.get(controller, `/projects/${projectId}/links/${linkId}`); } - deleteLink(server: Server, link: Link) { - return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`); + deleteLink(controller:Controller , link: Link) { + return this.httpController.delete(controller, `/projects/${link.project_id}/links/${link.link_id}`); } - updateLink(server: Server, link: Link) { + updateLink(controller:Controller , link: Link) { link.x = Math.round(link.x); link.y = Math.round(link.y); - return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, link); + return this.httpController.put(controller, `/projects/${link.project_id}/links/${link.link_id}`, link); } - updateLinkStyle(server: Server, link: Link) { - return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, link); + updateLinkStyle(controller:Controller , link: Link) { + return this.httpController.put(controller, `/projects/${link.project_id}/links/${link.link_id}`, link); } - getAvailableFilters(server: Server, link: Link) { - return this.httpServer.get( - server, + getAvailableFilters(controller:Controller , link: Link) { + return this.httpController.get( + controller, `/projects/${link.project_id}/links/${link.link_id}/available_filters` ); } - updateNodes(server: Server, link: Link, nodes: LinkNode[]) { + updateNodes(controller:Controller , link: Link, nodes: LinkNode[]) { const requestNodes = nodes.map((linkNode) => { return { node_id: linkNode.node_id, @@ -96,22 +96,22 @@ export class LinkService { }; }); - return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, { nodes: requestNodes }); + return this.httpController.put(controller, `/projects/${link.project_id}/links/${link.link_id}`, { nodes: requestNodes }); } - startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) { - return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/capture/start`, settings); + startCaptureOnLink(controller:Controller , link: Link, settings: CapturingSettings) { + return this.httpController.post(controller, `/projects/${link.project_id}/links/${link.link_id}/capture/start`, settings); } - stopCaptureOnLink(server: Server, link: Link) { - return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/capture/stop`, {}); + stopCaptureOnLink(controller:Controller , link: Link) { + return this.httpController.post(controller, `/projects/${link.project_id}/links/${link.link_id}/capture/stop`, {}); } - resetLink(server: Server, link: Link) { - return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/reset`, {}); + resetLink(controller:Controller , link: Link) { + return this.httpController.post(controller, `/projects/${link.project_id}/links/${link.link_id}/reset`, {}); } - streamPcap(server: Server, link: Link) { - return this.httpServer.get(server, `/projects/${link.project_id}/links/${link.link_id}/capture/stream`); + streamPcap(controller:Controller , link: Link) { + return this.httpController.get(controller, `/projects/${link.project_id}/links/${link.link_id}/capture/stream`); } } diff --git a/src/app/services/login.service.ts b/src/app/services/login.service.ts index a5ff85b7..2044c948 100644 --- a/src/app/services/login.service.ts +++ b/src/app/services/login.service.ts @@ -1,16 +1,16 @@ import { HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import 'rxjs/add/operator/map'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; import { AuthResponse } from '../models/authResponse'; @Injectable() export class LoginService { - server_id:string ='' - constructor(private httpServer: HttpServer) {} + controller_id:string ='' + constructor(private httpController: HttpController) {} - login(server: Server, username: string, password: string) { + login(controller:Controller , username: string, password: string) { const payload = new HttpParams() .set('username', username) .set('password', password); @@ -19,13 +19,13 @@ export class LoginService { headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded') }; - return this.httpServer.post(server, '/users/login', payload, options); + return this.httpController.post(controller, '/users/login', payload, options); } - getLoggedUser(server: Server) { - return this.httpServer.get(server, "/users/me").toPromise() + getLoggedUser(controller:Controller ) { + return this.httpController.get(controller, "/users/me").toPromise() } - async getLoggedUserRefToken(server: Server,current_user):Promise { - return await this.httpServer.post(server, "/users/authenticate", {"username":current_user.username,"password":current_user.password}).toPromise() + async getLoggedUserRefToken(controller:Controller ,current_user):Promise { + return await this.httpController.post(controller, "/users/authenticate", {"username":current_user.username,"password":current_user.password}).toPromise() } } diff --git a/src/app/services/node.service.spec.ts b/src/app/services/node.service.spec.ts index 7760fc7b..562c8cf7 100644 --- a/src/app/services/node.service.spec.ts +++ b/src/app/services/node.service.spec.ts @@ -5,34 +5,34 @@ import { environment } from 'environments/environment'; import { Label } from '../cartography/models/label'; import { Node } from '../cartography/models/node'; import { Project } from '../models/project'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Template } from '../models/template'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { NodeService } from './node.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; describe('NodeService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; + let httpController: HttpController; let service: NodeService; - let server: Server; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], providers: [ - HttpServer, + HttpController, NodeService, ], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); + httpController = TestBed.get(HttpController); service = TestBed.get(NodeService); - server = getTestServer(); + controller = getTestController(); }); afterEach(() => { @@ -48,7 +48,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.start(server, node).subscribe(); + service.start(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id/start`); expect(req.request.method).toEqual('POST'); @@ -60,7 +60,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.stop(server, node).subscribe(); + service.stop(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id/stop`); expect(req.request.method).toEqual('POST'); @@ -72,7 +72,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.suspend(server, node).subscribe(); + service.suspend(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id/suspend`); expect(req.request.method).toEqual('POST'); @@ -84,7 +84,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.reload(server, node).subscribe(); + service.reload(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id/reload`); expect(req.request.method).toEqual('POST'); @@ -96,7 +96,7 @@ describe('NodeService', () => { project_id: '1', } as Project; - service.startAll(server, project).subscribe(); + service.startAll(controller, project).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/1/nodes/start`); expect(req.request.method).toEqual('POST'); @@ -108,7 +108,7 @@ describe('NodeService', () => { project_id: '1', } as Project; - service.stopAll(server, project).subscribe(); + service.stopAll(controller, project).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/1/nodes/stop`); expect(req.request.method).toEqual('POST'); @@ -120,7 +120,7 @@ describe('NodeService', () => { project_id: '1', } as Project; - service.suspendAll(server, project).subscribe(); + service.suspendAll(controller, project).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/1/nodes/suspend`); expect(req.request.method).toEqual('POST'); @@ -132,7 +132,7 @@ describe('NodeService', () => { project_id: '1', } as Project; - service.reloadAll(server, project).subscribe(); + service.reloadAll(controller, project).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/1/nodes/reload`); expect(req.request.method).toEqual('POST'); @@ -145,7 +145,7 @@ describe('NodeService', () => { const template = new Template(); template.template_id = 'mytemplate'; - service.createFromTemplate(server, project, template, 10, 20, 'compute').subscribe(); + service.createFromTemplate(controller, project, template, 10, 20, 'compute').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/templates/mytemplate`); expect(req.request.method).toEqual('POST'); @@ -164,7 +164,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.updatePosition(server, project, node, 10, 20).subscribe(); + service.updatePosition(controller, project, node, 10, 20).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id`); expect(req.request.method).toEqual('PUT'); @@ -182,7 +182,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.updatePosition(server, project, node, 10.1, 20.6).subscribe(); + service.updatePosition(controller, project, node, 10.1, 20.6).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id`); expect(req.request.method).toEqual('PUT'); @@ -204,7 +204,7 @@ describe('NodeService', () => { label.x = 10; label.y = 20; - service.updateLabel(server, node, label).subscribe(); + service.updateLabel(controller, node, label).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id`); expect(req.request.method).toEqual('PUT'); @@ -227,7 +227,7 @@ describe('NodeService', () => { node.y = 20; node.z = 30; - service.update(server, node).subscribe(); + service.update(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id`); expect(req.request.method).toEqual('PUT'); @@ -243,7 +243,7 @@ describe('NodeService', () => { node.project_id = 'myproject'; node.node_id = 'id'; - service.delete(server, node).subscribe(); + service.delete(controller, node).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes/id`); expect(req.request.method).toEqual('DELETE'); @@ -254,7 +254,7 @@ describe('NodeService', () => { node.project_id = 'project_id_1'; node.node_id = 'node_id_1'; - service.duplicate(server, node).subscribe(); + service.duplicate(controller, node).subscribe(); const req = httpTestingController.expectOne( `http://127.0.0.1:3080/${environment.current_version}/projects/${node.project_id}/nodes/${node.node_id}/duplicate` diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index 3b70fadb..dd0e781a 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -4,63 +4,63 @@ import 'rxjs/add/operator/map'; import { Label } from '../cartography/models/label'; import { Node } from '../cartography/models/node'; import { Project } from '../models/project'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Template } from '../models/template'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class NodeService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getNodeById(server: Server, projectId: string, nodeId: string) { - return this.httpServer.get(server, `/projects/${projectId}/nodes/${nodeId}`); + getNodeById(controller:Controller , projectId: string, nodeId: string) { + return this.httpController.get(controller, `/projects/${projectId}/nodes/${nodeId}`); } - isolate(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/isolate`, {}); + isolate(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/isolate`, {}); } - unisolate(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/unisolate`, {}); + unisolate(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/unisolate`, {}); } - start(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/start`, {}); + start(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/start`, {}); } - startAll(server: Server, project: Project) { - return this.httpServer.post(server, `/projects/${project.project_id}/nodes/start`, {}); + startAll(controller:Controller , project: Project) { + return this.httpController.post(controller, `/projects/${project.project_id}/nodes/start`, {}); } - stop(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/stop`, {}); + stop(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/stop`, {}); } - stopAll(server: Server, project: Project) { - return this.httpServer.post(server, `/projects/${project.project_id}/nodes/stop`, {}); + stopAll(controller:Controller , project: Project) { + return this.httpController.post(controller, `/projects/${project.project_id}/nodes/stop`, {}); } - suspend(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/suspend`, {}); + suspend(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/suspend`, {}); } - suspendAll(server: Server, project: Project) { - return this.httpServer.post(server, `/projects/${project.project_id}/nodes/suspend`, {}); + suspendAll(controller:Controller , project: Project) { + return this.httpController.post(controller, `/projects/${project.project_id}/nodes/suspend`, {}); } - reload(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/reload`, {}); + reload(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/reload`, {}); } - reloadAll(server: Server, project: Project) { - return this.httpServer.post(server, `/projects/${project.project_id}/nodes/reload`, {}); + reloadAll(controller:Controller , project: Project) { + return this.httpController.post(controller, `/projects/${project.project_id}/nodes/reload`, {}); } - resetAllNodes(server: Server, project: Project) { - return this.httpServer.post(server, `/projects/${project.project_id}/nodes/console/reset`, {}); + resetAllNodes(controller:Controller , project: Project) { + return this.httpController.post(controller, `/projects/${project.project_id}/nodes/console/reset`, {}); } createFromTemplate( - server: Server, + controller:Controller , project: Project, template: Template, x: number, @@ -68,20 +68,20 @@ export class NodeService { compute_id: string ): Observable { if (!compute_id) { - return this.httpServer.post(server, `/projects/${project.project_id}/templates/${template.template_id}`, { + return this.httpController.post(controller, `/projects/${project.project_id}/templates/${template.template_id}`, { x: Math.round(x), y: Math.round(y), compute_id: 'local', }); } - return this.httpServer.post(server, `/projects/${project.project_id}/templates/${template.template_id}`, { + return this.httpController.post(controller, `/projects/${project.project_id}/templates/${template.template_id}`, { x: Math.round(x), y: Math.round(y), compute_id: compute_id, }); } - updatePosition(server: Server, project: Project, node: Node, x: number, y: number): Observable { + updatePosition(controller:Controller , project: Project, node: Node, x: number, y: number): Observable { let xPosition: number = Math.round(x); let yPosition: number = Math.round(y); @@ -93,14 +93,14 @@ export class NodeService { yPosition = Math.round(yPosition - node.height / 2); } - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { x: xPosition, y: yPosition, }); } - updateLabel(server: Server, node: Node, label: Label): Observable { - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + updateLabel(controller:Controller , node: Node, label: Label): Observable { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { label: { rotation: label.rotation, style: label.style, @@ -111,22 +111,22 @@ export class NodeService { }); } - updateSymbol(server: Server, node: Node, changedSymbol: string): Observable { - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + updateSymbol(controller:Controller , node: Node, changedSymbol: string): Observable { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { symbol: changedSymbol, }); } - update(server: Server, node: Node): Observable { - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + update(controller:Controller , node: Node): Observable { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { x: Math.round(node.x), y: Math.round(node.y), z: node.z, }); } - updateNode(server: Server, node: Node): Observable { - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + updateNode(controller:Controller , node: Node): Observable { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { console_type: node.console_type, console_auto_start: node.console_auto_start, locked: node.locked, @@ -135,8 +135,8 @@ export class NodeService { }); } - updateNodeWithCustomAdapters(server: Server, node: Node): Observable { - return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + updateNodeWithCustomAdapters(controller:Controller , node: Node): Observable { + return this.httpController.put(controller, `/projects/${node.project_id}/nodes/${node.node_id}`, { console_type: node.console_type, console_auto_start: node.console_auto_start, custom_adapters: node.custom_adapters, @@ -145,43 +145,43 @@ export class NodeService { }); } - delete(server: Server, node: Node) { - return this.httpServer.delete(server, `/projects/${node.project_id}/nodes/${node.node_id}`); + delete(controller:Controller , node: Node) { + return this.httpController.delete(controller, `/projects/${node.project_id}/nodes/${node.node_id}`); } - duplicate(server: Server, node: Node) { - return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/duplicate`, { + duplicate(controller:Controller , node: Node) { + return this.httpController.post(controller, `/projects/${node.project_id}/nodes/${node.node_id}/duplicate`, { x: node.x + 10, y: node.y + 10, z: node.z, }); } - getNode(server: Server, node: Node) { - return this.httpServer.get(server, `/projects/${node.project_id}/nodes/${node.node_id}`); + getNode(controller:Controller , node: Node) { + return this.httpController.get(controller, `/projects/${node.project_id}/nodes/${node.node_id}`); } getDefaultCommand(): string { return `putty.exe -telnet \%h \%p -wt \"\%d\" -gns3 5 -skin 4`; } - getNetworkConfiguration(server: Server, node: Node) { - return this.httpServer.get( - server, + getNetworkConfiguration(controller:Controller , node: Node) { + return this.httpController.get( + controller, `/projects/${node.project_id}/nodes/${node.node_id}/files/etc/network/interfaces`, { responseType: 'text' as 'json' } ); } - saveNetworkConfiguration(server: Server, node: Node, configuration: string) { - return this.httpServer.post( - server, + saveNetworkConfiguration(controller:Controller , node: Node, configuration: string) { + return this.httpController.post( + controller, `/projects/${node.project_id}/nodes/${node.node_id}/files/etc/network/interfaces`, configuration ); } - getStartupConfiguration(server: Server, node: Node) { + getStartupConfiguration(controller:Controller , node: Node) { let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`; if (node.node_type === 'vpcs') { @@ -192,10 +192,10 @@ export class NodeService { urlPath += `/files/configs/i${node.node_id}_startup-config.cfg`; } - return this.httpServer.get(server, urlPath, { responseType: 'text' as 'json' }); + return this.httpController.get(controller, urlPath, { responseType: 'text' as 'json' }); } - getPrivateConfiguration(server: Server, node: Node) { + getPrivateConfiguration(controller:Controller , node: Node) { let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`; if (node.node_type === 'iou') { @@ -204,10 +204,10 @@ export class NodeService { urlPath += `/files/configs/i${node.node_id}_private-config.cfg`; } - return this.httpServer.get(server, urlPath, { responseType: 'text' as 'json' }); + return this.httpController.get(controller, urlPath, { responseType: 'text' as 'json' }); } - saveConfiguration(server: Server, node: Node, configuration: string) { + saveConfiguration(controller:Controller , node: Node, configuration: string) { let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`; if (node.node_type === 'vpcs') { @@ -218,10 +218,10 @@ export class NodeService { urlPath += `/files/configs/i${node.node_id}_startup-config.cfg`; } - return this.httpServer.post(server, urlPath, configuration); + return this.httpController.post(controller, urlPath, configuration); } - savePrivateConfiguration(server: Server, node: Node, configuration: string) { + savePrivateConfiguration(controller:Controller , node: Node, configuration: string) { let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`; if (node.node_type === 'iou') { @@ -230,6 +230,6 @@ export class NodeService { urlPath += `/files/configs/i${node.node_id}_private-config.cfg`; } - return this.httpServer.post(server, urlPath, configuration); + return this.httpController.post(controller, urlPath, configuration); } } diff --git a/src/app/services/nodeConsole.service.ts b/src/app/services/nodeConsole.service.ts index e38e4617..ba66c829 100644 --- a/src/app/services/nodeConsole.service.ts +++ b/src/app/services/nodeConsole.service.ts @@ -1,5 +1,5 @@ import { EventEmitter, Injectable } from '@angular/core'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Subject } from 'rxjs'; import { Node } from '../cartography/models/node'; import { Router } from '@angular/router'; @@ -66,13 +66,13 @@ export class NodeConsoleService { return this.defaultConsoleHeight / this.defaultNumberOfRows; } - getUrl(server: Server, node: Node) { + getUrl(controller:Controller , node: Node) { let protocol:string = "ws" - if (server.protocol === "https:") { + if (controller.protocol === "https:") { protocol = "wss" } - return `${protocol}://${server.host}:${server.port}/${environment.current_version}/projects/${node.project_id}/nodes/${node.node_id}/console/ws` + return `${protocol}://${controller.host}:${controller.port}/${environment.current_version}/projects/${node.project_id}/nodes/${node.node_id}/console/ws` } openConsolesForAllNodesInWidget(nodes: Node[]) { diff --git a/src/app/services/notification.service.ts b/src/app/services/notification.service.ts index c159a83a..e0f01206 100644 --- a/src/app/services/notification.service.ts +++ b/src/app/services/notification.service.ts @@ -1,25 +1,25 @@ import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; @Injectable() export class NotificationService { - notificationsPath(server: Server): string { + notificationsPath(controller:Controller ): string { let protocol:string = "ws" - if (server.protocol === "https:") { + if (controller.protocol === "https:") { protocol = "wss" } - return `${protocol}://${server.host}:${server.port}/${environment.current_version}/notifications/ws?token=${server.authToken}`; + return `${protocol}://${controller.host}:${controller.port}/${environment.current_version}/notifications/ws?token=${controller.authToken}`; } - projectNotificationsPath(server: Server, project_id: string): string { + projectNotificationsPath(controller:Controller , project_id: string): string { let protocol:string = "ws" - if (server.protocol === "https:") { + if (controller.protocol === "https:") { protocol = "wss" } - return `${protocol}://${server.host}:${server.port}/${environment.current_version}/projects/${project_id}/notifications/ws?token=${server.authToken}`; + return `${protocol}://${controller.host}:${controller.port}/${environment.current_version}/projects/${project_id}/notifications/ws?token=${controller.authToken}`; } } diff --git a/src/app/services/packet-capture.service.ts b/src/app/services/packet-capture.service.ts index 890543e6..943d0310 100644 --- a/src/app/services/packet-capture.service.ts +++ b/src/app/services/packet-capture.service.ts @@ -1,15 +1,15 @@ import { Injectable } from '@angular/core'; import { Link } from '../models/link'; import { Project } from '../models/project'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; @Injectable() export class PacketCaptureService { constructor() {} - startCapture(server: Server, project: Project, link: Link, name: string) { + startCapture(controller:Controller , project: Project, link: Link, name: string) { location.assign( - `gns3+pcap://${server.host}:${server.port}?project_id=${project.project_id}&link_id=${link.link_id}&name=${name}` + `gns3+pcap://${controller.host}:${controller.port}?project_id=${project.project_id}&link_id=${link.link_id}&name=${name}` ); } } diff --git a/src/app/services/permissions.service.spec.ts b/src/app/services/permissions.service.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/services/permissions.service.ts b/src/app/services/permissions.service.ts new file mode 100644 index 00000000..7ee71e87 --- /dev/null +++ b/src/app/services/permissions.service.ts @@ -0,0 +1,42 @@ +/* +* 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'; +import {HttpController} from "./http-controller.service"; +import {Controller} from "../models/controller"; +import {Permission} from "../models/api/permission"; +import {Observable} from "rxjs/Rx"; + +@Injectable({ + providedIn: 'root' +}) +export class PermissionsService { + + constructor(private httpController: HttpController) { + } + + list(controller: Controller) { + return this.httpController.get(controller, '/permissions'); + } + + add(controller: Controller, permission: Permission): Observable { + return this.httpController.post(controller, '/permissions', permission); + } + + update(controller: Controller, permission: Permission): Observable { + return this.httpController.put(controller, `/permissions/${permission.permission_id}`, permission); + } + + delete(controller: Controller, permission_id: string) { + return this.httpController.delete(controller, `/permissions/${permission_id}`); + } +} diff --git a/src/app/services/project.service.spec.ts b/src/app/services/project.service.spec.ts index d3719f07..5d1f5502 100644 --- a/src/app/services/project.service.spec.ts +++ b/src/app/services/project.service.spec.ts @@ -4,13 +4,13 @@ import { TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; import { of } from 'rxjs'; import { Project } from '../models/project'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { ProjectService } from './project.service'; import { RecentlyOpenedProjectService } from './recentlyOpenedProject.service'; import { SettingsService } from './settings.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; /** * Mocks ProjectsService so it's not based on settings @@ -18,15 +18,15 @@ import { getTestServer } from './testing'; export class MockedProjectService { public projects: Project[] = []; - list(server: Server) { + list(controller:Controller ) { return of(this.projects); } - open(server: Server, project: Project) { + open(controller:Controller , project: Project) { return of(project); } - close(server: Server, project: Project) { + close(controller:Controller , project: Project) { return of(project); } @@ -34,22 +34,22 @@ export class MockedProjectService { return project.readonly; } - links(server: Server, project_id: string) { + links(controller:Controller , project_id: string) { return of([]); } - delete(server: Server, project_id: string) { + delete(controller:Controller , project_id: string) { return of(project_id); } - duplicate(server: Server, project_id: string) { + duplicate(controller:Controller , project_id: string) { return of(project_id); } - getStatistics(server: Server, project_id: string) { + getStatistics(controller:Controller , project_id: string) { return of({}); } - exportPortableProject(server: Server, formData:{}) { + exportPortableProject(controller:Controller , formData:{}) { return of({}); } getCompression() { @@ -63,16 +63,16 @@ export class MockedProjectService { describe('ProjectService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; + let httpController: HttpController; let service: ProjectService; - let server: Server; + let controller:Controller ; let settingsService: SettingsService; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], providers: [ - HttpServer, + HttpController, ProjectService, RecentlyOpenedProjectService, { provide: SettingsService }, @@ -81,11 +81,11 @@ describe('ProjectService', () => { httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); + httpController = TestBed.get(HttpController); service = TestBed.get(ProjectService); settingsService = TestBed.get(SettingsService); - server = getTestServer(); + controller = getTestController(); }); afterEach(() => { @@ -97,14 +97,14 @@ describe('ProjectService', () => { }); it('should get the project', () => { - service.get(server, 'myproject').subscribe(); + service.get(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject`); expect(req.request.method).toEqual('GET'); }); it('should open the project', () => { - service.open(server, 'myproject').subscribe(); + service.open(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/open`); expect(req.request.method).toEqual('POST'); @@ -112,7 +112,7 @@ describe('ProjectService', () => { }); it('should close the project', () => { - service.close(server, 'myproject').subscribe(); + service.close(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/close`); expect(req.request.method).toEqual('POST'); @@ -120,42 +120,42 @@ describe('ProjectService', () => { }); it('should list projects', () => { - service.list(server).subscribe(); + service.list(controller).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects`); expect(req.request.method).toEqual('GET'); }); it('should get nodes of project', () => { - service.nodes(server, 'myproject').subscribe(); + service.nodes(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/nodes`); expect(req.request.method).toEqual('GET'); }); it('should get links of project', () => { - service.links(server, 'myproject').subscribe(); + service.links(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/links`); expect(req.request.method).toEqual('GET'); }); it('should get drawings of project', () => { - service.drawings(server, 'myproject').subscribe(); + service.drawings(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/drawings`); expect(req.request.method).toEqual('GET'); }); it('should delete the project', () => { - service.delete(server, 'myproject').subscribe(); + service.delete(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject`); expect(req.request.method).toEqual('DELETE'); }); it('should duplicate the project', () => { - service.duplicate(server, 'projectId', 'projectName').subscribe(); + service.duplicate(controller, 'projectId', 'projectName').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/projectId/duplicate`); expect(req.request.method).toEqual('POST'); diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 9e356ad1..49035b3a 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -5,8 +5,8 @@ import { Drawing } from '../cartography/models/drawing'; import { Node } from '../cartography/models/node'; import { Link } from '../models/link'; import { Project } from '../models/project'; -import { Server } from '../models/server'; -import { HttpServer } from './http-server.service'; +import{ Controller } from '../models/controller'; +import { HttpController } from './http-controller.service'; import { RecentlyOpenedProjectService } from './recentlyOpenedProject.service'; import { SettingsService } from './settings.service'; @@ -34,7 +34,7 @@ export class ProjectService { public projectListSubject = new Subject(); constructor( - private httpServer: HttpServer, + private httpController: HttpController, private settingsService: SettingsService, private recentlyOpenedProjectService: RecentlyOpenedProjectService ) {} @@ -43,49 +43,50 @@ export class ProjectService { this.projectListSubject.next(true); } - getReadmeFile(server: Server, project_id: string) { - return this.httpServer.getText(server, `/projects/${project_id}/files/README.txt`); + getReadmeFile(controller:Controller , project_id: string) { + return this.httpController.getText(controller, `/projects/${project_id}/files/README.txt`); } - postReadmeFile(server: Server, project_id: string, readme: string) { - return this.httpServer.post(server, `/projects/${project_id}/files/README.txt`, readme); + postReadmeFile(controller:Controller , project_id: string, readme: string) { + return this.httpController.post(controller, `/projects/${project_id}/files/README.txt`, readme); } - get(server: Server, project_id: string) { - return this.httpServer.get(server, `/projects/${project_id}`); + get(controller:Controller , project_id: string) { + return this.httpController.get(controller, `/projects/${project_id}`); } - open(server: Server, project_id: string) { - return this.httpServer.post(server, `/projects/${project_id}/open`, {}); + open(controller:Controller , project_id: string) { + return this.httpController.post(controller, `/projects/${project_id}/open`, {}); } - close(server: Server, project_id: string) { + close(controller:Controller , project_id: string) { this.recentlyOpenedProjectService.removeData(); - return this.httpServer.post(server, `/projects/${project_id}/close`, {}); + return this.httpController.post(controller, `/projects/${project_id}/close`, {}); } - list(server: Server) { - return this.httpServer.get(server, '/projects'); + list(controller:Controller ) { + return this.httpController.get(controller, '/projects'); } - nodes(server: Server, project_id: string) { - return this.httpServer.get(server, `/projects/${project_id}/nodes`); + nodes(controller:Controller , project_id: string) { + return this.httpController.get(controller, `/projects/${project_id}/nodes`); } - links(server: Server, project_id: string) { - return this.httpServer.get(server, `/projects/${project_id}/links`); + links(controller:Controller , project_id: string) { + debugger + return this.httpController.get(controller, `/projects/${project_id}/links`); } - drawings(server: Server, project_id: string) { - return this.httpServer.get(server, `/projects/${project_id}/drawings`); + drawings(controller:Controller , project_id: string) { + return this.httpController.get(controller, `/projects/${project_id}/drawings`); } - add(server: Server, project_name: string, project_id: string): Observable { - return this.httpServer.post(server, `/projects`, { name: project_name, project_id: project_id }); + add(controller:Controller , project_name: string, project_id: string): Observable { + return this.httpController.post(controller, `/projects`, { name: project_name, project_id: project_id }); } - update(server: Server, project: Project): Observable { - return this.httpServer.put(server, `/projects/${project.project_id}`, { + update(controller:Controller , project: Project): Observable { + return this.httpController.put(controller, `/projects/${project.project_id}`, { auto_close: project.auto_close, auto_open: project.auto_open, auto_start: project.auto_start, @@ -98,28 +99,28 @@ export class ProjectService { }); } - delete(server: Server, project_id: string): Observable { - return this.httpServer.delete(server, `/projects/${project_id}`); + delete(controller:Controller , project_id: string): Observable { + return this.httpController.delete(controller, `/projects/${project_id}`); } - getUploadPath(server: Server, uuid: string, project_name: string) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/projects/${uuid}/import?name=${project_name}`; + getUploadPath(controller:Controller , uuid: string, project_name: string) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/projects/${uuid}/import?name=${project_name}`; } - getExportPath(server: Server, project: Project) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/projects/${project.project_id}/export`; + getExportPath(controller:Controller , project: Project) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/projects/${project.project_id}/export`; } - export(server: Server, project_id: string): Observable { - return this.httpServer.get(server, `/projects/${project_id}/export`); + export(controller:Controller , project_id: string): Observable { + return this.httpController.get(controller, `/projects/${project_id}/export`); } - getStatistics(server: Server, project_id: string): Observable { - return this.httpServer.get(server, `/projects/${project_id}/stats`); + getStatistics(controller:Controller , project_id: string): Observable { + return this.httpController.get(controller, `/projects/${project_id}/stats`); } - duplicate(server: Server, project_id: string, project_name): Observable { - return this.httpServer.post(server, `/projects/${project_id}/duplicate`, { name: project_name }); + duplicate(controller:Controller , project_id: string, project_name): Observable { + return this.httpController.post(controller, `/projects/${project_id}/duplicate`, { name: project_name }); } isReadOnly(project: Project) { @@ -137,11 +138,11 @@ export class ProjectService { }; - getexportPortableProjectPath(server:Server, project_id: string,formData:any={}) { + getexportPortableProjectPath(controller :Controller, project_id: string,formData:any={}) { if (formData.compression_level != null && formData.compression_level !='') { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/projects/${project_id}/export?include_snapshots=${formData.include_snapshots}&include_images=${formData.include_base_image}&reset_mac_addresses=${formData.reset_mac_address}&compression=${formData.compression}&compression_level=${formData.compression_level}&token=${server.authToken}`; + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/projects/${project_id}/export?include_snapshots=${formData.include_snapshots}&include_images=${formData.include_base_image}&reset_mac_addresses=${formData.reset_mac_address}&compression=${formData.compression}&compression_level=${formData.compression_level}&token=${controller.authToken}`; } else { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/projects/${project_id}/export?include_snapshots=${formData.include_snapshots}&include_images=${formData.include_base_image}&reset_mac_addresses=${formData.reset_mac_address}&compression=${formData.compression}&token=${server.authToken}`; + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/projects/${project_id}/export?include_snapshots=${formData.include_snapshots}&include_images=${formData.include_base_image}&reset_mac_addresses=${formData.reset_mac_address}&compression=${formData.compression}&token=${controller.authToken}`; } } diff --git a/src/app/services/qemu.service.spec.ts b/src/app/services/qemu.service.spec.ts index b2c80f11..3379270c 100644 --- a/src/app/services/qemu.service.spec.ts +++ b/src/app/services/qemu.service.spec.ts @@ -2,29 +2,29 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { QemuTemplate } from '../models/templates/qemu-template'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { QemuService } from './qemu.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; describe('QemuService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, QemuService], + providers: [HttpController, QemuService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); }); afterEach(() => { @@ -80,7 +80,7 @@ describe('QemuService', () => { usage: '', }; - service.saveTemplate(server, template).subscribe(); + service.saveTemplate(controller, template).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates/1`); expect(req.request.method).toEqual('PUT'); @@ -132,7 +132,7 @@ describe('QemuService', () => { usage: '', }; - service.addTemplate(server, template).subscribe(); + service.addTemplate(controller, template).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates`); expect(req.request.method).toEqual('POST'); diff --git a/src/app/services/qemu.service.ts b/src/app/services/qemu.service.ts index 62b38c83..0bf589e9 100644 --- a/src/app/services/qemu.service.ts +++ b/src/app/services/qemu.service.ts @@ -3,45 +3,45 @@ import { Observable } from 'rxjs'; import { QemuBinary } from '../models/qemu/qemu-binary'; import { QemuImage } from '../models/qemu/qemu-image'; import { QemuImg } from '../models/qemu/qemu-img'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { QemuTemplate } from '../models/templates/qemu-template'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class QemuService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - getTemplates(server: Server): Observable { - return this.httpServer.get(server, '/templates') as Observable; + getTemplates(controller:Controller ): Observable { + return this.httpController.get(controller, '/templates') as Observable; } - getTemplate(server: Server, template_id: string): Observable { - return this.httpServer.get(server, `/templates/${template_id}`) as Observable; + getTemplate(controller:Controller , template_id: string): Observable { + return this.httpController.get(controller, `/templates/${template_id}`) as Observable; } - getImagePath(server: Server, filename: string): string { - return `${server.protocol}//${server.host}:${server.port}/images/upload/${filename}`; + getImagePath(controller:Controller , filename: string): string { + return `${controller.protocol}//${controller.host}:${controller.port}/images/upload/${filename}`; } - getBinaries(server: Server): Observable { - return this.httpServer.get(server, '/computes/local/qemu/binaries') as Observable; + getBinaries(controller:Controller ): Observable { + return this.httpController.get(controller, '/computes/local/qemu/binaries') as Observable; } - getImages(server: Server): Observable { - return this.httpServer.get(server, '/images?image_type=qemu') as Observable; + getImages(controller:Controller ): Observable { + return this.httpController.get(controller, '/images?image_type=qemu') as Observable; } - addImage(server: Server, qemuImg: QemuImg): Observable { - return this.httpServer.post(server, '/images/upload', qemuImg) as Observable; + addImage(controller:Controller , qemuImg: QemuImg): Observable { + return this.httpController.post(controller, '/images/upload', qemuImg) as Observable; } - addTemplate(server: Server, qemuTemplate: QemuTemplate): Observable { - return this.httpServer.post(server, `/templates`, qemuTemplate) as Observable; + addTemplate(controller:Controller , qemuTemplate: QemuTemplate): Observable { + return this.httpController.post(controller, `/templates`, qemuTemplate) as Observable; } - saveTemplate(server: Server, qemuTemplate: QemuTemplate): Observable { - return this.httpServer.put( - server, + saveTemplate(controller:Controller , qemuTemplate: QemuTemplate): Observable { + return this.httpController.put( + controller, `/templates/${qemuTemplate.template_id}`, qemuTemplate ) as Observable; diff --git a/src/app/services/recentlyOpenedProject.service.ts b/src/app/services/recentlyOpenedProject.service.ts index d9753e96..610414d0 100644 --- a/src/app/services/recentlyOpenedProject.service.ts +++ b/src/app/services/recentlyOpenedProject.service.ts @@ -2,36 +2,36 @@ import { Injectable } from '@angular/core'; @Injectable() export class RecentlyOpenedProjectService { - private serverId: string; + private controllerId: string; private projectId: string; - private serverIdProjectList: string; + private controllerIdProjectList: string; - setServerId(serverId: string) { - this.serverId = serverId; + setcontrollerId(controllerId: string) { + this.controllerId = controllerId; } setProjectId(projectId: string) { this.projectId = projectId; } - setServerIdProjectList(serverId: string) { - this.serverIdProjectList = serverId; + setcontrollerIdProjectList(controllerId: string) { + this.controllerIdProjectList = controllerId; } - getServerId(): string { - return this.serverId; + getcontrollerId(): string { + return this.controllerId; } getProjectId(): string { return this.projectId; } - getServerIdProjectList(): string { - return this.serverIdProjectList; + getcontrollerIdProjectList(): string { + return this.controllerIdProjectList; } removeData() { - (this.serverId = ''), (this.projectId = ''); + (this.controllerId = ''), (this.projectId = ''); } } diff --git a/src/app/services/role.service.spec.ts b/src/app/services/role.service.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/services/role.service.ts b/src/app/services/role.service.ts new file mode 100644 index 00000000..b5184fd6 --- /dev/null +++ b/src/app/services/role.service.ts @@ -0,0 +1,55 @@ +/* +* 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'; +import {HttpController} from "./http-controller.service"; +import {Controller} from "../models/controller"; +import {Group} from "../models/groups/group"; +import {Role} from "../models/api/role"; +import {Permission} from "@models/api/permission"; + +@Injectable({ + providedIn: 'root' +}) +export class RoleService { + + constructor(private httpController: HttpController) { } + + get(controller: Controller) { + return this.httpController.get(controller, '/roles'); + } + + delete(controller: Controller, role_id: string) { + return this.httpController.delete(controller, `/roles/${role_id}`); + } + + create(controller: Controller, newRole: { name: string; description: string }) { + return this.httpController.post(controller, `/roles`, newRole); + } + + getById(controller: Controller, roleId: string) { + return this.httpController.get(controller, `/roles/${roleId}`); + } + + update(controller: Controller, role: Role) { + return this.httpController.put(controller, `/roles/${role.role_id}`, {name: role.name, description: role.description}); + } + + addPermission(controller: Controller, role: Role, permission: Permission) { + return this.httpController.put(controller, `/roles/${role.role_id}/permissions/${permission.permission_id}`, {}); + + } + + removePermission(controller: Controller, role: Role, permission: Permission) { + return this.httpController.delete(controller, `/roles/${role.role_id}/permissions/${permission.permission_id}`); + } +} diff --git a/src/app/services/server-management.service.ts b/src/app/services/server-management.service.ts deleted file mode 100644 index 10376c07..00000000 --- a/src/app/services/server-management.service.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Injectable, OnDestroy } from '@angular/core'; -import { ElectronService } from 'ngx-electron'; -import { Subject } from 'rxjs'; -import { Server } from '../models/server'; - -export interface ServerStateEvent { - serverName: string; - status: 'starting' | 'started' | 'errored' | 'stopped' | 'stderr'; - message: string; -} - -@Injectable() -export class ServerManagementService implements OnDestroy { - serverStatusChanged = new Subject(); - - constructor(private electronService: ElectronService) { - if (this.electronService.isElectronApp) { - this.electronService.ipcRenderer.on(this.statusChannel, (event, data) => { - this.serverStatusChanged.next(data); - }); - } - } - - get statusChannel() { - return 'local-server-status-events'; - } - - async start(server: Server) { - var startingEvent: ServerStateEvent = { - serverName: server.name, - status: 'starting', - message: '', - }; - this.serverStatusChanged.next(startingEvent); - return await this.electronService.remote.require('./local-server.js').startLocalServer(server); - } - - async stop(server: Server) { - return await this.electronService.remote.require('./local-server.js').stopLocalServer(server); - } - - async stopAll() { - return await this.electronService.remote.require('./local-server.js').stopAllLocalServers(); - } - - getRunningServers() { - if (this.electronService.isElectronApp) { - return this.electronService.remote.require('./local-server.js').getRunningServers(); - } - return []; - } - - ngOnDestroy() { - if (this.electronService.isElectronApp) { - this.electronService.ipcRenderer.removeAllListeners(this.statusChannel); - } - } -} diff --git a/src/app/services/server-settings.service.spec.ts b/src/app/services/server-settings.service.spec.ts deleted file mode 100644 index 10274799..00000000 --- a/src/app/services/server-settings.service.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { inject, TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; -import { Server } from '../models/server'; -import { QemuSettings } from '../models/settings/qemu-settings'; -import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; -import { ServerSettingsService } from './server-settings.service'; - -export class MockedServerSettingsService { - getSettingsForQemu(server: Server) { - return of([]); - } - - updateSettingsForQemu(server: Server, qemuSettings: QemuSettings) { - return of([]); - } -} - -describe('ServerSettingsService', () => { - let httpServer: HttpServer; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, ServerSettingsService], - }); - - httpServer = TestBed.get(HttpServer); - }); - - it('should be created', inject([ServerSettingsService], (service: ServerSettingsService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/src/app/services/server-settings.service.ts b/src/app/services/server-settings.service.ts deleted file mode 100644 index dd25bafd..00000000 --- a/src/app/services/server-settings.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Server } from '../models/server'; -import { ServerSettings } from '../models/serverSettings'; -import { QemuSettings } from '../models/settings/qemu-settings'; -import { HttpServer } from './http-server.service'; - -@Injectable() -export class ServerSettingsService { - constructor(private httpServer: HttpServer) {} - - get(server: Server) { - return this.httpServer.get(server, `/settings`); - } - - update(server: Server, serverSettings: ServerSettings) { - return this.httpServer.post(server, `/settings`, serverSettings); - } - - getSettingsForQemu(server: Server) { - return this.httpServer.get(server, `/settings/qemu`); - } - - updateSettingsForQemu(server: Server, qemuSettings: QemuSettings) { - return this.httpServer.put(server, `/settings/qemu`, { - enable_hardware_acceleration: qemuSettings.enable_hardware_acceleration, - require_hardware_acceleration: qemuSettings.require_hardware_acceleration, - }); - } -} diff --git a/src/app/services/server.database.ts b/src/app/services/server.database.ts deleted file mode 100644 index cd3abaea..00000000 --- a/src/app/services/server.database.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { Server } from '../models/server'; - -@Injectable() -export class ServerDatabase { - dataChange: BehaviorSubject = new BehaviorSubject([]); - - constructor() {} - - get data(): Server[] { - return this.dataChange.value; - } - - public addServer(server: Server) { - const servers = this.data.slice(); - servers.push(server); - this.dataChange.next(servers); - } - - public addServers(servers: Server[]) { - this.dataChange.next(servers); - } - - public remove(server: Server) { - const index = this.data.indexOf(server); - if (index >= 0) { - this.data.splice(index, 1); - this.dataChange.next(this.data.slice()); - } - } - - public find(serverName: string) { - return this.data.find((server) => server.name === serverName); - } - - public findIndex(serverName: string) { - return this.data.findIndex((server) => server.name === serverName); - } - - public update(server: Server) { - const index = this.findIndex(server.name); - if (index >= 0) { - this.data[index] = server; - this.dataChange.next(this.data.slice()); - } - } -} diff --git a/src/app/services/server.service.spec.ts b/src/app/services/server.service.spec.ts deleted file mode 100644 index 9b4e4f10..00000000 --- a/src/app/services/server.service.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Server } from '../models/server'; - -export class MockedServerService { - public servers: Server[] = []; - - public create(server: Server) { - return new Promise((resolve, reject) => { - this.servers.push(server); - resolve(server); - }); - } - - public get(server_id: number) { - const server = new Server(); - server.id = server_id; - return Promise.resolve(server); - } - - public getLocalServer(hostname: string, port: number) { - return new Promise((resolve, reject) => { - const server = new Server(); - server.id = 99; - resolve(server); - }); - } - - public findAll() { - return new Promise((resolve, reject) => { - resolve(this.servers); - }); - } - - public getServerUrl(server: Server) { - return `${server.host}:${server.port}`; - } -} diff --git a/src/app/services/server.service.ts b/src/app/services/server.service.ts deleted file mode 100644 index f40f57a3..00000000 --- a/src/app/services/server.service.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { Server, ServerProtocol } from '../models/server'; -import { HttpServer } from './http-server.service'; - -@Injectable() -export class ServerService { - private serverIds: string[] = []; - public serviceInitialized: Subject = new Subject(); - public isServiceInitialized: boolean; - - constructor(private httpServer: HttpServer) { - this.serverIds = this.getServerIds(); - this.isServiceInitialized = true; - this.serviceInitialized.next(this.isServiceInitialized); - } - - getServerIds() : string[]{ - let str = localStorage.getItem("serverIds"); - if (str?.length > 0) { - return str.split(","); - } - return []; - } - - updateServerIds() { - localStorage.removeItem("serverIds"); - localStorage.setItem("serverIds", this.serverIds.toString()); - } - - public get(id: number): Promise { - let server: Server = JSON.parse(localStorage.getItem(`server-${id}`)); - let promise = new Promise((resolve) => { - resolve(server); - }); - return promise; - } - - public create(server: Server) { - server.id = this.serverIds.length + 1; - localStorage.setItem(`server-${server.id}`, JSON.stringify(server)); - - this.serverIds.push(`server-${server.id}`); - this.updateServerIds(); - - let promise = new Promise((resolve) => { - resolve(server); - }); - return promise; - } - - public update(server: Server) { - localStorage.removeItem(`server-${server.id}`); - localStorage.setItem(`server-${server.id}`, JSON.stringify(server)); - - let promise = new Promise((resolve) => { - resolve(server); - }); - return promise; - } - - public findAll() { - let promise = new Promise((resolve) => { - let servers: Server[] = []; - this.serverIds.forEach((n) => { - let server: Server = JSON.parse(localStorage.getItem(n)); - servers.push(server); - }); - resolve(servers); - }); - return promise; - } - - public delete(server: Server) { - localStorage.removeItem(`server-${server.id}`); - this.serverIds = this.serverIds.filter((n) => n !== `server-${server.id}`); - this.updateServerIds(); - - let promise = new Promise((resolve) => { - resolve(server.id); - }); - return promise; - } - - public getServerUrl(server: Server) { - return `${server.protocol}//${server.host}:${server.port}/`; - } - - public checkServerVersion(server: Server): Observable { - return this.httpServer.get(server, '/version'); - } - - public getLocalServer(host: string, port: number) { - const promise = new Promise((resolve, reject) => { - this.findAll().then((servers: Server[]) => { - const local = servers.find((server) => server.location === 'bundled'); - if (local) { - local.host = host; - local.port = port; - local.protocol = location.protocol as ServerProtocol; - this.update(local).then((updated) => { - resolve(updated); - }, reject); - } else { - const server = new Server(); - server.name = 'local'; - server.host = host; - server.port = port; - server.location = 'bundled'; - server.protocol = location.protocol as ServerProtocol; - this.create(server).then((created) => { - resolve(created); - }, reject); - } - }, reject); - }); - - return promise; - } -} diff --git a/src/app/services/snapshot.service.spec.ts b/src/app/services/snapshot.service.spec.ts index 2c677c0b..878daa3b 100644 --- a/src/app/services/snapshot.service.spec.ts +++ b/src/app/services/snapshot.service.spec.ts @@ -2,31 +2,31 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Snapshot } from '../models/snapshot'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { SnapshotService } from './snapshot.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; describe('SnapshotService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; + let httpController: HttpController; let service: SnapshotService; - let server: Server; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, HttpClient,SnapshotService], + providers: [HttpController, HttpClient,SnapshotService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); + httpController = TestBed.get(HttpController); service = TestBed.get(SnapshotService); - server = getTestServer(); + controller = getTestController(); }); afterEach(() => { @@ -39,7 +39,7 @@ describe('SnapshotService', () => { it('should create snapshot', inject([SnapshotService], (service: SnapshotService) => { const snapshot = new Snapshot(); - service.create(server, 'myproject', snapshot).subscribe(); + service.create(controller, 'myproject', snapshot).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/snapshots`); expect(req.request.method).toEqual('POST'); @@ -47,7 +47,7 @@ describe('SnapshotService', () => { })); it('should list snapshots', inject([SnapshotService], (service: SnapshotService) => { - service.list(server, 'myproject').subscribe(); + service.list(controller, 'myproject').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/projects/myproject/snapshots`); expect(req.request.method).toEqual('GET'); diff --git a/src/app/services/snapshot.service.ts b/src/app/services/snapshot.service.ts index e1973e81..cc03bb51 100644 --- a/src/app/services/snapshot.service.ts +++ b/src/app/services/snapshot.service.ts @@ -1,25 +1,25 @@ import { Injectable } from '@angular/core'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Snapshot } from '../models/snapshot'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class SnapshotService { - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} - create(server: Server, project_id: string, snapshot: Snapshot) { - return this.httpServer.post(server, `/projects/${project_id}/snapshots`, snapshot); + create(controller:Controller , project_id: string, snapshot: Snapshot) { + return this.httpController.post(controller, `/projects/${project_id}/snapshots`, snapshot); } - delete(server: Server, project_id: string, snapshot_id: string) { - return this.httpServer.delete(server, `/projects/${project_id}/snapshots/${snapshot_id}`); + delete(controller:Controller , project_id: string, snapshot_id: string) { + return this.httpController.delete(controller, `/projects/${project_id}/snapshots/${snapshot_id}`); } - list(server: Server, project_id: string) { - return this.httpServer.get(server, `/projects/${project_id}/snapshots`); + list(controller:Controller , project_id: string) { + return this.httpController.get(controller, `/projects/${project_id}/snapshots`); } - restore(server: Server, project_id: string, snapshot_id: string) { - return this.httpServer.post(server, `/projects/${project_id}/snapshots/${snapshot_id}/restore`, {}); + restore(controller:Controller , project_id: string, snapshot_id: string) { + return this.httpController.post(controller, `/projects/${project_id}/snapshots/${snapshot_id}/restore`, {}); } } diff --git a/src/app/services/symbol.service.spec.ts b/src/app/services/symbol.service.spec.ts index 153aaee4..f865bfe3 100644 --- a/src/app/services/symbol.service.spec.ts +++ b/src/app/services/symbol.service.spec.ts @@ -3,29 +3,29 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { inject, TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; import { of } from 'rxjs'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Symbol } from '../models/symbol'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { SymbolService } from './symbol.service'; -import { getTestServer } from './testing'; +import { getTestController } from './testing'; describe('SymbolService', () => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; - let httpServer: HttpServer; - let server: Server; + let httpController: HttpController; + let controller:Controller ; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [HttpServer, SymbolService], + providers: [HttpController, SymbolService], }); httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); - httpServer = TestBed.get(HttpServer); - server = getTestServer(); + httpController = TestBed.get(HttpController); + controller = getTestController(); }); afterEach(() => { @@ -37,14 +37,14 @@ describe('SymbolService', () => { })); it('should list symbols', inject([SymbolService], (service: SymbolService) => { - service.list(server).subscribe(); + service.list(controller).subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/symbols`); expect(req.request.method).toEqual('GET'); })); it('should get raw symbol', inject([SymbolService], (service: SymbolService) => { - service.raw(server, ':my/tested.png').subscribe(); + service.raw(controller, ':my/tested.png').subscribe(); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/symbols/:my/tested.png/raw`); expect(req.request.method).toEqual('GET'); diff --git a/src/app/services/symbol.service.ts b/src/app/services/symbol.service.ts index bf7eeb05..7304128a 100644 --- a/src/app/services/symbol.service.ts +++ b/src/app/services/symbol.service.ts @@ -3,9 +3,9 @@ import { Template } from '../models/template'; import { BehaviorSubject, Observable } from 'rxjs'; import { shareReplay } from 'rxjs/operators'; import { Node } from '../cartography/models/node'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Symbol } from '../models/symbol'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { environment } from 'environments/environment'; const CACHE_SIZE = 1; @@ -16,7 +16,7 @@ export class SymbolService { private cache: Observable; private maximumSymbolSize: number = 80; - constructor(private httpServer: HttpServer) {} + constructor(private httpController: HttpController) {} getMaximumSymbolSize() { return this.maximumSymbolSize; @@ -26,9 +26,9 @@ export class SymbolService { return this.symbols.getValue().find((symbol: Symbol) => symbol.symbol_id === symbol_id); } - getDimensions(server: Server, symbol_id: string): Observable { + getDimensions(controller:Controller , symbol_id: string): Observable { const encoded_uri = encodeURI(symbol_id); - return this.httpServer.get(server, `/symbols/${encoded_uri}/dimensions`); + return this.httpController.get(controller, `/symbols/${encoded_uri}/dimensions`); } scaleDimensionsForNode(node: Node): SymbolDimension { @@ -43,30 +43,30 @@ export class SymbolService { return this.symbols.getValue().find((symbol: Symbol) => symbol.filename === symbol_filename); } - add(server: Server, symbolName: string, symbol: string) { + add(controller:Controller , symbolName: string, symbol: string) { this.cache = null; - return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol); + return this.httpController.post(controller, `/symbols/${symbolName}/raw`, symbol); } - load(server: Server): Observable { - return this.httpServer.get(server, '/symbols'); + load(controller:Controller ): Observable { + return this.httpController.get(controller, '/symbols'); } - list(server: Server) { + list(controller:Controller ) { if (!this.cache) { - this.cache = this.load(server).pipe(shareReplay(CACHE_SIZE)); + this.cache = this.load(controller).pipe(shareReplay(CACHE_SIZE)); } return this.cache; } - raw(server: Server, symbol_id: string) { + raw(controller:Controller , symbol_id: string) { const encoded_uri = encodeURI(symbol_id); - return this.httpServer.getText(server, `/symbols/${encoded_uri}/raw`); + return this.httpController.getText(controller, `/symbols/${encoded_uri}/raw`); } - getSymbolFromTemplate(server: Server, template: Template) { - return `${server.protocol}//${server.host}:${server.port}/${environment.current_version}/symbols/${template.symbol}/raw`; + getSymbolFromTemplate(controller:Controller , template: Template) { + return `${controller.protocol}//${controller.host}:${controller.port}/${environment.current_version}/symbols/${template.symbol}/raw`; } } diff --git a/src/app/services/template.service.spec.ts b/src/app/services/template.service.spec.ts index 82cb9b64..46232238 100644 --- a/src/app/services/template.service.spec.ts +++ b/src/app/services/template.service.spec.ts @@ -2,9 +2,9 @@ import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { environment } from 'environments/environment'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; import { TemplateService } from './template.service'; describe('TemplateService', () => { @@ -15,7 +15,7 @@ describe('TemplateService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, AppTestingModule], - providers: [TemplateService, HttpServer, HttpClient], + providers: [TemplateService, HttpController, HttpClient], }); httpClient = TestBed.get(HttpClient); @@ -27,12 +27,12 @@ describe('TemplateService', () => { httpTestingController.verify(); }); - it('should ask for the list from server', () => { - const server = new Server(); - server.host = '127.0.0.1'; - server.port = 3080; + it('should ask for the list from controller', () => { + const controller = new Controller (); + controller.host = '127.0.0.1'; + controller.port = 3080; - service.list(server).subscribe(() => {}); + service.list(controller).subscribe(() => {}); const req = httpTestingController.expectOne(`http://127.0.0.1:3080/${environment.current_version}/templates`); expect(req.request.url).toBe(`http://127.0.0.1:3080/${environment.current_version}/templates`); diff --git a/src/app/services/template.service.ts b/src/app/services/template.service.ts index 9d1fca0b..84e0fcc6 100644 --- a/src/app/services/template.service.ts +++ b/src/app/services/template.service.ts @@ -1,21 +1,21 @@ import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import 'rxjs/add/operator/map'; -import { Server } from '../models/server'; +import{ Controller } from '../models/controller'; import { Template } from '../models/template'; -import { HttpServer } from './http-server.service'; +import { HttpController } from './http-controller.service'; @Injectable() export class TemplateService { public newTemplateCreated: Subject